1 """DataUpdateCoordinators for the Fronius integration."""
3 from __future__
import annotations
5 from abc
import ABC, abstractmethod
6 from datetime
import timedelta
7 from typing
import TYPE_CHECKING, Any
9 from pyfronius
import BadStatusError, FroniusError
16 SOLAR_NET_ID_POWER_FLOW,
22 INVERTER_ENTITY_DESCRIPTIONS,
23 LOGGER_ENTITY_DESCRIPTIONS,
24 METER_ENTITY_DESCRIPTIONS,
25 OHMPILOT_ENTITY_DESCRIPTIONS,
26 POWER_FLOW_ENTITY_DESCRIPTIONS,
27 STORAGE_ENTITY_DESCRIPTIONS,
28 FroniusSensorEntityDescription,
32 from .
import FroniusSolarNet
33 from .sensor
import _FroniusSensorEntity
37 ABC, DataUpdateCoordinator[dict[SolarNetId, dict[str, Any]]]
39 """Query Fronius endpoint and keep track of seen conditions."""
41 default_interval: timedelta
42 error_interval: timedelta
43 valid_descriptions: list[FroniusSensorEntityDescription]
45 MAX_FAILED_UPDATES = 3
47 def __init__(self, *args: Any, solar_net: FroniusSolarNet, **kwargs: Any) ->
None:
48 """Set up the FroniusCoordinatorBase class."""
52 self.unregistered_descriptors: dict[
53 SolarNetId, list[FroniusSensorEntityDescription]
55 super().
__init__(*args, update_interval=self.default_interval, **kwargs)
59 """Return data per solar net id from pyfronius."""
62 """Fetch the latest data from the source."""
63 async
with self.solar_net.coordinator_lock:
65 data = await self._update_method()
66 except FroniusError
as err:
67 self._failed_update_count += 1
68 if self._failed_update_count == self.MAX_FAILED_UPDATES:
76 for solar_net_id
in data:
77 if solar_net_id
not in self.unregistered_descriptors:
79 self.unregistered_descriptors[solar_net_id] = (
80 self.valid_descriptions.copy()
85 def add_entities_for_seen_keys[_FroniusEntityT: _FroniusSensorEntity](
87 async_add_entities: AddEntitiesCallback,
88 entity_constructor: type[_FroniusEntityT],
90 """Add entities for received keys and registers listener for future seen keys.
92 Called from a platforms `async_setup_entry`.
97 """Add entities for keys seen for the first time."""
98 new_entities: list[_FroniusEntityT] = []
99 for solar_net_id, device_data
in self.
datadata.items():
100 remaining_unregistered_descriptors = []
101 for description
in self.unregistered_descriptors[solar_net_id]:
102 key = description.response_key
or description.key
103 if key
not in device_data:
104 remaining_unregistered_descriptors.append(description)
106 if device_data[key][
"value"]
is None:
107 remaining_unregistered_descriptors.append(description)
112 description=description,
113 solar_net_id=solar_net_id,
116 self.unregistered_descriptors[solar_net_id] = (
117 remaining_unregistered_descriptors
122 self.
solar_netsolar_net.config_entry.async_on_unload(
128 """Query Fronius device inverter endpoint and keep track of seen conditions."""
132 valid_descriptions = INVERTER_ENTITY_DESCRIPTIONS
137 self, *args: Any, inverter_info: FroniusDeviceInfo, **kwargs: Any
139 """Set up a Fronius inverter device scope coordinator."""
144 """Return data per solar net id from pyfronius."""
150 data = await self.
solar_netsolar_net.fronius.current_inverter_data(
153 except BadStatusError:
164 """Query Fronius logger info endpoint and keep track of seen conditions."""
168 valid_descriptions = LOGGER_ENTITY_DESCRIPTIONS
171 """Return data per solar net id from pyfronius."""
172 data = await self.
solar_netsolar_net.fronius.current_logger_info()
173 return {SOLAR_NET_ID_SYSTEM: data}
177 """Query Fronius system meter endpoint and keep track of seen conditions."""
181 valid_descriptions = METER_ENTITY_DESCRIPTIONS
184 """Return data per solar net id from pyfronius."""
185 data = await self.
solar_netsolar_net.fronius.current_system_meter_data()
186 return data[
"meters"]
190 """Query Fronius Ohmpilots and keep track of seen conditions."""
194 valid_descriptions = OHMPILOT_ENTITY_DESCRIPTIONS
197 """Return data per solar net id from pyfronius."""
198 data = await self.
solar_netsolar_net.fronius.current_system_ohmpilot_data()
199 return data[
"ohmpilots"]
203 """Query Fronius power flow endpoint and keep track of seen conditions."""
207 valid_descriptions = POWER_FLOW_ENTITY_DESCRIPTIONS
210 """Return data per solar net id from pyfronius."""
211 data = await self.
solar_netsolar_net.fronius.current_power_flow()
212 return {SOLAR_NET_ID_POWER_FLOW: data}
216 """Query Fronius system storage endpoint and keep track of seen conditions."""
220 valid_descriptions = STORAGE_ENTITY_DESCRIPTIONS
223 """Return data per solar net id from pyfronius."""
224 data = await self.
solar_netsolar_net.fronius.current_system_storage_data()
225 return data[
"storages"]
None __init__(self, *Any args, FroniusSolarNet solar_net, **Any kwargs)
None _add_entities_for_unregistered_descriptors()
dict[SolarNetId, Any] _async_update_data(self)
dict[SolarNetId, Any] _update_method(self)
None __init__(self, *Any args, FroniusDeviceInfo inverter_info, **Any kwargs)
dict[SolarNetId, Any] _update_method(self)
dict[SolarNetId, Any] _update_method(self)
dict[SolarNetId, Any] _update_method(self)
dict[SolarNetId, Any] _update_method(self)
dict[SolarNetId, Any] _update_method(self)
dict[SolarNetId, Any] _update_method(self)
Callable[[], None] async_add_listener(self, CALLBACK_TYPE update_callback, Any context=None)
None update_interval(self, timedelta|None value)
timedelta|None update_interval(self)
Callable[[], None] async_add_listener(self, CALLBACK_TYPE update_callback, Any context=None)