mirror of
https://github.com/home-assistant/core.git
synced 2025-07-23 13:17:32 +00:00
Add support for adjusting flux_led effects speed (#59679)
This commit is contained in:
parent
5550b5445b
commit
cb3b19b000
@ -35,7 +35,10 @@ from .const import (
|
|||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
PLATFORMS_BY_TYPE: Final = {DeviceType.Bulb: ["light"], DeviceType.Switch: ["switch"]}
|
PLATFORMS_BY_TYPE: Final = {
|
||||||
|
DeviceType.Bulb: ["light", "number"],
|
||||||
|
DeviceType.Switch: ["switch"],
|
||||||
|
}
|
||||||
DISCOVERY_INTERVAL: Final = timedelta(minutes=15)
|
DISCOVERY_INTERVAL: Final = timedelta(minutes=15)
|
||||||
REQUEST_REFRESH_DELAY: Final = 1.5
|
REQUEST_REFRESH_DELAY: Final = 1.5
|
||||||
|
|
||||||
|
@ -4,8 +4,31 @@ import asyncio
|
|||||||
import socket
|
import socket
|
||||||
from typing import Final
|
from typing import Final
|
||||||
|
|
||||||
|
from flux_led.const import (
|
||||||
|
COLOR_MODE_CCT as FLUX_COLOR_MODE_CCT,
|
||||||
|
COLOR_MODE_RGB as FLUX_COLOR_MODE_RGB,
|
||||||
|
COLOR_MODE_RGBW as FLUX_COLOR_MODE_RGBW,
|
||||||
|
COLOR_MODE_RGBWW as FLUX_COLOR_MODE_RGBWW,
|
||||||
|
)
|
||||||
|
|
||||||
|
from homeassistant.components.light import (
|
||||||
|
COLOR_MODE_COLOR_TEMP,
|
||||||
|
COLOR_MODE_RGB,
|
||||||
|
COLOR_MODE_RGBW,
|
||||||
|
COLOR_MODE_RGBWW,
|
||||||
|
)
|
||||||
|
|
||||||
DOMAIN: Final = "flux_led"
|
DOMAIN: Final = "flux_led"
|
||||||
|
|
||||||
|
|
||||||
|
FLUX_COLOR_MODE_TO_HASS: Final = {
|
||||||
|
FLUX_COLOR_MODE_RGB: COLOR_MODE_RGB,
|
||||||
|
FLUX_COLOR_MODE_RGBW: COLOR_MODE_RGBW,
|
||||||
|
FLUX_COLOR_MODE_RGBWW: COLOR_MODE_RGBWW,
|
||||||
|
FLUX_COLOR_MODE_CCT: COLOR_MODE_COLOR_TEMP,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
API: Final = "flux_api"
|
API: Final = "flux_api"
|
||||||
|
|
||||||
SIGNAL_STATE_UPDATED = "flux_led_{}_state_updated"
|
SIGNAL_STATE_UPDATED = "flux_led_{}_state_updated"
|
||||||
@ -48,6 +71,9 @@ CONF_SPEED_PCT: Final = "speed_pct"
|
|||||||
CONF_TRANSITION: Final = "transition"
|
CONF_TRANSITION: Final = "transition"
|
||||||
|
|
||||||
|
|
||||||
|
EFFECT_SUPPORT_MODES = {COLOR_MODE_RGB, COLOR_MODE_RGBW, COLOR_MODE_RGBWW}
|
||||||
|
|
||||||
|
|
||||||
CONF_CUSTOM_EFFECT_COLORS: Final = "custom_effect_colors"
|
CONF_CUSTOM_EFFECT_COLORS: Final = "custom_effect_colors"
|
||||||
CONF_CUSTOM_EFFECT_SPEED_PCT: Final = "custom_effect_speed_pct"
|
CONF_CUSTOM_EFFECT_SPEED_PCT: Final = "custom_effect_speed_pct"
|
||||||
CONF_CUSTOM_EFFECT_TRANSITION: Final = "custom_effect_transition"
|
CONF_CUSTOM_EFFECT_TRANSITION: Final = "custom_effect_transition"
|
||||||
|
@ -42,32 +42,11 @@ class FluxEntity(CoordinatorEntity):
|
|||||||
sw_version=str(self._device.version_num),
|
sw_version=str(self._device.version_num),
|
||||||
)
|
)
|
||||||
|
|
||||||
@property
|
|
||||||
def is_on(self) -> bool:
|
|
||||||
"""Return true if device is on."""
|
|
||||||
return cast(bool, self._device.is_on)
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def extra_state_attributes(self) -> dict[str, str]:
|
def extra_state_attributes(self) -> dict[str, str]:
|
||||||
"""Return the attributes."""
|
"""Return the attributes."""
|
||||||
return {"ip_address": self._device.ipaddr}
|
return {"ip_address": self._device.ipaddr}
|
||||||
|
|
||||||
async def async_turn_on(self, **kwargs: Any) -> None:
|
|
||||||
"""Turn the specified device on."""
|
|
||||||
await self._async_turn_on(**kwargs)
|
|
||||||
self.async_write_ha_state()
|
|
||||||
await self.coordinator.async_request_refresh()
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
async def _async_turn_on(self, **kwargs: Any) -> None:
|
|
||||||
"""Turn the specified device on."""
|
|
||||||
|
|
||||||
async def async_turn_off(self, **kwargs: Any) -> None:
|
|
||||||
"""Turn the specified device off."""
|
|
||||||
await self._device.async_turn_off()
|
|
||||||
self.async_write_ha_state()
|
|
||||||
await self.coordinator.async_request_refresh()
|
|
||||||
|
|
||||||
@callback
|
@callback
|
||||||
def _handle_coordinator_update(self) -> None:
|
def _handle_coordinator_update(self) -> None:
|
||||||
"""Handle updated data from the coordinator."""
|
"""Handle updated data from the coordinator."""
|
||||||
@ -85,3 +64,28 @@ class FluxEntity(CoordinatorEntity):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
await super().async_added_to_hass()
|
await super().async_added_to_hass()
|
||||||
|
|
||||||
|
|
||||||
|
class FluxOnOffEntity(FluxEntity):
|
||||||
|
"""Representation of a Flux entity that supports on/off."""
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_on(self) -> bool:
|
||||||
|
"""Return true if device is on."""
|
||||||
|
return cast(bool, self._device.is_on)
|
||||||
|
|
||||||
|
async def async_turn_on(self, **kwargs: Any) -> None:
|
||||||
|
"""Turn the specified device on."""
|
||||||
|
await self._async_turn_on(**kwargs)
|
||||||
|
self.async_write_ha_state()
|
||||||
|
await self.coordinator.async_request_refresh()
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
async def _async_turn_on(self, **kwargs: Any) -> None:
|
||||||
|
"""Turn the specified device on."""
|
||||||
|
|
||||||
|
async def async_turn_off(self, **kwargs: Any) -> None:
|
||||||
|
"""Turn the specified device off."""
|
||||||
|
await self._device.async_turn_off()
|
||||||
|
self.async_write_ha_state()
|
||||||
|
await self.coordinator.async_request_refresh()
|
||||||
|
@ -6,13 +6,6 @@ import logging
|
|||||||
import random
|
import random
|
||||||
from typing import Any, Final, cast
|
from typing import Any, Final, cast
|
||||||
|
|
||||||
from flux_led.const import (
|
|
||||||
COLOR_MODE_CCT as FLUX_COLOR_MODE_CCT,
|
|
||||||
COLOR_MODE_DIM as FLUX_COLOR_MODE_DIM,
|
|
||||||
COLOR_MODE_RGB as FLUX_COLOR_MODE_RGB,
|
|
||||||
COLOR_MODE_RGBW as FLUX_COLOR_MODE_RGBW,
|
|
||||||
COLOR_MODE_RGBWW as FLUX_COLOR_MODE_RGBWW,
|
|
||||||
)
|
|
||||||
from flux_led.utils import (
|
from flux_led.utils import (
|
||||||
color_temp_to_white_levels,
|
color_temp_to_white_levels,
|
||||||
rgbcw_brightness,
|
rgbcw_brightness,
|
||||||
@ -33,7 +26,6 @@ from homeassistant.components.light import (
|
|||||||
ATTR_WHITE,
|
ATTR_WHITE,
|
||||||
COLOR_MODE_BRIGHTNESS,
|
COLOR_MODE_BRIGHTNESS,
|
||||||
COLOR_MODE_COLOR_TEMP,
|
COLOR_MODE_COLOR_TEMP,
|
||||||
COLOR_MODE_ONOFF,
|
|
||||||
COLOR_MODE_RGB,
|
COLOR_MODE_RGB,
|
||||||
COLOR_MODE_RGBW,
|
COLOR_MODE_RGBW,
|
||||||
COLOR_MODE_RGBWW,
|
COLOR_MODE_RGBWW,
|
||||||
@ -78,6 +70,7 @@ from .const import (
|
|||||||
CONF_TRANSITION,
|
CONF_TRANSITION,
|
||||||
DEFAULT_EFFECT_SPEED,
|
DEFAULT_EFFECT_SPEED,
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
|
EFFECT_SUPPORT_MODES,
|
||||||
FLUX_HOST,
|
FLUX_HOST,
|
||||||
FLUX_LED_DISCOVERY,
|
FLUX_LED_DISCOVERY,
|
||||||
FLUX_MAC,
|
FLUX_MAC,
|
||||||
@ -89,22 +82,13 @@ from .const import (
|
|||||||
TRANSITION_JUMP,
|
TRANSITION_JUMP,
|
||||||
TRANSITION_STROBE,
|
TRANSITION_STROBE,
|
||||||
)
|
)
|
||||||
from .entity import FluxEntity
|
from .entity import FluxOnOffEntity
|
||||||
|
from .util import _flux_color_mode_to_hass, _hass_color_modes
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
SUPPORT_FLUX_LED: Final = SUPPORT_TRANSITION
|
SUPPORT_FLUX_LED: Final = SUPPORT_TRANSITION
|
||||||
|
|
||||||
|
|
||||||
FLUX_COLOR_MODE_TO_HASS: Final = {
|
|
||||||
FLUX_COLOR_MODE_RGB: COLOR_MODE_RGB,
|
|
||||||
FLUX_COLOR_MODE_RGBW: COLOR_MODE_RGBW,
|
|
||||||
FLUX_COLOR_MODE_RGBWW: COLOR_MODE_RGBWW,
|
|
||||||
FLUX_COLOR_MODE_CCT: COLOR_MODE_COLOR_TEMP,
|
|
||||||
}
|
|
||||||
|
|
||||||
EFFECT_SUPPORT_MODES = {COLOR_MODE_RGB, COLOR_MODE_RGBW, COLOR_MODE_RGBWW}
|
|
||||||
|
|
||||||
# Constant color temp values for 2 flux_led special modes
|
# Constant color temp values for 2 flux_led special modes
|
||||||
# Warm-white and Cool-white modes
|
# Warm-white and Cool-white modes
|
||||||
COLOR_TEMP_WARM_VS_COLD_WHITE_CUT_OFF: Final = 285
|
COLOR_TEMP_WARM_VS_COLD_WHITE_CUT_OFF: Final = 285
|
||||||
@ -148,15 +132,6 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def _flux_color_mode_to_hass(flux_color_mode: str, flux_color_modes: set[str]) -> str:
|
|
||||||
"""Map the flux color mode to Home Assistant color mode."""
|
|
||||||
if flux_color_mode == FLUX_COLOR_MODE_DIM:
|
|
||||||
if len(flux_color_modes) > 1:
|
|
||||||
return COLOR_MODE_WHITE
|
|
||||||
return COLOR_MODE_BRIGHTNESS
|
|
||||||
return FLUX_COLOR_MODE_TO_HASS.get(flux_color_mode, COLOR_MODE_ONOFF)
|
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_platform(
|
async def async_setup_platform(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
config: ConfigType,
|
config: ConfigType,
|
||||||
@ -242,7 +217,7 @@ async def async_setup_entry(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class FluxLight(FluxEntity, CoordinatorEntity, LightEntity):
|
class FluxLight(FluxOnOffEntity, CoordinatorEntity, LightEntity):
|
||||||
"""Representation of a Flux light."""
|
"""Representation of a Flux light."""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
@ -261,10 +236,7 @@ class FluxLight(FluxEntity, CoordinatorEntity, LightEntity):
|
|||||||
color_temperature_kelvin_to_mired(self._device.max_temp) + 1
|
color_temperature_kelvin_to_mired(self._device.max_temp) + 1
|
||||||
) # for rounding
|
) # for rounding
|
||||||
self._attr_max_mireds = color_temperature_kelvin_to_mired(self._device.min_temp)
|
self._attr_max_mireds = color_temperature_kelvin_to_mired(self._device.min_temp)
|
||||||
self._attr_supported_color_modes = {
|
self._attr_supported_color_modes = _hass_color_modes(self._device)
|
||||||
_flux_color_mode_to_hass(mode, self._device.color_modes)
|
|
||||||
for mode in self._device.color_modes
|
|
||||||
}
|
|
||||||
if self._attr_supported_color_modes.intersection(EFFECT_SUPPORT_MODES):
|
if self._attr_supported_color_modes.intersection(EFFECT_SUPPORT_MODES):
|
||||||
self._attr_supported_features |= SUPPORT_EFFECT
|
self._attr_supported_features |= SUPPORT_EFFECT
|
||||||
self._attr_effect_list = [*self._device.effect_list, EFFECT_RANDOM]
|
self._attr_effect_list = [*self._device.effect_list, EFFECT_RANDOM]
|
||||||
@ -405,7 +377,9 @@ class FluxLight(FluxEntity, CoordinatorEntity, LightEntity):
|
|||||||
self._custom_effect_transition,
|
self._custom_effect_transition,
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
await self._device.async_set_effect(effect, DEFAULT_EFFECT_SPEED)
|
await self._device.async_set_effect(
|
||||||
|
effect, self._device.speed or DEFAULT_EFFECT_SPEED
|
||||||
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
# Handle brightness adjustment in CCT Color Mode
|
# Handle brightness adjustment in CCT Color Mode
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
"name": "Flux LED/MagicHome",
|
"name": "Flux LED/MagicHome",
|
||||||
"config_flow": true,
|
"config_flow": true,
|
||||||
"documentation": "https://www.home-assistant.io/integrations/flux_led",
|
"documentation": "https://www.home-assistant.io/integrations/flux_led",
|
||||||
"requirements": ["flux_led==0.24.24"],
|
"requirements": ["flux_led==0.24.27"],
|
||||||
"quality_scale": "platinum",
|
"quality_scale": "platinum",
|
||||||
"codeowners": ["@icemanch"],
|
"codeowners": ["@icemanch"],
|
||||||
"iot_class": "local_push",
|
"iot_class": "local_push",
|
||||||
|
79
homeassistant/components/flux_led/number.py
Normal file
79
homeassistant/components/flux_led/number.py
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
"""Support for LED numbers."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing import cast
|
||||||
|
|
||||||
|
from homeassistant import config_entries
|
||||||
|
from homeassistant.components.number import NumberEntity
|
||||||
|
from homeassistant.components.number.const import MODE_SLIDER
|
||||||
|
from homeassistant.const import CONF_NAME
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.exceptions import HomeAssistantError
|
||||||
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
|
from homeassistant.helpers.update_coordinator import CoordinatorEntity
|
||||||
|
|
||||||
|
from . import FluxLedUpdateCoordinator
|
||||||
|
from .const import DOMAIN, EFFECT_SUPPORT_MODES
|
||||||
|
from .entity import FluxEntity
|
||||||
|
from .util import _hass_color_modes
|
||||||
|
|
||||||
|
|
||||||
|
async def async_setup_entry(
|
||||||
|
hass: HomeAssistant,
|
||||||
|
entry: config_entries.ConfigEntry,
|
||||||
|
async_add_entities: AddEntitiesCallback,
|
||||||
|
) -> None:
|
||||||
|
"""Set up the Flux lights."""
|
||||||
|
coordinator: FluxLedUpdateCoordinator = hass.data[DOMAIN][entry.entry_id]
|
||||||
|
|
||||||
|
color_modes = _hass_color_modes(coordinator.device)
|
||||||
|
if not color_modes.intersection(EFFECT_SUPPORT_MODES):
|
||||||
|
return
|
||||||
|
|
||||||
|
async_add_entities(
|
||||||
|
[
|
||||||
|
FluxNumber(
|
||||||
|
coordinator,
|
||||||
|
entry.unique_id,
|
||||||
|
entry.data[CONF_NAME],
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class FluxNumber(FluxEntity, CoordinatorEntity, NumberEntity):
|
||||||
|
"""Defines a flux_led speed number."""
|
||||||
|
|
||||||
|
_attr_min_value = 1
|
||||||
|
_attr_max_value = 100
|
||||||
|
_attr_step = 1
|
||||||
|
_attr_mode = MODE_SLIDER
|
||||||
|
_attr_icon = "mdi:speedometer"
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
coordinator: FluxLedUpdateCoordinator,
|
||||||
|
unique_id: str | None,
|
||||||
|
name: str,
|
||||||
|
) -> None:
|
||||||
|
"""Initialize the flux number."""
|
||||||
|
super().__init__(coordinator, unique_id, name)
|
||||||
|
self._attr_name = f"{name} Effect Speed"
|
||||||
|
|
||||||
|
@property
|
||||||
|
def value(self) -> float:
|
||||||
|
"""Return the effect speed."""
|
||||||
|
return cast(float, self._device.speed)
|
||||||
|
|
||||||
|
async def async_set_value(self, value: float) -> None:
|
||||||
|
"""Set the flux speed value."""
|
||||||
|
current_effect = self._device.effect
|
||||||
|
new_speed = int(value)
|
||||||
|
if not current_effect:
|
||||||
|
raise HomeAssistantError(
|
||||||
|
"Speed can only be adjusted when an effect is active"
|
||||||
|
)
|
||||||
|
if self._device.original_addressable and not self._device.is_on:
|
||||||
|
raise HomeAssistantError("Speed can only be adjusted when the light is on")
|
||||||
|
await self._device.async_set_effect(current_effect, new_speed)
|
||||||
|
await self.coordinator.async_request_refresh()
|
@ -12,7 +12,7 @@ from homeassistant.helpers.update_coordinator import CoordinatorEntity
|
|||||||
|
|
||||||
from . import FluxLedUpdateCoordinator
|
from . import FluxLedUpdateCoordinator
|
||||||
from .const import DOMAIN
|
from .const import DOMAIN
|
||||||
from .entity import FluxEntity
|
from .entity import FluxOnOffEntity
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_entry(
|
async def async_setup_entry(
|
||||||
@ -33,7 +33,7 @@ async def async_setup_entry(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class FluxSwitch(FluxEntity, CoordinatorEntity, SwitchEntity):
|
class FluxSwitch(FluxOnOffEntity, CoordinatorEntity, SwitchEntity):
|
||||||
"""Representation of a Flux switch."""
|
"""Representation of a Flux switch."""
|
||||||
|
|
||||||
async def _async_turn_on(self, **kwargs: Any) -> None:
|
async def _async_turn_on(self, **kwargs: Any) -> None:
|
||||||
|
27
homeassistant/components/flux_led/util.py
Normal file
27
homeassistant/components/flux_led/util.py
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
"""Utils for FluxLED/MagicHome."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from flux_led.aio import AIOWifiLedBulb
|
||||||
|
from flux_led.const import COLOR_MODE_DIM as FLUX_COLOR_MODE_DIM
|
||||||
|
|
||||||
|
from homeassistant.components.light import (
|
||||||
|
COLOR_MODE_BRIGHTNESS,
|
||||||
|
COLOR_MODE_ONOFF,
|
||||||
|
COLOR_MODE_WHITE,
|
||||||
|
)
|
||||||
|
|
||||||
|
from .const import FLUX_COLOR_MODE_TO_HASS
|
||||||
|
|
||||||
|
|
||||||
|
def _hass_color_modes(device: AIOWifiLedBulb) -> set[str]:
|
||||||
|
color_modes = device.color_modes
|
||||||
|
return {_flux_color_mode_to_hass(mode, color_modes) for mode in color_modes}
|
||||||
|
|
||||||
|
|
||||||
|
def _flux_color_mode_to_hass(flux_color_mode: str, flux_color_modes: set[str]) -> str:
|
||||||
|
"""Map the flux color mode to Home Assistant color mode."""
|
||||||
|
if flux_color_mode == FLUX_COLOR_MODE_DIM:
|
||||||
|
if len(flux_color_modes) > 1:
|
||||||
|
return COLOR_MODE_WHITE
|
||||||
|
return COLOR_MODE_BRIGHTNESS
|
||||||
|
return FLUX_COLOR_MODE_TO_HASS.get(flux_color_mode, COLOR_MODE_ONOFF)
|
@ -658,7 +658,7 @@ fjaraskupan==1.0.2
|
|||||||
flipr-api==1.4.1
|
flipr-api==1.4.1
|
||||||
|
|
||||||
# homeassistant.components.flux_led
|
# homeassistant.components.flux_led
|
||||||
flux_led==0.24.24
|
flux_led==0.24.27
|
||||||
|
|
||||||
# homeassistant.components.homekit
|
# homeassistant.components.homekit
|
||||||
fnvhash==0.1.0
|
fnvhash==0.1.0
|
||||||
|
@ -399,7 +399,7 @@ fjaraskupan==1.0.2
|
|||||||
flipr-api==1.4.1
|
flipr-api==1.4.1
|
||||||
|
|
||||||
# homeassistant.components.flux_led
|
# homeassistant.components.flux_led
|
||||||
flux_led==0.24.24
|
flux_led==0.24.27
|
||||||
|
|
||||||
# homeassistant.components.homekit
|
# homeassistant.components.homekit
|
||||||
fnvhash==0.1.0
|
fnvhash==0.1.0
|
||||||
|
@ -67,8 +67,11 @@ def _mocked_bulb() -> AIOWifiLedBulb:
|
|||||||
bulb.brightness = 128
|
bulb.brightness = 128
|
||||||
bulb.model_num = 0x35
|
bulb.model_num = 0x35
|
||||||
bulb.effect = None
|
bulb.effect = None
|
||||||
|
bulb.speed = 50
|
||||||
bulb.model = "Smart Bulb (0x35)"
|
bulb.model = "Smart Bulb (0x35)"
|
||||||
bulb.version_num = 8
|
bulb.version_num = 8
|
||||||
|
bulb.original_addressable = False
|
||||||
|
bulb.addressable = False
|
||||||
bulb.rgbwcapable = True
|
bulb.rgbwcapable = True
|
||||||
bulb.color_modes = {FLUX_COLOR_MODE_RGB, FLUX_COLOR_MODE_CCT}
|
bulb.color_modes = {FLUX_COLOR_MODE_RGB, FLUX_COLOR_MODE_CCT}
|
||||||
bulb.color_mode = FLUX_COLOR_MODE_RGB
|
bulb.color_mode = FLUX_COLOR_MODE_RGB
|
||||||
@ -115,6 +118,16 @@ async def async_mock_device_turn_on(hass: HomeAssistant, bulb: AIOWifiLedBulb) -
|
|||||||
await hass.async_block_till_done()
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
|
||||||
|
async def async_mock_effect_speed(
|
||||||
|
hass: HomeAssistant, bulb: AIOWifiLedBulb, effect: str, speed: int
|
||||||
|
) -> None:
|
||||||
|
"""Mock the device being on with an effect."""
|
||||||
|
bulb.speed = speed
|
||||||
|
bulb.effect = effect
|
||||||
|
bulb.data_receive_callback()
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
|
||||||
def _patch_discovery(device=None, no_device=False):
|
def _patch_discovery(device=None, no_device=False):
|
||||||
async def _discovery(*args, **kwargs):
|
async def _discovery(*args, **kwargs):
|
||||||
if no_device:
|
if no_device:
|
||||||
|
227
tests/components/flux_led/test_number.py
Normal file
227
tests/components/flux_led/test_number.py
Normal file
@ -0,0 +1,227 @@
|
|||||||
|
"""Tests for the flux_led number platform."""
|
||||||
|
|
||||||
|
|
||||||
|
from flux_led.const import COLOR_MODE_RGB as FLUX_COLOR_MODE_RGB
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from homeassistant.components import flux_led
|
||||||
|
from homeassistant.components.flux_led.const import DOMAIN
|
||||||
|
from homeassistant.components.number import (
|
||||||
|
ATTR_VALUE,
|
||||||
|
DOMAIN as NUMBER_DOMAIN,
|
||||||
|
SERVICE_SET_VALUE,
|
||||||
|
)
|
||||||
|
from homeassistant.const import ATTR_ENTITY_ID, CONF_HOST, CONF_NAME, STATE_ON
|
||||||
|
from homeassistant.core import HomeAssistant
|
||||||
|
from homeassistant.exceptions import HomeAssistantError
|
||||||
|
from homeassistant.helpers import entity_registry as er
|
||||||
|
from homeassistant.setup import async_setup_component
|
||||||
|
|
||||||
|
from . import (
|
||||||
|
DEFAULT_ENTRY_TITLE,
|
||||||
|
IP_ADDRESS,
|
||||||
|
MAC_ADDRESS,
|
||||||
|
_mocked_bulb,
|
||||||
|
_patch_discovery,
|
||||||
|
_patch_wifibulb,
|
||||||
|
async_mock_device_turn_off,
|
||||||
|
async_mock_device_turn_on,
|
||||||
|
async_mock_effect_speed,
|
||||||
|
)
|
||||||
|
|
||||||
|
from tests.common import MockConfigEntry
|
||||||
|
|
||||||
|
|
||||||
|
async def test_number_unique_id(hass: HomeAssistant) -> None:
|
||||||
|
"""Test a number unique id."""
|
||||||
|
config_entry = MockConfigEntry(
|
||||||
|
domain=DOMAIN,
|
||||||
|
data={CONF_HOST: IP_ADDRESS, CONF_NAME: DEFAULT_ENTRY_TITLE},
|
||||||
|
unique_id=MAC_ADDRESS,
|
||||||
|
)
|
||||||
|
config_entry.add_to_hass(hass)
|
||||||
|
bulb = _mocked_bulb()
|
||||||
|
with _patch_discovery(device=bulb), _patch_wifibulb(device=bulb):
|
||||||
|
await async_setup_component(hass, flux_led.DOMAIN, {flux_led.DOMAIN: {}})
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
entity_id = "number.az120444_aabbccddeeff_effect_speed"
|
||||||
|
entity_registry = er.async_get(hass)
|
||||||
|
assert entity_registry.async_get(entity_id).unique_id == MAC_ADDRESS
|
||||||
|
|
||||||
|
|
||||||
|
async def test_rgb_light_effect_speed(hass: HomeAssistant) -> None:
|
||||||
|
"""Test an rgb light with an effect."""
|
||||||
|
config_entry = MockConfigEntry(
|
||||||
|
domain=DOMAIN,
|
||||||
|
data={CONF_HOST: IP_ADDRESS, CONF_NAME: DEFAULT_ENTRY_TITLE},
|
||||||
|
unique_id=MAC_ADDRESS,
|
||||||
|
)
|
||||||
|
config_entry.add_to_hass(hass)
|
||||||
|
bulb = _mocked_bulb()
|
||||||
|
bulb.raw_state = bulb.raw_state._replace(model_num=0x33) # RGB only model
|
||||||
|
|
||||||
|
bulb.color_modes = {FLUX_COLOR_MODE_RGB}
|
||||||
|
bulb.color_mode = FLUX_COLOR_MODE_RGB
|
||||||
|
|
||||||
|
with _patch_discovery(device=bulb), _patch_wifibulb(device=bulb):
|
||||||
|
await async_setup_component(hass, flux_led.DOMAIN, {flux_led.DOMAIN: {}})
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
await async_mock_device_turn_on(hass, bulb)
|
||||||
|
|
||||||
|
light_entity_id = "light.az120444_aabbccddeeff"
|
||||||
|
number_entity_id = "number.az120444_aabbccddeeff_effect_speed"
|
||||||
|
with pytest.raises(HomeAssistantError):
|
||||||
|
await hass.services.async_call(
|
||||||
|
NUMBER_DOMAIN,
|
||||||
|
SERVICE_SET_VALUE,
|
||||||
|
{ATTR_ENTITY_ID: number_entity_id, ATTR_VALUE: 100},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
state = hass.states.get(light_entity_id)
|
||||||
|
assert state.state == STATE_ON
|
||||||
|
|
||||||
|
bulb.effect = "colorloop"
|
||||||
|
bulb.speed = 50
|
||||||
|
await async_mock_device_turn_off(hass, bulb)
|
||||||
|
state = hass.states.get(number_entity_id)
|
||||||
|
assert state.state == "50"
|
||||||
|
|
||||||
|
await hass.services.async_call(
|
||||||
|
NUMBER_DOMAIN,
|
||||||
|
SERVICE_SET_VALUE,
|
||||||
|
{ATTR_ENTITY_ID: number_entity_id, ATTR_VALUE: 100},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
bulb.async_set_effect.assert_called_with("colorloop", 100)
|
||||||
|
bulb.async_set_effect.reset_mock()
|
||||||
|
|
||||||
|
await async_mock_effect_speed(hass, bulb, "red_fade", 50)
|
||||||
|
await hass.services.async_call(
|
||||||
|
NUMBER_DOMAIN,
|
||||||
|
SERVICE_SET_VALUE,
|
||||||
|
{ATTR_ENTITY_ID: number_entity_id, ATTR_VALUE: 50},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
bulb.async_set_effect.assert_called_with("red_fade", 50)
|
||||||
|
bulb.async_set_effect.reset_mock()
|
||||||
|
|
||||||
|
state = hass.states.get(number_entity_id)
|
||||||
|
assert state.state == "50"
|
||||||
|
|
||||||
|
|
||||||
|
async def test_original_addressable_light_effect_speed(hass: HomeAssistant) -> None:
|
||||||
|
"""Test an original addressable light with an effect."""
|
||||||
|
config_entry = MockConfigEntry(
|
||||||
|
domain=DOMAIN,
|
||||||
|
data={CONF_HOST: IP_ADDRESS, CONF_NAME: DEFAULT_ENTRY_TITLE},
|
||||||
|
unique_id=MAC_ADDRESS,
|
||||||
|
)
|
||||||
|
config_entry.add_to_hass(hass)
|
||||||
|
bulb = _mocked_bulb()
|
||||||
|
bulb.original_addressable = True
|
||||||
|
bulb.raw_state = bulb.raw_state._replace(
|
||||||
|
model_num=0xA1
|
||||||
|
) # Original addressable model
|
||||||
|
bulb.color_modes = {FLUX_COLOR_MODE_RGB}
|
||||||
|
bulb.color_mode = FLUX_COLOR_MODE_RGB
|
||||||
|
bulb.effect = "7 colors change gradually"
|
||||||
|
bulb.speed = 50
|
||||||
|
with _patch_discovery(device=bulb), _patch_wifibulb(device=bulb):
|
||||||
|
await async_setup_component(hass, flux_led.DOMAIN, {flux_led.DOMAIN: {}})
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
await async_mock_device_turn_on(hass, bulb)
|
||||||
|
|
||||||
|
light_entity_id = "light.az120444_aabbccddeeff"
|
||||||
|
number_entity_id = "number.az120444_aabbccddeeff_effect_speed"
|
||||||
|
|
||||||
|
state = hass.states.get(light_entity_id)
|
||||||
|
assert state.state == STATE_ON
|
||||||
|
|
||||||
|
state = hass.states.get(number_entity_id)
|
||||||
|
assert state.state == "50"
|
||||||
|
|
||||||
|
await async_mock_device_turn_off(hass, bulb)
|
||||||
|
|
||||||
|
with pytest.raises(HomeAssistantError):
|
||||||
|
await hass.services.async_call(
|
||||||
|
NUMBER_DOMAIN,
|
||||||
|
SERVICE_SET_VALUE,
|
||||||
|
{ATTR_ENTITY_ID: number_entity_id, ATTR_VALUE: 100},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
await async_mock_device_turn_on(hass, bulb)
|
||||||
|
await hass.services.async_call(
|
||||||
|
NUMBER_DOMAIN,
|
||||||
|
SERVICE_SET_VALUE,
|
||||||
|
{ATTR_ENTITY_ID: number_entity_id, ATTR_VALUE: 100},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
bulb.async_set_effect.assert_called_with("7 colors change gradually", 100)
|
||||||
|
bulb.async_set_effect.reset_mock()
|
||||||
|
await async_mock_effect_speed(hass, bulb, "7 colors run in olivary", 100)
|
||||||
|
|
||||||
|
state = hass.states.get(number_entity_id)
|
||||||
|
assert state.state == "100"
|
||||||
|
|
||||||
|
|
||||||
|
async def test_addressable_light_effect_speed(hass: HomeAssistant) -> None:
|
||||||
|
"""Test an addressable light with an effect."""
|
||||||
|
config_entry = MockConfigEntry(
|
||||||
|
domain=DOMAIN,
|
||||||
|
data={CONF_HOST: IP_ADDRESS, CONF_NAME: DEFAULT_ENTRY_TITLE},
|
||||||
|
unique_id=MAC_ADDRESS,
|
||||||
|
)
|
||||||
|
config_entry.add_to_hass(hass)
|
||||||
|
bulb = _mocked_bulb()
|
||||||
|
bulb.addressable = True
|
||||||
|
bulb.raw_state = bulb.raw_state._replace(
|
||||||
|
model_num=0xA2
|
||||||
|
) # Original addressable model
|
||||||
|
bulb.color_modes = {FLUX_COLOR_MODE_RGB}
|
||||||
|
bulb.color_mode = FLUX_COLOR_MODE_RGB
|
||||||
|
bulb.effect = "RBM 1"
|
||||||
|
bulb.speed = 50
|
||||||
|
with _patch_discovery(device=bulb), _patch_wifibulb(device=bulb):
|
||||||
|
await async_setup_component(hass, flux_led.DOMAIN, {flux_led.DOMAIN: {}})
|
||||||
|
await hass.async_block_till_done()
|
||||||
|
|
||||||
|
await async_mock_device_turn_on(hass, bulb)
|
||||||
|
|
||||||
|
light_entity_id = "light.az120444_aabbccddeeff"
|
||||||
|
number_entity_id = "number.az120444_aabbccddeeff_effect_speed"
|
||||||
|
|
||||||
|
state = hass.states.get(light_entity_id)
|
||||||
|
assert state.state == STATE_ON
|
||||||
|
|
||||||
|
state = hass.states.get(number_entity_id)
|
||||||
|
assert state.state == "50"
|
||||||
|
|
||||||
|
await async_mock_device_turn_off(hass, bulb)
|
||||||
|
|
||||||
|
await hass.services.async_call(
|
||||||
|
NUMBER_DOMAIN,
|
||||||
|
SERVICE_SET_VALUE,
|
||||||
|
{ATTR_ENTITY_ID: number_entity_id, ATTR_VALUE: 100},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
bulb.async_set_effect.assert_called_with("RBM 1", 100)
|
||||||
|
bulb.async_set_effect.reset_mock()
|
||||||
|
|
||||||
|
await async_mock_device_turn_on(hass, bulb)
|
||||||
|
await hass.services.async_call(
|
||||||
|
NUMBER_DOMAIN,
|
||||||
|
SERVICE_SET_VALUE,
|
||||||
|
{ATTR_ENTITY_ID: number_entity_id, ATTR_VALUE: 100},
|
||||||
|
blocking=True,
|
||||||
|
)
|
||||||
|
bulb.async_set_effect.assert_called_with("RBM 1", 100)
|
||||||
|
bulb.async_set_effect.reset_mock()
|
||||||
|
await async_mock_effect_speed(hass, bulb, "RBM 2", 100)
|
||||||
|
|
||||||
|
state = hass.states.get(number_entity_id)
|
||||||
|
assert state.state == "100"
|
Loading…
x
Reference in New Issue
Block a user