Fix/api calls (#138)

* add update coordinator

* down to 30s coordinator update.

* fix style.

* bump pyvesync

* bump pyvesync

* sourcery refactor.

* Fix missing vs_mode_auto (#143)

* Update manifest.json
This commit is contained in:
Vincent Le Bourlot 2023-04-28 09:57:43 +02:00 committed by GitHub
parent 8044649ba6
commit 2e2f77a95e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 205 additions and 88 deletions

View File

@ -1,11 +1,13 @@
"""VeSync integration.""" """VeSync integration."""
import logging import logging
from datetime import timedelta
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_PASSWORD, CONF_USERNAME, Platform from homeassistant.const import CONF_PASSWORD, CONF_USERNAME, Platform
from homeassistant.core import HomeAssistant, ServiceCall from homeassistant.core import HomeAssistant, ServiceCall
from homeassistant.helpers import config_validation as cv from homeassistant.helpers import config_validation as cv
from homeassistant.helpers.dispatcher import async_dispatcher_send from homeassistant.helpers.dispatcher import async_dispatcher_send
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
from pyvesync.vesync import VeSync from pyvesync.vesync import VeSync
from .common import async_process_devices from .common import async_process_devices
@ -53,13 +55,35 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> b
_LOGGER.error("Unable to login to the VeSync server") _LOGGER.error("Unable to login to the VeSync server")
return False return False
device_dict = await async_process_devices(hass, manager)
forward_setup = hass.config_entries.async_forward_entry_setup forward_setup = hass.config_entries.async_forward_entry_setup
hass.data[DOMAIN] = {config_entry.entry_id: {}} hass.data[DOMAIN] = {config_entry.entry_id: {}}
hass.data[DOMAIN][config_entry.entry_id][VS_MANAGER] = manager hass.data[DOMAIN][config_entry.entry_id][VS_MANAGER] = manager
# Create a DataUpdateCoordinator for the manager
async def async_update_data():
"""Fetch data from API endpoint."""
try:
await hass.async_add_executor_job(manager.update)
except Exception as err:
raise UpdateFailed(f"Update failed: {err}")
coordinator = DataUpdateCoordinator(
hass,
_LOGGER,
name="vesync",
update_method=async_update_data,
update_interval=timedelta(seconds=30),
)
# Fetch initial data so we have data when entities subscribe
await coordinator.async_refresh()
# Store the coordinator instance in hass.data
hass.data[DOMAIN][config_entry.entry_id]["coordinator"] = coordinator
device_dict = await async_process_devices(hass, manager)
for p, vs_p in PLATFORMS.items(): for p, vs_p in PLATFORMS.items():
hass.data[DOMAIN][config_entry.entry_id][vs_p] = [] hass.data[DOMAIN][config_entry.entry_id][vs_p] = []
if device_dict[vs_p]: if device_dict[vs_p]:

View File

@ -21,29 +21,33 @@ async def async_setup_entry(
) -> None: ) -> None:
"""Set up binary sensors.""" """Set up binary sensors."""
coordinator = hass.data[DOMAIN][config_entry.entry_id]["coordinator"]
@callback @callback
def discover(devices): def discover(devices):
"""Add new devices to platform.""" """Add new devices to platform."""
_setup_entities(devices, async_add_entities) _setup_entities(devices, async_add_entities, coordinator)
config_entry.async_on_unload( config_entry.async_on_unload(
async_dispatcher_connect(hass, VS_DISCOVERY.format(VS_BINARY_SENSORS), discover) async_dispatcher_connect(hass, VS_DISCOVERY.format(VS_BINARY_SENSORS), discover)
) )
_setup_entities( _setup_entities(
hass.data[DOMAIN][config_entry.entry_id][VS_BINARY_SENSORS], async_add_entities hass.data[DOMAIN][config_entry.entry_id][VS_BINARY_SENSORS],
async_add_entities,
coordinator,
) )
@callback @callback
def _setup_entities(devices, async_add_entities): def _setup_entities(devices, async_add_entities, coordinator):
"""Check if device is online and add entity.""" """Check if device is online and add entity."""
entities = [] entities = []
for dev in devices: for dev in devices:
if has_feature(dev, "details", "water_lacks"): if has_feature(dev, "details", "water_lacks"):
entities.append(VeSyncOutOfWaterSensor(dev)) entities.append(VeSyncOutOfWaterSensor(dev, coordinator))
if has_feature(dev, "details", "water_tank_lifted"): if has_feature(dev, "details", "water_tank_lifted"):
entities.append(VeSyncWaterTankLiftedSensor(dev)) entities.append(VeSyncWaterTankLiftedSensor(dev, coordinator))
async_add_entities(entities, update_before_add=True) async_add_entities(entities, update_before_add=True)
@ -51,9 +55,9 @@ def _setup_entities(devices, async_add_entities):
class VeSyncBinarySensorEntity(VeSyncBaseEntity, BinarySensorEntity): class VeSyncBinarySensorEntity(VeSyncBaseEntity, BinarySensorEntity):
"""Representation of a binary sensor describing diagnostics of a VeSync humidifier.""" """Representation of a binary sensor describing diagnostics of a VeSync humidifier."""
def __init__(self, humidifier): def __init__(self, humidifier, coordinator):
"""Initialize the VeSync humidifier device.""" """Initialize the VeSync humidifier device."""
super().__init__(humidifier) super().__init__(humidifier, coordinator)
self.smarthumidifier = humidifier self.smarthumidifier = humidifier
@property @property

View File

@ -3,6 +3,7 @@ import logging
from homeassistant.components.diagnostics import async_redact_data from homeassistant.components.diagnostics import async_redact_data
from homeassistant.helpers.entity import Entity, ToggleEntity from homeassistant.helpers.entity import Entity, ToggleEntity
from homeassistant.helpers.update_coordinator import CoordinatorEntity
from pyvesync.vesyncfan import model_features from pyvesync.vesyncfan import model_features
from .const import ( from .const import (
@ -48,7 +49,6 @@ async def async_process_devices(hass, manager):
VS_BINARY_SENSORS: [], VS_BINARY_SENSORS: [],
} }
await hass.async_add_executor_job(manager.update)
redacted = async_redact_data( redacted = async_redact_data(
{k: [d.__dict__ for d in v] for k, v in manager._dev_list.items()}, {k: [d.__dict__ for d in v] for k, v in manager._dev_list.items()},
["cid", "uuid", "mac_id"], ["cid", "uuid", "mac_id"],
@ -105,12 +105,13 @@ async def async_process_devices(hass, manager):
return devices return devices
class VeSyncBaseEntity(Entity): class VeSyncBaseEntity(CoordinatorEntity, Entity):
"""Base class for VeSync Entity Representations.""" """Base class for VeSync Entity Representations."""
def __init__(self, device): def __init__(self, device, coordinator):
"""Initialize the VeSync device.""" """Initialize the VeSync device."""
self.device = device self.device = device
super().__init__(coordinator, context=device)
@property @property
def base_unique_id(self): def base_unique_id(self):
@ -152,14 +153,20 @@ class VeSyncBaseEntity(Entity):
"sw_version": self.device.current_firm_version, "sw_version": self.device.current_firm_version,
} }
def update(self): async def async_added_to_hass(self):
"""Update vesync device.""" """When entity is added to hass."""
self.device.update() self.async_on_remove(
self.coordinator.async_add_listener(self.async_write_ha_state)
)
class VeSyncDevice(VeSyncBaseEntity, ToggleEntity): class VeSyncDevice(VeSyncBaseEntity, ToggleEntity):
"""Base class for VeSync Device Representations.""" """Base class for VeSync Device Representations."""
def __init__(self, device, coordinator):
"""Initialize the VeSync device."""
super().__init__(device, coordinator)
@property @property
def is_on(self): def is_on(self):
"""Return True if device is on.""" """Return True if device is on."""

View File

@ -33,32 +33,38 @@ async def async_setup_entry(
) -> None: ) -> None:
"""Set up the VeSync fan platform.""" """Set up the VeSync fan platform."""
coordinator = hass.data[DOMAIN][config_entry.entry_id]["coordinator"]
@callback @callback
def discover(devices): def discover(devices):
"""Add new devices to platform.""" """Add new devices to platform."""
_setup_entities(devices, async_add_entities) _setup_entities(devices, async_add_entities, coordinator)
config_entry.async_on_unload( config_entry.async_on_unload(
async_dispatcher_connect(hass, VS_DISCOVERY.format(VS_FANS), discover) async_dispatcher_connect(hass, VS_DISCOVERY.format(VS_FANS), discover)
) )
_setup_entities( _setup_entities(
hass.data[DOMAIN][config_entry.entry_id][VS_FANS], async_add_entities hass.data[DOMAIN][config_entry.entry_id][VS_FANS],
async_add_entities,
coordinator,
) )
@callback @callback
def _setup_entities(devices, async_add_entities): def _setup_entities(devices, async_add_entities, coordinator):
"""Check if device is online and add entity.""" """Check if device is online and add entity."""
async_add_entities([VeSyncFanHA(dev) for dev in devices], update_before_add=True) async_add_entities(
[VeSyncFanHA(dev, coordinator) for dev in devices], update_before_add=True
)
class VeSyncFanHA(VeSyncDevice, FanEntity): class VeSyncFanHA(VeSyncDevice, FanEntity):
"""Representation of a VeSync fan.""" """Representation of a VeSync fan."""
def __init__(self, fan): def __init__(self, fan, coordinator):
"""Initialize the VeSync fan device.""" """Initialize the VeSync fan device."""
super().__init__(fan) super().__init__(fan, coordinator)
self.smartfan = fan self.smartfan = fan
self._speed_range = (1, 1) self._speed_range = (1, 1)
self._attr_preset_modes = [VS_MODE_MANUAL, VS_MODE_AUTO, VS_MODE_SLEEP] self._attr_preset_modes = [VS_MODE_MANUAL, VS_MODE_AUTO, VS_MODE_SLEEP]

