Measured on a real installation with two bikes: the two "Last Seen"
sensors were the number one and number two writers in the entire Home
Assistant database, ahead of a three-phase energy meter. The integration
accounted for 26.5% of all recorder writes on that system.
Last Seen moved on every BLE notification, about once a second, or 2834
rows an hour per bike. The entity exists to say how fresh the values are,
which needs nothing near that resolution, so it now advances at
LAST_SEEN_RESOLUTION granularity. `self._last_seen` stays exact - that is
what gets persisted and restored - only the entity is throttled. Measured
after: 120 rows an hour, the theoretical maximum for a 30s window.
The distance sensors carried four decimals of false precision, because
the ebikemotion frames divide by 10000: a range that is really "14.6" was
reported as 14.6065, then 14.6529, then 14.6297, each one another state
write and another database row. They are rounded to 0.1 km now.
Home Assistant offers integrations no way to exclude an entity from the
recorder - `entity_filter` comes from user configuration only, and
`_unrecorded_attributes` covers attributes rather than states - so
reducing how often the state changes is the only fix that works without
asking every user to edit configuration.yaml.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FyabWZzd7HoLpyBwEa5Zzh
Setup no longer depends on the bike being reachable. The coordinator is
built from an address and resolves the BLEDevice per connect attempt, so
a parked or switched-off bike loads the entry instead of raising
ConfigEntryNotReady and leaving every entity unavailable.
Parser state is persisted through helpers.storage.Store and restored
before the platforms are set up, so entities carry their last values and
the VIN on their first state write. What survives is a whitelist:
battery and EBM counters yes, motor and assist no - a restored speed
reading is indistinguishable from live data on a parked bike. The
connection switch position is restored too, so a restart no longer wakes
a bike the user deliberately disconnected.
Also fixes three defects found while building this:
- Store.async_delay_save debounces rather than throttles, so re-arming on
every notification postponed the write for as long as the bike stayed
connected and nothing reached disk except on a clean shutdown.
- establish_connection had no disconnected_callback, so a dropped link
left _is_connected True: the connectivity sensor lied and the poll
never retried.
- _connect read self._client back across the 200ms handshake, which a
concurrent teardown could clear underneath it.
Connecting now starts on the bike's advertisement instead of the next
poll tick, and an unreachable bike says why - distinguishing "switched
off" from "seen only by a passive proxy that cannot connect".
Renames the connection switch to Auto-connect and drops the hardcoded
English name on the connectivity sensor, which had been defeating its
translation key.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FyabWZzd7HoLpyBwEa5Zzh