diff --git a/custom_components/vesync/__init__.py b/custom_components/vesync/__init__.py index 41bb19f..35026ea 100644 --- a/custom_components/vesync/__init__.py +++ b/custom_components/vesync/__init__.py @@ -59,8 +59,6 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> b _LOGGER.error("Unable to login to the VeSync server") return False - forward_setup = hass.config_entries.async_forward_entry_setup - hass.data[DOMAIN] = {config_entry.entry_id: {}} hass.data[DOMAIN][config_entry.entry_id][VS_MANAGER] = manager @@ -88,34 +86,48 @@ async def async_update_data(): device_dict = await async_process_devices(hass, manager) + platforms_to_setup = [] for p, vs_p in PLATFORMS.items(): hass.data[DOMAIN][config_entry.entry_id][vs_p] = [] if device_dict[vs_p]: hass.data[DOMAIN][config_entry.entry_id][vs_p].extend(device_dict[vs_p]) - hass.async_create_task(forward_setup(config_entry, p)) + platforms_to_setup.append(p) + + if platforms_to_setup: + await hass.config_entries.async_forward_entry_setups( + config_entry, platforms_to_setup + ) async def async_new_device_discovery(service: ServiceCall) -> None: """Discover if new devices should be added.""" manager = hass.data[DOMAIN][config_entry.entry_id][VS_MANAGER] dev_dict = await async_process_devices(hass, manager) - def _add_new_devices(platform: str) -> None: + new_platforms: list[Platform] = [] + + def _add_new_devices(platform: Platform) -> None: """Add new devices to hass.""" old_devices = hass.data[DOMAIN][config_entry.entry_id][PLATFORMS[platform]] if new_devices := list( set(dev_dict.get(VS_SWITCHES, [])).difference(old_devices) ): + had_devices = bool(old_devices) old_devices.extend(new_devices) - if old_devices: + if had_devices: async_dispatcher_send( hass, VS_DISCOVERY.format(PLATFORMS[platform]), new_devices ) else: - hass.async_create_task(forward_setup(config_entry, platform)) + new_platforms.append(platform) for k in PLATFORMS: _add_new_devices(k) + if new_platforms: + await hass.config_entries.async_forward_entry_setups( + config_entry, new_platforms + ) + hass.services.async_register( DOMAIN, SERVICE_UPDATE_DEVS, async_new_device_discovery ) diff --git a/custom_components/vesync/light.py b/custom_components/vesync/light.py index 73d0160..d7dc0c0 100644 --- a/custom_components/vesync/light.py +++ b/custom_components/vesync/light.py @@ -3,11 +3,13 @@ from homeassistant.components.light import ( ATTR_BRIGHTNESS, - ATTR_COLOR_TEMP, - COLOR_MODE_BRIGHTNESS, - COLOR_MODE_COLOR_TEMP, + ATTR_COLOR_TEMP_KELVIN, + ColorMode, LightEntity, ) + +MIN_COLOR_TEMP_KELVIN = 2700 +MAX_COLOR_TEMP_KELVIN = 6500 from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.dispatcher import async_dispatcher_connect @@ -102,18 +104,23 @@ def turn_on(self, **kwargs): """Turn the device on.""" attribute_adjustment_only = False # set white temperature - if self.color_mode in (COLOR_MODE_COLOR_TEMP,) and ATTR_COLOR_TEMP in kwargs: - # get white temperature from HA data - color_temp = int(kwargs[ATTR_COLOR_TEMP]) - # ensure value between min-max supported Mireds - color_temp = max(self.min_mireds, min(color_temp, self.max_mireds)) - # convert Mireds to Percent value that api expects + if ( + self.color_mode == ColorMode.COLOR_TEMP + and ATTR_COLOR_TEMP_KELVIN in kwargs + ): + # get white temperature from HA data (in Kelvin) + kelvin = int(kwargs[ATTR_COLOR_TEMP_KELVIN]) + # ensure value within supported Kelvin range + kelvin = max( + self.min_color_temp_kelvin, min(kelvin, self.max_color_temp_kelvin) + ) + # convert Kelvin to percent value that api expects + # (pyvesync scale: 0 = warmest, 100 = coldest — matches Kelvin direction) color_temp = round( - ((color_temp - self.min_mireds) / (self.max_mireds - self.min_mireds)) + (kelvin - self.min_color_temp_kelvin) + / (self.max_color_temp_kelvin - self.min_color_temp_kelvin) * 100 ) - # flip cold/warm to what pyvesync api expects - color_temp = 100 - color_temp # ensure value between 0-100 color_temp = max(0, min(color_temp, 100)) # call pyvesync library api method to set color_temp @@ -122,7 +129,7 @@ def turn_on(self, **kwargs): attribute_adjustment_only = True # set brightness level if ( - self.color_mode in (COLOR_MODE_BRIGHTNESS, COLOR_MODE_COLOR_TEMP) + self.color_mode in (ColorMode.BRIGHTNESS, ColorMode.COLOR_TEMP) and ATTR_BRIGHTNESS in kwargs ): # get brightness from HA data @@ -147,12 +154,12 @@ def __init__(self, device, coordinator) -> None: @property def color_mode(self): """Set color mode for this entity.""" - return COLOR_MODE_BRIGHTNESS + return ColorMode.BRIGHTNESS @property def supported_color_modes(self): """Flag supported color_modes (in an array format).""" - return [COLOR_MODE_BRIGHTNESS] + return {ColorMode.BRIGHTNESS} class VeSyncTunableWhiteLightHA(VeSyncBaseLight, LightEntity): @@ -163,51 +170,48 @@ def __init__(self, device, coordinator) -> None: super().__init__(device, coordinator) @property - def color_temp(self): - """Get device white temperature.""" - # get value from pyvesync library api, + def color_temp_kelvin(self): + """Get device white temperature in Kelvin.""" result = self.device.color_temp_pct try: - # check for validity of brightness value received color_temp_value = int(result) except ValueError: - # deal if any unexpected/non numeric value _LOGGER.debug( "VeSync - received unexpected 'color_temp_pct' value from pyvesync api: %s", result, ) - return 0 - # flip cold/warm - color_temp_value = 100 - color_temp_value + return None # ensure value between 0-100 color_temp_value = max(0, min(color_temp_value, 100)) - # convert percent value to Mireds - color_temp_value = round( - self.min_mireds - + ((self.max_mireds - self.min_mireds) / 100 * color_temp_value) + # convert percent value to Kelvin + # (pyvesync scale: 0 = warmest, 100 = coldest — matches Kelvin direction) + kelvin = round( + self.min_color_temp_kelvin + + (self.max_color_temp_kelvin - self.min_color_temp_kelvin) + * color_temp_value + / 100 ) - # ensure value between minimum and maximum Mireds - return max(self.min_mireds, min(color_temp_value, self.max_mireds)) + return max(self.min_color_temp_kelvin, min(kelvin, self.max_color_temp_kelvin)) @property - def min_mireds(self): - """Set device coldest white temperature.""" - return 154 # 154 Mireds ( 1,000,000 divided by 6500 Kelvin = 154 Mireds) + def min_color_temp_kelvin(self): + """Set device warmest white temperature.""" + return MIN_COLOR_TEMP_KELVIN @property - def max_mireds(self): - """Set device warmest white temperature.""" - return 370 # 370 Mireds ( 1,000,000 divided by 2700 Kelvin = 370 Mireds) + def max_color_temp_kelvin(self): + """Set device coldest white temperature.""" + return MAX_COLOR_TEMP_KELVIN @property def color_mode(self): """Set color mode for this entity.""" - return COLOR_MODE_COLOR_TEMP + return ColorMode.COLOR_TEMP @property def supported_color_modes(self): """Flag supported color_modes (in an array format).""" - return [COLOR_MODE_COLOR_TEMP] + return {ColorMode.COLOR_TEMP} class VeSyncNightLightHA(VeSyncDimmableLightHA):