Files
Shinebridge/haos-addon/src/inverters.py
T
retr0 20d935bd73 Feature: grid_power Sensor für intuitive Anzeige (positiv = Netzbezug)
goodwe_client: grid_power = -active_power für Visualisierung
inverters.py: grid_power Sensor ergänzt, active_power als "roh" markiert
EMS _get_pv_surplus() bleibt unverändert (nutzt active_power direkt)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-28 13:20:25 +02:00

256 lines
20 KiB
Python

from dataclasses import dataclass
from typing import List, Optional
@dataclass
class Sensor:
id: str
name: str
reg: int
count: int # number of 16-bit registers (1 or 2)
scale: float
unit: str
device_class: Optional[str]
state_class: str
icon: str
data_type: str = "uint16" # "uint16", "uint32", "float32"
@dataclass
class Inverter:
id: str
name: str
manufacturer: str
sensors: List[Sensor]
# Register ranges to batch-read as (start, length) tuples (FC04 input registers)
read_ranges: List[tuple]
protocol: str = "modbus" # "modbus" | "goodwe_udp"
goodwe_family: str = "" # ET / ES / DT — nur für goodwe_udp
def _mic_sensors() -> List[Sensor]:
return [
Sensor("pv_voltage", "PV Spannung", 3, 1, 0.1, "V", "voltage", "measurement", "mdi:solar-panel"),
Sensor("pv_current", "PV Strom", 4, 1, 0.1, "A", "current", "measurement", "mdi:solar-panel"),
Sensor("pv_power", "PV Leistung", 5, 2, 0.1, "W", "power", "measurement", "mdi:solar-panel"),
Sensor("grid_frequency", "Netz-Frequenz", 37, 1, 0.01, "Hz", "frequency", "measurement", "mdi:sine-wave"),
Sensor("grid_voltage", "Netz-Spannung", 38, 1, 0.1, "V", "voltage", "measurement", "mdi:flash"),
Sensor("grid_current", "Netz-Strom", 39, 1, 0.1, "A", "current", "measurement", "mdi:flash"),
Sensor("ac_power", "AC Ausgangsleistung", 40, 2, 0.1, "W", "power", "measurement", "mdi:flash"),
Sensor("energy_today", "Energie Heute", 53, 2, 0.1, "kWh", "energy", "total_increasing", "mdi:solar-power"),
Sensor("energy_total", "Energie Gesamt", 55, 2, 0.1, "kWh", "energy", "total_increasing", "mdi:solar-power"),
Sensor("inverter_temp", "Wechselrichter Temp.", 93, 1, 0.1, "°C", "temperature", "measurement", "mdi:thermometer"),
]
def _sph_sensors() -> List[Sensor]:
return [
Sensor("pv1_voltage", "PV1 Spannung", 3, 1, 0.1, "V", "voltage", "measurement", "mdi:solar-panel"),
Sensor("pv1_current", "PV1 Strom", 4, 1, 0.1, "A", "current", "measurement", "mdi:solar-panel"),
Sensor("pv1_power", "PV1 Leistung", 5, 2, 0.1, "W", "power", "measurement", "mdi:solar-panel"),
Sensor("pv2_voltage", "PV2 Spannung", 7, 1, 0.1, "V", "voltage", "measurement", "mdi:solar-panel"),
Sensor("pv2_current", "PV2 Strom", 8, 1, 0.1, "A", "current", "measurement", "mdi:solar-panel"),
Sensor("pv2_power", "PV2 Leistung", 9, 2, 0.1, "W", "power", "measurement", "mdi:solar-panel"),
Sensor("ac_power_total", "AC Gesamtleistung", 35, 2, 0.1, "W", "power", "measurement", "mdi:flash"),
Sensor("grid_frequency", "Netz-Frequenz", 37, 1, 0.01, "Hz", "frequency", "measurement", "mdi:sine-wave"),
Sensor("grid_voltage_l1", "Netz-Spannung L1", 38, 1, 0.1, "V", "voltage", "measurement", "mdi:flash"),
Sensor("grid_current_l1", "Netz-Strom L1", 39, 1, 0.1, "A", "current", "measurement", "mdi:flash"),
Sensor("grid_voltage_l2", "Netz-Spannung L2", 42, 1, 0.1, "V", "voltage", "measurement", "mdi:flash"),
Sensor("grid_current_l2", "Netz-Strom L2", 43, 1, 0.1, "A", "current", "measurement", "mdi:flash"),
Sensor("grid_voltage_l3", "Netz-Spannung L3", 46, 1, 0.1, "V", "voltage", "measurement", "mdi:flash"),
Sensor("grid_current_l3", "Netz-Strom L3", 47, 1, 0.1, "A", "current", "measurement", "mdi:flash"),
Sensor("energy_today", "Energie Heute", 53, 2, 0.1, "kWh", "energy", "total_increasing", "mdi:solar-power"),
Sensor("energy_total", "Energie Gesamt", 55, 2, 0.1, "kWh", "energy", "total_increasing", "mdi:solar-power"),
Sensor("inverter_temp", "Wechselrichter Temp.", 93, 1, 0.1, "°C", "temperature", "measurement", "mdi:thermometer"),
Sensor("bat_discharge_power", "Batterie Entladeleistung", 1009, 2, 0.1, "W", "power", "measurement", "mdi:battery-minus"),
Sensor("bat_charge_power", "Batterie Ladeleistung", 1011, 2, 0.1, "W", "power", "measurement", "mdi:battery-plus"),
Sensor("bat_voltage", "Batterie Spannung", 1013, 1, 0.1, "V", "voltage", "measurement", "mdi:battery"),
Sensor("bat_soc", "Batterie Ladezustand", 1014, 1, 1.0, "%", "battery", "measurement", "mdi:battery"),
Sensor("bat_temperature", "Batterie Temp.", 1040, 1, 0.1, "°C", "temperature", "measurement", "mdi:thermometer"),
Sensor("power_to_grid", "Einspeisung", 1021, 2, 0.1, "W", "power", "measurement", "mdi:transmission-tower-export"),
Sensor("power_to_user", "Netzbezug", 1029, 2, 0.1, "W", "power", "measurement", "mdi:transmission-tower-import"),
Sensor("energy_import_total", "Netzbezug Gesamt", 1046, 2, 0.1, "kWh", "energy", "total_increasing", "mdi:transmission-tower-import"),
Sensor("energy_export_total", "Einspeisung Gesamt", 1050, 2, 0.1, "kWh", "energy", "total_increasing", "mdi:transmission-tower-export"),
Sensor("bat_discharge_total", "Batterie Entladung Ges.",1054, 2, 0.1, "kWh", "energy", "total_increasing", "mdi:battery-minus"),
Sensor("bat_charge_total", "Batterie Ladung Ges.", 1058, 2, 0.1, "kWh", "energy", "total_increasing", "mdi:battery-plus"),
]
def _mod_sensors() -> List[Sensor]:
return [
Sensor("pv1_voltage", "PV1 Spannung", 3, 1, 0.1, "V", "voltage", "measurement", "mdi:solar-panel"),
Sensor("pv1_current", "PV1 Strom", 4, 1, 0.1, "A", "current", "measurement", "mdi:solar-panel"),
Sensor("pv1_power", "PV1 Leistung", 5, 2, 0.1, "W", "power", "measurement", "mdi:solar-panel"),
Sensor("pv2_voltage", "PV2 Spannung", 7, 1, 0.1, "V", "voltage", "measurement", "mdi:solar-panel"),
Sensor("pv2_current", "PV2 Strom", 8, 1, 0.1, "A", "current", "measurement", "mdi:solar-panel"),
Sensor("pv2_power", "PV2 Leistung", 9, 2, 0.1, "W", "power", "measurement", "mdi:solar-panel"),
Sensor("ac_power_total", "AC Gesamtleistung", 35, 2, 0.1, "W", "power", "measurement", "mdi:flash"),
Sensor("grid_frequency", "Netz-Frequenz", 37, 1, 0.01, "Hz", "frequency", "measurement", "mdi:sine-wave"),
Sensor("grid_voltage_l1","Netz-Spannung L1", 38, 1, 0.1, "V", "voltage", "measurement", "mdi:flash"),
Sensor("grid_current_l1","Netz-Strom L1", 39, 1, 0.1, "A", "current", "measurement", "mdi:flash"),
Sensor("grid_voltage_l2","Netz-Spannung L2", 42, 1, 0.1, "V", "voltage", "measurement", "mdi:flash"),
Sensor("grid_current_l2","Netz-Strom L2", 43, 1, 0.1, "A", "current", "measurement", "mdi:flash"),
Sensor("grid_voltage_l3","Netz-Spannung L3", 46, 1, 0.1, "V", "voltage", "measurement", "mdi:flash"),
Sensor("grid_current_l3","Netz-Strom L3", 47, 1, 0.1, "A", "current", "measurement", "mdi:flash"),
Sensor("energy_today", "Energie Heute", 53, 2, 0.1, "kWh", "energy", "total_increasing", "mdi:solar-power"),
Sensor("energy_total", "Energie Gesamt", 55, 2, 0.1, "kWh", "energy", "total_increasing", "mdi:solar-power"),
Sensor("inverter_temp", "Wechselrichter Temp.",93, 1, 0.1, "°C", "temperature","measurement", "mdi:thermometer"),
]
def _goodwe_et_sensors() -> List[Sensor]:
return [
# PV
Sensor("vpv1", "PV1 Spannung", 0, 1, 1.0, "V", "voltage", "measurement", "mdi:solar-panel"),
Sensor("ipv1", "PV1 Strom", 0, 1, 1.0, "A", "current", "measurement", "mdi:solar-panel"),
Sensor("ppv1", "PV1 Leistung", 0, 1, 1.0, "W", "power", "measurement", "mdi:solar-panel"),
Sensor("vpv2", "PV2 Spannung", 0, 1, 1.0, "V", "voltage", "measurement", "mdi:solar-panel"),
Sensor("ipv2", "PV2 Strom", 0, 1, 1.0, "A", "current", "measurement", "mdi:solar-panel"),
Sensor("ppv2", "PV2 Leistung", 0, 1, 1.0, "W", "power", "measurement", "mdi:solar-panel"),
Sensor("ppv", "PV Gesamtleistung", 0, 1, 1.0, "W", "power", "measurement", "mdi:solar-power"),
# Grid
Sensor("vgrid", "Netz-Spannung L1", 0, 1, 1.0, "V", "voltage", "measurement", "mdi:flash"),
Sensor("igrid", "Netz-Strom L1", 0, 1, 1.0, "A", "current", "measurement", "mdi:flash"),
Sensor("fgrid", "Netz-Frequenz", 0, 1, 1.0, "Hz", "frequency", "measurement", "mdi:sine-wave"),
Sensor("pgrid", "Netz-Leistung L1", 0, 1, 1.0, "W", "power", "measurement", "mdi:flash"),
Sensor("vgrid2", "Netz-Spannung L2", 0, 1, 1.0, "V", "voltage", "measurement", "mdi:flash"),
Sensor("igrid2", "Netz-Strom L2", 0, 1, 1.0, "A", "current", "measurement", "mdi:flash"),
Sensor("pgrid2", "Netz-Leistung L2", 0, 1, 1.0, "W", "power", "measurement", "mdi:flash"),
Sensor("vgrid3", "Netz-Spannung L3", 0, 1, 1.0, "V", "voltage", "measurement", "mdi:flash"),
Sensor("igrid3", "Netz-Strom L3", 0, 1, 1.0, "A", "current", "measurement", "mdi:flash"),
Sensor("pgrid3", "Netz-Leistung L3", 0, 1, 1.0, "W", "power", "measurement", "mdi:flash"),
# Leistung
Sensor("total_inverter_power","Wechselrichter Gesamtleist.",0, 1, 1.0, "W", "power", "measurement", "mdi:flash"),
Sensor("active_power", "Wirkleistung Netz (roh)", 0, 1, 1.0, "W", "power", "measurement", "mdi:transmission-tower"),
Sensor("grid_power", "Netzleistung", 0, 1, 1.0, "W", "power", "measurement", "mdi:transmission-tower"),
Sensor("house_consumption", "Hausverbrauch", 0, 1, 1.0, "W", "power", "measurement", "mdi:home"),
# Batterie
Sensor("vbattery1", "Batterie Spannung", 0, 1, 1.0, "V", "voltage", "measurement", "mdi:battery"),
Sensor("ibattery1", "Batterie Strom", 0, 1, 1.0, "A", "current", "measurement", "mdi:battery"),
Sensor("pbattery1", "Batterie Leistung", 0, 1, 1.0, "W", "power", "measurement", "mdi:battery"),
Sensor("bat_charge_power", "Batterie Ladeleistung", 0, 1, 1.0, "W", "power", "measurement", "mdi:battery-plus"),
Sensor("bat_discharge_power", "Batterie Entladeleistung", 0, 1, 1.0, "W", "power", "measurement", "mdi:battery-minus"),
Sensor("battery_soc", "Batterie Ladezustand", 0, 1, 1.0, "%", "battery", "measurement", "mdi:battery"),
Sensor("battery_soh", "Batterie Gesundheit", 0, 1, 1.0, "%", None, "measurement", "mdi:battery-heart"),
Sensor("battery_temperature", "Batterie Temperatur", 0, 1, 1.0, "°C", "temperature", "measurement", "mdi:thermometer"),
Sensor("temperature", "Wechselrichter Temperatur", 0, 1, 1.0, "°C", "temperature", "measurement", "mdi:thermometer"),
# Energie
Sensor("e_day", "PV Energie Heute", 0, 1, 1.0, "kWh", "energy", "total_increasing", "mdi:solar-power"),
Sensor("e_total", "PV Energie Gesamt", 0, 1, 1.0, "kWh", "energy", "total_increasing", "mdi:solar-power"),
Sensor("e_day_exp", "Einspeisung Heute", 0, 1, 1.0, "kWh", "energy", "total_increasing", "mdi:transmission-tower-export"),
Sensor("e_total_exp", "Einspeisung Gesamt", 0, 1, 1.0, "kWh", "energy", "total_increasing", "mdi:transmission-tower-export"),
Sensor("e_day_imp", "Netzbezug Heute", 0, 1, 1.0, "kWh", "energy", "total_increasing", "mdi:transmission-tower-import"),
Sensor("e_total_imp", "Netzbezug Gesamt", 0, 1, 1.0, "kWh", "energy", "total_increasing", "mdi:transmission-tower-import"),
Sensor("e_bat_charge_day", "Batterie Ladung Heute", 0, 1, 1.0, "kWh", "energy", "total_increasing", "mdi:battery-plus"),
Sensor("e_bat_charge_total", "Batterie Ladung Gesamt", 0, 1, 1.0, "kWh", "energy", "total_increasing", "mdi:battery-plus"),
Sensor("e_bat_discharge_day", "Batterie Entladung Heute", 0, 1, 1.0, "kWh", "energy", "total_increasing", "mdi:battery-minus"),
Sensor("e_bat_discharge_total","Batterie Entladung Gesamt",0, 1, 1.0, "kWh", "energy", "total_increasing", "mdi:battery-minus"),
]
def _sdm630_sensors() -> List[Sensor]:
f = "float32"
return [
Sensor("voltage_l1", "Spannung L1", 0, 2, 1.0, "V", "voltage", "measurement", "mdi:flash", f),
Sensor("voltage_l2", "Spannung L2", 2, 2, 1.0, "V", "voltage", "measurement", "mdi:flash", f),
Sensor("voltage_l3", "Spannung L3", 4, 2, 1.0, "V", "voltage", "measurement", "mdi:flash", f),
Sensor("current_l1", "Strom L1", 6, 2, 1.0, "A", "current", "measurement", "mdi:flash", f),
Sensor("current_l2", "Strom L2", 8, 2, 1.0, "A", "current", "measurement", "mdi:flash", f),
Sensor("current_l3", "Strom L3", 10, 2, 1.0, "A", "current", "measurement", "mdi:flash", f),
Sensor("power_l1", "Wirkleistung L1", 12, 2, 1.0, "W", "power", "measurement", "mdi:flash", f),
Sensor("power_l2", "Wirkleistung L2", 14, 2, 1.0, "W", "power", "measurement", "mdi:flash", f),
Sensor("power_l3", "Wirkleistung L3", 16, 2, 1.0, "W", "power", "measurement", "mdi:flash", f),
Sensor("power_factor_l1", "Leistungsfaktor L1", 30, 2, 1.0, "", None, "measurement", "mdi:sine-wave", f),
Sensor("power_factor_l2", "Leistungsfaktor L2", 32, 2, 1.0, "", None, "measurement", "mdi:sine-wave", f),
Sensor("power_factor_l3", "Leistungsfaktor L3", 34, 2, 1.0, "", None, "measurement", "mdi:sine-wave", f),
Sensor("total_power", "Gesamtwirkleistung", 48, 2, 1.0, "W", "power", "measurement", "mdi:transmission-tower", f),
Sensor("frequency", "Frequenz", 70, 2, 1.0, "Hz", "frequency", "measurement", "mdi:sine-wave", f),
Sensor("import_kwh", "Bezug Gesamt", 72, 2, 1.0, "kWh", "energy", "total_increasing", "mdi:transmission-tower-import", f),
Sensor("export_kwh", "Einspeisung Gesamt", 74, 2, 1.0, "kWh", "energy", "total_increasing", "mdi:transmission-tower-export", f),
]
def _kathrein_sensors() -> List[Sensor]:
f = "float32"
return [
# Meter (Float32, FC03 Holding Registers ab 0x0030)
Sensor("voltage_l1", "Spannung L1", 0x0030, 2, 1.0, "V", "voltage", "measurement", "mdi:flash", f),
Sensor("voltage_l2", "Spannung L2", 0x0032, 2, 1.0, "V", "voltage", "measurement", "mdi:flash", f),
Sensor("voltage_l3", "Spannung L3", 0x0034, 2, 1.0, "V", "voltage", "measurement", "mdi:flash", f),
Sensor("current_l1", "Strom L1", 0x0036, 2, 1.0, "A", "current", "measurement", "mdi:flash", f),
Sensor("current_l2", "Strom L2", 0x0038, 2, 1.0, "A", "current", "measurement", "mdi:flash", f),
Sensor("current_l3", "Strom L3", 0x003A, 2, 1.0, "A", "current", "measurement", "mdi:flash", f),
Sensor("power_l1", "Ladeleistung L1", 0x003C, 2, 1.0, "W", "power", "measurement", "mdi:ev-station", f),
Sensor("power_l2", "Ladeleistung L2", 0x003E, 2, 1.0, "W", "power", "measurement", "mdi:ev-station", f),
Sensor("power_l3", "Ladeleistung L3", 0x0040, 2, 1.0, "W", "power", "measurement", "mdi:ev-station", f),
Sensor("total_power", "Ladeleistung Gesamt", 0x0054, 2, 1.0, "W", "power", "measurement", "mdi:ev-station", f),
Sensor("session_energy", "Energie Session", 0x0069, 2, 1.0, "Wh", "energy", "total_increasing", "mdi:battery-charging", "uint32"),
Sensor("total_energy", "Energie Gesamt", 0x005C, 2, 1.0, "Wh", "energy", "total_increasing", "mdi:counter", f),
Sensor("frequency", "Frequenz", 0x005E, 2, 1.0, "Hz", "frequency", "measurement", "mdi:sine-wave", f),
# EVSE Status (UINT16)
Sensor("charging_state", "Ladezustand", 0x0060, 1, 1.0, "", None, "measurement", "mdi:ev-plug-type2"),
Sensor("granted_current", "Gewährter Strom", 0x0065, 1, 1.0, "mA", "current", "measurement", "mdi:current-ac"),
Sensor("granted_power", "Gewährte Leistung", 0x0066, 1, 1.0, "W", "power", "measurement", "mdi:ev-station"),
Sensor("charging_duration","Ladedauer", 0x0067, 2, 1.0, "s", "duration", "measurement", "mdi:timer", "uint32"),
# EMS (wird vom Controller geschrieben, hier zum Monitoring)
Sensor("ems_current_sp", "EMS Stromsollwert", 0x00A2, 1, 1.0, "mA", "current", "measurement", "mdi:tune"),
]
INVERTERS = {
"MIC_1500_TL_X": Inverter(
id="MIC_1500_TL_X",
name="Growatt MIC 1500 TL-X",
manufacturer="Growatt",
sensors=_mic_sensors(),
read_ranges=[(3, 91), (93, 1)], # regs 3-93
),
"MIC_2000_TL_X": Inverter(
id="MIC_2000_TL_X",
name="Growatt MIC 2000 TL-X",
manufacturer="Growatt",
sensors=_mic_sensors(),
read_ranges=[(3, 91), (93, 1)],
),
"SPH_5000_TL3": Inverter(
id="SPH_5000_TL3",
name="Growatt SPH 5000 TL3-BH-UP",
manufacturer="Growatt",
sensors=_sph_sensors(),
read_ranges=[(3, 91), (93, 1), (1009, 52)], # regs 3-93 + 1009-1060
),
"MOD_6000_TL3": Inverter(
id="MOD_6000_TL3",
name="Growatt MOD 6000 TL3-XH",
manufacturer="Growatt",
sensors=_mod_sensors(),
read_ranges=[(3, 91), (93, 1)],
),
"SDM_630": Inverter(
id="SDM_630",
name="Eastron SDM-630",
manufacturer="Eastron",
sensors=_sdm630_sensors(),
read_ranges=[(0, 76)],
),
"GW10KN_ET": Inverter(
id="GW10KN_ET",
name="Goodwe GW10KN-ET",
manufacturer="Goodwe",
sensors=_goodwe_et_sensors(),
read_ranges=[],
protocol="goodwe_udp",
goodwe_family="ET",
),
"KATHREIN_WALLBOX": Inverter(
id="KATHREIN_WALLBOX",
name="Kathrein Wallbox",
manufacturer="Kathrein",
sensors=_kathrein_sensors(),
# Meter-Block + EVSE-Status + EMS-Setpoint
read_ranges=[(0x0030, 48), (0x0060, 10), (0x00A2, 1)],
protocol="kathrein",
goodwe_family="",
),
}