Stabilise the uptime sensor timestamp between polls - #148
Open
shauneccles wants to merge 2 commits into
Open
Conversation
The router reports uptime as a seconds counter, so the boot timestamp is derived as `now - uptime`. native_value recomputed this live on every read, but Home Assistant polls the sensor on its own schedule, decoupled from the router's 30s system-status refresh. Between refreshes the uptime value is frozen while utcnow() advances, so the derived boot time drifts forward on each read until it crosses the 15s deviation tolerance and re-anchors -- emitting a stream of spurious state changes whenever the jump crosses a minute boundary. Recompute only when the router reports a fresh uptime value, and gate the committed timestamp with a deviation tolerance, mirroring core's UniFi integration (value_fn + value_changed_fn, 120s). Switch to dt_util and store the result in _attr_native_value. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Open
8 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The Uptime sensor's boot timestamp drifts and flaps instead of staying constant, producing a stream of spurious state changes (and recorder/history churn). This recomputes it stably, aligning the implementation with Home Assistant core's UniFi integration.
Root cause
The router exposes uptime as a seconds counter, so the sensor derives the boot time as
now - uptime. The oldnative_valuerecomputed this live on every property read:But HA polls the sensor on its own schedule, decoupled from the router's 30 s
system_statusrefresh (router.py:async_track_time_interval(self.update_states, SCAN_INTERVAL)). Between refreshes theuptimevalue is frozen whileutcnow()keeps advancing, sonow - uptimedrifts forward on each read. Once the drift exceeds the 15 s deviation tolerance it re-anchors — and whenever that jump lands in a different minute bucket, the displayed timestamp visibly changes.Evidence (from my live HA instance)
sensor.gl_inet_mt6000_uptime— the router has been continuously up since 2026-06-15 ~06:04 UTC, so the boot timestamp should be a flat line. Instead (all times UTC):Flapping across a minute boundary — the same two values alternate every poll:
last_updated)Continuous ramp — when
system_statusgoes stale (e.g. the router is briefly unreachable, which also shows up in the logs below) the frozenuptime+ advancingutcnow()makes the boot time climb 30 s on every 30 s poll:last_updated)Over those ~34 minutes the reported boot time advanced ~21 minutes — while the router never rebooted. Every row above is a separate state change persisted to the recorder.
Corresponding router-unreachable window in
home-assistant.log(the trigger for the stale-data ramp):Fix
uptimevalue — between polls the cached_attr_native_valueis returned unchanged, so it can no longer drift against the clock.UPTIME_DEVIATION), and switched to thedt_utilimport convention.Alignment with core HA patterns
This mirrors how core handles derived uptime timestamps:
now - uptimederivation plus avalue_changed_fntolerance gate (120 s) so the timestamp doesn't flap —unifi/sensor.py(async_client_uptime_value_fn/async_uptime_value_changed_fn). The freshness UniFi gets from event-driven pushes, glinet's polled model gets from theuptime != self._last_uptimeguard.systemmonitor/coordinator.py.Test plan
ruff checkandpy_compilepass.🤖 Generated with Claude Code