Design¶
Ziel¶
Eine Integration verbindet PV-Wechselrichter, Batterien und Wärmepumpen verschiedener Hersteller mit Home Assistant, ohne Cloud-Abhängigkeit. Herstellerunterschiede liegen in JSON-Profilen; der Kern kennt nur Modbus, Dekodierung, Entities, Lizenzierung, Support und Diagnose.
Komponenten¶
ConfigEntry
├─ Profil (JSON)
├─ Transport ── AsyncModbusTcpClient ── TCP :502
│ └─ DemoTransport (simuliert)
├─ Coordinator (Poll-Intervall, UpdateFailed)
├─ LicenseManager (instanzweit)
├─ SupportAccessController (pro Eintrag)
└─ Entities
├─ RegisterSensor pro sichtbarem Register
├─ LicenseStatusSensor
├─ SupportRemainingSensor
├─ ConnectionBinarySensor
└─ SupportAccessSwitch
Hardware Abstraction Layer¶
profiles.py parst und prüft Profile, gruppiert Register zu zusammenhängenden
Leseblöcken und dekodiert jeden Wert mit modbus_decode.py.
modbus_client.py ist eine kleine asyncio-Implementierung von Modbus TCP:
- Function 3 (Holding lesen), 4 (Input lesen), 6 (einzeln schreiben), 16 (mehrere schreiben),
- ein Lock pro Client, weil Gateways meist nur einen Socket zulassen,
- Prüfung von Transaction-ID, Protocol-ID und Unit-ID,
- Timeout schließt den Socket und löst einen Reconnect aus,
- Zähler für Requests, Fehler, Exceptions und Latenz.
scale ist ein Divisor, passend zum technischen Design-Dokument
("scale": 10 mit Rohwert 5000 ergibt 500.0).
Profile sind Daten¶
Eingebaute Profile liegen in custom_components/sg_energy_hub/profiles/.
Betreiber können Dateien in <HA-Konfiguration>/sg_energy_hub/profiles/
ablegen. Doppelte IDs und überlappende Registerbereiche werden abgelehnt. Ein
neuer Hersteller braucht normalerweise keine Python-Änderung.
Profile tragen ihren Prüfstatus. Das Deye-Beispiel aus dem Design-Dokument wird
mit "verified": false ausgeliefert; Herstellerprofile werden erst nach einem
Hardware-Test als verifiziert markiert.
Lizenzierung¶
license.py prüft Ed25519-Signaturen über ein kanonisches JSON-Payload. Der
Public Key steht in const.py; der private Schlüssel bleibt beim Hersteller.
Bindung: Das Payload enthält die Home-Assistant-Instanz-UUID
(homeassistant.helpers.instance_id). Ein kopiertes Konfigurationsverzeichnis
verschiebt die Lizenz daher nicht.
Zustände:
keine Lizenz, Trial < 30 Tage -> trial, Basis-Features
signierte Lizenz, nicht abgelaufen -> active, Pro-Features
abgelaufen < 14 Tage -> grace, Pro-Features
abgelaufen >= 14 Tage -> expired, Basis-Features
keine Lizenz, Trial vorbei -> free, Basis-Features
gating.py filtert Register (basic versus Pro) und schützt den
Schreibzugriff. Pro-Entities erscheinen nach dem Neuladen des Eintrags bei der
Lizenzaktivierung.
Support-Zugriff¶
Der Controller besitzt die Session-Lebensdauer und den Timeout. Ein Provider
besitzt den Tunnel. Version 0.1.0 liefert einen manual-Provider, der keine
Netzwerkverbindung öffnet; Schalter und Dienste sind trotzdem vollständig
testbar. Tokens werden nur bei konfigurierter URL vom Lizenzserver angefordert,
an den Provider übergeben und nie geloggt oder gespeichert.
Diagnose¶
diagnostics.py baut ein JSON-Payload mit:
- Integrations-, Home-Assistant-, Python- und Plattformversion,
- Modus, Profilmetadaten, Poll-Intervall, letzter Exception und Modbus-Statistik,
- Lizenzstatus, Instanz-UUID und letzter Prüfung,
- aktiver Support-Session,
- Register-Dump mit Adressen, Typen, Einheiten, Skalierungen und letzten Werten,
- den letzten 200 Log-Zeilen mit
sg_energy_hub.
Schlüssel mit password, token, secret, api_key oder private werden
redigiert. Upload und AES-GCM-Verpackung sind nicht Teil von 0.1.0.
Fehlermodell¶
- Ein fehlender Wert ist
None→unknown; die Integration erfindet nie0. - Ein fehlgeschlagener Poll wirft
UpdateFailed→ alle Entitiesunavailable; keine veralteten Daten. - Ein kaputtes Profil wirft
ConfigEntryError; ein nicht erreichbares GerätConfigEntryNotReady, damit Home Assistant erneut versucht. - Wire-Fehler sind
ModbusConnectionError/ModbusTimeoutError; Gerätefehler sindModbusExceptionErrormit Exception-Code.
Bewusste Grenzen¶
| Bereich | 0.1.0 |
|---|---|
| mDNS/Zeroconf-Discovery | nicht implementiert |
| Register-Probing | nicht implementiert |
| Profil-Sync vom Lizenzserver | nicht implementiert, last_check wird gespeichert |
| Verschlüsselter Diagnose-Upload | nicht implementiert |
| WireGuard/Tailscale | nur Schnittstelle |
| Herstellerprofile | Demo und ein unverifiziertes Deye-Beispiel |
Diese Punkte sind Schnittstellen, keine versteckten Features. Die nächsten Schritte lassen sich ohne Änderung am Config Entry oder Profilformat ergänzen.