1
mirror of https://github.com/home-assistant/core synced 2024-08-02 23:40:32 +02:00
ha-core/homeassistant/components/fritzbox/light.py
Michael ccad6a8f07
Add configuration url to AVM Fritz!Smarthome (#57711)
* add configuration url

* extend data update coordinator

* improve exception handling during data update

* store coordinator after first refresh

* fix light init
2021-10-31 12:12:25 -07:00

154 lines
5.1 KiB
Python

"""Support for AVM FRITZ!SmartHome lightbulbs."""
from __future__ import annotations
from typing import Any
from homeassistant.components.light import (
ATTR_BRIGHTNESS,
ATTR_COLOR_TEMP,
ATTR_HS_COLOR,
COLOR_MODE_COLOR_TEMP,
COLOR_MODE_HS,
LightEntity,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.util import color
from . import FritzBoxEntity
from .const import (
COLOR_MODE,
COLOR_TEMP_MODE,
CONF_COORDINATOR,
DOMAIN as FRITZBOX_DOMAIN,
)
from .coordinator import FritzboxDataUpdateCoordinator
SUPPORTED_COLOR_MODES = {COLOR_MODE_COLOR_TEMP, COLOR_MODE_HS}
async def async_setup_entry(
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
) -> None:
"""Set up the FRITZ!SmartHome light from ConfigEntry."""
entities: list[FritzboxLight] = []
coordinator = hass.data[FRITZBOX_DOMAIN][entry.entry_id][CONF_COORDINATOR]
for ain, device in coordinator.data.items():
if not device.has_lightbulb:
continue
supported_color_temps = await hass.async_add_executor_job(
device.get_color_temps
)
supported_colors = await hass.async_add_executor_job(device.get_colors)
entities.append(
FritzboxLight(
coordinator,
ain,
supported_colors,
supported_color_temps,
)
)
async_add_entities(entities)
class FritzboxLight(FritzBoxEntity, LightEntity):
"""The light class for FRITZ!SmartHome lightbulbs."""
def __init__(
self,
coordinator: FritzboxDataUpdateCoordinator,
ain: str,
supported_colors: dict,
supported_color_temps: list[str],
) -> None:
"""Initialize the FritzboxLight entity."""
super().__init__(coordinator, ain, None)
max_kelvin = int(max(supported_color_temps))
min_kelvin = int(min(supported_color_temps))
# max kelvin is min mireds and min kelvin is max mireds
self._attr_min_mireds = color.color_temperature_kelvin_to_mired(max_kelvin)
self._attr_max_mireds = color.color_temperature_kelvin_to_mired(min_kelvin)
# Fritz!DECT 500 only supports 12 values for hue, with 3 saturations each.
# Map supported colors to dict {hue: [sat1, sat2, sat3]} for easier lookup
self._supported_hs = {}
for values in supported_colors.values():
hue = int(values[0][0])
self._supported_hs[hue] = [
int(values[0][1]),
int(values[1][1]),
int(values[2][1]),
]
@property
def is_on(self) -> bool:
"""If the light is currently on or off."""
return self.device.state # type: ignore [no-any-return]
@property
def brightness(self) -> int:
"""Return the current Brightness."""
return self.device.level # type: ignore [no-any-return]
@property
def hs_color(self) -> tuple[float, float] | None:
"""Return the hs color value."""
if self.device.color_mode != COLOR_MODE:
return None
hue = self.device.hue
saturation = self.device.saturation
return (hue, float(saturation) * 100.0 / 255.0)
@property
def color_temp(self) -> int | None:
"""Return the CT color value."""
if self.device.color_mode != COLOR_TEMP_MODE:
return None
kelvin = self.device.color_temp
return color.color_temperature_kelvin_to_mired(kelvin)
@property
def supported_color_modes(self) -> set:
"""Flag supported color modes."""
return SUPPORTED_COLOR_MODES
async def async_turn_on(self, **kwargs: Any) -> None:
"""Turn the light on."""
if kwargs.get(ATTR_BRIGHTNESS) is not None:
level = kwargs[ATTR_BRIGHTNESS]
await self.hass.async_add_executor_job(self.device.set_level, level)
if kwargs.get(ATTR_HS_COLOR) is not None:
hass_hue = int(kwargs[ATTR_HS_COLOR][0])
hass_saturation = round(kwargs[ATTR_HS_COLOR][1] * 255.0 / 100.0)
# find supported hs values closest to what user selected
hue = min(self._supported_hs.keys(), key=lambda x: abs(x - hass_hue))
saturation = min(
self._supported_hs[hue], key=lambda x: abs(x - hass_saturation)
)
await self.hass.async_add_executor_job(
self.device.set_color, (hue, saturation)
)
if kwargs.get(ATTR_COLOR_TEMP) is not None:
kelvin = color.color_temperature_kelvin_to_mired(kwargs[ATTR_COLOR_TEMP])
await self.hass.async_add_executor_job(self.device.set_color_temp, kelvin)
await self.hass.async_add_executor_job(self.device.set_state_on)
await self.coordinator.async_refresh()
async def async_turn_off(self, **kwargs: Any) -> None:
"""Turn the light off."""
await self.hass.async_add_executor_job(self.device.set_state_off)
await self.coordinator.async_refresh()