Home Assistant Unofficial Reference 2024.12.1
sensor.py
Go to the documentation of this file.
1 """Support for Fronius devices."""
2 
3 from __future__ import annotations
4 
5 from collections.abc import Callable
6 from dataclasses import dataclass
7 from typing import TYPE_CHECKING, Any, Final
8 
10  SensorDeviceClass,
11  SensorEntity,
12  SensorEntityDescription,
13  SensorStateClass,
14 )
15 from homeassistant.const import (
16  PERCENTAGE,
17  EntityCategory,
18  UnitOfApparentPower,
19  UnitOfElectricCurrent,
20  UnitOfElectricPotential,
21  UnitOfEnergy,
22  UnitOfFrequency,
23  UnitOfPower,
24  UnitOfReactivePower,
25  UnitOfTemperature,
26 )
27 from homeassistant.core import HomeAssistant, callback
28 from homeassistant.helpers.device_registry import DeviceInfo
29 from homeassistant.helpers.dispatcher import async_dispatcher_connect
30 from homeassistant.helpers.entity_platform import AddEntitiesCallback
31 from homeassistant.helpers.typing import StateType
32 from homeassistant.helpers.update_coordinator import CoordinatorEntity
33 
34 from .const import (
35  DOMAIN,
36  SOLAR_NET_DISCOVERY_NEW,
37  InverterStatusCodeOption,
38  MeterLocationCodeOption,
39  OhmPilotStateCodeOption,
40  get_inverter_status_message,
41  get_meter_location_description,
42  get_ohmpilot_state_message,
43 )
44 
45 if TYPE_CHECKING:
46  from . import FroniusConfigEntry
47  from .coordinator import (
48  FroniusCoordinatorBase,
49  FroniusInverterUpdateCoordinator,
50  FroniusLoggerUpdateCoordinator,
51  FroniusMeterUpdateCoordinator,
52  FroniusOhmpilotUpdateCoordinator,
53  FroniusPowerFlowUpdateCoordinator,
54  FroniusStorageUpdateCoordinator,
55  )
56 
57 ENERGY_VOLT_AMPERE_REACTIVE_HOUR: Final = "varh"
58 
59 
61  hass: HomeAssistant,
62  config_entry: FroniusConfigEntry,
63  async_add_entities: AddEntitiesCallback,
64 ) -> None:
65  """Set up Fronius sensor entities based on a config entry."""
66  solar_net = config_entry.runtime_data
67 
68  for inverter_coordinator in solar_net.inverter_coordinators:
69  inverter_coordinator.add_entities_for_seen_keys(
70  async_add_entities, InverterSensor
71  )
72  if solar_net.logger_coordinator is not None:
73  solar_net.logger_coordinator.add_entities_for_seen_keys(
74  async_add_entities, LoggerSensor
75  )
76  if solar_net.meter_coordinator is not None:
77  solar_net.meter_coordinator.add_entities_for_seen_keys(
78  async_add_entities, MeterSensor
79  )
80  if solar_net.ohmpilot_coordinator is not None:
81  solar_net.ohmpilot_coordinator.add_entities_for_seen_keys(
82  async_add_entities, OhmpilotSensor
83  )
84  if solar_net.power_flow_coordinator is not None:
85  solar_net.power_flow_coordinator.add_entities_for_seen_keys(
86  async_add_entities, PowerFlowSensor
87  )
88  if solar_net.storage_coordinator is not None:
89  solar_net.storage_coordinator.add_entities_for_seen_keys(
90  async_add_entities, StorageSensor
91  )
92 
93  @callback
94  def async_add_new_entities(coordinator: FroniusInverterUpdateCoordinator) -> None:
95  """Add newly found inverter entities."""
96  coordinator.add_entities_for_seen_keys(async_add_entities, InverterSensor)
97 
98  config_entry.async_on_unload(
100  hass,
101  SOLAR_NET_DISCOVERY_NEW,
102  async_add_new_entities,
103  )
104  )
105 
106 
107 @dataclass(frozen=True)
109  """Describes Fronius sensor entity."""
110 
111  default_value: StateType | None = None
112  # Gen24 devices may report 0 for total energy while doing firmware updates.
113  # Handling such values shall mitigate spikes in delta calculations.
114  invalid_when_falsy: bool = False
115  response_key: str | None = None
116  value_fn: Callable[[StateType], StateType] | None = None
117 
118 
119 INVERTER_ENTITY_DESCRIPTIONS: list[FroniusSensorEntityDescription] = [
121  key="energy_day",
122  native_unit_of_measurement=UnitOfEnergy.WATT_HOUR,
123  device_class=SensorDeviceClass.ENERGY,
124  state_class=SensorStateClass.TOTAL_INCREASING,
125  ),
127  key="energy_year",
128  native_unit_of_measurement=UnitOfEnergy.WATT_HOUR,
129  device_class=SensorDeviceClass.ENERGY,
130  state_class=SensorStateClass.TOTAL_INCREASING,
131  ),
133  key="energy_total",
134  native_unit_of_measurement=UnitOfEnergy.WATT_HOUR,
135  device_class=SensorDeviceClass.ENERGY,
136  state_class=SensorStateClass.TOTAL_INCREASING,
137  invalid_when_falsy=True,
138  ),
140  key="frequency_ac",
141  default_value=0,
142  native_unit_of_measurement=UnitOfFrequency.HERTZ,
143  device_class=SensorDeviceClass.FREQUENCY,
144  state_class=SensorStateClass.MEASUREMENT,
145  entity_registry_enabled_default=False,
146  ),
148  key="current_ac",
149  default_value=0,
150  native_unit_of_measurement=UnitOfElectricCurrent.AMPERE,
151  device_class=SensorDeviceClass.CURRENT,
152  state_class=SensorStateClass.MEASUREMENT,
153  ),
155  key="current_dc",
156  default_value=0,
157  native_unit_of_measurement=UnitOfElectricCurrent.AMPERE,
158  device_class=SensorDeviceClass.CURRENT,
159  state_class=SensorStateClass.MEASUREMENT,
160  ),
162  key="current_dc_2",
163  default_value=0,
164  native_unit_of_measurement=UnitOfElectricCurrent.AMPERE,
165  device_class=SensorDeviceClass.CURRENT,
166  state_class=SensorStateClass.MEASUREMENT,
167  ),
169  key="power_ac",
170  default_value=0,
171  native_unit_of_measurement=UnitOfPower.WATT,
172  device_class=SensorDeviceClass.POWER,
173  state_class=SensorStateClass.MEASUREMENT,
174  ),
176  key="voltage_ac",
177  default_value=0,
178  native_unit_of_measurement=UnitOfElectricPotential.VOLT,
179  device_class=SensorDeviceClass.VOLTAGE,
180  state_class=SensorStateClass.MEASUREMENT,
181  entity_registry_enabled_default=False,
182  ),
184  key="voltage_dc",
185  default_value=0,
186  native_unit_of_measurement=UnitOfElectricPotential.VOLT,
187  device_class=SensorDeviceClass.VOLTAGE,
188  state_class=SensorStateClass.MEASUREMENT,
189  ),
191  key="voltage_dc_2",
192  default_value=0,
193  native_unit_of_measurement=UnitOfElectricPotential.VOLT,
194  device_class=SensorDeviceClass.VOLTAGE,
195  state_class=SensorStateClass.MEASUREMENT,
196  ),
197  # device status entities
199  key="inverter_state",
200  entity_category=EntityCategory.DIAGNOSTIC,
201  ),
203  key="error_code",
204  entity_category=EntityCategory.DIAGNOSTIC,
205  ),
207  key="status_code",
208  entity_category=EntityCategory.DIAGNOSTIC,
209  entity_registry_enabled_default=False,
210  ),
212  key="status_message",
213  response_key="status_code",
214  entity_category=EntityCategory.DIAGNOSTIC,
215  device_class=SensorDeviceClass.ENUM,
216  options=[opt.value for opt in InverterStatusCodeOption],
217  value_fn=get_inverter_status_message,
218  ),
220  key="led_state",
221  entity_category=EntityCategory.DIAGNOSTIC,
222  entity_registry_enabled_default=False,
223  ),
225  key="led_color",
226  entity_category=EntityCategory.DIAGNOSTIC,
227  entity_registry_enabled_default=False,
228  ),
229 ]
230 
231 LOGGER_ENTITY_DESCRIPTIONS: list[FroniusSensorEntityDescription] = [
233  key="co2_factor",
234  state_class=SensorStateClass.MEASUREMENT,
235  ),
237  key="cash_factor",
238  state_class=SensorStateClass.MEASUREMENT,
239  ),
241  key="delivery_factor",
242  state_class=SensorStateClass.MEASUREMENT,
243  ),
244 ]
245 
246 METER_ENTITY_DESCRIPTIONS: list[FroniusSensorEntityDescription] = [
248  key="current_ac_phase_1",
249  native_unit_of_measurement=UnitOfElectricCurrent.AMPERE,
250  device_class=SensorDeviceClass.CURRENT,
251  state_class=SensorStateClass.MEASUREMENT,
252  entity_registry_enabled_default=False,
253  ),
255  key="current_ac_phase_2",
256  native_unit_of_measurement=UnitOfElectricCurrent.AMPERE,
257  device_class=SensorDeviceClass.CURRENT,
258  state_class=SensorStateClass.MEASUREMENT,
259  entity_registry_enabled_default=False,
260  ),
262  key="current_ac_phase_3",
263  native_unit_of_measurement=UnitOfElectricCurrent.AMPERE,
264  device_class=SensorDeviceClass.CURRENT,
265  state_class=SensorStateClass.MEASUREMENT,
266  entity_registry_enabled_default=False,
267  ),
269  key="energy_reactive_ac_consumed",
270  native_unit_of_measurement=ENERGY_VOLT_AMPERE_REACTIVE_HOUR,
271  state_class=SensorStateClass.TOTAL_INCREASING,
272  entity_registry_enabled_default=False,
273  invalid_when_falsy=True,
274  ),
276  key="energy_reactive_ac_produced",
277  native_unit_of_measurement=ENERGY_VOLT_AMPERE_REACTIVE_HOUR,
278  state_class=SensorStateClass.TOTAL_INCREASING,
279  entity_registry_enabled_default=False,
280  invalid_when_falsy=True,
281  ),
283  key="energy_real_ac_minus",
284  native_unit_of_measurement=UnitOfEnergy.WATT_HOUR,
285  device_class=SensorDeviceClass.ENERGY,
286  state_class=SensorStateClass.TOTAL_INCREASING,
287  entity_registry_enabled_default=False,
288  invalid_when_falsy=True,
289  ),
291  key="energy_real_ac_plus",
292  native_unit_of_measurement=UnitOfEnergy.WATT_HOUR,
293  device_class=SensorDeviceClass.ENERGY,
294  state_class=SensorStateClass.TOTAL_INCREASING,
295  entity_registry_enabled_default=False,
296  invalid_when_falsy=True,
297  ),
299  key="energy_real_consumed",
300  native_unit_of_measurement=UnitOfEnergy.WATT_HOUR,
301  device_class=SensorDeviceClass.ENERGY,
302  state_class=SensorStateClass.TOTAL_INCREASING,
303  invalid_when_falsy=True,
304  ),
306  key="energy_real_produced",
307  native_unit_of_measurement=UnitOfEnergy.WATT_HOUR,
308  device_class=SensorDeviceClass.ENERGY,
309  state_class=SensorStateClass.TOTAL_INCREASING,
310  invalid_when_falsy=True,
311  ),
313  key="frequency_phase_average",
314  native_unit_of_measurement=UnitOfFrequency.HERTZ,
315  device_class=SensorDeviceClass.FREQUENCY,
316  state_class=SensorStateClass.MEASUREMENT,
317  ),
319  key="meter_location",
320  entity_category=EntityCategory.DIAGNOSTIC,
321  value_fn=int, # type: ignore[arg-type]
322  ),
324  key="meter_location_description",
325  response_key="meter_location",
326  entity_category=EntityCategory.DIAGNOSTIC,
327  device_class=SensorDeviceClass.ENUM,
328  options=[opt.value for opt in MeterLocationCodeOption],
329  value_fn=get_meter_location_description,
330  ),
332  key="power_apparent_phase_1",
333  native_unit_of_measurement=UnitOfApparentPower.VOLT_AMPERE,
334  device_class=SensorDeviceClass.APPARENT_POWER,
335  state_class=SensorStateClass.MEASUREMENT,
336  entity_registry_enabled_default=False,
337  ),
339  key="power_apparent_phase_2",
340  native_unit_of_measurement=UnitOfApparentPower.VOLT_AMPERE,
341  device_class=SensorDeviceClass.APPARENT_POWER,
342  state_class=SensorStateClass.MEASUREMENT,
343  entity_registry_enabled_default=False,
344  ),
346  key="power_apparent_phase_3",
347  native_unit_of_measurement=UnitOfApparentPower.VOLT_AMPERE,
348  device_class=SensorDeviceClass.APPARENT_POWER,
349  state_class=SensorStateClass.MEASUREMENT,
350  entity_registry_enabled_default=False,
351  ),
353  key="power_apparent",
354  native_unit_of_measurement=UnitOfApparentPower.VOLT_AMPERE,
355  device_class=SensorDeviceClass.APPARENT_POWER,
356  state_class=SensorStateClass.MEASUREMENT,
357  entity_registry_enabled_default=False,
358  ),
360  key="power_factor_phase_1",
361  device_class=SensorDeviceClass.POWER_FACTOR,
362  state_class=SensorStateClass.MEASUREMENT,
363  entity_registry_enabled_default=False,
364  ),
366  key="power_factor_phase_2",
367  device_class=SensorDeviceClass.POWER_FACTOR,
368  state_class=SensorStateClass.MEASUREMENT,
369  entity_registry_enabled_default=False,
370  ),
372  key="power_factor_phase_3",
373  device_class=SensorDeviceClass.POWER_FACTOR,
374  state_class=SensorStateClass.MEASUREMENT,
375  entity_registry_enabled_default=False,
376  ),
378  key="power_factor",
379  device_class=SensorDeviceClass.POWER_FACTOR,
380  state_class=SensorStateClass.MEASUREMENT,
381  ),
383  key="power_reactive_phase_1",
384  native_unit_of_measurement=UnitOfReactivePower.VOLT_AMPERE_REACTIVE,
385  device_class=SensorDeviceClass.REACTIVE_POWER,
386  state_class=SensorStateClass.MEASUREMENT,
387  entity_registry_enabled_default=False,
388  ),
390  key="power_reactive_phase_2",
391  native_unit_of_measurement=UnitOfReactivePower.VOLT_AMPERE_REACTIVE,
392  device_class=SensorDeviceClass.REACTIVE_POWER,
393  state_class=SensorStateClass.MEASUREMENT,
394  entity_registry_enabled_default=False,
395  ),
397  key="power_reactive_phase_3",
398  native_unit_of_measurement=UnitOfReactivePower.VOLT_AMPERE_REACTIVE,
399  device_class=SensorDeviceClass.REACTIVE_POWER,
400  state_class=SensorStateClass.MEASUREMENT,
401  entity_registry_enabled_default=False,
402  ),
404  key="power_reactive",
405  native_unit_of_measurement=UnitOfReactivePower.VOLT_AMPERE_REACTIVE,
406  device_class=SensorDeviceClass.REACTIVE_POWER,
407  state_class=SensorStateClass.MEASUREMENT,
408  entity_registry_enabled_default=False,
409  ),
411  key="power_real_phase_1",
412  native_unit_of_measurement=UnitOfPower.WATT,
413  device_class=SensorDeviceClass.POWER,
414  state_class=SensorStateClass.MEASUREMENT,
415  entity_registry_enabled_default=False,
416  ),
418  key="power_real_phase_2",
419  native_unit_of_measurement=UnitOfPower.WATT,
420  device_class=SensorDeviceClass.POWER,
421  state_class=SensorStateClass.MEASUREMENT,
422  entity_registry_enabled_default=False,
423  ),
425  key="power_real_phase_3",
426  native_unit_of_measurement=UnitOfPower.WATT,
427  device_class=SensorDeviceClass.POWER,
428  state_class=SensorStateClass.MEASUREMENT,
429  entity_registry_enabled_default=False,
430  ),
432  key="power_real",
433  native_unit_of_measurement=UnitOfPower.WATT,
434  device_class=SensorDeviceClass.POWER,
435  state_class=SensorStateClass.MEASUREMENT,
436  ),
438  key="voltage_ac_phase_1",
439  native_unit_of_measurement=UnitOfElectricPotential.VOLT,
440  device_class=SensorDeviceClass.VOLTAGE,
441  state_class=SensorStateClass.MEASUREMENT,
442  entity_registry_enabled_default=False,
443  ),
445  key="voltage_ac_phase_2",
446  native_unit_of_measurement=UnitOfElectricPotential.VOLT,
447  device_class=SensorDeviceClass.VOLTAGE,
448  state_class=SensorStateClass.MEASUREMENT,
449  entity_registry_enabled_default=False,
450  ),
452  key="voltage_ac_phase_3",
453  native_unit_of_measurement=UnitOfElectricPotential.VOLT,
454  device_class=SensorDeviceClass.VOLTAGE,
455  state_class=SensorStateClass.MEASUREMENT,
456  entity_registry_enabled_default=False,
457  ),
459  key="voltage_ac_phase_to_phase_12",
460  native_unit_of_measurement=UnitOfElectricPotential.VOLT,
461  device_class=SensorDeviceClass.VOLTAGE,
462  state_class=SensorStateClass.MEASUREMENT,
463  entity_registry_enabled_default=False,
464  ),
466  key="voltage_ac_phase_to_phase_23",
467  native_unit_of_measurement=UnitOfElectricPotential.VOLT,
468  device_class=SensorDeviceClass.VOLTAGE,
469  state_class=SensorStateClass.MEASUREMENT,
470  entity_registry_enabled_default=False,
471  ),
473  key="voltage_ac_phase_to_phase_31",
474  native_unit_of_measurement=UnitOfElectricPotential.VOLT,
475  device_class=SensorDeviceClass.VOLTAGE,
476  state_class=SensorStateClass.MEASUREMENT,
477  entity_registry_enabled_default=False,
478  ),
479 ]
480 
481 OHMPILOT_ENTITY_DESCRIPTIONS: list[FroniusSensorEntityDescription] = [
483  key="energy_real_ac_consumed",
484  native_unit_of_measurement=UnitOfEnergy.WATT_HOUR,
485  device_class=SensorDeviceClass.ENERGY,
486  state_class=SensorStateClass.TOTAL_INCREASING,
487  invalid_when_falsy=True,
488  ),
490  key="power_real_ac",
491  native_unit_of_measurement=UnitOfPower.WATT,
492  device_class=SensorDeviceClass.POWER,
493  state_class=SensorStateClass.MEASUREMENT,
494  ),
496  key="temperature_channel_1",
497  native_unit_of_measurement=UnitOfTemperature.CELSIUS,
498  device_class=SensorDeviceClass.TEMPERATURE,
499  state_class=SensorStateClass.MEASUREMENT,
500  ),
502  key="error_code",
503  entity_category=EntityCategory.DIAGNOSTIC,
504  ),
506  key="state_code",
507  entity_category=EntityCategory.DIAGNOSTIC,
508  ),
510  key="state_message",
511  response_key="state_code",
512  entity_category=EntityCategory.DIAGNOSTIC,
513  device_class=SensorDeviceClass.ENUM,
514  options=[opt.value for opt in OhmPilotStateCodeOption],
515  value_fn=get_ohmpilot_state_message,
516  ),
517 ]
518 
519 POWER_FLOW_ENTITY_DESCRIPTIONS: list[FroniusSensorEntityDescription] = [
521  key="energy_day",
522  native_unit_of_measurement=UnitOfEnergy.WATT_HOUR,
523  device_class=SensorDeviceClass.ENERGY,
524  state_class=SensorStateClass.TOTAL_INCREASING,
525  entity_registry_enabled_default=False,
526  ),
528  key="energy_year",
529  native_unit_of_measurement=UnitOfEnergy.WATT_HOUR,
530  device_class=SensorDeviceClass.ENERGY,
531  state_class=SensorStateClass.TOTAL_INCREASING,
532  entity_registry_enabled_default=False,
533  ),
535  key="energy_total",
536  native_unit_of_measurement=UnitOfEnergy.WATT_HOUR,
537  device_class=SensorDeviceClass.ENERGY,
538  state_class=SensorStateClass.TOTAL_INCREASING,
539  invalid_when_falsy=True,
540  entity_registry_enabled_default=False,
541  ),
543  key="meter_mode",
544  entity_category=EntityCategory.DIAGNOSTIC,
545  ),
547  key="power_battery",
548  default_value=0,
549  native_unit_of_measurement=UnitOfPower.WATT,
550  device_class=SensorDeviceClass.POWER,
551  state_class=SensorStateClass.MEASUREMENT,
552  entity_registry_enabled_default=False,
553  ),
555  key="power_battery_discharge",
556  response_key="power_battery",
557  default_value=0,
558  value_fn=lambda value: max(value, 0), # type: ignore[type-var]
559  native_unit_of_measurement=UnitOfPower.WATT,
560  device_class=SensorDeviceClass.POWER,
561  state_class=SensorStateClass.MEASUREMENT,
562  ),
564  key="power_battery_charge",
565  response_key="power_battery",
566  default_value=0,
567  value_fn=lambda value: max(0 - value, 0), # type: ignore[operator]
568  native_unit_of_measurement=UnitOfPower.WATT,
569  device_class=SensorDeviceClass.POWER,
570  state_class=SensorStateClass.MEASUREMENT,
571  ),
573  key="power_grid",
574  default_value=0,
575  native_unit_of_measurement=UnitOfPower.WATT,
576  device_class=SensorDeviceClass.POWER,
577  state_class=SensorStateClass.MEASUREMENT,
578  entity_registry_enabled_default=False,
579  ),
581  key="power_grid_import",
582  response_key="power_grid",
583  default_value=0,
584  value_fn=lambda value: max(value, 0), # type: ignore[type-var]
585  native_unit_of_measurement=UnitOfPower.WATT,
586  device_class=SensorDeviceClass.POWER,
587  state_class=SensorStateClass.MEASUREMENT,
588  ),
590  key="power_grid_export",
591  response_key="power_grid",
592  default_value=0,
593  value_fn=lambda value: max(0 - value, 0), # type: ignore[operator]
594  native_unit_of_measurement=UnitOfPower.WATT,
595  device_class=SensorDeviceClass.POWER,
596  state_class=SensorStateClass.MEASUREMENT,
597  ),
599  key="power_load",
600  default_value=0,
601  native_unit_of_measurement=UnitOfPower.WATT,
602  device_class=SensorDeviceClass.POWER,
603  state_class=SensorStateClass.MEASUREMENT,
604  entity_registry_enabled_default=False,
605  ),
607  key="power_load_generated",
608  response_key="power_load",
609  default_value=0,
610  value_fn=lambda value: max(value, 0), # type: ignore[type-var]
611  native_unit_of_measurement=UnitOfPower.WATT,
612  device_class=SensorDeviceClass.POWER,
613  state_class=SensorStateClass.MEASUREMENT,
614  entity_registry_enabled_default=False,
615  ),
617  key="power_load_consumed",
618  response_key="power_load",
619  default_value=0,
620  value_fn=lambda value: max(0 - value, 0), # type: ignore[operator]
621  native_unit_of_measurement=UnitOfPower.WATT,
622  device_class=SensorDeviceClass.POWER,
623  state_class=SensorStateClass.MEASUREMENT,
624  ),
626  key="power_photovoltaics",
627  default_value=0,
628  native_unit_of_measurement=UnitOfPower.WATT,
629  device_class=SensorDeviceClass.POWER,
630  state_class=SensorStateClass.MEASUREMENT,
631  ),
633  key="relative_autonomy",
634  default_value=0,
635  native_unit_of_measurement=PERCENTAGE,
636  state_class=SensorStateClass.MEASUREMENT,
637  ),
639  key="relative_self_consumption",
640  default_value=0,
641  native_unit_of_measurement=PERCENTAGE,
642  state_class=SensorStateClass.MEASUREMENT,
643  ),
644 ]
645 
646 STORAGE_ENTITY_DESCRIPTIONS: list[FroniusSensorEntityDescription] = [
648  key="capacity_maximum",
649  native_unit_of_measurement=UnitOfEnergy.WATT_HOUR,
650  entity_category=EntityCategory.DIAGNOSTIC,
651  ),
653  key="capacity_designed",
654  native_unit_of_measurement=UnitOfEnergy.WATT_HOUR,
655  entity_category=EntityCategory.DIAGNOSTIC,
656  ),
658  key="current_dc",
659  native_unit_of_measurement=UnitOfElectricCurrent.AMPERE,
660  device_class=SensorDeviceClass.CURRENT,
661  state_class=SensorStateClass.MEASUREMENT,
662  ),
664  key="voltage_dc",
665  native_unit_of_measurement=UnitOfElectricPotential.VOLT,
666  device_class=SensorDeviceClass.VOLTAGE,
667  state_class=SensorStateClass.MEASUREMENT,
668  ),
670  key="voltage_dc_maximum_cell",
671  native_unit_of_measurement=UnitOfElectricPotential.VOLT,
672  device_class=SensorDeviceClass.VOLTAGE,
673  state_class=SensorStateClass.MEASUREMENT,
674  entity_registry_enabled_default=False,
675  ),
677  key="voltage_dc_minimum_cell",
678  native_unit_of_measurement=UnitOfElectricPotential.VOLT,
679  device_class=SensorDeviceClass.VOLTAGE,
680  state_class=SensorStateClass.MEASUREMENT,
681  entity_registry_enabled_default=False,
682  ),
684  key="state_of_charge",
685  native_unit_of_measurement=PERCENTAGE,
686  device_class=SensorDeviceClass.BATTERY,
687  state_class=SensorStateClass.MEASUREMENT,
688  ),
690  key="temperature_cell",
691  native_unit_of_measurement=UnitOfTemperature.CELSIUS,
692  device_class=SensorDeviceClass.TEMPERATURE,
693  state_class=SensorStateClass.MEASUREMENT,
694  ),
695 ]
696 
697 
698 class _FroniusSensorEntity(CoordinatorEntity["FroniusCoordinatorBase"], SensorEntity):
699  """Defines a Fronius coordinator entity."""
700 
701  entity_description: FroniusSensorEntityDescription
702 
703  _attr_has_entity_name = True
704 
705  def __init__(
706  self,
707  coordinator: FroniusCoordinatorBase,
708  description: FroniusSensorEntityDescription,
709  solar_net_id: str,
710  ) -> None:
711  """Set up an individual Fronius meter sensor."""
712  super().__init__(coordinator)
713  self.entity_descriptionentity_description = description
714  self.response_keyresponse_key = description.response_key or description.key
715  self.solar_net_idsolar_net_id = solar_net_id
716  self._attr_native_value_attr_native_value = self._get_entity_value_get_entity_value()
717  self._attr_translation_key_attr_translation_key = description.key
718 
719  def _device_data(self) -> dict[str, Any]:
720  """Extract information for SolarNet device from coordinator data."""
721  return self.coordinator.data[self.solar_net_idsolar_net_id]
722 
723  def _get_entity_value(self) -> Any:
724  """Extract entity value from coordinator. Raises KeyError if not included in latest update."""
725  new_value = self.coordinator.data[self.solar_net_idsolar_net_id][self.response_keyresponse_key]["value"]
726  if new_value is None:
727  return self.entity_descriptionentity_description.default_value
728  if self.entity_descriptionentity_description.invalid_when_falsy and not new_value:
729  return None
730  if self.entity_descriptionentity_description.value_fn is not None:
731  new_value = self.entity_descriptionentity_description.value_fn(new_value)
732  if isinstance(new_value, float):
733  return round(new_value, 4)
734  return new_value
735 
736  @callback
737  def _handle_coordinator_update(self) -> None:
738  """Handle updated data from the coordinator."""
739  try:
740  self._attr_native_value_attr_native_value = self._get_entity_value_get_entity_value()
741  except KeyError:
742  # sets state to `None` if no default_value is defined in entity description
743  # KeyError: raised when omitted in response - eg. at night when no production
744  self._attr_native_value_attr_native_value = self.entity_descriptionentity_description.default_value
745  self.async_write_ha_stateasync_write_ha_state()
746 
747 
749  """Defines a Fronius inverter device sensor entity."""
750 
751  def __init__(
752  self,
753  coordinator: FroniusInverterUpdateCoordinator,
754  description: FroniusSensorEntityDescription,
755  solar_net_id: str,
756  ) -> None:
757  """Set up an individual Fronius inverter sensor."""
758  super().__init__(coordinator, description, solar_net_id)
759  # device_info created in __init__ from a `GetInverterInfo` request
760  self._attr_device_info_attr_device_info = coordinator.inverter_info.device_info
761  self._attr_unique_id_attr_unique_id = (
762  f"{coordinator.inverter_info.unique_id}-{description.key}"
763  )
764 
765 
767  """Defines a Fronius logger device sensor entity."""
768 
769  def __init__(
770  self,
771  coordinator: FroniusLoggerUpdateCoordinator,
772  description: FroniusSensorEntityDescription,
773  solar_net_id: str,
774  ) -> None:
775  """Set up an individual Fronius meter sensor."""
776  super().__init__(coordinator, description, solar_net_id)
777  logger_data = self._device_data_device_data()
778  # Logger device is already created in FroniusSolarNet._create_solar_net_device
779  self._attr_device_info_attr_device_info = coordinator.solar_net.system_device_info
780  self._attr_native_unit_of_measurement_attr_native_unit_of_measurement = logger_data[self.response_keyresponse_key].get(
781  "unit"
782  )
783  self._attr_unique_id_attr_unique_id = (
784  f'{logger_data["unique_identifier"]["value"]}-{description.key}'
785  )
786 
787 
789  """Defines a Fronius meter device sensor entity."""
790 
791  def __init__(
792  self,
793  coordinator: FroniusMeterUpdateCoordinator,
794  description: FroniusSensorEntityDescription,
795  solar_net_id: str,
796  ) -> None:
797  """Set up an individual Fronius meter sensor."""
798  super().__init__(coordinator, description, solar_net_id)
799  meter_data = self._device_data_device_data()
800  # S0 meters connected directly to inverters respond "n.a." as serial number
801  # `model` contains the inverter id: "S0 Meter at inverter 1"
802  if (meter_uid := meter_data["serial"]["value"]) == "n.a.":
803  meter_uid = (
804  f"{coordinator.solar_net.solar_net_device_id}:"
805  f'{meter_data["model"]["value"]}'
806  )
807 
808  self._attr_device_info_attr_device_info = DeviceInfo(
809  identifiers={(DOMAIN, meter_uid)},
810  manufacturer=meter_data["manufacturer"]["value"],
811  model=meter_data["model"]["value"],
812  name=meter_data["model"]["value"],
813  via_device=(DOMAIN, coordinator.solar_net.solar_net_device_id),
814  )
815  self._attr_unique_id_attr_unique_id = f"{meter_uid}-{description.key}"
816 
817 
819  """Defines a Fronius Ohmpilot sensor entity."""
820 
821  def __init__(
822  self,
823  coordinator: FroniusOhmpilotUpdateCoordinator,
824  description: FroniusSensorEntityDescription,
825  solar_net_id: str,
826  ) -> None:
827  """Set up an individual Fronius meter sensor."""
828  super().__init__(coordinator, description, solar_net_id)
829  device_data = self._device_data_device_data()
830 
831  self._attr_device_info_attr_device_info = DeviceInfo(
832  identifiers={(DOMAIN, device_data["serial"]["value"])},
833  manufacturer=device_data["manufacturer"]["value"],
834  model=f"{device_data['model']['value']} {device_data['hardware']['value']}",
835  name=device_data["model"]["value"],
836  sw_version=device_data["software"]["value"],
837  via_device=(DOMAIN, coordinator.solar_net.solar_net_device_id),
838  )
839  self._attr_unique_id_attr_unique_id = f'{device_data["serial"]["value"]}-{description.key}'
840 
841 
843  """Defines a Fronius power flow sensor entity."""
844 
845  def __init__(
846  self,
847  coordinator: FroniusPowerFlowUpdateCoordinator,
848  description: FroniusSensorEntityDescription,
849  solar_net_id: str,
850  ) -> None:
851  """Set up an individual Fronius power flow sensor."""
852  super().__init__(coordinator, description, solar_net_id)
853  # SolarNet device is already created in FroniusSolarNet._create_solar_net_device
854  self._attr_device_info_attr_device_info = coordinator.solar_net.system_device_info
855  self._attr_unique_id_attr_unique_id = (
856  f"{coordinator.solar_net.solar_net_device_id}-power_flow-{description.key}"
857  )
858 
859 
861  """Defines a Fronius storage device sensor entity."""
862 
863  def __init__(
864  self,
865  coordinator: FroniusStorageUpdateCoordinator,
866  description: FroniusSensorEntityDescription,
867  solar_net_id: str,
868  ) -> None:
869  """Set up an individual Fronius storage sensor."""
870  super().__init__(coordinator, description, solar_net_id)
871  storage_data = self._device_data_device_data()
872 
873  self._attr_unique_id_attr_unique_id = f'{storage_data["serial"]["value"]}-{description.key}'
874  self._attr_device_info_attr_device_info = DeviceInfo(
875  identifiers={(DOMAIN, storage_data["serial"]["value"])},
876  manufacturer=storage_data["manufacturer"]["value"],
877  model=storage_data["model"]["value"],
878  name=storage_data["model"]["value"],
879  via_device=(DOMAIN, coordinator.solar_net.solar_net_device_id),
880  )
None __init__(self, FroniusInverterUpdateCoordinator coordinator, FroniusSensorEntityDescription description, str solar_net_id)
Definition: sensor.py:756
None __init__(self, FroniusLoggerUpdateCoordinator coordinator, FroniusSensorEntityDescription description, str solar_net_id)
Definition: sensor.py:774
None __init__(self, FroniusMeterUpdateCoordinator coordinator, FroniusSensorEntityDescription description, str solar_net_id)
Definition: sensor.py:796
None __init__(self, FroniusOhmpilotUpdateCoordinator coordinator, FroniusSensorEntityDescription description, str solar_net_id)
Definition: sensor.py:826
None __init__(self, FroniusPowerFlowUpdateCoordinator coordinator, FroniusSensorEntityDescription description, str solar_net_id)
Definition: sensor.py:850
None __init__(self, FroniusStorageUpdateCoordinator coordinator, FroniusSensorEntityDescription description, str solar_net_id)
Definition: sensor.py:868
None __init__(self, FroniusCoordinatorBase coordinator, FroniusSensorEntityDescription description, str solar_net_id)
Definition: sensor.py:710
web.Response get(self, web.Request request, str config_key)
Definition: view.py:88
None async_setup_entry(HomeAssistant hass, FroniusConfigEntry config_entry, AddEntitiesCallback async_add_entities)
Definition: sensor.py:64
None async_add_new_entities(Router router, AddEntitiesCallback async_add_entities, set[str] tracked)
Callable[[], None] async_dispatcher_connect(HomeAssistant hass, str signal, Callable[..., Any] target)
Definition: dispatcher.py:103