ShineBridge v1.10.0 — Neuer Geräte-Typ: Growatt ShineWifi-X über bestehende HA-Entity (ESPHome)

Statt selbst per Modbus/UDP zu pollen, kann ShineBridge jetzt einen Wechselrichter
einbinden, der bereits per ESPHome nativ in Home Assistant läuft — nützlich für
die ShineWifi-X-Variante, die keine eigene Modbus-TCP-Schnittstelle hat.

- Neuer ha_entity_client.py: liest Sensor-Werte über die interne Supervisor-API
  (http://supervisor/core/api), braucht dafür 'homeassistant_api: true' in
  config.yaml (neu gesetzt — Add-on muss dafür einmal neu installiert werden)
- Neuer Geräte-Typ 'GROWATT_WIFI_X' in inverters.py, protocol='ha_entity'
- Feste Suffix-Zuordnung (dcpower→pv_power, acpower→ac_power, energytoday→
  energy_today, ...) passend zur esphome-growatt-Komponente aus
  growatt-diagnose-tool/ShineWifi-X — Entity-Id ergibt sich als
  sensor.<prefix>_<suffix>
- Neues Feld 'HA Entity-Prefix' im Geräte-Dialog statt Modbus-IP/Port/Adresse,
  blendet sich abhängig vom gewählten Gerätetyp ein/aus
- Läuft danach durch dieselbe Aggregations-/Dashboard-Logik wie jedes andere
  Gerät (kein Sonderfall in EMS/Finanzen nötig, da Netzbezug bereits über den
  bestehenden Zähler erfasst wird — dieser Wechselrichter liefert nur PV-Werte)

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
retr0
2026-08-25 14:28:45 +02:00
co-authored by Claude Sonnet 5
parent 9d954d6bd6
commit 6f30fe6b1c
5 changed files with 134 additions and 12 deletions
+27 -10
View File
@@ -335,12 +335,19 @@
<input type="text" id="modal-name" placeholder="z.B. Dach Süd"></div>
<div class="field"><label>Gerätetyp</label>
<select id="modal-model"></select></div>
<div class="field"><label>IP-Adresse</label>
<input type="text" id="modal-ip" placeholder="10.10.20.190"></div>
<div class="field"><label>Modbus Port</label>
<input type="number" id="modal-port" value="502"></div>
<div class="field"><label>Modbus Slave-Adresse</label>
<input type="number" id="modal-addr" value="1" min="1" max="247"></div>
<div id="modbus-fields">
<div class="field"><label>IP-Adresse</label>
<input type="text" id="modal-ip" placeholder="10.10.20.190"></div>
<div class="field"><label>Modbus Port</label>
<input type="number" id="modal-port" value="502"></div>
<div class="field"><label>Modbus Slave-Adresse</label>
<input type="number" id="modal-addr" value="1" min="1" max="247"></div>
</div>
<div id="ha-entity-fields" style="display:none">
<div class="field"><label>HA Entity-Prefix</label>
<input type="text" id="modal-ha-prefix" placeholder="growatt_wifi_x_1">
<div style="font-size:11px;color:var(--muted);margin-top:3px">Ohne "sensor."-Präfix — z.B. bei <code>sensor.growatt_wifi_x_1_dcpower</code> ist der Wert <code>growatt_wifi_x_1</code>. Braucht ein bereits per ESPHome in HA eingebundenes Gerät, keinen direkten Netzwerkzugriff.</div></div>
</div>
<div class="field"><label>MQTT Topic-Präfix</label>
<input type="text" id="modal-prefix" placeholder="growatt/wechselrichter1"></div>
<div class="field"><label>Abfrageintervall (Sekunden)</label>
@@ -1036,7 +1043,9 @@ function renderInverterList() {
</div>
</div>
<div class="inv-card-meta">
📡 ${esc(inv.modbus_ip)}:${inv.modbus_port || 502} · Slave ${inv.modbus_address || 1}<br>
${inv.inverter_model === "GROWATT_WIFI_X"
? `🏠 HA-Entity: ${esc(inv.ha_entity_prefix || "–")}`
: `📡 ${esc(inv.modbus_ip)}:${inv.modbus_port || 502} · Slave ${inv.modbus_address || 1}`}<br>
📨 ${esc(inv.mqtt_topic_prefix)}<br>
⏱ alle ${inv.update_interval || 30}s
</div>
@@ -1049,16 +1058,19 @@ function renderInverterList() {
el.innerHTML = cards + `<div class="add-btn" onclick="openModal()">+ Gerät hinzufügen</div>`;
}
function toggleEmsSection(model) {
function onModelChange(model) {
document.getElementById("ems-section").style.display =
model === "KATHREIN_WALLBOX" ? "" : "none";
const isHaEntity = model === "GROWATT_WIFI_X";
document.getElementById("modbus-fields").style.display = isHaEntity ? "none" : "";
document.getElementById("ha-entity-fields").style.display = isHaEntity ? "" : "none";
}
async function openModal(invId) {
await loadModels();
const modal = document.getElementById("modal-backdrop");
const modelSel = document.getElementById("modal-model");
modelSel.onchange = () => toggleEmsSection(modelSel.value);
modelSel.onchange = () => onModelChange(modelSel.value);
if (invId) {
const inv = invertersList.find(i => i.id === invId) || {};
document.getElementById("modal-title").textContent = "Gerät bearbeiten";
@@ -1068,6 +1080,7 @@ async function openModal(invId) {
document.getElementById("modal-ip").value = inv.modbus_ip || "";
document.getElementById("modal-port").value = inv.modbus_port || 502;
document.getElementById("modal-addr").value = inv.modbus_address || 1;
document.getElementById("modal-ha-prefix").value = inv.ha_entity_prefix || "";
document.getElementById("modal-prefix").value = inv.mqtt_topic_prefix || "";
document.getElementById("modal-interval").value = inv.update_interval || 30;
document.getElementById("ems-min-pv").value = inv.ems_min_pv ?? 1400;
@@ -1083,6 +1096,7 @@ async function openModal(invId) {
document.getElementById("modal-ip").value = "";
document.getElementById("modal-port").value = "502";
document.getElementById("modal-addr").value = "1";
document.getElementById("modal-ha-prefix").value = "";
document.getElementById("modal-prefix").value = "growatt/wechselrichter" + (invertersList.length + 1);
document.getElementById("modal-interval").value = "30";
document.getElementById("ems-min-pv").value = "1400";
@@ -1091,7 +1105,7 @@ async function openModal(invId) {
document.getElementById("ems-phases").value = "3";
document.getElementById("ems-max-current").value = "32";
}
toggleEmsSection(modelSel.value);
onModelChange(modelSel.value);
modal.classList.add("open");
}
@@ -1119,6 +1133,9 @@ async function saveInverter() {
mqtt_topic_prefix: document.getElementById("modal-prefix").value.trim(),
update_interval: parseInt(document.getElementById("modal-interval").value),
};
if (model === "GROWATT_WIFI_X") {
inv.ha_entity_prefix = document.getElementById("modal-ha-prefix").value.trim();
}
if (model === "KATHREIN_WALLBOX") {
inv.ems_min_pv = parseInt(document.getElementById("ems-min-pv").value);
inv.ems_timeout = parseFloat(document.getElementById("ems-timeout").value);