fix(v1.8.27): Fahrzeugerkennung + Wizard überschreibt Inverterliste

Bug 1 (inverters.py): Kathrein-Register 0x0061-0x0064 existieren nicht —
(0x0060, 10) schlug daher immer mit IllegalAddress fehl, charging_state
wurde nie gelesen → EMS meldete dauerhaft "kein Fahrzeug". Fix: aufgeteilt
in (0x0060, 1) + (0x0065, 6), sodass die Lücke übersprungen wird.

Bug 2 (index.html): wizardStep2Next() postete [neues_gerät] statt
[...invertersList, neues_gerät] → überschrieb die gesamte Inverterliste.
Wenn der Wizard bei einem bestehenden Setup erschien, flogen alle anderen
Geräte raus. Fix: bestehende Geräte werden beibehalten.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
retr0
2026-05-08 10:58:44 +02:00
parent 5564a50c3c
commit c4047fc804
4 changed files with 9 additions and 6 deletions
+1 -1
View File
@@ -1,5 +1,5 @@
name: ShineBridge name: ShineBridge
version: "1.8.26" version: "1.8.27"
slug: shinebridge slug: shinebridge
description: Growatt Wechselrichter lokal in Home Assistant — Modbus TCP via ShineLAN-X, MQTT Discovery, Web UI description: Growatt Wechselrichter lokal in Home Assistant — Modbus TCP via ShineLAN-X, MQTT Discovery, Web UI
url: https://gitea.bitfire.work/retr0/shinebridge url: https://gitea.bitfire.work/retr0/shinebridge
+3 -2
View File
@@ -247,8 +247,9 @@ INVERTERS = {
name="Kathrein Wallbox", name="Kathrein Wallbox",
manufacturer="Kathrein", manufacturer="Kathrein",
sensors=_kathrein_sensors(), sensors=_kathrein_sensors(),
# Meter-Block + EVSE-Status + EMS-Setpoint # Meter-Block 0x0030-0x005F + charging_state 0x0060 (solo, 0x0061-0x0064 existieren nicht)
read_ranges=[(0x0030, 48), (0x0060, 10), (0x00A2, 1)], # + EVSE-Status 0x0065-0x006A + EMS-Setpoint 0x00A2
read_ranges=[(0x0030, 48), (0x0060, 1), (0x0065, 6), (0x00A2, 1)],
protocol="kathrein", protocol="kathrein",
goodwe_family="", goodwe_family="",
), ),
+1 -1
View File
@@ -345,7 +345,7 @@ def _poll_loop(inv_cfg: Dict[str, Any], stop: threading.Event):
# EMS: PV-Überschuss aus anderen Geräten holen und Ladestrom regeln # EMS: PV-Überschuss aus anderen Geräten holen und Ladestrom regeln
if ems is not None and values is not None and inv_cfg.get("ems_enabled", True): if ems is not None and values is not None and inv_cfg.get("ems_enabled", True):
pv_surplus = _get_pv_surplus() pv_surplus = _get_pv_surplus()
# 0x0060 gibt IllegalAddress zurück wenn kein Auto angesteckt → State 0 (Idle) # charging_state aus 0x0060 (solo-Read); fehlt bei kein Fahrzeug → 0 (Idle)
charging_state = int(values.get("charging_state", 0)) charging_state = int(values.get("charging_state", 0))
wallbox_power = values.get("total_power", 0.0) wallbox_power = values.get("total_power", 0.0)
ems_status = ems.update(reader, pv_surplus, charging_state, wallbox_power) ems_status = ems.update(reader, pv_surplus, charging_state, wallbox_power)
+4 -2
View File
@@ -1693,7 +1693,7 @@ async function wizardStep2Next() {
if (!name || !ip) { showToast("Name und IP sind Pflichtfelder", "err"); return; } if (!name || !ip) { showToast("Name und IP sind Pflichtfelder", "err"); return; }
const model = document.getElementById("wz-inv-model").value; const model = document.getElementById("wz-inv-model").value;
const id = Math.random().toString(36).slice(2, 10); const id = Math.random().toString(36).slice(2, 10);
const body = [{ const newInv = {
id, id,
name, name,
inverter_model: model, inverter_model: model,
@@ -1702,7 +1702,9 @@ async function wizardStep2Next() {
modbus_address: parseInt(document.getElementById("wz-inv-addr").value) || 1, modbus_address: parseInt(document.getElementById("wz-inv-addr").value) || 1,
mqtt_topic_prefix: `growatt/${name.toLowerCase().replace(/\s+/g, "_")}`, mqtt_topic_prefix: `growatt/${name.toLowerCase().replace(/\s+/g, "_")}`,
update_interval: 30, update_interval: 30,
}]; };
// Bestehende Geräte behalten — Wizard darf nicht die komplette Liste überschreiben
const body = [...invertersList, newInv];
try { try {
await fetchJSON(api("api/inverters-config"), { await fetchJSON(api("api/inverters-config"), {
method: "POST", headers: {"Content-Type": "application/json"}, method: "POST", headers: {"Content-Type": "application/json"},