diff --git a/.coveragerc b/.coveragerc index 2b71ba546cc..d66f4032f74 100644 --- a/.coveragerc +++ b/.coveragerc @@ -1042,6 +1042,7 @@ omit = homeassistant/components/vesync/common.py homeassistant/components/vesync/const.py homeassistant/components/vesync/fan.py + homeassistant/components/vesync/light.py homeassistant/components/vesync/switch.py homeassistant/components/viaggiatreno/sensor.py homeassistant/components/vicare/* diff --git a/homeassistant/components/vesync/__init__.py b/homeassistant/components/vesync/__init__.py index 94a0d5c2f25..24bd0f000df 100644 --- a/homeassistant/components/vesync/__init__.py +++ b/homeassistant/components/vesync/__init__.py @@ -18,11 +18,12 @@ from .const import ( VS_DISCOVERY, VS_DISPATCHERS, VS_FANS, + VS_LIGHTS, VS_MANAGER, VS_SWITCHES, ) -PLATFORMS = ["switch", "fan"] +PLATFORMS = ["switch", "fan", "light"] _LOGGER = logging.getLogger(__name__) @@ -85,6 +86,7 @@ async def async_setup_entry(hass, config_entry): switches = hass.data[DOMAIN][VS_SWITCHES] = [] fans = hass.data[DOMAIN][VS_FANS] = [] + lights = hass.data[DOMAIN][VS_LIGHTS] = [] hass.data[DOMAIN][VS_DISPATCHERS] = [] @@ -96,15 +98,21 @@ async def async_setup_entry(hass, config_entry): fans.extend(device_dict[VS_FANS]) hass.async_create_task(forward_setup(config_entry, "fan")) + if device_dict[VS_LIGHTS]: + lights.extend(device_dict[VS_LIGHTS]) + hass.async_create_task(forward_setup(config_entry, "light")) + async def async_new_device_discovery(service): """Discover if new devices should be added.""" manager = hass.data[DOMAIN][VS_MANAGER] switches = hass.data[DOMAIN][VS_SWITCHES] fans = hass.data[DOMAIN][VS_FANS] + lights = hass.data[DOMAIN][VS_LIGHTS] dev_dict = await async_process_devices(hass, manager) switch_devs = dev_dict.get(VS_SWITCHES, []) fan_devs = dev_dict.get(VS_FANS, []) + light_devs = dev_dict.get(VS_LIGHTS, []) switch_set = set(switch_devs) new_switches = list(switch_set.difference(switches)) @@ -126,6 +134,16 @@ async def async_setup_entry(hass, config_entry): fans.extend(new_fans) hass.async_create_task(forward_setup(config_entry, "fan")) + light_set = set(light_devs) + new_lights = list(light_set.difference(lights)) + if new_lights and lights: + lights.extend(new_lights) + async_dispatcher_send(hass, VS_DISCOVERY.format(VS_LIGHTS), new_lights) + return + if new_lights and not lights: + lights.extend(new_lights) + hass.async_create_task(forward_setup(config_entry, "light")) + hass.services.async_register( DOMAIN, SERVICE_UPDATE_DEVS, async_new_device_discovery ) diff --git a/homeassistant/components/vesync/common.py b/homeassistant/components/vesync/common.py index 42e3516f085..240a5e48287 100644 --- a/homeassistant/components/vesync/common.py +++ b/homeassistant/components/vesync/common.py @@ -3,7 +3,7 @@ import logging from homeassistant.helpers.entity import ToggleEntity -from .const import VS_FANS, VS_SWITCHES +from .const import VS_FANS, VS_LIGHTS, VS_SWITCHES _LOGGER = logging.getLogger(__name__) @@ -13,6 +13,7 @@ async def async_process_devices(hass, manager): devices = {} devices[VS_SWITCHES] = [] devices[VS_FANS] = [] + devices[VS_LIGHTS] = [] await hass.async_add_executor_job(manager.update) @@ -28,7 +29,9 @@ async def async_process_devices(hass, manager): for switch in manager.switches: if not switch.is_dimmable(): devices[VS_SWITCHES].append(switch) - _LOGGER.info("%d VeSync standard switches found", len(manager.switches)) + else: + devices[VS_LIGHTS].append(switch) + _LOGGER.info("%d VeSync switches found", len(manager.switches)) return devices diff --git a/homeassistant/components/vesync/const.py b/homeassistant/components/vesync/const.py index 9923ab94ecf..5d9dfc8aa5d 100644 --- a/homeassistant/components/vesync/const.py +++ b/homeassistant/components/vesync/const.py @@ -7,4 +7,5 @@ SERVICE_UPDATE_DEVS = "update_devices" VS_SWITCHES = "switches" VS_FANS = "fans" +VS_LIGHTS = "lights" VS_MANAGER = "manager" diff --git a/homeassistant/components/vesync/light.py b/homeassistant/components/vesync/light.py new file mode 100644 index 00000000000..53dfdc5f0a9 --- /dev/null +++ b/homeassistant/components/vesync/light.py @@ -0,0 +1,85 @@ +"""Support for VeSync dimmers.""" +import logging + +from homeassistant.components.light import ( + ATTR_BRIGHTNESS, + SUPPORT_BRIGHTNESS, + LightEntity, +) +from homeassistant.core import callback +from homeassistant.helpers.dispatcher import async_dispatcher_connect + +from .common import VeSyncDevice +from .const import DOMAIN, VS_DISCOVERY, VS_DISPATCHERS, VS_LIGHTS + +_LOGGER = logging.getLogger(__name__) + +DEV_TYPE_TO_HA = { + "ESD16": "light", + "ESWD16": "light", +} + + +async def async_setup_entry(hass, config_entry, async_add_entities): + """Set up lights.""" + + async def async_discover(devices): + """Add new devices to platform.""" + _async_setup_entities(devices, async_add_entities) + + disp = async_dispatcher_connect( + hass, VS_DISCOVERY.format(VS_LIGHTS), async_discover + ) + hass.data[DOMAIN][VS_DISPATCHERS].append(disp) + + _async_setup_entities(hass.data[DOMAIN][VS_LIGHTS], async_add_entities) + return True + + +@callback +def _async_setup_entities(devices, async_add_entities): + """Check if device is online and add entity.""" + dev_list = [] + for dev in devices: + if DEV_TYPE_TO_HA.get(dev.device_type) == "light": + dev_list.append(VeSyncDimmerHA(dev)) + else: + _LOGGER.debug( + "%s - Unknown device type - %s", dev.device_name, dev.device_type + ) + continue + + async_add_entities(dev_list, update_before_add=True) + + +class VeSyncDimmerHA(VeSyncDevice, LightEntity): + """Representation of a VeSync dimmer.""" + + def __init__(self, dimmer): + """Initialize the VeSync dimmer device.""" + super().__init__(dimmer) + self.dimmer = dimmer + + def turn_on(self, **kwargs): + """Turn the device on.""" + if ATTR_BRIGHTNESS in kwargs: + # get brightness from HA data + brightness = int(kwargs[ATTR_BRIGHTNESS]) + # convert to percent that vesync api expects + brightness = round((brightness / 255) * 100) + # clamp to 1-100 + brightness = max(1, min(brightness, 100)) + self.dimmer.set_brightness(brightness) + # Avoid turning device back on if this is just a brightness adjustment + if not self.is_on: + self.device.turn_on() + + @property + def supported_features(self): + """Get supported features for this entity.""" + return SUPPORT_BRIGHTNESS + + @property + def brightness(self): + """Get dimmer brightness.""" + return round((int(self.dimmer.brightness) / 100) * 255)