diff --git a/.coveragerc b/.coveragerc index eb8b643d1b634aea9e80197256d3fd4a563fcf51..bd19ab31b5288337b395d53e44307e20baf43203 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 a1eb8373f2122d859f85eaa33c6b6180e1184e3e..2612cc3fd18194c89158a813eacc79e723117231 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 ed56e42342d845a2eef2e11a0f12b69b8f452912..f40fd7785a16f338b708c843f22a967ff8f74505 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 0000000000000000000000000000000000000000..4fc8f4c21208e9eb3518034cf979a6b5451fe298 --- /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 aa8955822402af62a29f341d36bd8dad4939fcea..1a6e94003ca24aa26072f09a933d8ddb7dbda595 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 a84eec07d68238a66975eaffd268118d499fe0c9..29020b1e9056203f43069a7c5095b2ef98fc294d 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 a323fd5e276ac8891c1172dac1157760ed1154d4..ce7e79bdff6420e896587b1a8f8dfd57412db823 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,