From 3727fb5288f894c64d4cb2f0c4dba77d7c0fed13 Mon Sep 17 00:00:00 2001 From: L-I-Am <liam.oorts@hotmail.com> Date: Wed, 27 Oct 2021 04:20:11 +0200 Subject: [PATCH] Broadlink Integration add support for LB1 (#50953) Co-authored-by: Felipe Martins Diel <41558831+felipediel@users.noreply.github.com> --- .coveragerc | 1 + CODEOWNERS | 2 +- homeassistant/components/broadlink/const.py | 2 + homeassistant/components/broadlink/light.py | 136 ++++++++++++++++++ .../components/broadlink/manifest.json | 2 +- homeassistant/components/broadlink/updater.py | 9 ++ tests/components/broadlink/__init__.py | 4 +- 7 files changed, 152 insertions(+), 4 deletions(-) create mode 100644 homeassistant/components/broadlink/light.py diff --git a/.coveragerc b/.coveragerc index eb8b643d1b6..bd19ab31b52 100644 --- a/.coveragerc +++ b/.coveragerc @@ -131,6 +131,7 @@ omit = homeassistant/components/braviatv/remote.py homeassistant/components/broadlink/__init__.py homeassistant/components/broadlink/const.py + homeassistant/components/broadlink/light.py homeassistant/components/broadlink/remote.py homeassistant/components/broadlink/switch.py homeassistant/components/broadlink/updater.py diff --git a/CODEOWNERS b/CODEOWNERS index a1eb8373f21..2612cc3fd18 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -78,7 +78,7 @@ homeassistant/components/bmw_connected_drive/* @gerard33 @rikroe homeassistant/components/bond/* @bdraco @prystupa @joshs85 homeassistant/components/bosch_shc/* @tschamm homeassistant/components/braviatv/* @bieniu @Drafteed -homeassistant/components/broadlink/* @danielhiversen @felipediel +homeassistant/components/broadlink/* @danielhiversen @felipediel @L-I-Am homeassistant/components/brother/* @bieniu homeassistant/components/brunt/* @eavanvalkenburg homeassistant/components/bsblan/* @liudger diff --git a/homeassistant/components/broadlink/const.py b/homeassistant/components/broadlink/const.py index ed56e42342d..f40fd7785a1 100644 --- a/homeassistant/components/broadlink/const.py +++ b/homeassistant/components/broadlink/const.py @@ -1,4 +1,5 @@ """Constants for the Broadlink integration.""" +from homeassistant.components.light import DOMAIN as LIGHT_DOMAIN from homeassistant.components.remote import DOMAIN as REMOTE_DOMAIN from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN from homeassistant.components.switch import DOMAIN as SWITCH_DOMAIN @@ -33,6 +34,7 @@ DOMAINS_AND_TYPES = { "SP4", "SP4B", }, + LIGHT_DOMAIN: {"LB1"}, } DEFAULT_PORT = 80 diff --git a/homeassistant/components/broadlink/light.py b/homeassistant/components/broadlink/light.py new file mode 100644 index 00000000000..4fc8f4c2120 --- /dev/null +++ b/homeassistant/components/broadlink/light.py @@ -0,0 +1,136 @@ +"""Support for Broadlink lights.""" +import logging + +from broadlink.exceptions import BroadlinkException + +from homeassistant.components.light import ( + ATTR_BRIGHTNESS, + ATTR_COLOR_MODE, + ATTR_COLOR_TEMP, + ATTR_HS_COLOR, + COLOR_MODE_BRIGHTNESS, + COLOR_MODE_COLOR_TEMP, + COLOR_MODE_HS, + COLOR_MODE_UNKNOWN, + LightEntity, +) + +from .const import DOMAIN +from .entity import BroadlinkEntity + +_LOGGER = logging.getLogger(__name__) + +BROADLINK_COLOR_MODE_RGB = 0 +BROADLINK_COLOR_MODE_WHITE = 1 +BROADLINK_COLOR_MODE_SCENES = 2 + + +async def async_setup_entry(hass, config_entry, async_add_entities): + """Set up the Broadlink light.""" + device = hass.data[DOMAIN].devices[config_entry.entry_id] + + if device.api.type == "LB1": + lights = [BroadlinkLight(device)] + + async_add_entities(lights) + + +class BroadlinkLight(BroadlinkEntity, LightEntity): + """Representation of a Broadlink light.""" + + def __init__(self, device): + """Initialize the light.""" + super().__init__(device) + self._attr_name = f"{device.name} Light" + self._attr_unique_id = device.unique_id + self._attr_supported_color_modes = set() + + data = self._coordinator.data + + if {"hue", "saturation"}.issubset(data): + self._attr_supported_color_modes.add(COLOR_MODE_HS) + if "colortemp" in data: + self._attr_supported_color_modes.add(COLOR_MODE_COLOR_TEMP) + if not self.supported_color_modes: + self._attr_supported_color_modes = {COLOR_MODE_BRIGHTNESS} + + self._update_state(data) + + def _update_state(self, data): + """Update the state of the entity.""" + if "pwr" in data: + self._attr_is_on = bool(data["pwr"]) + + if "brightness" in data: + self._attr_brightness = round(data["brightness"] * 2.55) + + if self.supported_color_modes == {COLOR_MODE_BRIGHTNESS}: + self._attr_color_mode = COLOR_MODE_BRIGHTNESS + return + + if {"hue", "saturation"}.issubset(data): + self._attr_hs_color = [data["hue"], data["saturation"]] + + if "colortemp" in data: + self._attr_color_temp = round((data["colortemp"] - 2700) / 100 + 153) + + if "bulb_colormode" in data: + if data["bulb_colormode"] == BROADLINK_COLOR_MODE_RGB: + self._attr_color_mode = COLOR_MODE_HS + elif data["bulb_colormode"] == BROADLINK_COLOR_MODE_WHITE: + self._attr_color_mode = COLOR_MODE_COLOR_TEMP + else: + # Scenes are not yet supported. + self._attr_color_mode = COLOR_MODE_UNKNOWN + + async def async_turn_on(self, **kwargs): + """Turn on the light.""" + state = {"pwr": 1} + + if ATTR_BRIGHTNESS in kwargs: + brightness = kwargs[ATTR_BRIGHTNESS] + state["brightness"] = round(brightness / 2.55) + + if self.supported_color_modes == {COLOR_MODE_BRIGHTNESS}: + state["bulb_colormode"] = BROADLINK_COLOR_MODE_WHITE + + elif ATTR_HS_COLOR in kwargs: + hs_color = kwargs[ATTR_HS_COLOR] + state["hue"] = int(hs_color[0]) + state["saturation"] = int(hs_color[1]) + state["bulb_colormode"] = BROADLINK_COLOR_MODE_RGB + + elif ATTR_COLOR_TEMP in kwargs: + color_temp = kwargs[ATTR_COLOR_TEMP] + state["colortemp"] = (color_temp - 153) * 100 + 2700 + state["bulb_colormode"] = BROADLINK_COLOR_MODE_WHITE + + elif ATTR_COLOR_MODE in kwargs: + color_mode = kwargs[ATTR_COLOR_MODE] + if color_mode == COLOR_MODE_HS: + state["bulb_colormode"] = BROADLINK_COLOR_MODE_RGB + elif color_mode == COLOR_MODE_COLOR_TEMP: + state["bulb_colormode"] = BROADLINK_COLOR_MODE_WHITE + else: + # Scenes are not yet supported. + state["bulb_colormode"] = BROADLINK_COLOR_MODE_SCENES + + await self._async_set_state(state) + + async def async_turn_off(self, **kwargs): + """Turn off the light.""" + await self._async_set_state({"pwr": 0}) + + async def _async_set_state(self, state): + """Set the state of the light.""" + try: + state = await self._device.async_request( + self._device.api.set_state, **state + ) + except (BroadlinkException, OSError) as err: + _LOGGER.error("Failed to set state: %s", err) + return False + + self._update_state(state) + self.async_write_ha_state() + return True diff --git a/homeassistant/components/broadlink/manifest.json b/homeassistant/components/broadlink/manifest.json index aa895582240..1a6e94003ca 100644 --- a/homeassistant/components/broadlink/manifest.json +++ b/homeassistant/components/broadlink/manifest.json @@ -3,7 +3,7 @@ "name": "Broadlink", "documentation": "https://www.home-assistant.io/integrations/broadlink", "requirements": ["broadlink==0.18.0"], - "codeowners": ["@danielhiversen", "@felipediel"], + "codeowners": ["@danielhiversen", "@felipediel", "@L-I-Am"], "config_flow": true, "dhcp": [ { diff --git a/homeassistant/components/broadlink/updater.py b/homeassistant/components/broadlink/updater.py index a84eec07d68..29020b1e905 100644 --- a/homeassistant/components/broadlink/updater.py +++ b/homeassistant/components/broadlink/updater.py @@ -16,6 +16,7 @@ def get_update_manager(device): update_managers = { "A1": BroadlinkA1UpdateManager, "BG1": BroadlinkBG1UpdateManager, + "LB1": BroadlinkLB1UpdateManager, "MP1": BroadlinkMP1UpdateManager, "RM4MINI": BroadlinkRMUpdateManager, "RM4PRO": BroadlinkRMUpdateManager, @@ -175,3 +176,11 @@ class BroadlinkSP4UpdateManager(BroadlinkUpdateManager): async def async_fetch_data(self): """Fetch data from the device.""" return await self.device.async_request(self.device.api.get_state) + + +class BroadlinkLB1UpdateManager(BroadlinkUpdateManager): + """Manages updates for Broadlink LB1 devices.""" + + async def async_fetch_data(self): + """Fetch data from the device.""" + return await self.device.async_request(self.device.api.get_state) diff --git a/tests/components/broadlink/__init__.py b/tests/components/broadlink/__init__.py index a323fd5e276..ce7e79bdff6 100644 --- a/tests/components/broadlink/__init__.py +++ b/tests/components/broadlink/__init__.py @@ -71,9 +71,9 @@ BROADLINK_DEVICES = { "Kitchen": ( # Not supported. "192.168.0.64", "34ea34b61d2c", - "LB1", + "SB800TD", "Broadlink", - "LB1", + "SB800TD", 0x504E, 57, 5, -- GitLab