View File

@ -22,6 +22,7 @@ from .const import (
DOMAIN, DOMAIN,
VS_DISCOVERY, VS_DISCOVERY,
VS_HUMIDIFIERS, VS_HUMIDIFIERS,
VS_MODE_AUTO,
VS_MODE_HUMIDITY, VS_MODE_HUMIDITY,
VS_MODE_MANUAL, VS_MODE_MANUAL,
VS_MODE_SLEEP, VS_MODE_SLEEP,
@ -36,8 +37,9 @@ MIN_HUMIDITY = 30
VS_TO_HA_MODE_MAP = { VS_TO_HA_MODE_MAP = {
VS_MODE_MANUAL: MODE_NORMAL, VS_MODE_AUTO: MODE_AUTO,
VS_MODE_HUMIDITY: MODE_AUTO, VS_MODE_HUMIDITY: MODE_AUTO,
VS_MODE_MANUAL: MODE_NORMAL,
VS_MODE_SLEEP: MODE_SLEEP, VS_MODE_SLEEP: MODE_SLEEP,
} }
@ -51,25 +53,30 @@ async def async_setup_entry(
) -> None: ) -> None:
"""Set up the VeSync humidifier platform.""" """Set up the VeSync humidifier platform."""
coordinator = hass.data[DOMAIN][config_entry.entry_id]["coordinator"]
@callback @callback
def discover(devices): def discover(devices):
"""Add new devices to platform.""" """Add new devices to platform."""
_setup_entities(devices, async_add_entities) _setup_entities(devices, async_add_entities, coordinator)
config_entry.async_on_unload( config_entry.async_on_unload(
async_dispatcher_connect(hass, VS_DISCOVERY.format(VS_HUMIDIFIERS), discover) async_dispatcher_connect(hass, VS_DISCOVERY.format(VS_HUMIDIFIERS), discover)
) )
_setup_entities( _setup_entities(
hass.data[DOMAIN][config_entry.entry_id][VS_HUMIDIFIERS], async_add_entities hass.data[DOMAIN][config_entry.entry_id][VS_HUMIDIFIERS],
async_add_entities,
coordinator,
) )
@callback @callback
def _setup_entities(devices, async_add_entities): def _setup_entities(devices, async_add_entities, coordinator):
"""Check if device is online and add entity.""" """Check if device is online and add entity."""
async_add_entities( async_add_entities(
[VeSyncHumidifierHA(dev) for dev in devices], update_before_add=True [VeSyncHumidifierHA(dev, coordinator) for dev in devices],
update_before_add=True,
) )
@ -93,9 +100,9 @@ class VeSyncHumidifierHA(VeSyncDevice, HumidifierEntity):
_attr_max_humidity = MAX_HUMIDITY _attr_max_humidity = MAX_HUMIDITY
_attr_min_humidity = MIN_HUMIDITY _attr_min_humidity = MIN_HUMIDITY
def __init__(self, humidifier: VeSyncHumid200300S): def __init__(self, humidifier: VeSyncHumid200300S, coordinator):
"""Initialize the VeSync humidifier device.""" """Initialize the VeSync humidifier device."""
super().__init__(humidifier) super().__init__(humidifier, coordinator)
self.smarthumidifier = humidifier self.smarthumidifier = humidifier
@property @property
@ -157,10 +164,10 @@ class VeSyncHumidifierHA(VeSyncDevice, HumidifierEntity):
raise ValueError( raise ValueError(
"{humidity} is not between {self.min_humidity} and {self.max_humidity} (inclusive)" "{humidity} is not between {self.min_humidity} and {self.max_humidity} (inclusive)"
) )
success = self.smarthumidifier.set_humidity(humidity) if self.smarthumidifier.set_humidity(humidity):
if not success:
raise ValueError("An error occurred while setting humidity.")
self.schedule_update_ha_state() self.schedule_update_ha_state()
else:
raise ValueError("An error occurred while setting humidity.")
def set_mode(self, mode: str) -> None: def set_mode(self, mode: str) -> None:
"""Set the mode of the device.""" """Set the mode of the device."""
@ -168,10 +175,10 @@ class VeSyncHumidifierHA(VeSyncDevice, HumidifierEntity):
raise ValueError( raise ValueError(
"{mode} is not one of the valid available modes: {self.available_modes}" "{mode} is not one of the valid available modes: {self.available_modes}"
) )
success = self.smarthumidifier.set_humidity_mode(_get_vs_mode(mode)) if self.smarthumidifier.set_humidity_mode(_get_vs_mode(mode)):
if not success:
raise ValueError("An error occurred while setting mode.")
self.schedule_update_ha_state() self.schedule_update_ha_state()
else:
raise ValueError("An error occurred while setting mode.")
def turn_on( def turn_on(
self, self,

View File

@ -27,31 +27,35 @@ async def async_setup_entry(
) -> None: ) -> None:
"""Set up lights.""" """Set up lights."""
coordinator = hass.data[DOMAIN][config_entry.entry_id]["coordinator"]
@callback @callback
def discover(devices): def discover(devices):
"""Add new devices to platform.""" """Add new devices to platform."""
_setup_entities(devices, async_add_entities) _setup_entities(devices, async_add_entities, coordinator)
config_entry.async_on_unload( config_entry.async_on_unload(
async_dispatcher_connect(hass, VS_DISCOVERY.format(VS_LIGHTS), discover) async_dispatcher_connect(hass, VS_DISCOVERY.format(VS_LIGHTS), discover)
) )
_setup_entities( _setup_entities(
hass.data[DOMAIN][config_entry.entry_id][VS_LIGHTS], async_add_entities hass.data[DOMAIN][config_entry.entry_id][VS_LIGHTS],
async_add_entities,
coordinator,
) )
@callback @callback
def _setup_entities(devices, async_add_entities): def _setup_entities(devices, async_add_entities, coordinator):
"""Check if device is online and add entity.""" """Check if device is online and add entity."""
entities = [] entities = []
for dev in devices: for dev in devices:
if DEV_TYPE_TO_HA.get(dev.device_type) in ("walldimmer", "bulb-dimmable"): if DEV_TYPE_TO_HA.get(dev.device_type) in ("walldimmer", "bulb-dimmable"):
entities.append(VeSyncDimmableLightHA(dev)) entities.append(VeSyncDimmableLightHA(dev, coordinator))
if DEV_TYPE_TO_HA.get(dev.device_type) in ("bulb-tunable-white",): if DEV_TYPE_TO_HA.get(dev.device_type) in ("bulb-tunable-white",):
entities.append(VeSyncTunableWhiteLightHA(dev)) entities.append(VeSyncTunableWhiteLightHA(dev, coordinator))
if hasattr(dev, "night_light") and dev.night_light: if hasattr(dev, "night_light") and dev.night_light:
entities.append(VeSyncNightLightHA(dev)) entities.append(VeSyncNightLightHA(dev, coordinator))
async_add_entities(entities, update_before_add=True) async_add_entities(entities, update_before_add=True)
@ -84,6 +88,10 @@ def _ha_brightness_to_vesync(ha_brightness):
class VeSyncBaseLight(VeSyncDevice, LightEntity): class VeSyncBaseLight(VeSyncDevice, LightEntity):
"""Base class for VeSync Light Devices Representations.""" """Base class for VeSync Light Devices Representations."""
def __init_(self, light, coordinator):
"""Initialize the VeSync light device."""
super().__init__(light, coordinator)
@property @property
def brightness(self): def brightness(self):
"""Get light brightness.""" """Get light brightness."""
@ -132,6 +140,10 @@ class VeSyncBaseLight(VeSyncDevice, LightEntity):
class VeSyncDimmableLightHA(VeSyncBaseLight, LightEntity): class VeSyncDimmableLightHA(VeSyncBaseLight, LightEntity):
"""Representation of a VeSync dimmable light device.""" """Representation of a VeSync dimmable light device."""
def __init__(self, device, coordinator):
"""Initialize the VeSync dimmable light device."""
super().__init__(device, coordinator)
@property @property
def color_mode(self): def color_mode(self):
"""Set color mode for this entity.""" """Set color mode for this entity."""
@ -146,6 +158,10 @@ class VeSyncDimmableLightHA(VeSyncBaseLight, LightEntity):
class VeSyncTunableWhiteLightHA(VeSyncBaseLight, LightEntity): class VeSyncTunableWhiteLightHA(VeSyncBaseLight, LightEntity):
"""Representation of a VeSync Tunable White Light device.""" """Representation of a VeSync Tunable White Light device."""
def __init__(self, device, coordinator):
"""Initialize the VeSync Tunable White Light device."""
super().__init__(device, coordinator)
@property @property
def color_temp(self): def color_temp(self):
"""Get device white temperature.""" """Get device white temperature."""
@ -197,9 +213,9 @@ class VeSyncTunableWhiteLightHA(VeSyncBaseLight, LightEntity):
class VeSyncNightLightHA(VeSyncDimmableLightHA): class VeSyncNightLightHA(VeSyncDimmableLightHA):
"""Representation of the night light on a VeSync device.""" """Representation of the night light on a VeSync device."""
def __init__(self, device): def __init__(self, device, coordinator):
"""Initialize the VeSync device.""" """Initialize the VeSync device."""
super().__init__(device) super().__init__(device, coordinator)
self.device = device self.device = device
self.has_brightness = has_feature( self.has_brightness = has_feature(
self.device, "details", "night_light_brightness" self.device, "details", "night_light_brightness"

View File

@ -13,5 +13,5 @@
"iot_class": "cloud_polling", "iot_class": "cloud_polling",
"issue_tracker": "https://github.com/vlebourl/custom_vesync", "issue_tracker": "https://github.com/vlebourl/custom_vesync",
"requirements": ["pyvesync==2.1.6"], "requirements": ["pyvesync==2.1.6"],
"version": "0.2.5" "version": "1.0.0"
} }

View File

@ -23,33 +23,37 @@ async def async_setup_entry(
) -> None: ) -> None:
"""Set up numbers.""" """Set up numbers."""
coordinator = hass.data[DOMAIN][config_entry.entry_id]["coordinator"]
@callback @callback
def discover(devices): def discover(devices):
"""Add new devices to platform.""" """Add new devices to platform."""
_setup_entities(devices, async_add_entities) _setup_entities(devices, async_add_entities, coordinator)
config_entry.async_on_unload( config_entry.async_on_unload(
async_dispatcher_connect(hass, VS_DISCOVERY.format(VS_NUMBERS), discover) async_dispatcher_connect(hass, VS_DISCOVERY.format(VS_NUMBERS), discover)
) )
_setup_entities( _setup_entities(
hass.data[DOMAIN][config_entry.entry_id][VS_NUMBERS], async_add_entities hass.data[DOMAIN][config_entry.entry_id][VS_NUMBERS],
async_add_entities,
coordinator,
) )
@callback @callback
def _setup_entities(devices, async_add_entities): def _setup_entities(devices, async_add_entities, coordinator):
"""Check if device is online and add entity.""" """Check if device is online and add entity."""
entities = [] entities = []
for dev in devices: for dev in devices:
if has_feature(dev, "details", "mist_virtual_level"): if has_feature(dev, "details", "mist_virtual_level"):
entities.append(VeSyncHumidifierMistLevelHA(dev)) entities.append(VeSyncHumidifierMistLevelHA(dev, coordinator))
if has_feature(dev, "config", "auto_target_humidity"): if has_feature(dev, "config", "auto_target_humidity"):
entities.append(VeSyncHumidifierTargetLevelHA(dev)) entities.append(VeSyncHumidifierTargetLevelHA(dev, coordinator))
if has_feature(dev, "details", "warm_mist_level"): if has_feature(dev, "details", "warm_mist_level"):
entities.append(VeSyncHumidifierWarmthLevelHA(dev)) entities.append(VeSyncHumidifierWarmthLevelHA(dev, coordinator))
if has_feature(dev, "config_dict", "levels"): if has_feature(dev, "config_dict", "levels"):
entities.append(VeSyncFanSpeedLevelHA(dev)) entities.append(VeSyncFanSpeedLevelHA(dev, coordinator))
async_add_entities(entities, update_before_add=True) async_add_entities(entities, update_before_add=True)
@ -57,9 +61,9 @@ def _setup_entities(devices, async_add_entities):
class VeSyncNumberEntity(VeSyncBaseEntity, NumberEntity): class VeSyncNumberEntity(VeSyncBaseEntity, NumberEntity):
"""Representation of a number for configuring a VeSync fan.""" """Representation of a number for configuring a VeSync fan."""
def __init__(self, device): def __init__(self, device, coordinator):
"""Initialize the VeSync fan device.""" """Initialize the VeSync fan device."""
super().__init__(device) super().__init__(device, coordinator)
@property @property
def entity_category(self): def entity_category(self):
@ -70,9 +74,9 @@ class VeSyncNumberEntity(VeSyncBaseEntity, NumberEntity):
class VeSyncFanSpeedLevelHA(VeSyncNumberEntity): class VeSyncFanSpeedLevelHA(VeSyncNumberEntity):
"""Representation of the fan speed level of a VeSync fan.""" """Representation of the fan speed level of a VeSync fan."""
def __init__(self, device): def __init__(self, device, coordinator):
"""Initialize the number entity.""" """Initialize the number entity."""
super().__init__(device) super().__init__(device, coordinator)
self._attr_native_min_value = device.config_dict["levels"][0] self._attr_native_min_value = device.config_dict["levels"][0]
self._attr_native_max_value = device.config_dict["levels"][-1] self._attr_native_max_value = device.config_dict["levels"][-1]
self._attr_native_step = 1 self._attr_native_step = 1
@ -105,9 +109,9 @@ class VeSyncFanSpeedLevelHA(VeSyncNumberEntity):
class VeSyncHumidifierMistLevelHA(VeSyncNumberEntity): class VeSyncHumidifierMistLevelHA(VeSyncNumberEntity):
"""Representation of the mist level of a VeSync humidifier.""" """Representation of the mist level of a VeSync humidifier."""
def __init__(self, device): def __init__(self, device, coordinator):
"""Initialize the number entity.""" """Initialize the number entity."""
super().__init__(device) super().__init__(device, coordinator)
self._attr_native_min_value = device.config_dict["mist_levels"][0] self._attr_native_min_value = device.config_dict["mist_levels"][0]
self._attr_native_max_value = device.config_dict["mist_levels"][-1] self._attr_native_max_value = device.config_dict["mist_levels"][-1]
self._attr_native_step = 1 self._attr_native_step = 1
@ -140,9 +144,9 @@ class VeSyncHumidifierMistLevelHA(VeSyncNumberEntity):
class VeSyncHumidifierWarmthLevelHA(VeSyncNumberEntity): class VeSyncHumidifierWarmthLevelHA(VeSyncNumberEntity):
"""Representation of the warmth level of a VeSync humidifier.""" """Representation of the warmth level of a VeSync humidifier."""
def __init__(self, device): def __init__(self, device, coordinator):
"""Initialize the number entity.""" """Initialize the number entity."""
super().__init__(device) super().__init__(device, coordinator)
self._attr_native_min_value = device.config_dict["warm_mist_levels"][0] self._attr_native_min_value = device.config_dict["warm_mist_levels"][0]
self._attr_native_max_value = device.config_dict["warm_mist_levels"][-1] self._attr_native_max_value = device.config_dict["warm_mist_levels"][-1]
self._attr_native_step = 1 self._attr_native_step = 1
@ -175,9 +179,9 @@ class VeSyncHumidifierWarmthLevelHA(VeSyncNumberEntity):
class VeSyncHumidifierTargetLevelHA(VeSyncNumberEntity): class VeSyncHumidifierTargetLevelHA(VeSyncNumberEntity):
"""Representation of the target humidity level of a VeSync humidifier.""" """Representation of the target humidity level of a VeSync humidifier."""
def __init__(self, device): def __init__(self, device, coordinator):
"""Initialize the number entity.""" """Initialize the number entity."""
super().__init__(device) super().__init__(device, coordinator)
self._attr_native_min_value = MIN_HUMIDITY self._attr_native_min_value = MIN_HUMIDITY
self._attr_native_max_value = MAX_HUMIDITY self._attr_native_max_value = MAX_HUMIDITY
self._attr_native_step = 1 self._attr_native_step = 1

