Home Assistant Unofficial Reference 2024.12.1
binary_sensor.py
Go to the documentation of this file.
1 """Viessmann ViCare sensor device."""
2 
3 from __future__ import annotations
4 
5 from collections.abc import Callable
6 from contextlib import suppress
7 from dataclasses import dataclass
8 import logging
9 
10 from PyViCare.PyViCareDevice import Device as PyViCareDevice
11 from PyViCare.PyViCareDeviceConfig import PyViCareDeviceConfig
12 from PyViCare.PyViCareHeatingDevice import (
13  HeatingDeviceWithComponent as PyViCareHeatingDeviceComponent,
14 )
15 from PyViCare.PyViCareUtils import (
16  PyViCareInvalidDataError,
17  PyViCareNotSupportedFeatureError,
18  PyViCareRateLimitError,
19 )
20 import requests
21 
23  BinarySensorDeviceClass,
24  BinarySensorEntity,
25  BinarySensorEntityDescription,
26 )
27 from homeassistant.config_entries import ConfigEntry
28 from homeassistant.core import HomeAssistant
29 from homeassistant.helpers.entity_platform import AddEntitiesCallback
30 
31 from .const import DEVICE_LIST, DOMAIN
32 from .entity import ViCareEntity
33 from .types import ViCareDevice, ViCareRequiredKeysMixin
34 from .utils import (
35  get_burners,
36  get_circuits,
37  get_compressors,
38  get_device_serial,
39  is_supported,
40 )
41 
42 _LOGGER = logging.getLogger(__name__)
43 
44 
45 @dataclass(frozen=True)
47  BinarySensorEntityDescription, ViCareRequiredKeysMixin
48 ):
49  """Describes ViCare binary sensor entity."""
50 
51  value_getter: Callable[[PyViCareDevice], bool]
52 
53 
54 CIRCUIT_SENSORS: tuple[ViCareBinarySensorEntityDescription, ...] = (
56  key="circulationpump_active",
57  translation_key="circulation_pump",
58  device_class=BinarySensorDeviceClass.RUNNING,
59  value_getter=lambda api: api.getCirculationPumpActive(),
60  ),
62  key="frost_protection_active",
63  translation_key="frost_protection",
64  value_getter=lambda api: api.getFrostProtectionActive(),
65  ),
66 )
67 
68 BURNER_SENSORS: tuple[ViCareBinarySensorEntityDescription, ...] = (
70  key="burner_active",
71  translation_key="burner",
72  device_class=BinarySensorDeviceClass.RUNNING,
73  value_getter=lambda api: api.getActive(),
74  ),
75 )
76 
77 COMPRESSOR_SENSORS: tuple[ViCareBinarySensorEntityDescription, ...] = (
79  key="compressor_active",
80  translation_key="compressor",
81  device_class=BinarySensorDeviceClass.RUNNING,
82  value_getter=lambda api: api.getActive(),
83  ),
84 )
85 
86 GLOBAL_SENSORS: tuple[ViCareBinarySensorEntityDescription, ...] = (
88  key="solar_pump_active",
89  translation_key="solar_pump",
90  device_class=BinarySensorDeviceClass.RUNNING,
91  value_getter=lambda api: api.getSolarPumpActive(),
92  ),
94  key="charging_active",
95  translation_key="domestic_hot_water_charging",
96  device_class=BinarySensorDeviceClass.RUNNING,
97  value_getter=lambda api: api.getDomesticHotWaterChargingActive(),
98  ),
100  key="dhw_circulationpump_active",
101  translation_key="domestic_hot_water_circulation_pump",
102  device_class=BinarySensorDeviceClass.RUNNING,
103  value_getter=lambda api: api.getDomesticHotWaterCirculationPumpActive(),
104  ),
106  key="dhw_pump_active",
107  translation_key="domestic_hot_water_pump",
108  device_class=BinarySensorDeviceClass.RUNNING,
109  value_getter=lambda api: api.getDomesticHotWaterPumpActive(),
110  ),
111 )
112 
113 
115  device_list: list[ViCareDevice],
116 ) -> list[ViCareBinarySensor]:
117  """Create ViCare binary sensor entities for a device."""
118 
119  entities: list[ViCareBinarySensor] = []
120  for device in device_list:
121  # add device entities
122  entities.extend(
124  description,
125  get_device_serial(device.api),
126  device.config,
127  device.api,
128  )
129  for description in GLOBAL_SENSORS
130  if is_supported(description.key, description, device.api)
131  )
132  # add component entities
133  for component_list, entity_description_list in (
134  (get_circuits(device.api), CIRCUIT_SENSORS),
135  (get_burners(device.api), BURNER_SENSORS),
136  (get_compressors(device.api), COMPRESSOR_SENSORS),
137  ):
138  entities.extend(
140  description,
141  get_device_serial(device.api),
142  device.config,
143  device.api,
144  component,
145  )
146  for component in component_list
147  for description in entity_description_list
148  if is_supported(description.key, description, component)
149  )
150  return entities
151 
152 
154  hass: HomeAssistant,
155  config_entry: ConfigEntry,
156  async_add_entities: AddEntitiesCallback,
157 ) -> None:
158  """Create the ViCare binary sensor devices."""
159  device_list = hass.data[DOMAIN][config_entry.entry_id][DEVICE_LIST]
160 
162  await hass.async_add_executor_job(
163  _build_entities,
164  device_list,
165  )
166  )
167 
168 
170  """Representation of a ViCare sensor."""
171 
172  entity_description: ViCareBinarySensorEntityDescription
173 
174  def __init__(
175  self,
176  description: ViCareBinarySensorEntityDescription,
177  device_serial: str | None,
178  device_config: PyViCareDeviceConfig,
179  device: PyViCareDevice,
180  component: PyViCareHeatingDeviceComponent | None = None,
181  ) -> None:
182  """Initialize the sensor."""
183  super().__init__(
184  description.key, device_serial, device_config, device, component
185  )
186  self.entity_descriptionentity_description = description
187 
188  @property
189  def available(self) -> bool:
190  """Return True if entity is available."""
191  return self._attr_is_on_attr_is_on is not None
192 
193  def update(self) -> None:
194  """Update state of sensor."""
195  try:
196  with suppress(PyViCareNotSupportedFeatureError):
197  self._attr_is_on_attr_is_on = self.entity_descriptionentity_description.value_getter(self._api)
198  except requests.exceptions.ConnectionError:
199  _LOGGER.error("Unable to retrieve data from ViCare server")
200  except ValueError:
201  _LOGGER.error("Unable to decode data from ViCare server")
202  except PyViCareRateLimitError as limit_exception:
203  _LOGGER.error("Vicare API rate limit exceeded: %s", limit_exception)
204  except PyViCareInvalidDataError as invalid_data_exception:
205  _LOGGER.error("Invalid data from Vicare server: %s", invalid_data_exception)
None __init__(self, ViCareBinarySensorEntityDescription description, str|None device_serial, PyViCareDeviceConfig device_config, PyViCareDevice device, PyViCareHeatingDeviceComponent|None component=None)
None async_setup_entry(HomeAssistant hass, ConfigEntry config_entry, AddEntitiesCallback async_add_entities)
list[ViCareBinarySensor] _build_entities(list[ViCareDevice] device_list)
str|None get_device_serial(PyViCareDevice device)
Definition: utils.py:35
list[PyViCareHeatingDeviceComponent] get_compressors(PyViCareDevice device)
Definition: utils.py:92
bool is_supported(str name, ViCareRequiredKeysMixin entity_description, vicare_device)
Definition: utils.py:56
list[PyViCareHeatingDeviceComponent] get_circuits(PyViCareDevice device)
Definition: utils.py:81
list[PyViCareHeatingDeviceComponent] get_burners(PyViCareDevice device)
Definition: utils.py:70