Home Assistant Unofficial Reference 2024.12.1
binary_sensor.py
Go to the documentation of this file.
1 """Support for Xiaomi Miio binary sensors."""
2 
3 from __future__ import annotations
4 
5 from collections.abc import Callable, Iterable
6 from dataclasses import dataclass
7 import logging
8 
10  BinarySensorDeviceClass,
11  BinarySensorEntity,
12  BinarySensorEntityDescription,
13 )
14 from homeassistant.config_entries import ConfigEntry
15 from homeassistant.const import CONF_DEVICE, CONF_MODEL, EntityCategory
16 from homeassistant.core import HomeAssistant, callback
17 from homeassistant.helpers.entity_platform import AddEntitiesCallback
18 
19 from . import VacuumCoordinatorDataAttributes
20 from .const import (
21  CONF_FLOW_TYPE,
22  DOMAIN,
23  KEY_COORDINATOR,
24  KEY_DEVICE,
25  MODEL_AIRFRESH_A1,
26  MODEL_AIRFRESH_T2017,
27  MODEL_FAN_ZA5,
28  MODELS_HUMIDIFIER_MIIO,
29  MODELS_HUMIDIFIER_MIOT,
30  MODELS_HUMIDIFIER_MJJSQ,
31  MODELS_VACUUM,
32  MODELS_VACUUM_WITH_MOP,
33  MODELS_VACUUM_WITH_SEPARATE_MOP,
34 )
35 from .entity import XiaomiCoordinatedMiioEntity
36 
37 _LOGGER = logging.getLogger(__name__)
38 
39 ATTR_NO_WATER = "no_water"
40 ATTR_PTC_STATUS = "ptc_status"
41 ATTR_POWERSUPPLY_ATTACHED = "powersupply_attached"
42 ATTR_WATER_TANK_DETACHED = "water_tank_detached"
43 ATTR_MOP_ATTACHED = "is_water_box_carriage_attached"
44 ATTR_WATER_BOX_ATTACHED = "is_water_box_attached"
45 ATTR_WATER_SHORTAGE = "is_water_shortage"
46 
47 
48 @dataclass(frozen=True)
50  """A class that describes binary sensor entities."""
51 
52  value: Callable | None = None
53  parent_key: str | None = None
54 
55 
56 BINARY_SENSOR_TYPES = (
58  key=ATTR_NO_WATER,
59  translation_key=ATTR_NO_WATER,
60  icon="mdi:water-off-outline",
61  entity_category=EntityCategory.DIAGNOSTIC,
62  ),
64  key=ATTR_WATER_TANK_DETACHED,
65  translation_key=ATTR_WATER_TANK_DETACHED,
66  icon="mdi:car-coolant-level",
67  device_class=BinarySensorDeviceClass.CONNECTIVITY,
68  value=lambda value: not value,
69  entity_category=EntityCategory.DIAGNOSTIC,
70  ),
72  key=ATTR_PTC_STATUS,
73  translation_key=ATTR_PTC_STATUS,
74  device_class=BinarySensorDeviceClass.POWER,
75  entity_category=EntityCategory.DIAGNOSTIC,
76  ),
78  key=ATTR_POWERSUPPLY_ATTACHED,
79  translation_key=ATTR_POWERSUPPLY_ATTACHED,
80  device_class=BinarySensorDeviceClass.PLUG,
81  entity_category=EntityCategory.DIAGNOSTIC,
82  ),
83 )
84 
85 AIRFRESH_A1_BINARY_SENSORS = (ATTR_PTC_STATUS,)
86 FAN_ZA5_BINARY_SENSORS = (ATTR_POWERSUPPLY_ATTACHED,)
87 
88 VACUUM_SENSORS = {
89  ATTR_MOP_ATTACHED: XiaomiMiioBinarySensorDescription(
90  key=ATTR_WATER_BOX_ATTACHED,
91  translation_key=ATTR_WATER_BOX_ATTACHED,
92  icon="mdi:square-rounded",
93  parent_key=VacuumCoordinatorDataAttributes.status,
94  entity_registry_enabled_default=True,
95  device_class=BinarySensorDeviceClass.CONNECTIVITY,
96  entity_category=EntityCategory.DIAGNOSTIC,
97  ),
98  ATTR_WATER_BOX_ATTACHED: XiaomiMiioBinarySensorDescription(
99  key=ATTR_WATER_BOX_ATTACHED,
100  translation_key=ATTR_WATER_BOX_ATTACHED,
101  icon="mdi:water",
102  parent_key=VacuumCoordinatorDataAttributes.status,
103  entity_registry_enabled_default=True,
104  device_class=BinarySensorDeviceClass.CONNECTIVITY,
105  entity_category=EntityCategory.DIAGNOSTIC,
106  ),
107  ATTR_WATER_SHORTAGE: XiaomiMiioBinarySensorDescription(
108  key=ATTR_WATER_SHORTAGE,
109  translation_key=ATTR_WATER_SHORTAGE,
110  icon="mdi:water",
111  parent_key=VacuumCoordinatorDataAttributes.status,
112  entity_registry_enabled_default=True,
113  device_class=BinarySensorDeviceClass.PROBLEM,
114  entity_category=EntityCategory.DIAGNOSTIC,
115  ),
116 }
117 
118 VACUUM_SENSORS_SEPARATE_MOP = {
119  **VACUUM_SENSORS,
120  ATTR_MOP_ATTACHED: XiaomiMiioBinarySensorDescription(
121  key=ATTR_MOP_ATTACHED,
122  translation_key=ATTR_MOP_ATTACHED,
123  icon="mdi:square-rounded",
124  parent_key=VacuumCoordinatorDataAttributes.status,
125  entity_registry_enabled_default=True,
126  device_class=BinarySensorDeviceClass.CONNECTIVITY,
127  entity_category=EntityCategory.DIAGNOSTIC,
128  ),
129 }
130 
131 HUMIDIFIER_MIIO_BINARY_SENSORS = (ATTR_WATER_TANK_DETACHED,)
132 HUMIDIFIER_MIOT_BINARY_SENSORS = (ATTR_WATER_TANK_DETACHED,)
133 HUMIDIFIER_MJJSQ_BINARY_SENSORS = (ATTR_NO_WATER, ATTR_WATER_TANK_DETACHED)
134 
135 
136 def _setup_vacuum_sensors(hass, config_entry, async_add_entities):
137  """Only vacuums with mop should have binary sensor registered."""
138  if config_entry.data[CONF_MODEL] not in MODELS_VACUUM_WITH_MOP:
139  return
140 
141  device = hass.data[DOMAIN][config_entry.entry_id].get(KEY_DEVICE)
142  coordinator = hass.data[DOMAIN][config_entry.entry_id][KEY_COORDINATOR]
143  entities = []
144  sensors = VACUUM_SENSORS
145 
146  if config_entry.data[CONF_MODEL] in MODELS_VACUUM_WITH_SEPARATE_MOP:
147  sensors = VACUUM_SENSORS_SEPARATE_MOP
148 
149  for sensor, description in sensors.items():
150  parent_key_data = getattr(coordinator.data, description.parent_key)
151  if getattr(parent_key_data, description.key, None) is None:
152  _LOGGER.debug(
153  "It seems the %s does not support the %s as the initial value is None",
154  config_entry.data[CONF_MODEL],
155  description.key,
156  )
157  continue
158  entities.append(
160  device,
161  config_entry,
162  f"{sensor}_{config_entry.unique_id}",
163  coordinator,
164  description,
165  )
166  )
167 
168  async_add_entities(entities)
169 
170 
172  hass: HomeAssistant,
173  config_entry: ConfigEntry,
174  async_add_entities: AddEntitiesCallback,
175 ) -> None:
176  """Set up the Xiaomi sensor from a config entry."""
177  entities = []
178 
179  if config_entry.data[CONF_FLOW_TYPE] == CONF_DEVICE:
180  model = config_entry.data[CONF_MODEL]
181  sensors: Iterable[str] = []
182  if model in MODEL_AIRFRESH_A1 or model in MODEL_AIRFRESH_T2017:
183  sensors = AIRFRESH_A1_BINARY_SENSORS
184  elif model in MODEL_FAN_ZA5:
185  sensors = FAN_ZA5_BINARY_SENSORS
186  elif model in MODELS_HUMIDIFIER_MIIO:
187  sensors = HUMIDIFIER_MIIO_BINARY_SENSORS
188  elif model in MODELS_HUMIDIFIER_MIOT:
189  sensors = HUMIDIFIER_MIOT_BINARY_SENSORS
190  elif model in MODELS_HUMIDIFIER_MJJSQ:
191  sensors = HUMIDIFIER_MJJSQ_BINARY_SENSORS
192  elif model in MODELS_VACUUM:
193  _setup_vacuum_sensors(hass, config_entry, async_add_entities)
194  return
195 
196  for description in BINARY_SENSOR_TYPES:
197  if description.key not in sensors:
198  continue
199  entities.append(
201  hass.data[DOMAIN][config_entry.entry_id][KEY_DEVICE],
202  config_entry,
203  f"{description.key}_{config_entry.unique_id}",
204  hass.data[DOMAIN][config_entry.entry_id][KEY_COORDINATOR],
205  description,
206  )
207  )
208 
209  async_add_entities(entities)
210 
211 
213  """Representation of a Xiaomi Humidifier binary sensor."""
214 
215  entity_description: XiaomiMiioBinarySensorDescription
216 
217  def __init__(self, device, entry, unique_id, coordinator, description):
218  """Initialize the entity."""
219  super().__init__(device, entry, unique_id, coordinator)
220 
221  self.entity_descriptionentity_description = description
222  self._attr_entity_registry_enabled_default_attr_entity_registry_enabled_default = (
223  description.entity_registry_enabled_default
224  )
225  self._attr_is_on_attr_is_on = self._determine_native_value_determine_native_value()
226 
227  @callback
228  def _handle_coordinator_update(self) -> None:
229  self._attr_is_on_attr_is_on = self._determine_native_value_determine_native_value()
230 
232 
234  """Determine native value."""
235  if self.entity_descriptionentity_description.parent_key is not None:
236  return self._extract_value_from_attribute(
237  getattr(self.coordinator.data, self.entity_descriptionentity_description.parent_key),
238  self.entity_descriptionentity_description.key,
239  )
240 
241  state = self._extract_value_from_attribute(
242  self.coordinator.data, self.entity_descriptionentity_description.key
243  )
244  if self.entity_descriptionentity_description.value is not None and state is not None:
245  return self.entity_descriptionentity_description.value(state)
246 
247  return state
def __init__(self, device, entry, unique_id, coordinator, description)
web.Response get(self, web.Request request, str config_key)
Definition: view.py:88
def _setup_vacuum_sensors(hass, config_entry, async_add_entities)
None async_setup_entry(HomeAssistant hass, ConfigEntry config_entry, AddEntitiesCallback async_add_entities)