Skip to content

Commit 7a944d7

Browse files
authored
Add files via upload
Three new sensors added: - `lifetime_energy_export_a` - Phase A energy export tracking - `lifetime_energy_export_b` - Phase B energy export tracking - `lifetime_energy_export_c` - Phase C energy export tracking Unit in kWh, persistent (survives a Home Assistant restart), increases only (no daily reset), MDI icon added
1 parent c4e1d9c commit 7a944d7

File tree

2 files changed

+79
-1
lines changed

2 files changed

+79
-1
lines changed

custom_components/apsystems_ecu_reader/const.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
CACHE_COUNTER_ICON = "mdi:counter"
1212
ECU_REBOOT_ICON = "mdi:restart"
1313
FROM_GRID_ICON = "mdi:transmission-tower-export"
14+
TO_GRID_ICON = "mdi:transmission-tower-import"
1415
CONSUMED_ICON = "mdi:transmission-tower"
1516
DOWNLOAD_ICON = "mdi:download"
1617

custom_components/apsystems_ecu_reader/sensor.py

Lines changed: 78 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"""sensor.py"""
22

33
import logging
4+
from datetime import datetime
45

56
from homeassistant.components.sensor import SensorEntity
67
from homeassistant.components.binary_sensor import BinarySensorEntity
@@ -35,6 +36,7 @@
3536
SOLAR_PANEL_ICON,
3637
CACHE_COUNTER_ICON,
3738
FROM_GRID_ICON,
39+
TO_GRID_ICON,
3840
CONSUMED_ICON,
3941
DOWNLOAD_ICON,
4042
INVERTER_MODEL_MAP,
@@ -235,6 +237,42 @@ async def async_setup_entry(hass, config_entry, add_entities):
235237
]
236238
)
237239

240+
# Add lifetime energy export sensors
241+
sensors.extend(
242+
[
243+
APsystemsECUSensor(
244+
coordinator,
245+
ecu,
246+
"lifetime_energy_export_a",
247+
label=f"{ecu.ecu.ecu_id} Lifetime Energy Export A",
248+
unit=UnitOfEnergy.KILO_WATT_HOUR,
249+
devclass=SensorDeviceClass.ENERGY,
250+
icon=TO_GRID_ICON,
251+
stateclass=SensorStateClass.TOTAL_INCREASING,
252+
),
253+
APsystemsECUSensor(
254+
coordinator,
255+
ecu,
256+
"lifetime_energy_export_b",
257+
label=f"{ecu.ecu.ecu_id} Lifetime Energy Export B",
258+
unit=UnitOfEnergy.KILO_WATT_HOUR,
259+
devclass=SensorDeviceClass.ENERGY,
260+
icon=TO_GRID_ICON,
261+
stateclass=SensorStateClass.TOTAL_INCREASING,
262+
),
263+
APsystemsECUSensor(
264+
coordinator,
265+
ecu,
266+
"lifetime_energy_export_c",
267+
label=f"{ecu.ecu.ecu_id} Lifetime Energy Export C",
268+
unit=UnitOfEnergy.KILO_WATT_HOUR,
269+
devclass=SensorDeviceClass.ENERGY,
270+
icon=TO_GRID_ICON,
271+
stateclass=SensorStateClass.TOTAL_INCREASING,
272+
),
273+
]
274+
)
275+
238276
# Add inverter binary sensors
239277
inverters = coordinator.data.get("inverters", {})
240278
for uid, inv_data in inverters.items():
@@ -570,12 +608,17 @@ def __init__(
570608
# self._disabled_by = disabled_by
571609
self._name = f"ECU {self._label}"
572610
self._state = None
611+
self._last_update_time = None
612+
self._last_power_value = None
573613

574614
async def async_added_to_hass(self):
575615
"""Handle entity that needs to be restored."""
576616
await super().async_added_to_hass()
577617
last_state = await self.async_get_last_state()
578-
if last_state and self._field == "lifetime_maximum_power":
618+
if last_state and (
619+
self._field == "lifetime_maximum_power"
620+
or self._field.startswith("lifetime_energy_export")
621+
):
579622
try:
580623
self._state = (
581624
0
@@ -605,6 +648,40 @@ def native_value(self):
605648
current_power = self.coordinator.data.get("current_power", 0) or 0
606649
self._state = max(self._state or 0, current_power)
607650
return round(self._state)
651+
elif self._field.startswith("lifetime_energy_export"):
652+
# Extract the phase (a, b, or c) from the field name
653+
phase = self._field.split("_")[-1] # Gets 'a', 'b', or 'c'
654+
grid_field = f"grid_ct_{phase}"
655+
656+
# Get current power and time
657+
current_power = self.coordinator.data.get(grid_field, 0) or 0
658+
current_time = datetime.now()
659+
660+
# Initialize state if None
661+
if self._state is None:
662+
self._state = 0.0
663+
664+
# Calculate energy increment if we have a previous timestamp
665+
if (
666+
self._last_update_time is not None
667+
and self._last_power_value is not None
668+
and self._last_power_value < 0
669+
): # Only accumulate when exporting (negative power)
670+
671+
time_delta_hours = (
672+
current_time - self._last_update_time
673+
).total_seconds() / 3600
674+
# Use absolute value of negative power for export energy calculation
675+
energy_increment_kwh = (
676+
abs(self._last_power_value) * time_delta_hours / 1000
677+
)
678+
self._state += energy_increment_kwh
679+
680+
# Update tracking variables
681+
self._last_update_time = current_time
682+
self._last_power_value = current_power
683+
684+
return round(self._state, 3)
608685
else:
609686
return self.coordinator.data.get(self._field, 0)
610687

0 commit comments

Comments
 (0)