Vesync air quality (#72658)
This commit is contained in:
parent
7ecb527648
commit
8c16ac2e47
5 changed files with 169 additions and 164 deletions
|
@ -20,6 +20,8 @@ async def async_process_devices(hass, manager):
|
||||||
|
|
||||||
if manager.fans:
|
if manager.fans:
|
||||||
devices[VS_FANS].extend(manager.fans)
|
devices[VS_FANS].extend(manager.fans)
|
||||||
|
# Expose fan sensors separately
|
||||||
|
devices[VS_SENSORS].extend(manager.fans)
|
||||||
_LOGGER.info("%d VeSync fans found", len(manager.fans))
|
_LOGGER.info("%d VeSync fans found", len(manager.fans))
|
||||||
|
|
||||||
if manager.bulbs:
|
if manager.bulbs:
|
||||||
|
@ -49,31 +51,25 @@ class VeSyncBaseEntity(Entity):
|
||||||
def __init__(self, device):
|
def __init__(self, device):
|
||||||
"""Initialize the VeSync device."""
|
"""Initialize the VeSync device."""
|
||||||
self.device = device
|
self.device = device
|
||||||
|
self._attr_unique_id = self.base_unique_id
|
||||||
|
self._attr_name = self.base_name
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def base_unique_id(self):
|
def base_unique_id(self):
|
||||||
"""Return the ID of this device."""
|
"""Return the ID of this device."""
|
||||||
|
# The unique_id property may be overridden in subclasses, such as in
|
||||||
|
# sensors. Maintaining base_unique_id allows us to group related
|
||||||
|
# entities under a single device.
|
||||||
if isinstance(self.device.sub_device_no, int):
|
if isinstance(self.device.sub_device_no, int):
|
||||||
return f"{self.device.cid}{str(self.device.sub_device_no)}"
|
return f"{self.device.cid}{str(self.device.sub_device_no)}"
|
||||||
return self.device.cid
|
return self.device.cid
|
||||||
|
|
||||||
@property
|
|
||||||
def unique_id(self):
|
|
||||||
"""Return the ID of this device."""
|
|
||||||
# The unique_id property may be overridden in subclasses, such as in sensors. Maintaining base_unique_id allows
|
|
||||||
# us to group related entities under a single device.
|
|
||||||
return self.base_unique_id
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def base_name(self):
|
def base_name(self):
|
||||||
"""Return the name of the device."""
|
"""Return the name of the device."""
|
||||||
|
# Same story here as `base_unique_id` above
|
||||||
return self.device.device_name
|
return self.device.device_name
|
||||||
|
|
||||||
@property
|
|
||||||
def name(self):
|
|
||||||
"""Return the name of the entity (may be overridden)."""
|
|
||||||
return self.base_name
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def available(self) -> bool:
|
def available(self) -> bool:
|
||||||
"""Return True if device is available."""
|
"""Return True if device is available."""
|
||||||
|
@ -98,6 +94,11 @@ class VeSyncBaseEntity(Entity):
|
||||||
class VeSyncDevice(VeSyncBaseEntity, ToggleEntity):
|
class VeSyncDevice(VeSyncBaseEntity, ToggleEntity):
|
||||||
"""Base class for VeSync Device Representations."""
|
"""Base class for VeSync Device Representations."""
|
||||||
|
|
||||||
|
@property
|
||||||
|
def details(self):
|
||||||
|
"""Provide access to the device details dictionary."""
|
||||||
|
return self.device.details
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_on(self):
|
def is_on(self):
|
||||||
"""Return True if device is on."""
|
"""Return True if device is on."""
|
||||||
|
|
|
@ -9,3 +9,31 @@ VS_FANS = "fans"
|
||||||
VS_LIGHTS = "lights"
|
VS_LIGHTS = "lights"
|
||||||
VS_SENSORS = "sensors"
|
VS_SENSORS = "sensors"
|
||||||
VS_MANAGER = "manager"
|
VS_MANAGER = "manager"
|
||||||
|
|
||||||
|
DEV_TYPE_TO_HA = {
|
||||||
|
"wifi-switch-1.3": "outlet",
|
||||||
|
"ESW03-USA": "outlet",
|
||||||
|
"ESW01-EU": "outlet",
|
||||||
|
"ESW15-USA": "outlet",
|
||||||
|
"ESWL01": "switch",
|
||||||
|
"ESWL03": "switch",
|
||||||
|
"ESO15-TB": "outlet",
|
||||||
|
}
|
||||||
|
|
||||||
|
SKU_TO_BASE_DEVICE = {
|
||||||
|
"LV-PUR131S": "LV-PUR131S",
|
||||||
|
"LV-RH131S": "LV-PUR131S", # Alt ID Model LV-PUR131S
|
||||||
|
"Core200S": "Core200S",
|
||||||
|
"LAP-C201S-AUSR": "Core200S", # Alt ID Model Core200S
|
||||||
|
"LAP-C202S-WUSR": "Core200S", # Alt ID Model Core200S
|
||||||
|
"Core300S": "Core300S",
|
||||||
|
"LAP-C301S-WJP": "Core300S", # Alt ID Model Core300S
|
||||||
|
"Core400S": "Core400S",
|
||||||
|
"LAP-C401S-WJP": "Core400S", # Alt ID Model Core400S
|
||||||
|
"LAP-C401S-WUSR": "Core400S", # Alt ID Model Core400S
|
||||||
|
"LAP-C401S-WAAA": "Core400S", # Alt ID Model Core400S
|
||||||
|
"Core600S": "Core600S",
|
||||||
|
"LAP-C601S-WUS": "Core600S", # Alt ID Model Core600S
|
||||||
|
"LAP-C601S-WUSR": "Core600S", # Alt ID Model Core600S
|
||||||
|
"LAP-C601S-WEU": "Core600S", # Alt ID Model Core600S
|
||||||
|
}
|
||||||
|
|
|
@ -14,26 +14,16 @@ from homeassistant.util.percentage import (
|
||||||
)
|
)
|
||||||
|
|
||||||
from .common import VeSyncDevice
|
from .common import VeSyncDevice
|
||||||
from .const import DOMAIN, VS_DISCOVERY, VS_FANS
|
from .const import DOMAIN, SKU_TO_BASE_DEVICE, VS_DISCOVERY, VS_FANS
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
DEV_TYPE_TO_HA = {
|
DEV_TYPE_TO_HA = {
|
||||||
"LV-PUR131S": "fan",
|
"LV-PUR131S": "fan",
|
||||||
"LV-RH131S": "fan", # Alt ID Model LV-PUR131S
|
|
||||||
"Core200S": "fan",
|
"Core200S": "fan",
|
||||||
"LAP-C201S-AUSR": "fan", # Alt ID Model Core200S
|
|
||||||
"LAP-C202S-WUSR": "fan", # Alt ID Model Core200S
|
|
||||||
"Core300S": "fan",
|
"Core300S": "fan",
|
||||||
"LAP-C301S-WJP": "fan", # Alt ID Model Core300S
|
|
||||||
"Core400S": "fan",
|
"Core400S": "fan",
|
||||||
"LAP-C401S-WJP": "fan", # Alt ID Model Core400S
|
|
||||||
"LAP-C401S-WUSR": "fan", # Alt ID Model Core400S
|
|
||||||
"LAP-C401S-WAAA": "fan", # Alt ID Model Core400S
|
|
||||||
"Core600S": "fan",
|
"Core600S": "fan",
|
||||||
"LAP-C601S-WUS": "fan", # Alt ID Model Core600S
|
|
||||||
"LAP-C601S-WUSR": "fan", # Alt ID Model Core600S
|
|
||||||
"LAP-C601S-WEU": "fan", # Alt ID Model Core600S
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FAN_MODE_AUTO = "auto"
|
FAN_MODE_AUTO = "auto"
|
||||||
|
@ -41,37 +31,17 @@ FAN_MODE_SLEEP = "sleep"
|
||||||
|
|
||||||
PRESET_MODES = {
|
PRESET_MODES = {
|
||||||
"LV-PUR131S": [FAN_MODE_AUTO, FAN_MODE_SLEEP],
|
"LV-PUR131S": [FAN_MODE_AUTO, FAN_MODE_SLEEP],
|
||||||
"LV-RH131S": [FAN_MODE_AUTO, FAN_MODE_SLEEP], # Alt ID Model LV-PUR131S
|
|
||||||
"Core200S": [FAN_MODE_SLEEP],
|
"Core200S": [FAN_MODE_SLEEP],
|
||||||
"LAP-C201S-AUSR": [FAN_MODE_SLEEP], # Alt ID Model Core200S
|
|
||||||
"LAP-C202S-WUSR": [FAN_MODE_SLEEP], # Alt ID Model Core200S
|
|
||||||
"Core300S": [FAN_MODE_AUTO, FAN_MODE_SLEEP],
|
"Core300S": [FAN_MODE_AUTO, FAN_MODE_SLEEP],
|
||||||
"LAP-C301S-WJP": [FAN_MODE_AUTO, FAN_MODE_SLEEP], # Alt ID Model Core300S
|
|
||||||
"Core400S": [FAN_MODE_AUTO, FAN_MODE_SLEEP],
|
"Core400S": [FAN_MODE_AUTO, FAN_MODE_SLEEP],
|
||||||
"LAP-C401S-WJP": [FAN_MODE_AUTO, FAN_MODE_SLEEP], # Alt ID Model Core400S
|
|
||||||
"LAP-C401S-WUSR": [FAN_MODE_AUTO, FAN_MODE_SLEEP], # Alt ID Model Core400S
|
|
||||||
"LAP-C401S-WAAA": [FAN_MODE_AUTO, FAN_MODE_SLEEP], # Alt ID Model Core400S
|
|
||||||
"Core600S": [FAN_MODE_AUTO, FAN_MODE_SLEEP],
|
"Core600S": [FAN_MODE_AUTO, FAN_MODE_SLEEP],
|
||||||
"LAP-C601S-WUS": [FAN_MODE_AUTO, FAN_MODE_SLEEP], # Alt ID Model Core600S
|
|
||||||
"LAP-C601S-WUSR": [FAN_MODE_AUTO, FAN_MODE_SLEEP], # Alt ID Model Core600S
|
|
||||||
"LAP-C601S-WEU": [FAN_MODE_AUTO, FAN_MODE_SLEEP], # Alt ID Model Core600S
|
|
||||||
}
|
}
|
||||||
SPEED_RANGE = { # off is not included
|
SPEED_RANGE = { # off is not included
|
||||||
"LV-PUR131S": (1, 3),
|
"LV-PUR131S": (1, 3),
|
||||||
"LV-RH131S": (1, 3), # ALt ID Model LV-PUR131S
|
|
||||||
"Core200S": (1, 3),
|
"Core200S": (1, 3),
|
||||||
"LAP-C201S-AUSR": (1, 3), # ALt ID Model Core200S
|
|
||||||
"LAP-C202S-WUSR": (1, 3), # ALt ID Model Core200S
|
|
||||||
"Core300S": (1, 3),
|
"Core300S": (1, 3),
|
||||||
"LAP-C301S-WJP": (1, 3), # ALt ID Model Core300S
|
|
||||||
"Core400S": (1, 4),
|
"Core400S": (1, 4),
|
||||||
"LAP-C401S-WJP": (1, 4), # ALt ID Model Core400S
|
|
||||||
"LAP-C401S-WUSR": (1, 4), # ALt ID Model Core400S
|
|
||||||
"LAP-C401S-WAAA": (1, 4), # ALt ID Model Core400S
|
|
||||||
"Core600S": (1, 4),
|
"Core600S": (1, 4),
|
||||||
"LAP-C601S-WUS": (1, 4), # ALt ID Model Core600S
|
|
||||||
"LAP-C601S-WUSR": (1, 4), # ALt ID Model Core600S
|
|
||||||
"LAP-C601S-WEU": (1, 4), # ALt ID Model Core600S
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -99,7 +69,7 @@ def _setup_entities(devices, async_add_entities):
|
||||||
"""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) == "fan":
|
if DEV_TYPE_TO_HA.get(SKU_TO_BASE_DEVICE.get(dev.device_type)) == "fan":
|
||||||
entities.append(VeSyncFanHA(dev))
|
entities.append(VeSyncFanHA(dev))
|
||||||
else:
|
else:
|
||||||
_LOGGER.warning(
|
_LOGGER.warning(
|
||||||
|
@ -128,19 +98,21 @@ class VeSyncFanHA(VeSyncDevice, FanEntity):
|
||||||
and (current_level := self.smartfan.fan_level) is not None
|
and (current_level := self.smartfan.fan_level) is not None
|
||||||
):
|
):
|
||||||
return ranged_value_to_percentage(
|
return ranged_value_to_percentage(
|
||||||
SPEED_RANGE[self.device.device_type], current_level
|
SPEED_RANGE[SKU_TO_BASE_DEVICE[self.device.device_type]], current_level
|
||||||
)
|
)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def speed_count(self) -> int:
|
def speed_count(self) -> int:
|
||||||
"""Return the number of speeds the fan supports."""
|
"""Return the number of speeds the fan supports."""
|
||||||
return int_states_in_range(SPEED_RANGE[self.device.device_type])
|
return int_states_in_range(
|
||||||
|
SPEED_RANGE[SKU_TO_BASE_DEVICE[self.device.device_type]]
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def preset_modes(self):
|
def preset_modes(self):
|
||||||
"""Get the list of available preset modes."""
|
"""Get the list of available preset modes."""
|
||||||
return PRESET_MODES[self.device.device_type]
|
return PRESET_MODES[SKU_TO_BASE_DEVICE.get(self.device.device_type)]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def preset_mode(self):
|
def preset_mode(self):
|
||||||
|
@ -171,15 +143,9 @@ class VeSyncFanHA(VeSyncDevice, FanEntity):
|
||||||
if hasattr(self.smartfan, "night_light"):
|
if hasattr(self.smartfan, "night_light"):
|
||||||
attr["night_light"] = self.smartfan.night_light
|
attr["night_light"] = self.smartfan.night_light
|
||||||
|
|
||||||
if self.smartfan.details.get("air_quality_value") is not None:
|
|
||||||
attr["air_quality"] = self.smartfan.details["air_quality_value"]
|
|
||||||
|
|
||||||
if hasattr(self.smartfan, "mode"):
|
if hasattr(self.smartfan, "mode"):
|
||||||
attr["mode"] = self.smartfan.mode
|
attr["mode"] = self.smartfan.mode
|
||||||
|
|
||||||
if hasattr(self.smartfan, "filter_life"):
|
|
||||||
attr["filter_life"] = self.smartfan.filter_life
|
|
||||||
|
|
||||||
return attr
|
return attr
|
||||||
|
|
||||||
def set_percentage(self, percentage):
|
def set_percentage(self, percentage):
|
||||||
|
@ -195,7 +161,7 @@ class VeSyncFanHA(VeSyncDevice, FanEntity):
|
||||||
self.smartfan.change_fan_speed(
|
self.smartfan.change_fan_speed(
|
||||||
math.ceil(
|
math.ceil(
|
||||||
percentage_to_ranged_value(
|
percentage_to_ranged_value(
|
||||||
SPEED_RANGE[self.device.device_type], percentage
|
SPEED_RANGE[SKU_TO_BASE_DEVICE[self.device.device_type]], percentage
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,25 +1,119 @@
|
||||||
"""Support for power & energy sensors for VeSync outlets."""
|
"""Support for power & energy sensors for VeSync outlets."""
|
||||||
|
from collections.abc import Callable
|
||||||
|
from dataclasses import dataclass
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from homeassistant.components.sensor import (
|
from homeassistant.components.sensor import (
|
||||||
SensorDeviceClass,
|
SensorDeviceClass,
|
||||||
SensorEntity,
|
SensorEntity,
|
||||||
|
SensorEntityDescription,
|
||||||
SensorStateClass,
|
SensorStateClass,
|
||||||
)
|
)
|
||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.const import ENERGY_KILO_WATT_HOUR, POWER_WATT
|
from homeassistant.const import (
|
||||||
|
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||||
|
ENERGY_KILO_WATT_HOUR,
|
||||||
|
PERCENTAGE,
|
||||||
|
POWER_WATT,
|
||||||
|
)
|
||||||
from homeassistant.core import HomeAssistant, callback
|
from homeassistant.core import HomeAssistant, callback
|
||||||
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||||
from homeassistant.helpers.entity import EntityCategory
|
from homeassistant.helpers.entity import EntityCategory
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
|
from homeassistant.helpers.typing import StateType
|
||||||
|
|
||||||
from .common import VeSyncBaseEntity
|
from .common import VeSyncBaseEntity, VeSyncDevice
|
||||||
from .const import DOMAIN, VS_DISCOVERY, VS_SENSORS
|
from .const import DEV_TYPE_TO_HA, DOMAIN, SKU_TO_BASE_DEVICE, VS_DISCOVERY, VS_SENSORS
|
||||||
from .switch import DEV_TYPE_TO_HA
|
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class VeSyncSensorEntityDescriptionMixin:
|
||||||
|
"""Mixin for required keys."""
|
||||||
|
|
||||||
|
value_fn: Callable[[VeSyncDevice], StateType]
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class VeSyncSensorEntityDescription(
|
||||||
|
SensorEntityDescription, VeSyncSensorEntityDescriptionMixin
|
||||||
|
):
|
||||||
|
"""Describe VeSync sensor entity."""
|
||||||
|
|
||||||
|
exists_fn: Callable[[VeSyncDevice], bool] = lambda _: True
|
||||||
|
update_fn: Callable[[VeSyncDevice], None] = lambda _: None
|
||||||
|
|
||||||
|
|
||||||
|
def update_energy(device):
|
||||||
|
"""Update outlet details and energy usage."""
|
||||||
|
device.update()
|
||||||
|
device.update_energy()
|
||||||
|
|
||||||
|
|
||||||
|
def sku_supported(device, supported):
|
||||||
|
"""Get the base device of which a device is an instance."""
|
||||||
|
return SKU_TO_BASE_DEVICE.get(device.device_type) in supported
|
||||||
|
|
||||||
|
|
||||||
|
def ha_dev_type(device):
|
||||||
|
"""Get the homeassistant device_type for a given device."""
|
||||||
|
return DEV_TYPE_TO_HA.get(device.device_type)
|
||||||
|
|
||||||
|
|
||||||
|
FILTER_LIFE_SUPPORTED = ["LV-PUR131S", "Core200S", "Core300S", "Core400S", "Core600S"]
|
||||||
|
AIR_QUALITY_SUPPORTED = ["LV-PUR131S", "Core400S", "Core600S"]
|
||||||
|
PM25_SUPPORTED = ["Core400S", "Core600S"]
|
||||||
|
|
||||||
|
SENSORS: tuple[VeSyncSensorEntityDescription, ...] = (
|
||||||
|
VeSyncSensorEntityDescription(
|
||||||
|
key="filter-life",
|
||||||
|
name="Filter Life",
|
||||||
|
native_unit_of_measurement=PERCENTAGE,
|
||||||
|
state_class=SensorStateClass.MEASUREMENT,
|
||||||
|
entity_category=EntityCategory.DIAGNOSTIC,
|
||||||
|
value_fn=lambda device: device.details["filter_life"],
|
||||||
|
exists_fn=lambda device: sku_supported(device, FILTER_LIFE_SUPPORTED),
|
||||||
|
),
|
||||||
|
VeSyncSensorEntityDescription(
|
||||||
|
key="air-quality",
|
||||||
|
name="Air Quality",
|
||||||
|
state_class=SensorStateClass.MEASUREMENT,
|
||||||
|
value_fn=lambda device: device.details["air_quality"],
|
||||||
|
exists_fn=lambda device: sku_supported(device, AIR_QUALITY_SUPPORTED),
|
||||||
|
),
|
||||||
|
VeSyncSensorEntityDescription(
|
||||||
|
key="pm25",
|
||||||
|
name="PM2.5",
|
||||||
|
device_class=SensorDeviceClass.PM25,
|
||||||
|
native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||||
|
state_class=SensorStateClass.MEASUREMENT,
|
||||||
|
value_fn=lambda device: device.details["air_quality_value"],
|
||||||
|
exists_fn=lambda device: sku_supported(device, PM25_SUPPORTED),
|
||||||
|
),
|
||||||
|
VeSyncSensorEntityDescription(
|
||||||
|
key="power",
|
||||||
|
name="current power",
|
||||||
|
device_class=SensorDeviceClass.POWER,
|
||||||
|
native_unit_of_measurement=POWER_WATT,
|
||||||
|
state_class=SensorStateClass.MEASUREMENT,
|
||||||
|
value_fn=lambda device: device.details["power"],
|
||||||
|
update_fn=update_energy,
|
||||||
|
exists_fn=lambda device: ha_dev_type(device) == "outlet",
|
||||||
|
),
|
||||||
|
VeSyncSensorEntityDescription(
|
||||||
|
key="energy",
|
||||||
|
name="energy use today",
|
||||||
|
device_class=SensorDeviceClass.ENERGY,
|
||||||
|
native_unit_of_measurement=ENERGY_KILO_WATT_HOUR,
|
||||||
|
state_class=SensorStateClass.TOTAL_INCREASING,
|
||||||
|
value_fn=lambda device: device.details["energy"],
|
||||||
|
update_fn=update_energy,
|
||||||
|
exists_fn=lambda device: ha_dev_type(device) == "outlet",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_entry(
|
async def async_setup_entry(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
config_entry: ConfigEntry,
|
config_entry: ConfigEntry,
|
||||||
|
@ -44,107 +138,33 @@ def _setup_entities(devices, async_add_entities):
|
||||||
"""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":
|
for description in SENSORS:
|
||||||
# Not an outlet that supports energy/power, so do not create sensor entities
|
if description.exists_fn(dev):
|
||||||
continue
|
entities.append(VeSyncSensorEntity(dev, description))
|
||||||
entities.append(VeSyncPowerSensor(dev))
|
|
||||||
entities.append(VeSyncEnergySensor(dev))
|
|
||||||
|
|
||||||
async_add_entities(entities, update_before_add=True)
|
async_add_entities(entities, update_before_add=True)
|
||||||
|
|
||||||
|
|
||||||
class VeSyncSensorEntity(VeSyncBaseEntity, SensorEntity):
|
class VeSyncSensorEntity(VeSyncBaseEntity, SensorEntity):
|
||||||
"""Representation of a sensor describing diagnostics of a VeSync outlet."""
|
"""Representation of a sensor describing a VeSync device."""
|
||||||
|
|
||||||
def __init__(self, plug):
|
entity_description: VeSyncSensorEntityDescription
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
device: VeSyncDevice,
|
||||||
|
description: VeSyncSensorEntityDescription,
|
||||||
|
) -> None:
|
||||||
"""Initialize the VeSync outlet device."""
|
"""Initialize the VeSync outlet device."""
|
||||||
super().__init__(plug)
|
super().__init__(device)
|
||||||
self.smartplug = plug
|
self.entity_description = description
|
||||||
|
self._attr_name = f"{super().name} {description.name}"
|
||||||
|
self._attr_unique_id = f"{super().unique_id}-{description.key}"
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def entity_category(self):
|
def native_value(self) -> StateType:
|
||||||
"""Return the diagnostic entity category."""
|
"""Return the state of the sensor."""
|
||||||
return EntityCategory.DIAGNOSTIC
|
return self.entity_description.value_fn(self.device)
|
||||||
|
|
||||||
|
def update(self) -> None:
|
||||||
class VeSyncPowerSensor(VeSyncSensorEntity):
|
"""Run the update function defined for the sensor."""
|
||||||
"""Representation of current power use for a VeSync outlet."""
|
return self.entity_description.update_fn(self.device)
|
||||||
|
|
||||||
@property
|
|
||||||
def unique_id(self):
|
|
||||||
"""Return unique ID for power sensor on device."""
|
|
||||||
return f"{super().unique_id}-power"
|
|
||||||
|
|
||||||
@property
|
|
||||||
def name(self):
|
|
||||||
"""Return sensor name."""
|
|
||||||
return f"{super().name} current power"
|
|
||||||
|
|
||||||
@property
|
|
||||||
def device_class(self):
|
|
||||||
"""Return the power device class."""
|
|
||||||
return SensorDeviceClass.POWER
|
|
||||||
|
|
||||||
@property
|
|
||||||
def native_value(self):
|
|
||||||
"""Return the current power usage in W."""
|
|
||||||
return self.smartplug.power
|
|
||||||
|
|
||||||
@property
|
|
||||||
def native_unit_of_measurement(self):
|
|
||||||
"""Return the Watt unit of measurement."""
|
|
||||||
return POWER_WATT
|
|
||||||
|
|
||||||
@property
|
|
||||||
def state_class(self):
|
|
||||||
"""Return the measurement state class."""
|
|
||||||
return SensorStateClass.MEASUREMENT
|
|
||||||
|
|
||||||
def update(self):
|
|
||||||
"""Update outlet details and energy usage."""
|
|
||||||
self.smartplug.update()
|
|
||||||
self.smartplug.update_energy()
|
|
||||||
|
|
||||||
|
|
||||||
class VeSyncEnergySensor(VeSyncSensorEntity):
|
|
||||||
"""Representation of current day's energy use for a VeSync outlet."""
|
|
||||||
|
|
||||||
def __init__(self, plug):
|
|
||||||
"""Initialize the VeSync outlet device."""
|
|
||||||
super().__init__(plug)
|
|
||||||
self.smartplug = plug
|
|
||||||
|
|
||||||
@property
|
|
||||||
def unique_id(self):
|
|
||||||
"""Return unique ID for power sensor on device."""
|
|
||||||
return f"{super().unique_id}-energy"
|
|
||||||
|
|
||||||
@property
|
|
||||||
def name(self):
|
|
||||||
"""Return sensor name."""
|
|
||||||
return f"{super().name} energy use today"
|
|
||||||
|
|
||||||
@property
|
|
||||||
def device_class(self):
|
|
||||||
"""Return the energy device class."""
|
|
||||||
return SensorDeviceClass.ENERGY
|
|
||||||
|
|
||||||
@property
|
|
||||||
def native_value(self):
|
|
||||||
"""Return the today total energy usage in kWh."""
|
|
||||||
return self.smartplug.energy_today
|
|
||||||
|
|
||||||
@property
|
|
||||||
def native_unit_of_measurement(self):
|
|
||||||
"""Return the kWh unit of measurement."""
|
|
||||||
return ENERGY_KILO_WATT_HOUR
|
|
||||||
|
|
||||||
@property
|
|
||||||
def state_class(self):
|
|
||||||
"""Return the total_increasing state class."""
|
|
||||||
return SensorStateClass.TOTAL_INCREASING
|
|
||||||
|
|
||||||
def update(self):
|
|
||||||
"""Update outlet details and energy usage."""
|
|
||||||
self.smartplug.update()
|
|
||||||
self.smartplug.update_energy()
|
|
||||||
|
|
|
@ -8,20 +8,10 @@ from homeassistant.helpers.dispatcher import async_dispatcher_connect
|
||||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||||
|
|
||||||
from .common import VeSyncDevice
|
from .common import VeSyncDevice
|
||||||
from .const import DOMAIN, VS_DISCOVERY, VS_SWITCHES
|
from .const import DEV_TYPE_TO_HA, DOMAIN, VS_DISCOVERY, VS_SWITCHES
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
DEV_TYPE_TO_HA = {
|
|
||||||
"wifi-switch-1.3": "outlet",
|
|
||||||
"ESW03-USA": "outlet",
|
|
||||||
"ESW01-EU": "outlet",
|
|
||||||
"ESW15-USA": "outlet",
|
|
||||||
"ESWL01": "switch",
|
|
||||||
"ESWL03": "switch",
|
|
||||||
"ESO15-TB": "outlet",
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
async def async_setup_entry(
|
async def async_setup_entry(
|
||||||
hass: HomeAssistant,
|
hass: HomeAssistant,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue