|
| 1 | +""" |
| 2 | +Diagnose-Export für die EcoFlow PowerOcean Plus Integration. |
| 3 | +
|
| 4 | +Zweck: |
| 5 | + Ermöglicht Nutzerinnen und Nutzern, über Home Assistant eine redigierte |
| 6 | + Diagnosedatei herunterzuladen und mit Maintainers zu teilen. |
| 7 | +
|
| 8 | +Input: |
| 9 | + - Home Assistant Instanz |
| 10 | + - Config Entry dieser Integration |
| 11 | +
|
| 12 | +Output: |
| 13 | + - JSON-kompatibles Dict mit redigierten Config-Daten und aktuellem |
| 14 | + Integrationsstatus (Coordinator-Daten, Verbindungszustand) |
| 15 | +
|
| 16 | +Wichtige Invarianten: |
| 17 | + - Keine sensiblen Daten im Klartext (Passwort, Token, User-ID, Seriennummer) |
| 18 | + - Ausgabe muss JSON-serialisierbar sein |
| 19 | +
|
| 20 | +Debug-Hinweis: |
| 21 | + - In HA: Geräte & Dienste -> EcoFlow PowerOcean -> Drei Punkte -> |
| 22 | + "Diagnose herunterladen" |
| 23 | +""" |
| 24 | + |
| 25 | +from __future__ import annotations |
| 26 | + |
| 27 | +from dataclasses import asdict, is_dataclass |
| 28 | +from typing import Any |
| 29 | + |
| 30 | +from homeassistant.components.diagnostics import async_redact_data |
| 31 | +from homeassistant.config_entries import ConfigEntry |
| 32 | +from homeassistant.const import CONF_EMAIL, CONF_PASSWORD |
| 33 | +from homeassistant.core import HomeAssistant |
| 34 | + |
| 35 | +from .const import CONF_SERIAL_NUMBER, DOMAIN |
| 36 | +from .coordinator import EcoFlowCoordinator |
| 37 | + |
| 38 | +TO_REDACT = { |
| 39 | + CONF_EMAIL, |
| 40 | + CONF_PASSWORD, |
| 41 | + CONF_SERIAL_NUMBER, |
| 42 | + "token", |
| 43 | + "_token", |
| 44 | + "userId", |
| 45 | + "_user_id", |
| 46 | + "certificateAccount", |
| 47 | + "_mqtt_user", |
| 48 | + "certificatePassword", |
| 49 | + "_mqtt_password", |
| 50 | + "serial_number", |
| 51 | +} |
| 52 | + |
| 53 | + |
| 54 | +def _to_jsonable(value: Any) -> Any: |
| 55 | + """Konvertiert beliebige Integrationsdaten in JSON-kompatible Strukturen.""" |
| 56 | + if is_dataclass(value): |
| 57 | + return _to_jsonable(asdict(value)) |
| 58 | + if isinstance(value, dict): |
| 59 | + return {str(k): _to_jsonable(v) for k, v in value.items()} |
| 60 | + if isinstance(value, (list, tuple, set)): |
| 61 | + return [_to_jsonable(v) for v in value] |
| 62 | + if isinstance(value, (str, int, float, bool)) or value is None: |
| 63 | + return value |
| 64 | + return str(value) |
| 65 | + |
| 66 | + |
| 67 | +async def async_get_config_entry_diagnostics( |
| 68 | + hass: HomeAssistant, entry: ConfigEntry |
| 69 | +) -> dict[str, Any]: |
| 70 | + """Liefert redigierte Diagnosedaten für einen Config Entry.""" |
| 71 | + coordinator: EcoFlowCoordinator | None = hass.data.get(DOMAIN, {}).get(entry.entry_id) |
| 72 | + |
| 73 | + coordinator_snapshot: dict[str, Any] = { |
| 74 | + "mqtt_connected": getattr(coordinator, "_mqtt_connected", None), |
| 75 | + "has_token": bool(getattr(coordinator, "_token", None)), |
| 76 | + "has_mqtt_credentials": bool( |
| 77 | + getattr(coordinator, "_mqtt_user", None) |
| 78 | + and getattr(coordinator, "_mqtt_password", None) |
| 79 | + ), |
| 80 | + "data": _to_jsonable(getattr(coordinator, "data", None)), |
| 81 | + } |
| 82 | + |
| 83 | + diagnostics = { |
| 84 | + "entry": entry.as_dict(), |
| 85 | + "coordinator": coordinator_snapshot, |
| 86 | + } |
| 87 | + |
| 88 | + return async_redact_data(diagnostics, TO_REDACT) |
0 commit comments