Stop double-converting filterUsage on AIR_FILTER/HEPA_FILTER (#330)
filterUsage is already a 0-100 percentage on every confirmed family, including ARTIK051_PRAC: filterStatus flips to 'wash' at filterUsage == '100' regardless of filterCapacity (60/224/500 across other fixtures), which only holds if filterUsage is already a percent. filter_usage_percent() divided by filterCapacity again, reading a filter due for washing as 20% fresh. air_filter_usage_hours had the mirror problem: it read filterUsage directly as an hour count with device_class=duration, when the field is a percent. It's now derived from the percentage and filterCapacity (new filter_usage_hours() in common.py) instead.
This commit is contained in:
4 files changed
+54
-27
No files matched your search
@@ -22,7 +22,7 @@ from ..entities import (
|
||||
SwitchDesc,
|
||||
)
|
||||
from . import common
|
||||
from .common import filter_usage_percent, normalize_temp_unit
|
||||
from .common import filter_usage_hours, filter_usage_percent, normalize_temp_unit
|
||||
from .laundry import option_write
|
||||
|
||||
|
||||
@@ -854,16 +854,17 @@ AIR_FILTER = Capability(
|
||||
icon="mdi:air-filter",
|
||||
entity_category="diagnostic",
|
||||
),
|
||||
# Lifetime hour counter, resets only on filter replacement.
|
||||
# Lifetime hour counter, resets only on filter replacement. Derived
|
||||
# from the percentage and filterCapacity (issue #330) -- filterUsage
|
||||
# itself is not an hour count.
|
||||
SensorDesc(
|
||||
key="air_filter_usage_hours",
|
||||
field="x.com.samsung.da.filterUsage",
|
||||
rep_fn=filter_usage_hours,
|
||||
device_class="duration",
|
||||
state_class="total_increasing",
|
||||
unit_fn=_filter_unit,
|
||||
icon="mdi:air-filter",
|
||||
entity_category="diagnostic",
|
||||
value_fn=_int,
|
||||
),
|
||||
# Locally writable alarm threshold (see _threshold_write); only
|
||||
# surfaces where supportedFilterDesiredUsage is advertised.
|
||||
@@ -925,13 +926,12 @@ AIR_FILTER_PM1 = Capability(
|
||||
),
|
||||
SensorDesc(
|
||||
key="air_filter_pm1_usage_hours",
|
||||
field="x.com.samsung.da.filterUsage",
|
||||
rep_fn=filter_usage_hours,
|
||||
device_class="duration",
|
||||
state_class="total_increasing",
|
||||
unit_fn=_filter_unit,
|
||||
icon="mdi:air-filter",
|
||||
entity_category="diagnostic",
|
||||
value_fn=_int,
|
||||
exists_fn=_has_filter_field("x.com.samsung.da.filterUsage"),
|
||||
),
|
||||
SelectDesc(
|
||||
|
||||
@@ -72,15 +72,25 @@ def epoch_to_utc(value):
|
||||
|
||||
|
||||
def filter_usage_percent(rep):
|
||||
"""Filter usage as a percentage of rated capacity. Several families
|
||||
report `filterUsage` as a raw count in `filterCapacityUnit` (e.g. 100 of
|
||||
a 500-hour capacity), so a plain value with a '%' unit would be wrong.
|
||||
Returns None when capacity is missing/zero."""
|
||||
used = _num(rep.get("x.com.samsung.da.filterUsage"))
|
||||
"""Filter usage as a percentage. `filterUsage` is already 0-100 on every
|
||||
family confirmed so far, including ARTIK051_PRAC (issue #330): its own
|
||||
fixture and three live heads all show `filterStatus == 'wash'` at
|
||||
`filterUsage == '100'` regardless of `filterCapacity` (60/224/500 across
|
||||
other families' fixtures), which only holds if `filterUsage` is already
|
||||
a percent -- dividing by capacity again would read that filter as fresh
|
||||
at 20%."""
|
||||
return int_or_none(rep.get("x.com.samsung.da.filterUsage"))
|
||||
|
||||
|
||||
def filter_usage_hours(rep):
|
||||
"""Elapsed filter hours, derived from the percentage and capacity rather
|
||||
than read off `filterUsage` directly -- `filterUsage` is a percent, not
|
||||
an hour count (issue #330). Returns None when capacity is missing/zero."""
|
||||
pct = filter_usage_percent(rep)
|
||||
cap = _num(rep.get("x.com.samsung.da.filterCapacity"))
|
||||
if used is None or not cap:
|
||||
if pct is None or not cap:
|
||||
return None
|
||||
return round(used / cap * 100)
|
||||
return round(pct / 100 * cap, 1)
|
||||
|
||||
|
||||
def normalize_temp_unit(raw, default="°F"):
|
||||
|
||||
Reference in new issue
Block a user