Home Assistant Unofficial Reference 2024.12.1
sensor.py
Go to the documentation of this file.
1 """Support for consuming values for the Volkszaehler API."""
2 
3 from __future__ import annotations
4 
5 from datetime import timedelta
6 import logging
7 
8 from volkszaehler import Volkszaehler
9 from volkszaehler.exceptions import VolkszaehlerApiConnectionError
10 import voluptuous as vol
11 
13  PLATFORM_SCHEMA as SENSOR_PLATFORM_SCHEMA,
14  SensorDeviceClass,
15  SensorEntity,
16  SensorEntityDescription,
17 )
18 from homeassistant.const import (
19  CONF_HOST,
20  CONF_MONITORED_CONDITIONS,
21  CONF_NAME,
22  CONF_PORT,
23  CONF_UUID,
24  UnitOfEnergy,
25  UnitOfPower,
26 )
27 from homeassistant.core import HomeAssistant
28 from homeassistant.exceptions import PlatformNotReady
29 from homeassistant.helpers.aiohttp_client import async_get_clientsession
31 from homeassistant.helpers.entity_platform import AddEntitiesCallback
32 from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
33 from homeassistant.util import Throttle
34 
35 _LOGGER = logging.getLogger(__name__)
36 
37 DEFAULT_HOST = "localhost"
38 DEFAULT_NAME = "Volkszaehler"
39 DEFAULT_PORT = 80
40 
41 MIN_TIME_BETWEEN_UPDATES = timedelta(minutes=1)
42 
43 SENSOR_TYPES: tuple[SensorEntityDescription, ...] = (
45  key="average",
46  name="Average",
47  native_unit_of_measurement=UnitOfPower.WATT,
48  device_class=SensorDeviceClass.POWER,
49  icon="mdi:power-off",
50  ),
52  key="consumption",
53  name="Consumption",
54  native_unit_of_measurement=UnitOfEnergy.WATT_HOUR,
55  device_class=SensorDeviceClass.ENERGY,
56  icon="mdi:power-plug",
57  ),
59  key="max",
60  name="Max",
61  native_unit_of_measurement=UnitOfPower.WATT,
62  device_class=SensorDeviceClass.POWER,
63  icon="mdi:arrow-up",
64  ),
66  key="min",
67  name="Min",
68  native_unit_of_measurement=UnitOfPower.WATT,
69  device_class=SensorDeviceClass.POWER,
70  icon="mdi:arrow-down",
71  ),
72 )
73 
74 SENSOR_KEYS: list[str] = [desc.key for desc in SENSOR_TYPES]
75 
76 PLATFORM_SCHEMA = SENSOR_PLATFORM_SCHEMA.extend(
77  {
78  vol.Required(CONF_UUID): cv.string,
79  vol.Optional(CONF_HOST, default=DEFAULT_HOST): cv.string,
80  vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
81  vol.Optional(CONF_PORT, default=DEFAULT_PORT): cv.port,
82  vol.Optional(CONF_MONITORED_CONDITIONS, default=["average"]): vol.All(
83  cv.ensure_list, [vol.In(SENSOR_KEYS)]
84  ),
85  }
86 )
87 
88 
90  hass: HomeAssistant,
91  config: ConfigType,
92  async_add_entities: AddEntitiesCallback,
93  discovery_info: DiscoveryInfoType | None = None,
94 ) -> None:
95  """Set up the Volkszaehler sensors."""
96 
97  host: str = config[CONF_HOST]
98  name: str = config[CONF_NAME]
99  port: int = config[CONF_PORT]
100  uuid: str = config[CONF_UUID]
101  conditions: list[str] = config[CONF_MONITORED_CONDITIONS]
102 
103  session = async_get_clientsession(hass)
104  vz_api = VolkszaehlerData(Volkszaehler(session, uuid, host=host, port=port))
105 
106  await vz_api.async_update()
107 
108  if vz_api.api.data is None:
109  raise PlatformNotReady
110 
111  entities = [
112  VolkszaehlerSensor(vz_api, name, description)
113  for description in SENSOR_TYPES
114  if description.key in conditions
115  ]
116 
117  async_add_entities(entities, True)
118 
119 
121  """Implementation of a Volkszaehler sensor."""
122 
123  def __init__(
124  self, vz_api: VolkszaehlerData, name: str, description: SensorEntityDescription
125  ) -> None:
126  """Initialize the Volkszaehler sensor."""
127  self.entity_descriptionentity_description = description
128  self.vz_apivz_api = vz_api
129 
130  self._attr_name_attr_name = f"{name} {description.name}"
131 
132  @property
133  def available(self) -> bool:
134  """Could the device be accessed during the last update call."""
135  return self.vz_apivz_api.available
136 
137  async def async_update(self) -> None:
138  """Get the latest data from REST API."""
139  await self.vz_apivz_api.async_update()
140 
141  if self.vz_apivz_api.api.data is not None:
142  self._attr_native_value_attr_native_value = round(
143  getattr(self.vz_apivz_api.api, self.entity_descriptionentity_description.key), 2
144  )
145 
146 
148  """The class for handling the data retrieval from the Volkszaehler API."""
149 
150  def __init__(self, api: Volkszaehler) -> None:
151  """Initialize the data object."""
152  self.apiapi = api
153  self.availableavailable = True
154 
155  @Throttle(MIN_TIME_BETWEEN_UPDATES)
156  async def async_update(self) -> None:
157  """Get the latest data from the Volkszaehler REST API."""
158 
159  try:
160  await self.apiapi.get_data()
161  self.availableavailable = True
162  except VolkszaehlerApiConnectionError:
163  _LOGGER.error("Unable to fetch data from the Volkszaehler API")
164  self.availableavailable = False
None __init__(self, VolkszaehlerData vz_api, str name, SensorEntityDescription description)
Definition: sensor.py:125
None async_setup_platform(HomeAssistant hass, ConfigType config, AddEntitiesCallback async_add_entities, DiscoveryInfoType|None discovery_info=None)
Definition: sensor.py:94
aiohttp.ClientSession async_get_clientsession(HomeAssistant hass, bool verify_ssl=True, socket.AddressFamily family=socket.AF_UNSPEC, ssl_util.SSLCipherList ssl_cipher=ssl_util.SSLCipherList.PYTHON_DEFAULT)