diff --git a/.coveragerc b/.coveragerc index c30c78ddf65..7a51a591780 100644 --- a/.coveragerc +++ b/.coveragerc @@ -288,6 +288,7 @@ omit = homeassistant/components/hyperion/light.py homeassistant/components/ialarm/alarm_control_panel.py homeassistant/components/iaqualink/climate.py + homeassistant/components/iaqualink/light.py homeassistant/components/icloud/device_tracker.py homeassistant/components/idteck_prox/* homeassistant/components/ifttt/* diff --git a/homeassistant/components/iaqualink/__init__.py b/homeassistant/components/iaqualink/__init__.py index 95c6f6895fc..c7b7bc472dd 100644 --- a/homeassistant/components/iaqualink/__init__.py +++ b/homeassistant/components/iaqualink/__init__.py @@ -6,10 +6,16 @@ import logging from aiohttp import CookieJar import voluptuous as vol -from iaqualink import AqualinkClient, AqualinkLoginException, AqualinkThermostat +from iaqualink import ( + AqualinkClient, + AqualinkLight, + AqualinkLoginException, + AqualinkThermostat, +) from homeassistant import config_entries from homeassistant.components.climate import DOMAIN as CLIMATE_DOMAIN +from homeassistant.components.light import DOMAIN as LIGHT_DOMAIN from homeassistant.config_entries import ConfigEntry from homeassistant.const import CONF_PASSWORD, CONF_USERNAME from homeassistant.core import callback @@ -67,6 +73,7 @@ async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry) -> None # These will contain the initialized devices climates = hass.data[DOMAIN][CLIMATE_DOMAIN] = [] + lights = hass.data[DOMAIN][LIGHT_DOMAIN] = [] session = async_create_clientsession(hass, cookie_jar=CookieJar(unsafe=True)) aqualink = AqualinkClient(username, password, session) @@ -88,11 +95,16 @@ async def async_setup_entry(hass: HomeAssistantType, entry: ConfigEntry) -> None for dev in devices.values(): if isinstance(dev, AqualinkThermostat): climates += [dev] + elif isinstance(dev, AqualinkLight): + lights += [dev] forward_setup = hass.config_entries.async_forward_entry_setup if climates: _LOGGER.debug("Got %s climates: %s", len(climates), climates) hass.async_create_task(forward_setup(entry, CLIMATE_DOMAIN)) + if lights: + _LOGGER.debug("Got %s lights: %s", len(lights), lights) + hass.async_create_task(forward_setup(entry, LIGHT_DOMAIN)) async def _async_systems_update(now): """Refresh internal state for all systems.""" @@ -112,6 +124,8 @@ async def async_unload_entry(hass: HomeAssistantType, entry: ConfigEntry) -> boo if hass.data[DOMAIN][CLIMATE_DOMAIN]: tasks += [forward_unload(entry, CLIMATE_DOMAIN)] + if hass.data[DOMAIN][LIGHT_DOMAIN]: + tasks += [forward_unload(entry, LIGHT_DOMAIN)] hass.data[DOMAIN].clear() diff --git a/homeassistant/components/iaqualink/light.py b/homeassistant/components/iaqualink/light.py new file mode 100644 index 00000000000..fbfb10783ee --- /dev/null +++ b/homeassistant/components/iaqualink/light.py @@ -0,0 +1,105 @@ +"""Support for Aqualink pool lights.""" +import logging + +from iaqualink import AqualinkLight, AqualinkLightEffect + +from homeassistant.components.light import ( + ATTR_BRIGHTNESS, + ATTR_EFFECT, + DOMAIN, + SUPPORT_BRIGHTNESS, + SUPPORT_EFFECT, + Light, +) +from homeassistant.config_entries import ConfigEntry +from homeassistant.helpers.typing import HomeAssistantType + +from . import AqualinkEntity, refresh_system +from .const import DOMAIN as AQUALINK_DOMAIN + +_LOGGER = logging.getLogger(__name__) + +PARALLEL_UPDATES = 0 + + +async def async_setup_entry( + hass: HomeAssistantType, config_entry: ConfigEntry, async_add_entities +) -> None: + """Set up discovered lights.""" + devs = [] + for dev in hass.data[AQUALINK_DOMAIN][DOMAIN]: + devs.append(HassAqualinkLight(dev)) + async_add_entities(devs, True) + + +class HassAqualinkLight(Light, AqualinkEntity): + """Representation of a light.""" + + def __init__(self, dev: AqualinkLight): + """Initialize the light.""" + self.dev = dev + + @property + def name(self) -> str: + """Return the name of the light.""" + return self.dev.label + + @property + def is_on(self) -> bool: + """Return whether the light is on or off.""" + return self.dev.is_on + + @refresh_system + async def async_turn_on(self, **kwargs) -> None: + """Turn on the light. + + This handles brightness and light effects for lights that do support + them. + """ + brightness = kwargs.get(ATTR_BRIGHTNESS) + effect = kwargs.get(ATTR_EFFECT) + + # For now I'm assuming lights support either effects or brightness. + if effect: + effect = AqualinkLightEffect[effect].value + await self.dev.set_effect(effect) + elif brightness: + # Aqualink supports percentages in 25% increments. + pct = int(round(brightness * 4.0 / 255)) * 25 + await self.dev.set_brightness(pct) + else: + await self.dev.turn_on() + + @refresh_system + async def async_turn_off(self, **kwargs) -> None: + """Turn off the light.""" + await self.dev.turn_off() + + @property + def brightness(self) -> int: + """Return current brightness of the light. + + The scale needs converting between 0-100 and 0-255. + """ + return self.dev.brightness * 255 / 100 + + @property + def effect(self) -> str: + """Return the current light effect if supported.""" + return AqualinkLightEffect(self.dev.effect).name + + @property + def effect_list(self) -> list: + """Return supported light effects.""" + return list(AqualinkLightEffect.__members__) + + @property + def supported_features(self) -> int: + """Return the list of features supported by the light.""" + if self.dev.is_dimmer: + return SUPPORT_BRIGHTNESS + + if self.dev.is_color: + return SUPPORT_EFFECT + + return 0