Round finish_time to the minute to stop recorder spam
_finish_time added datetime.now(timezone.utc) (fresh seconds/ microseconds every call) to the device's remaining-time duration, so the returned timestamp differed at the sub-minute level on nearly every poll even when remainingTime itself hadn't changed. The recorder logged a new history/logbook entry each time, while the UI rounds the display down to the minute, making repeated polls look like duplicate identical entries. Round the result down to the minute so the entity only changes state when the estimate actually shifts.
This commit is contained in:
1 parent
e99a8a6b05
commit
fe9a1128ea
2 files changed
+36
-1
No files matched your search
@@ -90,7 +90,14 @@ def _finish_time(rep):
|
||||
total_s = _remaining_seconds(rep.get('x.com.samsung.da.remainingTime'))
|
||||
if not total_s:
|
||||
return None
|
||||
return datetime.now(timezone.utc) + timedelta(seconds=total_s)
|
||||
# Round to whole minutes -- remainingTime itself only has minute
|
||||
# resolution, but datetime.now() always carries fresh seconds/
|
||||
# microseconds, so an unrounded result changes on nearly every poll
|
||||
# even when the device-reported remaining time hasn't. That floods
|
||||
# the recorder history/logbook with values that look identical once
|
||||
# the UI rounds them down for display.
|
||||
finish = datetime.now(timezone.utc) + timedelta(seconds=total_s)
|
||||
return finish.replace(second=0, microsecond=0)
|
||||
|
||||
|
||||
def _completion_minutes(rep):
|
||||
|
||||
@@ -62,6 +62,34 @@ class TestCompletionMinutes:
|
||||
assert desc.rep_fn(rep) is None
|
||||
|
||||
|
||||
class TestFinishTime:
|
||||
"""issue: remainingTime only has minute resolution, but datetime.now()
|
||||
always carries fresh seconds/microseconds -- an unrounded finish_time
|
||||
changed on nearly every poll even when remainingTime hadn't, flooding
|
||||
the recorder history/logbook with values that looked identical once
|
||||
the UI rounded them down to the minute for display."""
|
||||
|
||||
def test_seconds_and_microseconds_are_zeroed(self):
|
||||
desc = next(e for e in OPERATIONAL_STATE.entities if e.key == 'finish_time')
|
||||
rep = {
|
||||
'x.com.samsung.da.state': 'Run',
|
||||
'x.com.samsung.da.remainingTime': '00:29:00',
|
||||
}
|
||||
result = desc.rep_fn(rep)
|
||||
assert result.second == 0
|
||||
assert result.microsecond == 0
|
||||
|
||||
def test_stable_across_polls_within_same_minute(self):
|
||||
desc = next(e for e in OPERATIONAL_STATE.entities if e.key == 'finish_time')
|
||||
rep = {
|
||||
'x.com.samsung.da.state': 'Run',
|
||||
'x.com.samsung.da.remainingTime': '00:29:00',
|
||||
}
|
||||
first = desc.rep_fn(rep)
|
||||
second = desc.rep_fn(rep)
|
||||
assert first == second
|
||||
|
||||
|
||||
class TestDelayFieldFallback:
|
||||
def test_reads_delay_end_time_when_delay_start_time_absent(self):
|
||||
from custom_components.localthings.registry.capabilities.operational import OPERATIONAL_STATE
|
||||
|
||||
Reference in new issue
Block a user