1 """Support for voltage, power & energy sensors for VeSync outlets."""
3 from __future__
import annotations
5 from collections.abc
import Callable
6 from dataclasses
import dataclass
9 from pyvesync.vesyncfan
import VeSyncAirBypass
10 from pyvesync.vesyncoutlet
import VeSyncOutlet
11 from pyvesync.vesyncswitch
import VeSyncSwitch
16 SensorEntityDescription,
21 CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
24 UnitOfElectricPotential,
33 from .const
import DEV_TYPE_TO_HA, DOMAIN, SKU_TO_BASE_DEVICE, VS_DISCOVERY, VS_SENSORS
34 from .entity
import VeSyncBaseEntity
36 _LOGGER = logging.getLogger(__name__)
39 @dataclass(frozen=True, kw_only=True)
41 """Describe VeSync sensor entity."""
43 value_fn: Callable[[VeSyncAirBypass | VeSyncOutlet | VeSyncSwitch], StateType]
45 exists_fn: Callable[[VeSyncAirBypass | VeSyncOutlet | VeSyncSwitch], bool] = (
48 update_fn: Callable[[VeSyncAirBypass | VeSyncOutlet | VeSyncSwitch],
None] = (
54 """Update outlet details and energy usage."""
56 device.update_energy()
60 """Get the base device of which a device is an instance."""
61 return SKU_TO_BASE_DEVICE.get(device.device_type)
in supported
65 """Get the homeassistant device_type for a given device."""
66 return DEV_TYPE_TO_HA.get(device.device_type)
69 FILTER_LIFE_SUPPORTED = [
79 AIR_QUALITY_SUPPORTED = [
96 SENSORS: tuple[VeSyncSensorEntityDescription, ...] = (
99 translation_key=
"filter_life",
100 native_unit_of_measurement=PERCENTAGE,
101 state_class=SensorStateClass.MEASUREMENT,
102 entity_category=EntityCategory.DIAGNOSTIC,
103 value_fn=
lambda device: device.filter_life,
104 exists_fn=
lambda device:
sku_supported(device, FILTER_LIFE_SUPPORTED),
108 translation_key=
"air_quality",
109 value_fn=
lambda device: device.details[
"air_quality"],
110 exists_fn=
lambda device:
sku_supported(device, AIR_QUALITY_SUPPORTED),
114 device_class=SensorDeviceClass.PM25,
115 native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
116 state_class=SensorStateClass.MEASUREMENT,
117 value_fn=
lambda device: device.details[
"air_quality_value"],
118 exists_fn=
lambda device:
sku_supported(device, PM25_SUPPORTED),
122 translation_key=
"current_power",
123 device_class=SensorDeviceClass.POWER,
124 native_unit_of_measurement=UnitOfPower.WATT,
125 state_class=SensorStateClass.MEASUREMENT,
126 value_fn=
lambda device: device.details[
"power"],
127 update_fn=update_energy,
128 exists_fn=
lambda device:
ha_dev_type(device) ==
"outlet",
132 translation_key=
"energy_today",
133 device_class=SensorDeviceClass.ENERGY,
134 native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR,
135 state_class=SensorStateClass.TOTAL_INCREASING,
136 value_fn=
lambda device: device.energy_today,
137 update_fn=update_energy,
138 exists_fn=
lambda device:
ha_dev_type(device) ==
"outlet",
142 translation_key=
"energy_week",
143 device_class=SensorDeviceClass.ENERGY,
144 native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR,
145 state_class=SensorStateClass.TOTAL_INCREASING,
146 value_fn=
lambda device: device.weekly_energy_total,
147 update_fn=update_energy,
148 exists_fn=
lambda device:
ha_dev_type(device) ==
"outlet",
151 key=
"energy-monthly",
152 translation_key=
"energy_month",
153 device_class=SensorDeviceClass.ENERGY,
154 native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR,
155 state_class=SensorStateClass.TOTAL_INCREASING,
156 value_fn=
lambda device: device.monthly_energy_total,
157 update_fn=update_energy,
158 exists_fn=
lambda device:
ha_dev_type(device) ==
"outlet",
162 translation_key=
"energy_year",
163 device_class=SensorDeviceClass.ENERGY,
164 native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR,
165 state_class=SensorStateClass.TOTAL_INCREASING,
166 value_fn=
lambda device: device.yearly_energy_total,
167 update_fn=update_energy,
168 exists_fn=
lambda device:
ha_dev_type(device) ==
"outlet",
172 translation_key=
"current_voltage",
173 device_class=SensorDeviceClass.VOLTAGE,
174 native_unit_of_measurement=UnitOfElectricPotential.VOLT,
175 state_class=SensorStateClass.MEASUREMENT,
176 value_fn=
lambda device: device.details[
"voltage"],
177 update_fn=update_energy,
178 exists_fn=
lambda device:
ha_dev_type(device) ==
"outlet",
185 config_entry: ConfigEntry,
186 async_add_entities: AddEntitiesCallback,
188 """Set up switches."""
192 """Add new devices to platform."""
195 config_entry.async_on_unload(
204 """Check if device is online and add entity."""
209 for description
in SENSORS
210 if description.exists_fn(dev)
212 update_before_add=
True,
217 """Representation of a sensor describing a VeSync device."""
219 entity_description: VeSyncSensorEntityDescription
223 device: VeSyncAirBypass | VeSyncOutlet | VeSyncSwitch,
224 description: VeSyncSensorEntityDescription,
226 """Initialize the VeSync outlet device."""
233 """Return the state of the sensor."""
237 """Run the update function defined for the sensor."""
None __init__(self, VeSyncAirBypass|VeSyncOutlet|VeSyncSwitch device, VeSyncSensorEntityDescription description)
StateType native_value(self)
list[tuple[str, int]] discover(HomeAssistant hass)
def _setup_entities(devices, async_add_entities)
def sku_supported(device, supported)
None async_setup_entry(HomeAssistant hass, ConfigEntry config_entry, AddEntitiesCallback async_add_entities)
def update_energy(device)
Callable[[], None] async_dispatcher_connect(HomeAssistant hass, str signal, Callable[..., Any] target)