Energieverbrauchssensoren - Technische Dokumentation¶
Diese Dokumentation beschreibt die technische Implementierung der Energieverbrauchssensoren (elektrisch und thermisch) in der Lambda Heat Pumps Integration.
Übersicht¶
Die Integration bietet zwei Arten von Energieverbrauchssensoren:
- Elektrische Energieverbrauchssensoren: Messen den Stromverbrauch (kWh)
- Thermische Energieverbrauchssensoren: Messen die Wärmeabgabe (kWh)
Beide Typen werden nach Betriebsart (heating, hot_water, cooling, defrost) und Zeitraum (total, daily, monthly, yearly) aufgeteilt.
Architektur¶
Komponenten¶
┌─────────────────────────────────────────────────────────────┐
│ Coordinator │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ _track_hp_energy_consumption() │ │
│ │ ├─ _track_hp_energy_type_consumption(electrical) │ │
│ │ └─ _track_hp_energy_type_consumption(thermal) │ │
│ └──────────────────────────────────────────────────────┘ │
│ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ _increment_energy_consumption() │ │
│ │ _increment_thermal_energy_consumption() │ │
│ └──────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ utils.py │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ increment_energy_consumption_counter() │ │
│ │ - sensor_type: "electrical" | "thermal" │ │
│ └──────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ sensor.py │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ LambdaEnergyConsumptionSensor │ │
│ │ - set_energy_value() │ │
│ │ - native_value (berechnet aus period) │ │
│ └──────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
Datenfluss¶
- Quellsensoren liefern kumulative Werte:
- Elektrisch:
compressor_power_consumption_accumulated(Register 1021) -
Thermisch:
compressor_thermal_energy_output_accumulated(Register 1022) -
Coordinator berechnet Deltas:
- Liest Quellsensor-Werte
- Berechnet Delta zwischen Updates
-
Erkennt Betriebsmodus-Wechsel (Flankenerkennung)
-
Utils aktualisieren Sensoren:
increment_energy_consumption_counter()aktualisiert alle Perioden-
Unterstützt sowohl elektrische als auch thermische Sensoren
-
Entities speichern Werte:
LambdaEnergyConsumptionSensorspeichert Total-Wert- Berechnet daily/monthly/yearly aus Total-Wert
Implementierung¶
1. Sensor-Erstellung¶
Sensoren werden in sensor.py erstellt:
# Elektrische Sensoren
for hp_idx in range(1, num_hps + 1):
for mode in ENERGY_CONSUMPTION_MODES:
for period in ENERGY_CONSUMPTION_PERIODS:
sensor_id = f"{mode}_energy_{period}"
sensor = LambdaEnergyConsumptionSensor(...)
# Thermische Sensoren
for hp_idx in range(1, num_hps + 1):
for mode in ENERGY_CONSUMPTION_MODES:
for period in ENERGY_CONSUMPTION_PERIODS:
sensor_id = f"{mode}_thermal_energy_{period}"
if sensor_template.get("data_type") == "thermal_calculated":
sensor = LambdaEnergyConsumptionSensor(...)
2. Sensor-Templates¶
Templates sind in const.py definiert:
ENERGY_CONSUMPTION_SENSOR_TEMPLATES = {
# Elektrische Sensoren
"heating_energy_total": {
"name": "Heating Energy Total",
"unit": "kWh",
"data_type": "energy_calculated",
"state_class": "total_increasing",
"device_class": "energy",
"operating_state": "heating",
"period": "total",
},
# Thermische Sensoren
"heating_thermal_energy_total": {
"name": "Heating Thermal Energy Total",
"unit": "kWh",
"data_type": "thermal_calculated",
"state_class": "total_increasing",
"device_class": "energy",
"operating_state": "heating",
"period": "total",
},
# ...
}
3. Coordinator-Tracking¶
Der Coordinator trackt beide Energiearten parallel:
async def _track_hp_energy_consumption(self, hp_idx, current_state, data):
# Elektrische Energie
await self._track_hp_energy_type_consumption(
hp_idx, current_state, data,
sensor_type="electrical",
default_sensor_id_template="sensor.{name_prefix}_hp{hp_idx}_compressor_power_consumption_accumulated",
increment_fn=self._increment_energy_consumption
)
# Thermische Energie
await self._track_hp_energy_type_consumption(
hp_idx, current_state, data,
sensor_type="thermal",
default_sensor_id_template="sensor.{name_prefix}_hp{hp_idx}_compressor_thermal_energy_output_accumulated",
increment_fn=self._increment_thermal_energy_consumption
)
4. Delta-Berechnung¶
Die generische Tracking-Funktion:
async def _track_hp_energy_type_consumption(
self, hp_idx, current_state, data, sensor_type,
default_sensor_id_template, unit_check_fn, convert_to_kwh_fn,
last_reading_dict, first_value_seen_dict, increment_fn
):
# 1. Lese Quellsensor
current_energy_state = self.hass.states.get(sensor_entity_id)
current_energy = float(current_energy_state.state)
# 2. Konvertiere zu kWh
current_energy_kwh = convert_to_kwh_fn(current_energy, unit)
# 3. Berechne Delta
last_energy = last_reading_dict.get(f"hp{hp_idx}", None)
energy_delta = calculate_energy_delta(current_energy_kwh, last_energy, max_delta=100.0)
# 4. Bestimme Betriebsmodus
mode = mode_mapping[current_state] # heating, hot_water, cooling, defrost
# 5. Aktualisiere Sensoren bei Moduswechsel oder kontinuierlich
if current_state != last_state or (mode == "stby" or energy_delta > 0):
await increment_fn(hp_idx, mode, energy_delta)
5. Sensor-Update¶
Die Update-Funktion aktualisiert alle Perioden:
async def increment_energy_consumption_counter(
hass, mode, hp_index, energy_delta, name_prefix,
use_legacy_modbus_names=True, energy_offsets=None,
sensor_type="electrical" # oder "thermal"
):
for period in ["total", "daily", "monthly", "yearly", "2h", "4h"]:
# Bestimme sensor_id basierend auf sensor_type
if sensor_type == "thermal":
sensor_id = f"{mode}_thermal_energy_{period}"
else:
sensor_id = f"{mode}_energy_{period}"
# Finde Entity
energy_entity = find_energy_entity(hass, entity_id)
# Berechne neuen Wert
current_value = float(state_obj.state)
new_value = current_value + energy_delta
# Wende Offset an (nur für total)
if period == "total" and energy_offsets:
new_value += offset
# Aktualisiere Entity
energy_entity.set_energy_value(new_value)
6. Entity-Implementierung¶
Die LambdaEnergyConsumptionSensor Klasse:
class LambdaEnergyConsumptionSensor(RestoreEntity, SensorEntity):
def __init__(self, hass, entry, sensor_id, name, entity_id,
unique_id, unit, state_class, device_class,
device_type, hp_index, mode, period):
self._energy_value = 0.0 # Total-Wert
self._period = period
# ...
@property
def native_value(self):
"""Berechnet Wert basierend auf period."""
if self._period == "total":
return self._energy_value
elif self._period == "daily":
return self._energy_value - self._yesterday_value
elif self._period == "monthly":
return self._energy_value - self._previous_monthly_value
# ...
def set_energy_value(self, value):
"""Wird von increment_energy_consumption_counter aufgerufen."""
self._energy_value = value
self.async_write_ha_state()
Quellsensoren¶
Elektrische Energie¶
- Sensor:
compressor_power_consumption_accumulated - Register: 1021 (HP1), 2021 (HP2), etc.
- Einheit: Wh (wird zu kWh konvertiert)
- Typ: int32, total_increasing
Thermische Energie¶
- Sensor:
compressor_thermal_energy_output_accumulated - Register: 1022 (HP1), 2022 (HP2), etc.
- Einheit: Wh (wird zu kWh konvertiert)
- Typ: int32, total_increasing
Betriebsmodus-Mapping¶
mode_mapping = {
0: "stby", # Standby
1: "heating", # CH - Heizen
2: "hot_water", # DHW - Warmwasser
3: "cooling", # CC - Kühlen
4: "stby", # Standby (alternativ)
5: "defrost", # DEFROST - Abtauen
}
Flankenerkennung¶
Die Integration nutzt Flankenerkennung, um Energie-Deltas exakt dem aktiven Betriebsmodus zuzuordnen:
- Moduswechsel erkannt: Delta wird dem neuen Modus zugeordnet
- Kontinuierlicher Betrieb: Delta wird dem aktuellen Modus zugeordnet
- Standby: Delta wird auch Standby zugeordnet (falls vorhanden)
Einheitenkonvertierung¶
Unterstützte Einheiten werden automatisch zu kWh konvertiert:
def _convert_energy_to_kwh_cached(self, value, unit):
if unit == "Wh":
return value / 1000.0
elif unit == "kWh":
return value
elif unit == "MWh":
return value * 1000.0
else:
return value # Fallback
Persistierung¶
- Total-Werte: Werden in
LambdaEnergyConsumptionSensorgespeichert (RestoreEntity) - Last Readings: Werden im Coordinator gespeichert (
_last_energy_reading,_last_thermal_energy_reading) - JSON-Persistierung: Coordinator speichert Werte in
cycle_energy_persist.json
Konfiguration¶
Externe Sensoren¶
Elektrische Sensoren können extern konfiguriert werden:
energy_consumption_sensors:
hp1:
electrical_sensor_entity_id: "sensor.shelly_lambda_gesamt_leistung"
Hinweis: Thermische Sensoren verwenden immer die internen Modbus-Sensoren.
Offsets¶
Offsets können für Total-Sensoren konfiguriert werden:
energy_consumption_offsets:
hp1:
heating_energy_total: 1000.0
heating_thermal_energy_total: 5000.0
# ...
Fehlerbehandlung¶
Sensor-Wechsel-Erkennung¶
- Automatische Erkennung von Sensorwechseln
- Nullwert-Schutz beim ersten Start
- Rückwärtssprung-Schutz (Sensor-Reset)
Zero-Value Protection¶
if current_energy_kwh == 0.0:
first_value_seen_dict[f"hp{hp_idx}"] = False
return # Warte auf ersten gültigen Wert
Overflow Protection¶
if current_energy_kwh < last_energy:
# Sensor wurde zurückgesetzt oder gewechselt
first_value_seen_dict[f"hp{hp_idx}"] = False
last_reading_dict[f"hp{hp_idx}"] = None
return
Erweiterungen¶
Neue Betriebsmodi hinzufügen¶
- Modus zu
ENERGY_CONSUMPTION_MODESinconst.pyhinzufügen - Sensor-Templates in
ENERGY_CONSUMPTION_SENSOR_TEMPLATEShinzufügen - Modus-Mapping in
_track_hp_energy_type_consumptionerweitern
Neue Zeiträume hinzufügen¶
- Zeitraum zu
ENERGY_CONSUMPTION_PERIODSinconst.pyhinzufügen - Sensor-Templates für alle Modi hinzufügen
- Reset-Logik in
LambdaEnergyConsumptionSensorerweitern
Debugging¶
Logging¶
Aktiviere Debug-Logging für detaillierte Informationen:
logger:
default: info
logs:
custom_components.lambda_heat_pumps.coordinator: debug
custom_components.lambda_heat_pumps.utils: debug
Wichtige Log-Meldungen¶
DEBUG-010: Tracking startet für HPDEBUG-014: Energie-Offsets werden geladenEnergy counters updated: Sensoren wurden aktualisiertINTERNAL-SENSOR: Interner Modbus-Sensor wird verwendet
Tests¶
Tests befinden sich in tests/test_energy_consumption_sensors.py:
- Sensor-Erstellung
- Delta-Berechnung
- Period-Berechnung (daily, monthly, yearly)
- Offset-Anwendung
- Einheitenkonvertierung