View File

@ -26,33 +26,42 @@ async def async_setup_entry(
) -> None: ) -> None:
"""Set up switches.""" """Set up switches."""
coordinator = hass.data[DOMAIN][config_entry.entry_id]["coordinator"]
@callback @callback
def discover(devices): def discover(devices):
"""Add new devices to platform.""" """Add new devices to platform."""
_setup_entities(devices, async_add_entities) _setup_entities(devices, async_add_entities, coordinator)
config_entry.async_on_unload( config_entry.async_on_unload(
async_dispatcher_connect(hass, VS_DISCOVERY.format(VS_SENSORS), discover) async_dispatcher_connect(hass, VS_DISCOVERY.format(VS_SENSORS), discover)
) )
_setup_entities( _setup_entities(
hass.data[DOMAIN][config_entry.entry_id][VS_SENSORS], async_add_entities hass.data[DOMAIN][config_entry.entry_id][VS_SENSORS],
async_add_entities,
coordinator,
) )
@callback @callback
def _setup_entities(devices, async_add_entities): def _setup_entities(devices, async_add_entities, coordinator):
"""Check if device is online and add entity.""" """Check if device is online and add entity."""
entities = [] entities = []
for dev in devices: for dev in devices:
if DEV_TYPE_TO_HA.get(dev.device_type) == "outlet": if DEV_TYPE_TO_HA.get(dev.device_type) == "outlet":
entities.extend((VeSyncPowerSensor(dev), VeSyncEnergySensor(dev))) entities.extend(
(
VeSyncPowerSensor(dev, coordinator),
VeSyncEnergySensor(dev, coordinator),
)
)
if has_feature(dev, "details", "humidity"): if has_feature(dev, "details", "humidity"):
entities.append(VeSyncHumiditySensor(dev)) entities.append(VeSyncHumiditySensor(dev, coordinator))
if has_feature(dev, "details", "air_quality"): if has_feature(dev, "details", "air_quality"):
entities.append(VeSyncAirQualitySensor(dev)) entities.append(VeSyncAirQualitySensor(dev, coordinator))
if has_feature(dev, "details", "filter_life"): if has_feature(dev, "details", "filter_life"):
entities.append(VeSyncFilterLifeSensor(dev)) entities.append(VeSyncFilterLifeSensor(dev, coordinator))
async_add_entities(entities, update_before_add=True) async_add_entities(entities, update_before_add=True)
@ -60,9 +69,9 @@ def _setup_entities(devices, async_add_entities):
class VeSyncOutletSensorEntity(VeSyncBaseEntity, SensorEntity): class VeSyncOutletSensorEntity(VeSyncBaseEntity, SensorEntity):
"""Representation of a sensor describing diagnostics of a VeSync outlet.""" """Representation of a sensor describing diagnostics of a VeSync outlet."""
def __init__(self, plug): def __init__(self, plug, coordinator):
"""Initialize the VeSync outlet device.""" """Initialize the VeSync outlet device."""
super().__init__(plug) super().__init__(plug, coordinator)
self.smartplug = plug self.smartplug = plug
@property @property
@ -74,6 +83,10 @@ class VeSyncOutletSensorEntity(VeSyncBaseEntity, SensorEntity):
class VeSyncPowerSensor(VeSyncOutletSensorEntity): class VeSyncPowerSensor(VeSyncOutletSensorEntity):
"""Representation of current power use for a VeSync outlet.""" """Representation of current power use for a VeSync outlet."""
def __init__(self, plug, coordinator):
"""Initialize the VeSync outlet device."""
super().__init__(plug, coordinator)
@property @property
def unique_id(self): def unique_id(self):
"""Return unique ID for power sensor on device.""" """Return unique ID for power sensor on device."""
@ -113,9 +126,9 @@ class VeSyncPowerSensor(VeSyncOutletSensorEntity):
class VeSyncEnergySensor(VeSyncOutletSensorEntity): class VeSyncEnergySensor(VeSyncOutletSensorEntity):
"""Representation of current day's energy use for a VeSync outlet.""" """Representation of current day's energy use for a VeSync outlet."""
def __init__(self, plug): def __init__(self, plug, coordinator):
"""Initialize the VeSync outlet device.""" """Initialize the VeSync outlet device."""
super().__init__(plug) super().__init__(plug, coordinator)
self.smartplug = plug self.smartplug = plug
@property @property
@ -157,9 +170,9 @@ class VeSyncEnergySensor(VeSyncOutletSensorEntity):
class VeSyncHumidifierSensorEntity(VeSyncBaseEntity, SensorEntity): class VeSyncHumidifierSensorEntity(VeSyncBaseEntity, SensorEntity):
"""Representation of a sensor describing diagnostics of a VeSync humidifier.""" """Representation of a sensor describing diagnostics of a VeSync humidifier."""
def __init__(self, humidifier): def __init__(self, humidifier, coordinator):
"""Initialize the VeSync humidifier device.""" """Initialize the VeSync humidifier device."""
super().__init__(humidifier) super().__init__(humidifier, coordinator)
self.smarthumidifier = humidifier self.smarthumidifier = humidifier
@property @property
@ -174,6 +187,10 @@ class VeSyncAirQualitySensor(VeSyncHumidifierSensorEntity):
_attr_state_class = SensorStateClass.MEASUREMENT _attr_state_class = SensorStateClass.MEASUREMENT
_attr_device_class = SensorDeviceClass.AQI _attr_device_class = SensorDeviceClass.AQI
def __init__(self, plug, coordinator):
"""Initialize the VeSync outlet device."""
super().__init__(plug, coordinator)
@property @property
def unique_id(self): def unique_id(self):
"""Return unique ID for air quality sensor on device.""" """Return unique ID for air quality sensor on device."""
@ -198,6 +215,10 @@ class VeSyncAirQualitySensor(VeSyncHumidifierSensorEntity):
class VeSyncFilterLifeSensor(VeSyncHumidifierSensorEntity): class VeSyncFilterLifeSensor(VeSyncHumidifierSensorEntity):
"""Representation of a filter life sensor.""" """Representation of a filter life sensor."""
def __init__(self, plug, coordinator):
"""Initialize the VeSync outlet device."""
super().__init__(plug, coordinator)
@property @property
def unique_id(self): def unique_id(self):
"""Return unique ID for filter life sensor on device.""" """Return unique ID for filter life sensor on device."""
@ -245,6 +266,10 @@ class VeSyncFilterLifeSensor(VeSyncHumidifierSensorEntity):
class VeSyncHumiditySensor(VeSyncHumidifierSensorEntity): class VeSyncHumiditySensor(VeSyncHumidifierSensorEntity):
"""Representation of current humidity for a VeSync humidifier.""" """Representation of current humidity for a VeSync humidifier."""
def __init__(self, humidity, coordinator):
"""Initialize the VeSync outlet device."""
super().__init__(humidity, coordinator)
@property @property
def unique_id(self): def unique_id(self):
"""Return unique ID for humidity sensor on device.""" """Return unique ID for humidity sensor on device."""

