Skip to content

Commit 14efe6d

Browse files
committed
feat: add UI debug mode and diagnostics export
1 parent ffccfc4 commit 14efe6d

9 files changed

Lines changed: 150 additions & 9 deletions

File tree

README.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,22 @@ Die kWh-Sensoren sind direkt einsatzbereit. Navigiere zu *Einstellungen → Dash
189189

190190
### Debug-Logging aktivieren
191191

192+
**Einfach über die UI (empfohlen):**
193+
194+
1. *Einstellungen → Geräte & Dienste → EcoFlow PowerOcean → Konfigurieren*
195+
2. Option **„Debug-Modus aktivieren“** einschalten
196+
3. Speichern (Integration wird neu geladen)
197+
198+
**Diagnose-Datei für Support/Issues exportieren:**
199+
200+
1. *Einstellungen → Geräte & Dienste → EcoFlow PowerOcean*
201+
2. Menü (⋮) → **„Diagnose herunterladen“**
202+
3. Die heruntergeladene Datei im GitHub-Issue anhängen
203+
204+
Die Diagnose redigiert sensible Daten (z. B. Passwort/Token/Seriennummer) automatisch.
205+
206+
**Alternativ per YAML:**
207+
192208
```yaml
193209
# configuration.yaml
194210
logger:

custom_components/ecoflow_powerocean/__init__.py

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,25 @@
2929
from homeassistant.core import HomeAssistant
3030
from homeassistant.exceptions import ConfigEntryNotReady
3131

32-
from .const import DOMAIN, PLATFORMS
32+
from .const import CONF_DEBUG_MODE, DEFAULT_DEBUG_MODE, DOMAIN, PLATFORMS
3333
from .coordinator import EcoFlowCoordinator
3434

3535
_LOGGER = logging.getLogger(__name__)
3636

3737

38+
def _apply_debug_logging(entry: ConfigEntry) -> None:
39+
"""
40+
Aktiviert/deaktiviert Debug-Logging für diese Integration.
41+
42+
Hinweis:
43+
Der Schalter wirkt auf den Integrations-Logger-Namespace
44+
`custom_components.ecoflow_powerocean`.
45+
"""
46+
debug_mode = bool(entry.options.get(CONF_DEBUG_MODE, DEFAULT_DEBUG_MODE))
47+
integration_logger = logging.getLogger("custom_components.ecoflow_powerocean")
48+
integration_logger.setLevel(logging.DEBUG if debug_mode else logging.NOTSET)
49+
50+
3851
async def _async_update_listener(hass: HomeAssistant, entry: ConfigEntry) -> None:
3952
"""Lädt die Integration neu wenn Options geändert wurden."""
4053
await hass.config_entries.async_reload(entry.entry_id)
@@ -59,6 +72,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
5972
ConfigEntryNotReady: Wenn die Verbindung nicht hergestellt werden kann.
6073
"""
6174
hass.data.setdefault(DOMAIN, {})
75+
_apply_debug_logging(entry)
6276

6377
coordinator = EcoFlowCoordinator(hass, entry)
6478

@@ -83,8 +97,9 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
8397
entry.async_on_unload(entry.add_update_listener(_async_update_listener))
8498

8599
_LOGGER.info(
86-
"EcoFlow PowerOcean Plus Integration gestartet (SN: %s)",
100+
"EcoFlow PowerOcean Plus Integration gestartet (SN: %s, debug_mode=%s)",
87101
coordinator.serial_number,
102+
bool(entry.options.get(CONF_DEBUG_MODE, DEFAULT_DEBUG_MODE)),
88103
)
89104
return True
90105

custom_components/ecoflow_powerocean/config_flow.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@
3030
from homeassistant.const import CONF_EMAIL, CONF_PASSWORD
3131
from homeassistant.core import callback
3232
from homeassistant.helpers.selector import (
33+
BooleanSelector,
34+
BooleanSelectorConfig,
3335
NumberSelector,
3436
NumberSelectorConfig,
3537
NumberSelectorMode,
@@ -41,8 +43,10 @@
4143
from .const import (
4244
API_LOGIN_URL,
4345
API_TIMEOUT,
46+
CONF_DEBUG_MODE,
4447
CONF_NUM_BATTERY_PACKS,
4548
CONF_SERIAL_NUMBER,
49+
DEFAULT_DEBUG_MODE,
4650
DEFAULT_NUM_BATTERY_PACKS,
4751
DOMAIN,
4852
MANUFACTURER,
@@ -143,6 +147,9 @@ async def async_step_init(
143147
self.config_entry.data.get(CONF_NUM_BATTERY_PACKS, DEFAULT_NUM_BATTERY_PACKS),
144148
)
145149
)
150+
current_debug_mode = bool(
151+
self.config_entry.options.get(CONF_DEBUG_MODE, DEFAULT_DEBUG_MODE)
152+
)
146153
return self.async_show_form(
147154
step_id="init",
148155
data_schema=vol.Schema({
@@ -154,6 +161,9 @@ async def async_step_init(
154161
mode=NumberSelectorMode.BOX,
155162
)
156163
),
164+
vol.Required(CONF_DEBUG_MODE, default=current_debug_mode): BooleanSelector(
165+
BooleanSelectorConfig()
166+
),
157167
}),
158168
)
159169

custom_components/ecoflow_powerocean/const.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,16 @@
2626
Sensor-Gruppen in Home Assistant angelegt werden. Muss der tatsächlichen
2727
Anzahl der physisch installierten EcoFlow Batterie-Packs entsprechen."""
2828

29+
CONF_DEBUG_MODE = "debug_mode"
30+
"""Aktiviert ausführliches Debug-Logging für diese Integration."""
31+
2932
DEFAULT_NUM_BATTERY_PACKS = 2
3033
"""Standard-Anzahl Batterie-Packs — passend für eine typische 10-kWh-Installation
3134
mit zwei 5-kWh EcoFlow Packs."""
3235

36+
DEFAULT_DEBUG_MODE = False
37+
"""Debug-Logging standardmäßig deaktiviert."""
38+
3339
# Hinweis: CONF_EMAIL und CONF_PASSWORD kommen aus homeassistant.const
3440

3541
# ── EcoFlow Cloud API ─────────────────────────────────────────────────────────
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
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)

custom_components/ecoflow_powerocean/manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"domain": "ecoflow_powerocean",
33
"name": "EcoFlow PowerOcean",
4-
"version": "0.3.3",
4+
"version": "0.3.4",
55
"codeowners": [],
66
"config_flow": true,
77
"documentation": "https://github.com/Feberdin/ecoflow-powerocean-ha",

custom_components/ecoflow_powerocean/strings.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,12 @@
3434
"init": {
3535
"title": "EcoFlow PowerOcean Plus — Optionen",
3636
"data": {
37-
"num_battery_packs": "Anzahl Batterie-Packs"
37+
"num_battery_packs": "Anzahl Batterie-Packs",
38+
"debug_mode": "Debug-Modus aktivieren"
3839
},
3940
"data_description": {
40-
"num_battery_packs": "Anzahl der physisch installierten Batterie-Packs (1–9). Nach dem Speichern wird die Integration automatisch neu geladen."
41+
"num_battery_packs": "Anzahl der physisch installierten Batterie-Packs (1–9). Nach dem Speichern wird die Integration automatisch neu geladen.",
42+
"debug_mode": "Aktiviert ausführliche Logs für diese Integration. Danach Integration neu laden und bei Bedarf Diagnose herunterladen."
4143
}
4244
}
4345
}

custom_components/ecoflow_powerocean/translations/de.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,12 @@
3434
"init": {
3535
"title": "EcoFlow PowerOcean Plus — Optionen",
3636
"data": {
37-
"num_battery_packs": "Anzahl Batterie-Packs"
37+
"num_battery_packs": "Anzahl Batterie-Packs",
38+
"debug_mode": "Debug-Modus aktivieren"
3839
},
3940
"data_description": {
40-
"num_battery_packs": "Anzahl der physisch installierten Batterie-Packs (1–9). Nach dem Speichern wird die Integration automatisch neu geladen."
41+
"num_battery_packs": "Anzahl der physisch installierten Batterie-Packs (1–9). Nach dem Speichern wird die Integration automatisch neu geladen.",
42+
"debug_mode": "Aktiviert ausführliche Logs für diese Integration. Danach Integration neu laden und bei Bedarf Diagnose herunterladen."
4143
}
4244
}
4345
}

custom_components/ecoflow_powerocean/translations/en.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,12 @@
3434
"init": {
3535
"title": "EcoFlow PowerOcean Plus — Options",
3636
"data": {
37-
"num_battery_packs": "Number of Battery Packs"
37+
"num_battery_packs": "Number of Battery Packs",
38+
"debug_mode": "Enable Debug Mode"
3839
},
3940
"data_description": {
40-
"num_battery_packs": "Number of physically installed battery packs (1–9). The integration will reload automatically after saving."
41+
"num_battery_packs": "Number of physically installed battery packs (1–9). The integration will reload automatically after saving.",
42+
"debug_mode": "Enables verbose logs for this integration. Reload the integration afterwards and download diagnostics if needed."
4143
}
4244
}
4345
}

0 commit comments

Comments
 (0)