|
27 | 27 | ) |
28 | 28 | from ._base import SolarAcceleratorSensorBase |
29 | 29 |
|
| 30 | +# Pusta diagnostyka — gdy write_manager jeszcze nie miał żadnego batcha |
| 31 | +_EMPTY_WRITE_STATS: dict[str, Any] = { |
| 32 | + "entities": {}, |
| 33 | + "last_batch_at": None, |
| 34 | + "last_batch_size": 0, |
| 35 | + "last_batch_acked": 0, |
| 36 | + "last_batch_failed": 0, |
| 37 | + "last_batch_retried": 0, |
| 38 | +} |
| 39 | + |
30 | 40 |
|
31 | 41 | class SolarAcceleratorStatusSensor(SolarAcceleratorSensorBase): |
32 | 42 | """Status połączenia z backendem (``connected``/``auth_error``/``error``/``disconnected``).""" |
@@ -187,3 +197,59 @@ def extra_state_attributes(self) -> dict[str, Any]: |
187 | 197 | attrs["ev_enabled"] = False |
188 | 198 |
|
189 | 199 | return attrs |
| 200 | + |
| 201 | + |
| 202 | +class SolarAcceleratorWriteStatsSensor(SolarAcceleratorSensorBase): |
| 203 | + """Diagnostyka write_managera — retry i finalny status per sterowana encja. |
| 204 | +
|
| 205 | + Main state = liczba komend z ostatniego batcha które wymagały retry (0 = OK). |
| 206 | + Atrybuty zawierają meta ostatniego batcha + kumulatywne statystyki per entity_id |
| 207 | + od startu integracji: ile razy komenda dla danej encji się powiodła, ile razy |
| 208 | + musieliśmy retry'ować, jaka była ostatnia żądana wartość i finalny status. |
| 209 | +
|
| 210 | + Sensor odświeża się natychmiast po każdym batchu — WriteManager woła |
| 211 | + ``coordinator_data['write_stats_notify']`` zaraz po ACK'owaniu komend. |
| 212 | + """ |
| 213 | + |
| 214 | + _attr_icon = "mdi:reload-alert" |
| 215 | + _attr_state_class = SensorStateClass.MEASUREMENT |
| 216 | + _attr_translation_key = "write_stats" |
| 217 | + _attr_entity_category = EntityCategory.DIAGNOSTIC |
| 218 | + |
| 219 | + def __init__( |
| 220 | + self, hass: HomeAssistant, entry: ConfigEntry, coordinator_data: dict[str, Any] |
| 221 | + ) -> None: |
| 222 | + """Zainicjalizuj sensor diagnostyki write_managera.""" |
| 223 | + super().__init__(hass, entry, coordinator_data, "write_stats") |
| 224 | + self._attr_name = "Diagnostyka komend" |
| 225 | + |
| 226 | + async def async_added_to_hass(self) -> None: |
| 227 | + """Po dodaniu do HA zarejestruj notifier — write_manager woła go po każdym batchu.""" |
| 228 | + await super().async_added_to_hass() |
| 229 | + # Schedule_update_ha_state można wołać synchronicznie z dowolnego kontekstu |
| 230 | + self.coordinator_data["write_stats_notify"] = self.async_schedule_update_ha_state |
| 231 | + |
| 232 | + async def async_will_remove_from_hass(self) -> None: |
| 233 | + """Wyczyść notifier — uniknij wołania callbacka po unmount.""" |
| 234 | + if self.coordinator_data.get("write_stats_notify") == self.async_schedule_update_ha_state: |
| 235 | + self.coordinator_data.pop("write_stats_notify", None) |
| 236 | + await super().async_will_remove_from_hass() |
| 237 | + |
| 238 | + @property |
| 239 | + def native_value(self) -> int: |
| 240 | + """Liczba komend z ostatniego batcha które wymagały co najmniej 1 retry.""" |
| 241 | + stats = self.coordinator_data.get("write_stats") or _EMPTY_WRITE_STATS |
| 242 | + return int(stats.get("last_batch_retried", 0)) |
| 243 | + |
| 244 | + @property |
| 245 | + def extra_state_attributes(self) -> dict[str, Any]: |
| 246 | + """Pełna diagnostyka batcha + kumulatywne statystyki per entity.""" |
| 247 | + stats = self.coordinator_data.get("write_stats") or _EMPTY_WRITE_STATS |
| 248 | + return { |
| 249 | + "last_batch_at": stats.get("last_batch_at"), |
| 250 | + "last_batch_size": stats.get("last_batch_size", 0), |
| 251 | + "last_batch_acked": stats.get("last_batch_acked", 0), |
| 252 | + "last_batch_failed": stats.get("last_batch_failed", 0), |
| 253 | + "last_batch_retried": stats.get("last_batch_retried", 0), |
| 254 | + "entities": stats.get("entities", {}), |
| 255 | + } |
0 commit comments