View File

@ -21,37 +21,41 @@ async def async_setup_entry(
) -> None: ) -> None:
"""Set up switches.""" """Set up switches."""
coordinator = hass.data[DOMAIN][config_entry.entry_id]["coordinator"]
@callback @callback
def discover(devices): def discover(devices):
"""Add new devices to platform.""" """Add new devices to platform."""
_setup_entities(devices, async_add_entities) _setup_entities(devices, async_add_entities, coordinator)
config_entry.async_on_unload( config_entry.async_on_unload(
async_dispatcher_connect(hass, VS_DISCOVERY.format(VS_SWITCHES), discover) async_dispatcher_connect(hass, VS_DISCOVERY.format(VS_SWITCHES), discover)
) )
_setup_entities( _setup_entities(
hass.data[DOMAIN][config_entry.entry_id][VS_SWITCHES], async_add_entities hass.data[DOMAIN][config_entry.entry_id][VS_SWITCHES],
async_add_entities,
coordinator,
) )
@callback @callback
def _setup_entities(devices, async_add_entities): def _setup_entities(devices, async_add_entities, coordinator):
"""Check if device is online and add entity.""" """Check if device is online and add entity."""
entities = [] entities = []
for dev in devices: for dev in devices:
if DEV_TYPE_TO_HA.get(dev.device_type) == "outlet": if DEV_TYPE_TO_HA.get(dev.device_type) == "outlet":
entities.append(VeSyncSwitchHA(dev)) entities.append(VeSyncSwitchHA(dev, coordinator))
if DEV_TYPE_TO_HA.get(dev.device_type) == "switch": if DEV_TYPE_TO_HA.get(dev.device_type) == "switch":
entities.append(VeSyncLightSwitch(dev)) entities.append(VeSyncLightSwitch(dev, coordinator))
if getattr(dev, "set_auto_mode", None): if getattr(dev, "set_auto_mode", None):
entities.append(VeSyncHumidifierAutoOnHA(dev)) entities.append(VeSyncHumidifierAutoOnHA(dev, coordinator))
if getattr(dev, "automatic_stop_on", None): if getattr(dev, "automatic_stop_on", None):
entities.append(VeSyncHumidifierAutomaticStopHA(dev)) entities.append(VeSyncHumidifierAutomaticStopHA(dev, coordinator))
if getattr(dev, "turn_on_display", None): if getattr(dev, "turn_on_display", None):
entities.append(VeSyncHumidifierDisplayHA(dev)) entities.append(VeSyncHumidifierDisplayHA(dev, coordinator))
if getattr(dev, "child_lock_on", None): if getattr(dev, "child_lock_on", None):
entities.append(VeSyncFanChildLockHA(dev)) entities.append(VeSyncFanChildLockHA(dev, coordinator))
async_add_entities(entities, update_before_add=True) async_add_entities(entities, update_before_add=True)
@ -59,6 +63,10 @@ def _setup_entities(devices, async_add_entities):
class VeSyncBaseSwitch(VeSyncDevice, SwitchEntity): class VeSyncBaseSwitch(VeSyncDevice, SwitchEntity):
"""Base class for VeSync switch Device Representations.""" """Base class for VeSync switch Device Representations."""
def __init__(self, plug, coordinator):
"""Initialize the VeSync outlet device."""
super().__init__(plug, coordinator)
def turn_on(self, **kwargs): def turn_on(self, **kwargs):
"""Turn the device on.""" """Turn the device on."""
self.device.turn_on() self.device.turn_on()
@ -67,9 +75,9 @@ class VeSyncBaseSwitch(VeSyncDevice, SwitchEntity):
class VeSyncSwitchHA(VeSyncBaseSwitch, SwitchEntity): class VeSyncSwitchHA(VeSyncBaseSwitch, SwitchEntity):
"""Representation of a VeSync switch.""" """Representation of a VeSync switch."""
def __init__(self, plug): def __init__(self, plug, coordinator):
"""Initialize the VeSync switch device.""" """Initialize the VeSync switch device."""
super().__init__(plug) super().__init__(plug, coordinator)
self.smartplug = plug self.smartplug = plug
@property @property
@ -95,18 +103,18 @@ class VeSyncSwitchHA(VeSyncBaseSwitch, SwitchEntity):
class VeSyncLightSwitch(VeSyncBaseSwitch, SwitchEntity): class VeSyncLightSwitch(VeSyncBaseSwitch, SwitchEntity):
"""Handle representation of VeSync Light Switch.""" """Handle representation of VeSync Light Switch."""
def __init__(self, switch): def __init__(self, switch, coordinator):
"""Initialize Light Switch device class.""" """Initialize Light Switch device class."""
super().__init__(switch) super().__init__(switch, coordinator)
self.switch = switch self.switch = switch
class VeSyncSwitchEntity(VeSyncBaseEntity, SwitchEntity): class VeSyncSwitchEntity(VeSyncBaseEntity, SwitchEntity):
"""Representation of a switch for configuring a VeSync humidifier.""" """Representation of a switch for configuring a VeSync humidifier."""
def __init__(self, humidifier): def __init__(self, humidifier, coordinator):
"""Initialize the VeSync humidifier device.""" """Initialize the VeSync humidifier device."""
super().__init__(humidifier) super().__init__(humidifier, coordinator)
self.smarthumidifier = humidifier self.smarthumidifier = humidifier
@property @property
@ -118,6 +126,10 @@ class VeSyncSwitchEntity(VeSyncBaseEntity, SwitchEntity):
class VeSyncFanChildLockHA(VeSyncSwitchEntity): class VeSyncFanChildLockHA(VeSyncSwitchEntity):
"""Representation of the child lock switch.""" """Representation of the child lock switch."""
def __init__(self, lock, coordinator):
"""Initialize the VeSync outlet device."""
super().__init__(lock, coordinator)
@property @property
def unique_id(self): def unique_id(self):
"""Return the ID of this display.""" """Return the ID of this display."""
@ -145,6 +157,10 @@ class VeSyncFanChildLockHA(VeSyncSwitchEntity):
class VeSyncHumidifierDisplayHA(VeSyncSwitchEntity): class VeSyncHumidifierDisplayHA(VeSyncSwitchEntity):
"""Representation of the child lock switch.""" """Representation of the child lock switch."""
def __init__(self, lock, coordinator):
"""Initialize the VeSync outlet device."""
super().__init__(lock, coordinator)
@property @property
def unique_id(self): def unique_id(self):
"""Return the ID of this display.""" """Return the ID of this display."""
@ -172,6 +188,10 @@ class VeSyncHumidifierDisplayHA(VeSyncSwitchEntity):
class VeSyncHumidifierAutomaticStopHA(VeSyncSwitchEntity): class VeSyncHumidifierAutomaticStopHA(VeSyncSwitchEntity):
"""Representation of the automatic stop toggle on a VeSync humidifier.""" """Representation of the automatic stop toggle on a VeSync humidifier."""
def __init__(self, automatic, coordinator):
"""Initialize the VeSync outlet device."""
super().__init__(automatic, coordinator)
@property @property
def unique_id(self): def unique_id(self):
"""Return the ID of this device.""" """Return the ID of this device."""
@ -199,6 +219,10 @@ class VeSyncHumidifierAutomaticStopHA(VeSyncSwitchEntity):
class VeSyncHumidifierAutoOnHA(VeSyncSwitchEntity): class VeSyncHumidifierAutoOnHA(VeSyncSwitchEntity):
"""Provide switch to turn off auto mode and set manual mist level 1 on a VeSync humidifier.""" """Provide switch to turn off auto mode and set manual mist level 1 on a VeSync humidifier."""
def __init__(self, autooff, coordinator):
"""Initialize the VeSync outlet device."""
super().__init__(autooff, coordinator)
@property @property
def unique_id(self): def unique_id(self):
"""Return the ID of this device.""" """Return the ID of this device."""