From 00c0e9b8da1405a159365e115915f6b8b9440ff1 Mon Sep 17 00:00:00 2001 From: Sjack-Sch <60797694+Sjack-Sch@users.noreply.github.com> Date: Sat, 19 Dec 2020 23:40:44 +0100 Subject: [PATCH] Home connect functional and ambient light added (#44091) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Update nl.json * added period to end of every logging entry. * Functional and ambient light added * Change to dict.get method * Update light.py * Update __init__.py Platforms sorted 🔡. * Update api.py - Removed all none light platform related changes. - Period removed from loggin. - Storing entities removed. - Not needed formating change reverted. - * Update const.py All words seperated with underscore. * Update nl.json Reverted change on translation file. * Update light.py -All words of constants seperated with underscore. - f-string used iso concatenation. - Added "ambient"to loggin text. - Removed self._state = false when color setting did not succeed. - Logging starts with a capital. * Update api.py - Removed ending perio in logging - Reverted formating - Removed self.device.entities.append(self) - * Update entity.py - Removed self.device.entities.append(self) * Update api.py - Adding newline at end of file - Added whitespave after "," * Update api.py Newline at end of file * Update const.py Removed unused. * Update light.py - seperated words with whitespaces - improved debug text * Update light.py remove state setting after an error --- .../components/home_connect/__init__.py | 2 +- homeassistant/components/home_connect/api.py | 36 +++- .../components/home_connect/const.py | 12 ++ .../components/home_connect/light.py | 203 ++++++++++++++++++ 4 files changed, 249 insertions(+), 4 deletions(-) create mode 100644 homeassistant/components/home_connect/light.py diff --git a/homeassistant/components/home_connect/__init__.py b/homeassistant/components/home_connect/__init__.py index 38f487a98a1..301bd1976e6 100644 --- a/homeassistant/components/home_connect/__init__.py +++ b/homeassistant/components/home_connect/__init__.py @@ -32,7 +32,7 @@ CONFIG_SCHEMA = vol.Schema( extra=vol.ALLOW_EXTRA, ) -PLATFORMS = ["binary_sensor", "sensor", "switch"] +PLATFORMS = ["binary_sensor", "light", "sensor", "switch"] async def async_setup(hass: HomeAssistant, config: dict) -> bool: diff --git a/homeassistant/components/home_connect/api.py b/homeassistant/components/home_connect/api.py index e1ee75297fd..8db8afa3a6b 100644 --- a/homeassistant/components/home_connect/api.py +++ b/homeassistant/components/home_connect/api.py @@ -168,6 +168,30 @@ class DeviceWithDoor(HomeConnectDevice): } +class DeviceWithLight(HomeConnectDevice): + """Device that has lighting.""" + + def get_light_entity(self): + """Get a dictionary with info about the lighting.""" + return { + "device": self, + "desc": "Light", + "ambient": None, + } + + +class DeviceWithAmbientLight(HomeConnectDevice): + """Device that has ambient lighting.""" + + def get_ambientlight_entity(self): + """Get a dictionary with info about the ambient lighting.""" + return { + "device": self, + "desc": "AmbientLight", + "ambient": True, + } + + class Dryer(DeviceWithDoor, DeviceWithPrograms): """Dryer class.""" @@ -202,7 +226,7 @@ class Dryer(DeviceWithDoor, DeviceWithPrograms): } -class Dishwasher(DeviceWithDoor, DeviceWithPrograms): +class Dishwasher(DeviceWithDoor, DeviceWithAmbientLight, DeviceWithPrograms): """Dishwasher class.""" PROGRAMS = [ @@ -335,7 +359,7 @@ class CoffeeMaker(DeviceWithPrograms): return {"switch": program_switches, "sensor": program_sensors} -class Hood(DeviceWithPrograms): +class Hood(DeviceWithLight, DeviceWithAmbientLight, DeviceWithPrograms): """Hood class.""" PROGRAMS = [ @@ -346,9 +370,15 @@ class Hood(DeviceWithPrograms): def get_entity_info(self): """Get a dictionary with infos about the associated entities.""" + light_entity = self.get_light_entity() + ambientlight_entity = self.get_ambientlight_entity() program_sensors = self.get_program_sensors() program_switches = self.get_program_switches() - return {"switch": program_switches, "sensor": program_sensors} + return { + "switch": program_switches, + "sensor": program_sensors, + "light": [light_entity, ambientlight_entity], + } class FridgeFreezer(DeviceWithDoor): diff --git a/homeassistant/components/home_connect/const.py b/homeassistant/components/home_connect/const.py index 10eb5dfd1e3..22ce4dba676 100644 --- a/homeassistant/components/home_connect/const.py +++ b/homeassistant/components/home_connect/const.py @@ -11,6 +11,18 @@ BSH_POWER_OFF = "BSH.Common.EnumType.PowerState.Off" BSH_POWER_STANDBY = "BSH.Common.EnumType.PowerState.Standby" BSH_ACTIVE_PROGRAM = "BSH.Common.Root.ActiveProgram" BSH_OPERATION_STATE = "BSH.Common.Status.OperationState" + +COOKING_LIGHTING = "Cooking.Common.Setting.Lighting" +COOKING_LIGHTING_BRIGHTNESS = "Cooking.Common.Setting.LightingBrightness" + +BSH_AMBIENT_LIGHT_ENABLED = "BSH.Common.Setting.AmbientLightEnabled" +BSH_AMBIENT_LIGHT_BRIGHTNESS = "BSH.Common.Setting.AmbientLightBrightness" +BSH_AMBIENT_LIGHT_COLOR = "BSH.Common.Setting.AmbientLightColor" +BSH_AMBIENT_LIGHT_COLOR_CUSTOM_COLOR = ( + "BSH.Common.EnumType.AmbientLightColor.CustomColor" +) +BSH_AMBIENT_LIGHT_CUSTOM_COLOR = "BSH.Common.Setting.AmbientLightCustomColor" + BSH_DOOR_STATE = "BSH.Common.Status.DoorState" SIGNAL_UPDATE_ENTITIES = "home_connect.update_entities" diff --git a/homeassistant/components/home_connect/light.py b/homeassistant/components/home_connect/light.py new file mode 100644 index 00000000000..a8d0d7ffbd3 --- /dev/null +++ b/homeassistant/components/home_connect/light.py @@ -0,0 +1,203 @@ +"""Provides a light for Home Connect.""" +import logging +from math import ceil + +from homeconnect.api import HomeConnectError + +from homeassistant.components.light import ( + ATTR_BRIGHTNESS, + ATTR_HS_COLOR, + SUPPORT_BRIGHTNESS, + SUPPORT_COLOR, + LightEntity, +) +import homeassistant.util.color as color_util + +from .const import ( + BSH_AMBIENT_LIGHT_BRIGHTNESS, + BSH_AMBIENT_LIGHT_COLOR, + BSH_AMBIENT_LIGHT_COLOR_CUSTOM_COLOR, + BSH_AMBIENT_LIGHT_CUSTOM_COLOR, + BSH_AMBIENT_LIGHT_ENABLED, + COOKING_LIGHTING, + COOKING_LIGHTING_BRIGHTNESS, + DOMAIN, +) +from .entity import HomeConnectEntity + +_LOGGER = logging.getLogger(__name__) + + +async def async_setup_entry(hass, config_entry, async_add_entities): + """Set up the Home Connect light.""" + + def get_entities(): + """Get a list of entities.""" + entities = [] + hc_api = hass.data[DOMAIN][config_entry.entry_id] + for device_dict in hc_api.devices: + entity_dicts = device_dict.get("entities", {}).get("light", []) + entity_list = [HomeConnectLight(**d) for d in entity_dicts] + entities += entity_list + return entities + + async_add_entities(await hass.async_add_executor_job(get_entities), True) + + +class HomeConnectLight(HomeConnectEntity, LightEntity): + """Light for Home Connect.""" + + def __init__(self, device, desc, ambient): + """Initialize the entity.""" + super().__init__(device, desc) + self._state = None + self._brightness = None + self._hs_color = None + self._ambient = ambient + if self._ambient: + self._brightness_key = BSH_AMBIENT_LIGHT_BRIGHTNESS + self._key = BSH_AMBIENT_LIGHT_ENABLED + self._custom_color_key = BSH_AMBIENT_LIGHT_CUSTOM_COLOR + self._color_key = BSH_AMBIENT_LIGHT_COLOR + else: + self._brightness_key = COOKING_LIGHTING_BRIGHTNESS + self._key = COOKING_LIGHTING + self._custom_color_key = None + self._color_key = None + + @property + def is_on(self): + """Return true if the light is on.""" + return bool(self._state) + + @property + def brightness(self): + """Return the brightness of the light.""" + return self._brightness + + @property + def hs_color(self): + """Return the color property.""" + return self._hs_color + + @property + def supported_features(self): + """Flag supported features.""" + if self._ambient: + return SUPPORT_BRIGHTNESS | SUPPORT_COLOR + return SUPPORT_BRIGHTNESS + + async def async_turn_on(self, **kwargs): + """Switch the light on, change brightness, change color.""" + if self._ambient: + if ATTR_BRIGHTNESS in kwargs or ATTR_HS_COLOR in kwargs: + try: + await self.hass.async_add_executor_job( + self.device.appliance.set_setting, + self._color_key, + BSH_AMBIENT_LIGHT_COLOR_CUSTOM_COLOR, + ) + except HomeConnectError as err: + _LOGGER.error("Error while trying selecting customcolor: %s", err) + if self._brightness is not None: + brightness = 10 + ceil(self._brightness / 255 * 90) + if ATTR_BRIGHTNESS in kwargs: + brightness = 10 + ceil(kwargs[ATTR_BRIGHTNESS] / 255 * 90) + + hs_color = kwargs.get(ATTR_HS_COLOR, default=self._hs_color) + + if hs_color is not None: + rgb = color_util.color_hsv_to_RGB(*hs_color, brightness) + hex_val = color_util.color_rgb_to_hex(rgb[0], rgb[1], rgb[2]) + try: + await self.hass.async_add_executor_job( + self.device.appliance.set_setting, + self._custom_color_key, + f"#{hex_val}", + ) + except HomeConnectError as err: + _LOGGER.error( + "Error while trying setting the color: %s", err + ) + else: + _LOGGER.debug("Switching ambient light on for: %s", self.name) + try: + await self.hass.async_add_executor_job( + self.device.appliance.set_setting, + self._key, + True, + ) + except HomeConnectError as err: + _LOGGER.error( + "Error while trying to turn on ambient light: %s", err + ) + + elif ATTR_BRIGHTNESS in kwargs: + _LOGGER.debug("Changing brightness for: %s", self.name) + brightness = 10 + ceil(kwargs[ATTR_BRIGHTNESS] / 255 * 90) + try: + await self.hass.async_add_executor_job( + self.device.appliance.set_setting, + self._brightness_key, + brightness, + ) + except HomeConnectError as err: + _LOGGER.error("Error while trying set the brightness: %s", err) + else: + _LOGGER.debug("Switching light on for: %s", self.name) + try: + await self.hass.async_add_executor_job( + self.device.appliance.set_setting, + self._key, + True, + ) + except HomeConnectError as err: + _LOGGER.error("Error while trying to turn on light: %s", err) + + self.async_entity_update() + + async def async_turn_off(self, **kwargs): + """Switch the light off.""" + _LOGGER.debug("Switching light off for: %s", self.name) + try: + await self.hass.async_add_executor_job( + self.device.appliance.set_setting, + self._key, + False, + ) + except HomeConnectError as err: + _LOGGER.error("Error while trying to turn off light: %s", err) + self.async_entity_update() + + async def async_update(self): + """Update the light's status.""" + if self.device.appliance.status.get(self._key, {}).get("value") is True: + self._state = True + elif self.device.appliance.status.get(self._key, {}).get("value") is False: + self._state = False + else: + self._state = None + + _LOGGER.debug("Updated, new light state: %s", self._state) + + if self._ambient: + color = self.device.appliance.status.get(self._custom_color_key, {}) + + if not color: + self._hs_color = None + self._brightness = None + else: + colorvalue = color.get("value")[1:] + rgb = color_util.rgb_hex_to_rgb_list(colorvalue) + hsv = color_util.color_RGB_to_hsv(rgb[0], rgb[1], rgb[2]) + self._hs_color = [hsv[0], hsv[1]] + self._brightness = ceil((hsv[2] - 10) * 255 / 90) + _LOGGER.debug("Updated, new brightness: %s", self._brightness) + + else: + brightness = self.device.appliance.status.get(self._brightness_key, {}) + if brightness is None: + self._brightness = None + else: + self._brightness = ceil((brightness.get("value") - 10) * 255 / 90) + _LOGGER.debug("Updated, new brightness: %s", self._brightness)