1 """Support for Xiaomi Mi Air Quality Monitor (PM2.5) and Humidifier."""
3 from __future__
import annotations
5 from collections.abc
import Iterable
6 from dataclasses
import dataclass
9 from miio
import AirQualityMonitor, DeviceException
10 from miio.gateway.gateway
import (
22 SensorEntityDescription,
29 CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
30 CONCENTRATION_PARTS_PER_MILLION,
37 REVOLUTIONS_PER_MINUTE,
51 from .
import VacuumCoordinatorDataAttributes
62 MODEL_AIRHUMIDIFIER_CA1,
63 MODEL_AIRHUMIDIFIER_CB1,
65 MODEL_AIRPURIFIER_3C_REV_A,
67 MODEL_AIRPURIFIER_4_LITE_RMA1,
68 MODEL_AIRPURIFIER_4_LITE_RMB1,
69 MODEL_AIRPURIFIER_4_PRO,
70 MODEL_AIRPURIFIER_MA2,
71 MODEL_AIRPURIFIER_PRO,
72 MODEL_AIRPURIFIER_PRO_V7,
75 MODEL_AIRPURIFIER_ZA1,
83 MODELS_AIR_QUALITY_MONITOR,
84 MODELS_HUMIDIFIER_MIIO,
85 MODELS_HUMIDIFIER_MIOT,
86 MODELS_HUMIDIFIER_MJJSQ,
93 from .entity
import XiaomiCoordinatedMiioEntity, XiaomiGatewayDevice, XiaomiMiioEntity
95 _LOGGER = logging.getLogger(__name__)
97 DEFAULT_NAME =
"Xiaomi Miio Sensor"
100 ATTR_ACTUAL_SPEED =
"actual_speed"
101 ATTR_AIR_QUALITY =
"air_quality"
104 ATTR_BATTERY =
"battery"
105 ATTR_CARBON_DIOXIDE =
"co2"
106 ATTR_CHARGING =
"charging"
107 ATTR_CONTROL_SPEED =
"control_speed"
108 ATTR_DISPLAY_CLOCK =
"display_clock"
109 ATTR_FAVORITE_SPEED =
"favorite_speed"
110 ATTR_FILTER_LIFE_REMAINING =
"filter_life_remaining"
111 ATTR_FILTER_HOURS_USED =
"filter_hours_used"
112 ATTR_FILTER_LEFT_TIME =
"filter_left_time"
113 ATTR_DUST_FILTER_LIFE_REMAINING =
"dust_filter_life_remaining"
114 ATTR_DUST_FILTER_LIFE_REMAINING_DAYS =
"dust_filter_life_remaining_days"
115 ATTR_UPPER_FILTER_LIFE_REMAINING =
"upper_filter_life_remaining"
116 ATTR_UPPER_FILTER_LIFE_REMAINING_DAYS =
"upper_filter_life_remaining_days"
117 ATTR_FILTER_USE =
"filter_use"
118 ATTR_HUMIDITY =
"humidity"
119 ATTR_ILLUMINANCE =
"illuminance"
120 ATTR_ILLUMINANCE_LUX =
"illuminance_lux"
121 ATTR_LOAD_POWER =
"load_power"
122 ATTR_MOTOR2_SPEED =
"motor2_speed"
123 ATTR_MOTOR_SPEED =
"motor_speed"
124 ATTR_NIGHT_MODE =
"night_mode"
125 ATTR_NIGHT_TIME_BEGIN =
"night_time_begin"
126 ATTR_NIGHT_TIME_END =
"night_time_end"
127 ATTR_PM10 =
"pm10_density"
129 ATTR_PM25_2 =
"pm25_2"
131 ATTR_PRESSURE =
"pressure"
132 ATTR_PURIFY_VOLUME =
"purify_volume"
133 ATTR_SENSOR_STATE =
"sensor_state"
134 ATTR_USE_TIME =
"use_time"
135 ATTR_WATER_LEVEL =
"water_level"
136 ATTR_DND_START =
"start"
138 ATTR_LAST_CLEAN_TIME =
"duration"
139 ATTR_LAST_CLEAN_AREA =
"area"
140 ATTR_STATUS_CLEAN_TIME =
"clean_time"
141 ATTR_STATUS_CLEAN_AREA =
"clean_area"
142 ATTR_LAST_CLEAN_START =
"start"
143 ATTR_LAST_CLEAN_END =
"end"
144 ATTR_CLEAN_HISTORY_TOTAL_DURATION =
"total_duration"
145 ATTR_CLEAN_HISTORY_TOTAL_AREA =
"total_area"
146 ATTR_CLEAN_HISTORY_COUNT =
"count"
147 ATTR_CLEAN_HISTORY_DUST_COLLECTION_COUNT =
"dust_collection_count"
148 ATTR_CONSUMABLE_STATUS_MAIN_BRUSH_LEFT =
"main_brush_left"
149 ATTR_CONSUMABLE_STATUS_SIDE_BRUSH_LEFT =
"side_brush_left"
150 ATTR_CONSUMABLE_STATUS_FILTER_LEFT =
"filter_left"
151 ATTR_CONSUMABLE_STATUS_SENSOR_DIRTY_LEFT =
"sensor_dirty_left"
154 @dataclass(frozen=True)
156 """Class that holds device specific info for a xiaomi aqara or humidifier sensor."""
158 attributes: tuple = ()
159 parent_key: str |
None =
None
164 key=ATTR_TEMPERATURE,
165 native_unit_of_measurement=UnitOfTemperature.CELSIUS,
166 device_class=SensorDeviceClass.TEMPERATURE,
167 state_class=SensorStateClass.MEASUREMENT,
171 native_unit_of_measurement=PERCENTAGE,
172 device_class=SensorDeviceClass.HUMIDITY,
173 state_class=SensorStateClass.MEASUREMENT,
177 native_unit_of_measurement=UnitOfPressure.HPA,
178 device_class=SensorDeviceClass.ATMOSPHERIC_PRESSURE,
179 state_class=SensorStateClass.MEASUREMENT,
183 translation_key=ATTR_LOAD_POWER,
184 native_unit_of_measurement=UnitOfPower.WATT,
185 device_class=SensorDeviceClass.POWER,
188 key=ATTR_WATER_LEVEL,
189 translation_key=ATTR_WATER_LEVEL,
190 native_unit_of_measurement=PERCENTAGE,
191 icon=
"mdi:water-check",
192 state_class=SensorStateClass.MEASUREMENT,
193 entity_category=EntityCategory.DIAGNOSTIC,
196 key=ATTR_ACTUAL_SPEED,
197 translation_key=ATTR_ACTUAL_SPEED,
198 native_unit_of_measurement=REVOLUTIONS_PER_MINUTE,
199 icon=
"mdi:fast-forward",
200 state_class=SensorStateClass.MEASUREMENT,
201 entity_category=EntityCategory.DIAGNOSTIC,
204 key=ATTR_CONTROL_SPEED,
205 translation_key=ATTR_CONTROL_SPEED,
206 native_unit_of_measurement=REVOLUTIONS_PER_MINUTE,
207 icon=
"mdi:fast-forward",
208 state_class=SensorStateClass.MEASUREMENT,
209 entity_category=EntityCategory.DIAGNOSTIC,
212 key=ATTR_FAVORITE_SPEED,
213 translation_key=ATTR_FAVORITE_SPEED,
214 native_unit_of_measurement=REVOLUTIONS_PER_MINUTE,
215 icon=
"mdi:fast-forward",
216 state_class=SensorStateClass.MEASUREMENT,
217 entity_category=EntityCategory.DIAGNOSTIC,
220 key=ATTR_MOTOR_SPEED,
221 translation_key=ATTR_MOTOR_SPEED,
222 native_unit_of_measurement=REVOLUTIONS_PER_MINUTE,
223 icon=
"mdi:fast-forward",
224 state_class=SensorStateClass.MEASUREMENT,
225 entity_category=EntityCategory.DIAGNOSTIC,
228 key=ATTR_MOTOR2_SPEED,
229 translation_key=ATTR_MOTOR2_SPEED,
230 native_unit_of_measurement=REVOLUTIONS_PER_MINUTE,
231 icon=
"mdi:fast-forward",
232 state_class=SensorStateClass.MEASUREMENT,
233 entity_category=EntityCategory.DIAGNOSTIC,
237 translation_key=ATTR_USE_TIME,
238 native_unit_of_measurement=UnitOfTime.SECONDS,
239 icon=
"mdi:progress-clock",
240 device_class=SensorDeviceClass.DURATION,
241 state_class=SensorStateClass.TOTAL_INCREASING,
242 entity_registry_enabled_default=
False,
243 entity_category=EntityCategory.DIAGNOSTIC,
246 key=ATTR_ILLUMINANCE,
247 translation_key=ATTR_ILLUMINANCE,
248 native_unit_of_measurement=UNIT_LUMEN,
249 state_class=SensorStateClass.MEASUREMENT,
252 key=ATTR_ILLUMINANCE,
253 native_unit_of_measurement=LIGHT_LUX,
254 device_class=SensorDeviceClass.ILLUMINANCE,
255 state_class=SensorStateClass.MEASUREMENT,
258 key=ATTR_AIR_QUALITY,
259 translation_key=ATTR_AIR_QUALITY,
260 native_unit_of_measurement=
"AQI",
262 state_class=SensorStateClass.MEASUREMENT,
266 translation_key=ATTR_TVOC,
267 state_class=SensorStateClass.MEASUREMENT,
268 native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
269 device_class=SensorDeviceClass.VOLATILE_ORGANIC_COMPOUNDS,
273 native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
274 device_class=SensorDeviceClass.PM10,
275 state_class=SensorStateClass.MEASUREMENT,
279 translation_key=ATTR_AQI,
280 native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
281 device_class=SensorDeviceClass.PM25,
282 state_class=SensorStateClass.MEASUREMENT,
286 native_unit_of_measurement=CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
287 device_class=SensorDeviceClass.PM25,
288 state_class=SensorStateClass.MEASUREMENT,
291 key=ATTR_FILTER_LIFE_REMAINING,
292 translation_key=ATTR_FILTER_LIFE_REMAINING,
293 native_unit_of_measurement=PERCENTAGE,
294 icon=
"mdi:air-filter",
295 state_class=SensorStateClass.MEASUREMENT,
296 attributes=(
"filter_type",),
297 entity_category=EntityCategory.DIAGNOSTIC,
300 key=ATTR_FILTER_HOURS_USED,
301 translation_key=ATTR_FILTER_HOURS_USED,
302 native_unit_of_measurement=UnitOfTime.HOURS,
303 icon=
"mdi:clock-outline",
304 device_class=SensorDeviceClass.DURATION,
305 state_class=SensorStateClass.MEASUREMENT,
306 entity_category=EntityCategory.DIAGNOSTIC,
309 key=ATTR_FILTER_LEFT_TIME,
310 translation_key=ATTR_FILTER_LEFT_TIME,
311 native_unit_of_measurement=UnitOfTime.DAYS,
312 icon=
"mdi:clock-outline",
313 device_class=SensorDeviceClass.DURATION,
314 state_class=SensorStateClass.MEASUREMENT,
315 entity_category=EntityCategory.DIAGNOSTIC,
318 key=ATTR_DUST_FILTER_LIFE_REMAINING,
319 translation_key=ATTR_DUST_FILTER_LIFE_REMAINING,
320 native_unit_of_measurement=PERCENTAGE,
321 icon=
"mdi:air-filter",
322 state_class=SensorStateClass.MEASUREMENT,
323 attributes=(
"filter_type",),
324 entity_category=EntityCategory.DIAGNOSTIC,
327 key=ATTR_DUST_FILTER_LIFE_REMAINING_DAYS,
328 translation_key=ATTR_DUST_FILTER_LIFE_REMAINING_DAYS,
329 native_unit_of_measurement=UnitOfTime.DAYS,
330 icon=
"mdi:clock-outline",
331 device_class=SensorDeviceClass.DURATION,
332 state_class=SensorStateClass.MEASUREMENT,
333 entity_category=EntityCategory.DIAGNOSTIC,
336 key=ATTR_UPPER_FILTER_LIFE_REMAINING,
337 translation_key=ATTR_UPPER_FILTER_LIFE_REMAINING,
338 native_unit_of_measurement=PERCENTAGE,
339 icon=
"mdi:air-filter",
340 state_class=SensorStateClass.MEASUREMENT,
341 attributes=(
"filter_type",),
342 entity_category=EntityCategory.DIAGNOSTIC,
345 key=ATTR_UPPER_FILTER_LIFE_REMAINING_DAYS,
346 translation_key=ATTR_UPPER_FILTER_LIFE_REMAINING_DAYS,
347 native_unit_of_measurement=UnitOfTime.DAYS,
348 icon=
"mdi:clock-outline",
349 device_class=SensorDeviceClass.DURATION,
350 state_class=SensorStateClass.MEASUREMENT,
351 entity_category=EntityCategory.DIAGNOSTIC,
354 key=ATTR_CARBON_DIOXIDE,
355 native_unit_of_measurement=CONCENTRATION_PARTS_PER_MILLION,
356 device_class=SensorDeviceClass.CO2,
357 state_class=SensorStateClass.MEASUREMENT,
360 key=ATTR_PURIFY_VOLUME,
361 translation_key=ATTR_PURIFY_VOLUME,
362 native_unit_of_measurement=UnitOfVolume.CUBIC_METERS,
363 device_class=SensorDeviceClass.VOLUME,
364 state_class=SensorStateClass.TOTAL_INCREASING,
365 entity_registry_enabled_default=
False,
366 entity_category=EntityCategory.DIAGNOSTIC,
370 native_unit_of_measurement=PERCENTAGE,
371 device_class=SensorDeviceClass.BATTERY,
372 state_class=SensorStateClass.MEASUREMENT,
373 entity_category=EntityCategory.DIAGNOSTIC,
377 HUMIDIFIER_MIIO_SENSORS = (
383 HUMIDIFIER_CA1_CB1_SENSORS = (
390 HUMIDIFIER_MIOT_SENSORS = (
397 HUMIDIFIER_MJJSQ_SENSORS = (ATTR_HUMIDITY, ATTR_TEMPERATURE)
399 PURIFIER_MIIO_SENSORS = (
400 ATTR_FILTER_LIFE_REMAINING,
408 PURIFIER_MIOT_SENSORS = (
409 ATTR_FILTER_LIFE_REMAINING,
418 PURIFIER_4_LITE_SENSORS = (
419 ATTR_FILTER_LIFE_REMAINING,
420 ATTR_FILTER_LEFT_TIME,
428 PURIFIER_4_SENSORS = (
429 ATTR_FILTER_LIFE_REMAINING,
430 ATTR_FILTER_LEFT_TIME,
439 PURIFIER_4_PRO_SENSORS = (
440 ATTR_FILTER_LIFE_REMAINING,
441 ATTR_FILTER_LEFT_TIME,
451 PURIFIER_3C_SENSORS = (
452 ATTR_FILTER_LIFE_REMAINING,
457 PURIFIER_ZA1_SENSORS = (
458 ATTR_FILTER_LIFE_REMAINING,
466 PURIFIER_MA2_SENSORS = (
467 ATTR_FILTER_LIFE_REMAINING,
476 PURIFIER_V2_SENSORS = (
477 ATTR_FILTER_LIFE_REMAINING,
486 PURIFIER_V3_SENSORS = (
487 ATTR_FILTER_LIFE_REMAINING,
489 ATTR_ILLUMINANCE_LUX,
496 PURIFIER_PRO_SENSORS = (
497 ATTR_FILTER_LIFE_REMAINING,
500 ATTR_ILLUMINANCE_LUX,
508 PURIFIER_PRO_V7_SENSORS = (
509 ATTR_FILTER_LIFE_REMAINING,
512 ATTR_ILLUMINANCE_LUX,
521 ATTR_FILTER_LIFE_REMAINING,
528 AIRFRESH_SENSORS_A1 = (
530 ATTR_DUST_FILTER_LIFE_REMAINING,
531 ATTR_DUST_FILTER_LIFE_REMAINING_DAYS,
537 AIRFRESH_SENSORS_T2017 = (
539 ATTR_DUST_FILTER_LIFE_REMAINING,
540 ATTR_DUST_FILTER_LIFE_REMAINING_DAYS,
541 ATTR_UPPER_FILTER_LIFE_REMAINING,
542 ATTR_UPPER_FILTER_LIFE_REMAINING_DAYS,
548 FAN_V2_V3_SENSORS = (
554 FAN_ZA5_SENSORS = (ATTR_HUMIDITY, ATTR_TEMPERATURE)
556 MODEL_TO_SENSORS_MAP: dict[str, tuple[str, ...]] = {
557 MODEL_AIRFRESH_A1: AIRFRESH_SENSORS_A1,
558 MODEL_AIRFRESH_VA2: AIRFRESH_SENSORS,
559 MODEL_AIRFRESH_VA4: AIRFRESH_SENSORS,
560 MODEL_AIRFRESH_T2017: AIRFRESH_SENSORS_T2017,
561 MODEL_AIRHUMIDIFIER_CA1: HUMIDIFIER_CA1_CB1_SENSORS,
562 MODEL_AIRHUMIDIFIER_CB1: HUMIDIFIER_CA1_CB1_SENSORS,
563 MODEL_AIRPURIFIER_3C: PURIFIER_3C_SENSORS,
564 MODEL_AIRPURIFIER_3C_REV_A: PURIFIER_3C_SENSORS,
565 MODEL_AIRPURIFIER_4_LITE_RMA1: PURIFIER_4_LITE_SENSORS,
566 MODEL_AIRPURIFIER_4_LITE_RMB1: PURIFIER_4_LITE_SENSORS,
567 MODEL_AIRPURIFIER_4: PURIFIER_4_SENSORS,
568 MODEL_AIRPURIFIER_4_PRO: PURIFIER_4_PRO_SENSORS,
569 MODEL_AIRPURIFIER_PRO: PURIFIER_PRO_SENSORS,
570 MODEL_AIRPURIFIER_PRO_V7: PURIFIER_PRO_V7_SENSORS,
571 MODEL_AIRPURIFIER_V2: PURIFIER_V2_SENSORS,
572 MODEL_AIRPURIFIER_V3: PURIFIER_V3_SENSORS,
573 MODEL_AIRPURIFIER_ZA1: PURIFIER_ZA1_SENSORS,
574 MODEL_AIRPURIFIER_MA2: PURIFIER_MA2_SENSORS,
575 MODEL_FAN_V2: FAN_V2_V3_SENSORS,
576 MODEL_FAN_V3: FAN_V2_V3_SENSORS,
577 MODEL_FAN_ZA5: FAN_ZA5_SENSORS,
583 icon=
"mdi:minus-circle-off",
584 translation_key=
"dnd_start",
585 device_class=SensorDeviceClass.TIMESTAMP,
586 parent_key=VacuumCoordinatorDataAttributes.dnd_status,
587 entity_registry_enabled_default=
False,
588 entity_category=EntityCategory.DIAGNOSTIC,
592 icon=
"mdi:minus-circle-off",
593 translation_key=
"dnd_end",
594 device_class=SensorDeviceClass.TIMESTAMP,
595 parent_key=VacuumCoordinatorDataAttributes.dnd_status,
596 entity_registry_enabled_default=
False,
597 entity_category=EntityCategory.DIAGNOSTIC,
600 key=ATTR_LAST_CLEAN_START,
601 icon=
"mdi:clock-time-twelve",
602 translation_key=
"last_clean_start",
603 device_class=SensorDeviceClass.TIMESTAMP,
604 parent_key=VacuumCoordinatorDataAttributes.last_clean_details,
605 entity_category=EntityCategory.DIAGNOSTIC,
608 key=ATTR_LAST_CLEAN_END,
609 icon=
"mdi:clock-time-twelve",
610 device_class=SensorDeviceClass.TIMESTAMP,
611 parent_key=VacuumCoordinatorDataAttributes.last_clean_details,
612 translation_key=
"last_clean_end",
613 entity_category=EntityCategory.DIAGNOSTIC,
616 native_unit_of_measurement=UnitOfTime.SECONDS,
617 icon=
"mdi:timer-sand",
618 device_class=SensorDeviceClass.DURATION,
619 key=ATTR_LAST_CLEAN_TIME,
620 parent_key=VacuumCoordinatorDataAttributes.last_clean_details,
621 translation_key=ATTR_LAST_CLEAN_TIME,
622 entity_category=EntityCategory.DIAGNOSTIC,
625 native_unit_of_measurement=UnitOfArea.SQUARE_METERS,
626 icon=
"mdi:texture-box",
627 key=ATTR_LAST_CLEAN_AREA,
628 parent_key=VacuumCoordinatorDataAttributes.last_clean_details,
629 translation_key=ATTR_LAST_CLEAN_AREA,
630 entity_category=EntityCategory.DIAGNOSTIC,
633 native_unit_of_measurement=UnitOfTime.SECONDS,
634 icon=
"mdi:timer-sand",
635 device_class=SensorDeviceClass.DURATION,
636 key=ATTR_STATUS_CLEAN_TIME,
637 parent_key=VacuumCoordinatorDataAttributes.status,
638 translation_key=ATTR_STATUS_CLEAN_TIME,
639 entity_category=EntityCategory.DIAGNOSTIC,
642 native_unit_of_measurement=UnitOfArea.SQUARE_METERS,
643 icon=
"mdi:texture-box",
644 key=ATTR_STATUS_CLEAN_AREA,
645 parent_key=VacuumCoordinatorDataAttributes.status,
646 entity_category=EntityCategory.DIAGNOSTIC,
647 translation_key=ATTR_STATUS_CLEAN_AREA,
650 native_unit_of_measurement=UnitOfTime.SECONDS,
651 device_class=SensorDeviceClass.DURATION,
652 icon=
"mdi:timer-sand",
653 key=ATTR_CLEAN_HISTORY_TOTAL_DURATION,
654 parent_key=VacuumCoordinatorDataAttributes.clean_history_status,
655 translation_key=ATTR_CLEAN_HISTORY_TOTAL_DURATION,
656 entity_registry_enabled_default=
False,
657 entity_category=EntityCategory.DIAGNOSTIC,
660 native_unit_of_measurement=UnitOfArea.SQUARE_METERS,
661 icon=
"mdi:texture-box",
662 key=ATTR_CLEAN_HISTORY_TOTAL_AREA,
663 parent_key=VacuumCoordinatorDataAttributes.clean_history_status,
664 translation_key=ATTR_CLEAN_HISTORY_TOTAL_AREA,
665 entity_registry_enabled_default=
False,
666 entity_category=EntityCategory.DIAGNOSTIC,
669 native_unit_of_measurement=
"",
671 state_class=SensorStateClass.TOTAL_INCREASING,
672 key=ATTR_CLEAN_HISTORY_COUNT,
673 parent_key=VacuumCoordinatorDataAttributes.clean_history_status,
674 translation_key=ATTR_CLEAN_HISTORY_COUNT,
675 entity_registry_enabled_default=
False,
676 entity_category=EntityCategory.DIAGNOSTIC,
679 native_unit_of_measurement=
"",
681 state_class=SensorStateClass.TOTAL_INCREASING,
682 key=ATTR_CLEAN_HISTORY_DUST_COLLECTION_COUNT,
683 parent_key=VacuumCoordinatorDataAttributes.clean_history_status,
684 translation_key=ATTR_CLEAN_HISTORY_DUST_COLLECTION_COUNT,
685 entity_registry_enabled_default=
False,
686 entity_category=EntityCategory.DIAGNOSTIC,
689 native_unit_of_measurement=UnitOfTime.SECONDS,
691 device_class=SensorDeviceClass.DURATION,
692 key=ATTR_CONSUMABLE_STATUS_MAIN_BRUSH_LEFT,
693 parent_key=VacuumCoordinatorDataAttributes.consumable_status,
694 translation_key=ATTR_CONSUMABLE_STATUS_MAIN_BRUSH_LEFT,
695 entity_category=EntityCategory.DIAGNOSTIC,
698 native_unit_of_measurement=UnitOfTime.SECONDS,
700 device_class=SensorDeviceClass.DURATION,
701 key=ATTR_CONSUMABLE_STATUS_SIDE_BRUSH_LEFT,
702 parent_key=VacuumCoordinatorDataAttributes.consumable_status,
703 translation_key=ATTR_CONSUMABLE_STATUS_SIDE_BRUSH_LEFT,
704 entity_category=EntityCategory.DIAGNOSTIC,
707 native_unit_of_measurement=UnitOfTime.SECONDS,
708 icon=
"mdi:air-filter",
709 device_class=SensorDeviceClass.DURATION,
710 key=ATTR_CONSUMABLE_STATUS_FILTER_LEFT,
711 parent_key=VacuumCoordinatorDataAttributes.consumable_status,
712 translation_key=ATTR_CONSUMABLE_STATUS_FILTER_LEFT,
713 entity_category=EntityCategory.DIAGNOSTIC,
716 native_unit_of_measurement=UnitOfTime.SECONDS,
717 icon=
"mdi:eye-outline",
718 device_class=SensorDeviceClass.DURATION,
719 key=ATTR_CONSUMABLE_STATUS_SENSOR_DIRTY_LEFT,
720 parent_key=VacuumCoordinatorDataAttributes.consumable_status,
721 translation_key=ATTR_CONSUMABLE_STATUS_SENSOR_DIRTY_LEFT,
722 entity_category=EntityCategory.DIAGNOSTIC,
728 """Set up the Xiaomi vacuum sensors."""
729 device = hass.data[DOMAIN][config_entry.entry_id].
get(KEY_DEVICE)
730 coordinator = hass.data[DOMAIN][config_entry.entry_id][KEY_COORDINATOR]
733 for sensor, description
in VACUUM_SENSORS.items():
734 parent_key_data = getattr(coordinator.data, description.parent_key)
735 if getattr(parent_key_data, description.key,
None)
is None:
737 "It seems the %s does not support the %s as the initial value is None",
738 config_entry.data[CONF_MODEL],
746 f
"{sensor}_{config_entry.unique_id}",
757 config_entry: ConfigEntry,
758 async_add_entities: AddEntitiesCallback,
760 """Set up the Xiaomi sensor from a config entry."""
761 entities: list[SensorEntity] = []
763 if config_entry.data[CONF_FLOW_TYPE] == CONF_GATEWAY:
764 gateway = hass.data[DOMAIN][config_entry.entry_id][CONF_GATEWAY]
766 if gateway.model
not in [
773 description = SENSOR_TYPES[ATTR_ILLUMINANCE]
776 gateway, config_entry.title, config_entry.unique_id, description
780 sub_devices = gateway.devices
781 for sub_device
in sub_devices.values():
782 coordinator = hass.data[DOMAIN][config_entry.entry_id][KEY_COORDINATOR][
785 for sensor, description
in SENSOR_TYPES.items():
786 if sensor
not in sub_device.status:
790 coordinator, sub_device, config_entry, description
793 elif config_entry.data[CONF_FLOW_TYPE] == CONF_DEVICE:
794 host = config_entry.data[CONF_HOST]
795 token = config_entry.data[CONF_TOKEN]
796 model: str = config_entry.data[CONF_MODEL]
798 if model
in (MODEL_FAN_ZA1, MODEL_FAN_ZA3, MODEL_FAN_ZA4, MODEL_FAN_P5):
801 if model
in MODELS_AIR_QUALITY_MONITOR:
802 unique_id = config_entry.unique_id
803 name = config_entry.title
804 _LOGGER.debug(
"Initializing with host %s (token %s...)", host, token[:5])
806 device = AirQualityMonitor(host, token)
807 description = SENSOR_TYPES[ATTR_AIR_QUALITY]
810 name, device, config_entry, unique_id, description
814 device = hass.data[DOMAIN][config_entry.entry_id][KEY_DEVICE]
815 sensors: Iterable[str] = []
816 if model
in MODEL_TO_SENSORS_MAP:
817 sensors = MODEL_TO_SENSORS_MAP[model]
818 elif model
in MODELS_HUMIDIFIER_MIOT:
819 sensors = HUMIDIFIER_MIOT_SENSORS
820 elif model
in MODELS_HUMIDIFIER_MJJSQ:
821 sensors = HUMIDIFIER_MJJSQ_SENSORS
822 elif model
in MODELS_HUMIDIFIER_MIIO:
823 sensors = HUMIDIFIER_MIIO_SENSORS
824 elif model
in MODELS_PURIFIER_MIIO:
825 sensors = PURIFIER_MIIO_SENSORS
826 elif model
in MODELS_PURIFIER_MIOT:
827 sensors = PURIFIER_MIOT_SENSORS
828 elif model
in MODELS_VACUUM
or model.startswith(
829 (ROBOROCK_GENERIC, ROCKROBO_GENERIC)
834 for sensor, description
in SENSOR_TYPES.items():
835 if sensor
not in sensors:
841 f
"{sensor}_{config_entry.unique_id}",
842 hass.data[DOMAIN][config_entry.entry_id][KEY_COORDINATOR],
851 """Representation of a Xiaomi generic sensor."""
853 entity_description: XiaomiMiioSensorDescription
855 def __init__(self, device, entry, unique_id, coordinator, description):
856 """Initialize the entity."""
857 super().
__init__(device, entry, unique_id, coordinator)
865 """Return state attributes with valid values."""
869 if hasattr(data, attr)
870 and (value := self._extract_value_from_attribute(data, attr))
is not None
875 """Fetch state from the device."""
879 if native_value
is not None:
882 self.coordinator.data
887 """Determine native value."""
889 native_value = self._extract_value_from_attribute(
894 native_value = self._extract_value_from_attribute(
900 and native_value
is not None
901 and (native_datetime := dt_util.parse_datetime(
str(native_value)))
904 return native_datetime.astimezone(dt_util.UTC)
910 """Representation of a Xiaomi Air Quality Monitor."""
912 def __init__(self, name, device, entry, unique_id, description):
913 """Initialize the entity."""
914 super().
__init__(name, device, entry, unique_id)
920 ATTR_BATTERY_LEVEL:
None,
922 ATTR_DISPLAY_CLOCK:
None,
923 ATTR_NIGHT_MODE:
None,
924 ATTR_NIGHT_TIME_BEGIN:
None,
925 ATTR_NIGHT_TIME_END:
None,
926 ATTR_SENSOR_STATE:
None,
932 """Return true when state is known."""
937 """Return the state of the device."""
942 """Return the state attributes of the device."""
946 """Fetch state from the miio device."""
948 state = await self.
hasshass.async_add_executor_job(self.
_device_device.status)
949 _LOGGER.debug(
"Got new state: %s", state)
952 self.
_state_state = state.aqi
955 ATTR_POWER: state.power,
956 ATTR_CHARGING: state.usb_power,
957 ATTR_BATTERY_LEVEL: state.battery,
958 ATTR_DISPLAY_CLOCK: state.display_clock,
959 ATTR_NIGHT_MODE: state.night_mode,
960 ATTR_NIGHT_TIME_BEGIN: state.night_time_begin,
961 ATTR_NIGHT_TIME_END: state.night_time_end,
962 ATTR_SENSOR_STATE: state.sensor_state,
966 except DeviceException
as ex:
969 _LOGGER.error(
"Got exception while fetching the state: %s", ex)
973 """Representation of a XiaomiGatewaySensor."""
975 def __init__(self, coordinator, sub_device, entry, description):
976 """Initialize the XiaomiSensor."""
977 super().
__init__(coordinator, sub_device, entry)
979 self.
_name_name_name = f
"{description.key} ({sub_device.sid})".capitalize()
984 """Return the state of the sensor."""
989 """Representation of the gateway device's illuminance sensor."""
991 def __init__(self, gateway_device, gateway_name, gateway_device_id, description):
992 """Initialize the entity."""
993 self.
_attr_name_attr_name = f
"{gateway_name} {description.name}"
996 identifiers={(DOMAIN, gateway_device_id)},
1005 """Return true when state is known."""
1010 """Return the state of the device."""
1014 """Fetch state from the device."""
1016 self.
_state_state = await self.
hasshass.async_add_executor_job(
1017 self.
_gateway_gateway.get_illumination
1020 except GatewayException
as ex:
1024 "Got exception while fetching the gateway illuminance state: %s", ex
SensorDeviceClass|None device_class(self)
def __init__(self, name, device, entry, unique_id, description)
def extra_state_attributes(self)
def __init__(self, gateway_device, gateway_name, gateway_device_id, description)
def __init__(self, coordinator, sub_device, entry, description)
def __init__(self, device, entry, unique_id, coordinator, description)
_attr_extra_state_attributes
def _handle_coordinator_update(self)
def _extract_attributes(self, data)
def _determine_native_value(self)
str|None device_class(self)
None async_write_ha_state(self)
web.Response get(self, web.Request request, str config_key)
IssData update(pyiss.ISS iss)
def _setup_vacuum_sensors(hass, config_entry, async_add_entities)
None async_setup_entry(HomeAssistant hass, ConfigEntry config_entry, AddEntitiesCallback async_add_entities)