Skip to content

Commit

Permalink
Merge pull request #323 from henricm/fix-zero-energy-values
Browse files Browse the repository at this point in the history
fix: ignore zero values for total-increasing energy sensors
  • Loading branch information
henricm authored Apr 5, 2023
2 parents 31d8cbc + e6e0865 commit 4ed35ba
Show file tree
Hide file tree
Showing 2 changed files with 112 additions and 15 deletions.
39 changes: 24 additions & 15 deletions custom_components/ferroamp/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,6 @@ def sso_event_received(msg):
precision_energy,
config_id,
model=model,
state_class=SensorStateClass.TOTAL_INCREASING
),
FaultcodeFerroampSensor(
"Faultcode",
Expand Down Expand Up @@ -300,7 +299,6 @@ def eso_event_received(msg):
interval,
precision_energy,
config_id,
state_class=SensorStateClass.TOTAL_INCREASING,
),
EnergyFerroampSensor(
"Total Energy Consumed",
Expand All @@ -312,7 +310,6 @@ def eso_event_received(msg):
interval,
precision_energy,
config_id,
state_class=SensorStateClass.TOTAL_INCREASING,
),
BatteryFerroampSensor(
"State of Charge",
Expand Down Expand Up @@ -627,6 +624,15 @@ def __init__(self, name, entity_prefix, key, unit: str | None, icon, device_id,
def present(self, event) -> bool:
return event.get(self._state_key, None) is not None

def get_value(self, event):
return event.get(self._state_key, None)

def get_float_value(self, event) -> float:
val = event.get(self._state_key, None)
if val is None:
return 0
return float(val["val"])

def add_event(self, event):
if not self.check_presence or self.present(event):
self.events.append(event)
Expand Down Expand Up @@ -706,10 +712,10 @@ def update_state_from_events(self, events) -> bool:
temp = None
count = 0
for event in events:
v = event.get(self._state_key, None)
v = self.get_value(event)
if v is not None:
count += 1
temp = (temp or 0) + float(v["val"])
temp = (temp or 0) + self.get_float_value(event)
if temp is None:
return False
else:
Expand All @@ -728,7 +734,7 @@ def __init__(self, name, entity_prefix, key, icon, device_id, device_name, inter
self._attr_state_class = SensorStateClass.MEASUREMENT

def get_voltage(self, event):
voltage = event.get(self._state_key, None)
voltage = self.get_value(event)
if voltage is not None:
voltage = dict(neg=float(voltage["neg"]), pos=float(voltage["pos"]))
return voltage
Expand Down Expand Up @@ -854,9 +860,14 @@ def __init__(self, name, entity_prefix, key, icon, device_id, device_name, inter
interval,
precision,
config_id,
state_class=SensorStateClass.TOTAL_INCREASING,
**kwargs
)

def add_event(self, event):
if self.get_float_value(event) > 0:
super().add_event(event)

def update_state_from_events(self, events):
temp = None
count = 0
Expand Down Expand Up @@ -1037,9 +1048,16 @@ def __init__(self, name, entity_prefix, key, icon, device_id, device_name, inter
interval,
precision,
config_id,
state_class=SensorStateClass.TOTAL_INCREASING,
**kwargs
)

def add_event(self, event):
phases = self.get_phases(event)
if phases is not None and (phases["L1"] is not None or phases["L2"] is not None or phases["L3"] is not None):
if (phases["L1"] + phases["L2"] + phases["L3"]) > 0:
super().add_event(event)

def get_phases(self, event):
phases = super().get_phases(event)
if phases is not None and (phases["L1"] is not None or phases["L2"] is not None or phases["L3"] is not None):
Expand Down Expand Up @@ -1304,7 +1322,6 @@ def ehub_sensors(slug, interval, precision_battery, precision_current, precision
interval,
precision_energy,
config_id,
state_class=SensorStateClass.TOTAL_INCREASING,
),
ThreePhaseEnergyFerroampSensor(
"External Energy Consumed",
Expand All @@ -1316,7 +1333,6 @@ def ehub_sensors(slug, interval, precision_battery, precision_current, precision
interval,
precision_energy,
config_id,
state_class=SensorStateClass.TOTAL_INCREASING,
),
ThreePhaseEnergyFerroampSensor(
"Inverter Energy Produced",
Expand All @@ -1328,7 +1344,6 @@ def ehub_sensors(slug, interval, precision_battery, precision_current, precision
interval,
precision_energy,
config_id,
state_class=SensorStateClass.TOTAL_INCREASING,
),
ThreePhaseEnergyFerroampSensor(
"Inverter Energy Consumed",
Expand All @@ -1340,7 +1355,6 @@ def ehub_sensors(slug, interval, precision_battery, precision_current, precision
interval,
precision_energy,
config_id,
state_class=SensorStateClass.TOTAL_INCREASING,
),
ThreePhaseEnergyFerroampSensor(
"Load Energy Produced",
Expand All @@ -1352,7 +1366,6 @@ def ehub_sensors(slug, interval, precision_battery, precision_current, precision
interval,
precision_energy,
config_id,
state_class=SensorStateClass.TOTAL_INCREASING,
),
ThreePhaseEnergyFerroampSensor(
"Load Energy Consumed",
Expand All @@ -1364,7 +1377,6 @@ def ehub_sensors(slug, interval, precision_battery, precision_current, precision
interval,
precision_energy,
config_id,
state_class=SensorStateClass.TOTAL_INCREASING,
),
EnergyFerroampSensor(
"Total Solar Energy",
Expand All @@ -1376,7 +1388,6 @@ def ehub_sensors(slug, interval, precision_battery, precision_current, precision
interval,
precision_energy,
config_id,
state_class=SensorStateClass.TOTAL_INCREASING,
),
EnergyFerroampSensor(
"Battery Energy Produced",
Expand All @@ -1388,7 +1399,6 @@ def ehub_sensors(slug, interval, precision_battery, precision_current, precision
interval,
precision_energy,
config_id,
state_class=SensorStateClass.TOTAL_INCREASING,
),
EnergyFerroampSensor(
"Battery Energy Consumed",
Expand All @@ -1400,7 +1410,6 @@ def ehub_sensors(slug, interval, precision_battery, precision_current, precision
interval,
precision_energy,
config_id,
state_class=SensorStateClass.TOTAL_INCREASING,
),
IntValFerroampSensor(
"System State",
Expand Down
88 changes: 88 additions & 0 deletions tests/test_sensor.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import uuid
from unittest.mock import patch
import unittest

import pytest
from homeassistant.const import (
Expand Down Expand Up @@ -1692,6 +1693,47 @@ async def test_always_increasing(hass, mqtt_mock):
sensor = hass.data[DOMAIN][DATA_DEVICES][config_entry.unique_id]["ferroamp_ehub"][entity.unique_id]
assert sensor.state == "1348.5"

async def test_always_increasing_zerovalues(hass, mqtt_mock):
mock_restore_cache(
hass,
[
State("sensor.ferroamp_total_solar_energy", "1348.5")
],
)

hass.state = CoreState.starting

config_entry = create_config()
config_entry.add_to_hass(hass)
await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()
topic = "extapi/data/ehub"
async_fire_mqtt_message(hass, topic, '{"id":{"val":"1"},"wpv":{"val": "4422089590383"}}')
async_fire_mqtt_message(hass, topic, '{"id":{"val":"1"},"wpv":{"val": "0"}}')
await hass.async_block_till_done()

er = entity_registry.async_get(hass)
entity = er.async_get("sensor.ferroamp_total_solar_energy")
assert entity is not None
sensor = hass.data[DOMAIN][DATA_DEVICES][config_entry.unique_id]["ferroamp_ehub"][entity.unique_id]
assert float(sensor.state) == pytest.approx(1348.5)

async_fire_mqtt_message(hass, topic, '{"id":{"val":"1"},"wpv":{"val": "4856400000000"}}')
async_fire_mqtt_message(hass, topic, '{"id":{"val":"1"},"wpv":{"val": "0"}}')
async_fire_mqtt_message(hass, topic, '{"id":{"val":"1"},"wpv":{"val": "0"}}')
async_fire_mqtt_message(hass, topic, '{"id":{"val":"1"},"wpv":{"val": "0"}}')
async_fire_mqtt_message(hass, topic, '{"id":{"val":"1"},"wpv":{"val": "0"}}')
async_fire_mqtt_message(hass, topic, '{"id":{"val":"1"},"wpv":{"val": "0"}}')
async_fire_mqtt_message(hass, topic, '{"id":{"val":"1"},"wpv":{"val": "0"}}')
async_fire_mqtt_message(hass, topic, '{"id":{"val":"1"},"wpv":{"val": "4856400000000"}}')
await hass.async_block_till_done()

er = entity_registry.async_get(hass)
entity = er.async_get("sensor.ferroamp_total_solar_energy")
assert entity is not None
sensor = hass.data[DOMAIN][DATA_DEVICES][config_entry.unique_id]["ferroamp_ehub"][entity.unique_id]
assert float(sensor.state) == pytest.approx(1349.0)


async def test_always_increasing_unknown_value(hass, mqtt_mock):
mock_restore_cache(
Expand Down Expand Up @@ -1771,6 +1813,52 @@ async def test_3phase_always_increasing(hass, mqtt_mock):
sensor = hass.data[DOMAIN][DATA_DEVICES][config_entry.unique_id]["ferroamp_ehub"][entity.unique_id]
assert sensor.state == "662.5"

async def test_3phase_always_increasing_zero_values(hass, mqtt_mock):
mock_restore_cache(
hass,
[
State("sensor.ferroamp_external_energy_produced", "662.5")
],
)

hass.state = CoreState.starting

config_entry = create_config()
config_entry.add_to_hass(hass)
await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()
topic = "extapi/data/ehub"
msg = '{"id":{"val":"1"},"wextprodq": {"L2": "1118056851556", "L3": "604554554552", "L1": "662115344893"}}'
async_fire_mqtt_message(hass, topic, msg)
msg = '{"id":{"val":"1"},"wextprodq": {"L2": "0", "L3": "0", "L1": "0"}}'
async_fire_mqtt_message(hass, topic, msg)
async_fire_mqtt_message(hass, topic, msg)
async_fire_mqtt_message(hass, topic, msg)
await hass.async_block_till_done()

er = entity_registry.async_get(hass)
entity = er.async_get("sensor.ferroamp_external_energy_produced")
assert entity is not None
sensor = hass.data[DOMAIN][DATA_DEVICES][config_entry.unique_id]["ferroamp_ehub"][entity.unique_id]
assert float(sensor.state) == pytest.approx(662.5)

msg = '{"id":{"val":"1"},"wextprodq": {"L2": "1118056851556", "L3": "604554554552", "L1": "662115344893"}}'
async_fire_mqtt_message(hass, topic, msg)
msg = '{"id":{"val":"1"},"wextprodq": {"L2": "0", "L3": "0", "L1": "0"}}'
async_fire_mqtt_message(hass, topic, msg)
async_fire_mqtt_message(hass, topic, msg)
async_fire_mqtt_message(hass, topic, msg)
msg = '{"id":{"val":"1"},"wextprodq": {"L2": "1119056851556", "L3": "604564554552", "L1": "662116344893"}}'
async_fire_mqtt_message(hass, topic, msg)
msg = '{"id":{"val":"1"},"wextprodq": {"L2": "0", "L3": "0", "L1": "0"}}'
async_fire_mqtt_message(hass, topic, msg)
await hass.async_block_till_done()

er = entity_registry.async_get(hass)
entity = er.async_get("sensor.ferroamp_external_energy_produced")
assert entity is not None
sensor = hass.data[DOMAIN][DATA_DEVICES][config_entry.unique_id]["ferroamp_ehub"][entity.unique_id]
assert float(sensor.state) == pytest.approx(662.7)

async def test_3phase_always_increasing_unknown_value(hass, mqtt_mock):
mock_restore_cache(
Expand Down

0 comments on commit 4ed35ba

Please sign in to comment.