3 from __future__
import annotations
5 from collections.abc
import Callable
6 from dataclasses
import dataclass
8 from yolink.const
import (
9 ATTR_DEVICE_CO_SMOKE_SENSOR,
11 ATTR_DEVICE_DOOR_SENSOR,
13 ATTR_DEVICE_LEAK_SENSOR,
15 ATTR_DEVICE_MANIPULATOR,
16 ATTR_DEVICE_MOTION_SENSOR,
17 ATTR_DEVICE_MULTI_OUTLET,
19 ATTR_DEVICE_POWER_FAILURE_ALARM,
21 ATTR_DEVICE_SMART_REMOTER,
23 ATTR_DEVICE_TH_SENSOR,
24 ATTR_DEVICE_THERMOSTAT,
25 ATTR_DEVICE_VIBRATION_SENSOR,
26 ATTR_DEVICE_WATER_DEPTH_SENSOR,
27 ATTR_DEVICE_WATER_METER_CONTROLLER,
28 ATTR_GARAGE_DOOR_CONTROLLER,
30 from yolink.device
import YoLinkDevice
35 SensorEntityDescription,
41 SIGNAL_STRENGTH_DECIBELS_MILLIWATT,
54 DEV_MODEL_PLUG_YS6602_EC,
55 DEV_MODEL_PLUG_YS6602_UC,
56 DEV_MODEL_PLUG_YS6803_EC,
57 DEV_MODEL_PLUG_YS6803_UC,
58 DEV_MODEL_TH_SENSOR_YS8004_EC,
59 DEV_MODEL_TH_SENSOR_YS8004_UC,
60 DEV_MODEL_TH_SENSOR_YS8008_EC,
61 DEV_MODEL_TH_SENSOR_YS8008_UC,
62 DEV_MODEL_TH_SENSOR_YS8014_EC,
63 DEV_MODEL_TH_SENSOR_YS8014_UC,
64 DEV_MODEL_TH_SENSOR_YS8017_EC,
65 DEV_MODEL_TH_SENSOR_YS8017_UC,
68 from .coordinator
import YoLinkCoordinator
69 from .entity
import YoLinkEntity
72 @dataclass(frozen=True, kw_only=True)
74 """YoLink SensorEntityDescription."""
76 exists_fn: Callable[[YoLinkDevice], bool] =
lambda _:
True
77 should_update_entity: Callable =
lambda state:
True
78 value: Callable =
lambda state: state
81 SENSOR_DEVICE_TYPE = [
83 ATTR_DEVICE_DOOR_SENSOR,
85 ATTR_DEVICE_LEAK_SENSOR,
86 ATTR_DEVICE_MOTION_SENSOR,
87 ATTR_DEVICE_MULTI_OUTLET,
88 ATTR_DEVICE_SMART_REMOTER,
90 ATTR_DEVICE_POWER_FAILURE_ALARM,
93 ATTR_DEVICE_TH_SENSOR,
94 ATTR_DEVICE_THERMOSTAT,
95 ATTR_DEVICE_VIBRATION_SENSOR,
96 ATTR_DEVICE_WATER_DEPTH_SENSOR,
97 ATTR_DEVICE_WATER_METER_CONTROLLER,
99 ATTR_DEVICE_MANIPULATOR,
100 ATTR_DEVICE_CO_SMOKE_SENSOR,
101 ATTR_GARAGE_DOOR_CONTROLLER,
104 BATTERY_POWER_SENSOR = [
105 ATTR_DEVICE_DOOR_SENSOR,
107 ATTR_DEVICE_LEAK_SENSOR,
108 ATTR_DEVICE_MOTION_SENSOR,
109 ATTR_DEVICE_POWER_FAILURE_ALARM,
111 ATTR_DEVICE_SMART_REMOTER,
112 ATTR_DEVICE_TH_SENSOR,
113 ATTR_DEVICE_VIBRATION_SENSOR,
115 ATTR_DEVICE_MANIPULATOR,
116 ATTR_DEVICE_CO_SMOKE_SENSOR,
117 ATTR_DEVICE_WATER_DEPTH_SENSOR,
118 ATTR_DEVICE_WATER_METER_CONTROLLER,
121 MCU_DEV_TEMPERATURE_SENSOR = [
122 ATTR_DEVICE_LEAK_SENSOR,
123 ATTR_DEVICE_MOTION_SENSOR,
124 ATTR_DEVICE_CO_SMOKE_SENSOR,
127 NONE_HUMIDITY_SENSOR_MODELS = [
128 DEV_MODEL_TH_SENSOR_YS8004_EC,
129 DEV_MODEL_TH_SENSOR_YS8004_UC,
130 DEV_MODEL_TH_SENSOR_YS8008_EC,
131 DEV_MODEL_TH_SENSOR_YS8008_UC,
132 DEV_MODEL_TH_SENSOR_YS8014_EC,
133 DEV_MODEL_TH_SENSOR_YS8014_UC,
134 DEV_MODEL_TH_SENSOR_YS8017_UC,
135 DEV_MODEL_TH_SENSOR_YS8017_EC,
138 POWER_SUPPORT_MODELS = [
139 DEV_MODEL_PLUG_YS6602_UC,
140 DEV_MODEL_PLUG_YS6602_EC,
141 DEV_MODEL_PLUG_YS6803_UC,
142 DEV_MODEL_PLUG_YS6803_EC,
147 """Convert battery to percentage."""
151 return percentage.ordered_list_item_to_percentage([1, 2, 3, 4], val)
156 """Convert volume to string."""
159 volume_level = {1:
"low", 2:
"medium", 3:
"high"}
160 return volume_level.get(val)
163 SENSOR_TYPES: tuple[YoLinkSensorEntityDescription, ...] = (
166 device_class=SensorDeviceClass.BATTERY,
167 native_unit_of_measurement=PERCENTAGE,
168 state_class=SensorStateClass.MEASUREMENT,
170 exists_fn=
lambda device: device.device_type
in BATTERY_POWER_SENSOR,
171 should_update_entity=
lambda value: value
is not None,
175 device_class=SensorDeviceClass.HUMIDITY,
176 native_unit_of_measurement=PERCENTAGE,
177 state_class=SensorStateClass.MEASUREMENT,
178 exists_fn=
lambda device: (
179 device.device_type
in [ATTR_DEVICE_TH_SENSOR]
180 and device.device_model_name
not in NONE_HUMIDITY_SENSOR_MODELS
185 device_class=SensorDeviceClass.TEMPERATURE,
186 native_unit_of_measurement=UnitOfTemperature.CELSIUS,
187 state_class=SensorStateClass.MEASUREMENT,
188 exists_fn=
lambda device: device.device_type
in [ATTR_DEVICE_TH_SENSOR],
192 key=
"devTemperature",
193 device_class=SensorDeviceClass.TEMPERATURE,
194 native_unit_of_measurement=UnitOfTemperature.CELSIUS,
195 state_class=SensorStateClass.MEASUREMENT,
196 exists_fn=
lambda device: device.device_type
in MCU_DEV_TEMPERATURE_SENSOR,
197 should_update_entity=
lambda value: value
is not None,
201 device_class=SensorDeviceClass.SIGNAL_STRENGTH,
202 native_unit_of_measurement=SIGNAL_STRENGTH_DECIBELS_MILLIWATT,
203 value=
lambda value: value[
"signal"]
if value
is not None else None,
204 state_class=SensorStateClass.MEASUREMENT,
205 entity_category=EntityCategory.DIAGNOSTIC,
206 entity_registry_enabled_default=
False,
207 should_update_entity=
lambda value: value
is not None,
211 translation_key=
"power_failure_alarm",
212 device_class=SensorDeviceClass.ENUM,
213 options=[
"normal",
"alert",
"off"],
214 exists_fn=
lambda device: device.device_type
in ATTR_DEVICE_POWER_FAILURE_ALARM,
218 translation_key=
"power_failure_alarm_mute",
219 device_class=SensorDeviceClass.ENUM,
220 options=[
"muted",
"unmuted"],
221 exists_fn=
lambda device: device.device_type
in ATTR_DEVICE_POWER_FAILURE_ALARM,
222 value=
lambda value:
"muted" if value
is True else "unmuted",
226 translation_key=
"power_failure_alarm_volume",
227 device_class=SensorDeviceClass.ENUM,
228 options=[
"low",
"medium",
"high"],
229 exists_fn=
lambda device: device.device_type
in ATTR_DEVICE_POWER_FAILURE_ALARM,
234 translation_key=
"power_failure_alarm_beep",
235 device_class=SensorDeviceClass.ENUM,
236 options=[
"enabled",
"disabled"],
237 exists_fn=
lambda device: device.device_type
in ATTR_DEVICE_POWER_FAILURE_ALARM,
238 value=
lambda value:
"enabled" if value
is True else "disabled",
242 device_class=SensorDeviceClass.DISTANCE,
243 native_unit_of_measurement=UnitOfLength.METERS,
244 exists_fn=
lambda device: device.device_type
in ATTR_DEVICE_WATER_DEPTH_SENSOR,
248 translation_key=
"water_meter_reading",
249 device_class=SensorDeviceClass.WATER,
250 native_unit_of_measurement=UnitOfVolume.CUBIC_METERS,
251 state_class=SensorStateClass.TOTAL_INCREASING,
252 should_update_entity=
lambda value: value
is not None,
253 exists_fn=
lambda device: (
254 device.device_type
in ATTR_DEVICE_WATER_METER_CONTROLLER
259 translation_key=
"current_power",
260 device_class=SensorDeviceClass.POWER,
261 native_unit_of_measurement=UnitOfPower.WATT,
262 state_class=SensorStateClass.MEASUREMENT,
263 should_update_entity=
lambda value: value
is not None,
264 exists_fn=
lambda device: device.device_model_name
in POWER_SUPPORT_MODELS,
265 value=
lambda value: value / 10
if value
is not None else None,
269 translation_key=
"power_consumption",
270 device_class=SensorDeviceClass.ENERGY,
271 native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR,
272 state_class=SensorStateClass.TOTAL,
273 should_update_entity=
lambda value: value
is not None,
274 exists_fn=
lambda device: device.device_model_name
in POWER_SUPPORT_MODELS,
275 value=
lambda value: value / 100
if value
is not None else None,
282 config_entry: ConfigEntry,
283 async_add_entities: AddEntitiesCallback,
285 """Set up YoLink Sensor from a config entry."""
286 device_coordinators = hass.data[DOMAIN][config_entry.entry_id].device_coordinators
287 sensor_device_coordinators = [
289 for device_coordinator
in device_coordinators.values()
290 if device_coordinator.device.device_type
in SENSOR_DEVICE_TYPE
295 sensor_device_coordinator,
298 for sensor_device_coordinator
in sensor_device_coordinators
299 for description
in SENSOR_TYPES
300 if description.exists_fn(sensor_device_coordinator.device)
305 """YoLink Sensor Entity."""
307 entity_description: YoLinkSensorEntityDescription
311 config_entry: ConfigEntry,
312 coordinator: YoLinkCoordinator,
313 description: YoLinkSensorEntityDescription,
315 """Init YoLink Sensor."""
316 super().
__init__(config_entry, coordinator)
319 f
"{coordinator.device.device_id} {self.entity_description.key}"
324 """Update HA Entity State."""
329 )
is None and self.
entity_descriptionentity_description.should_update_entity(attr_val)
is False:
336 """Return true is device is available."""
337 return super().available
and self.coordinator.dev_online
None update_entity_state(self, dict state)
None __init__(self, ConfigEntry config_entry, YoLinkCoordinator coordinator, YoLinkSensorEntityDescription description)
None async_write_ha_state(self)
int|None cvt_battery(int|None val)
str|None cvt_volume(int|None val)
None async_setup_entry(HomeAssistant hass, ConfigEntry config_entry, AddEntitiesCallback async_add_entities)