Skip to content

Log connection events and signal strength in the BLE envelope - #154

Merged
dzid26 merged 2 commits into
mainfrom
work/link-events-rssi
Oct 8, 2026
Merged

dzid26 merged 2 commits into
mainfrom
work/link-events-rssi

Conversation

@dzid26

@dzid26 dzid26 commented Oct 8, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Follows #148 and #149 (the BleRecord envelope). Owner direction, 2026-10-08: "We should log connection state as well. Could be added to the envelope, together with RSSI?" No tracking issue.

  • RSSI on every record. BleRecord.rssi (5, optional sint32, in dBm) is the phone's latest RSSI for the car when the record was acquired, absent when unknown. The controller passes the value it already holds for the car (latestRssi(address)) into each HistoryStore call: status, charge, drive and connection.
  • Connection events. New payload connection_event (6, first in the oneof): ConnectionEvent.State CONNECTED when a connection becomes ready (where firstStatusAfterConnect resets) and DISCONNECTED when a connection that had become ready ends. They go to <vehicleId>.connection.pblog through VehicleLogs; acquired_at is the event time and rssi the last RSSI before it. A connection attempt that never became ready logs nothing, so a car out of range does not spam the log. Log only: no read model or UI.
  • Held-back status flush removed. StatusLogGate, its test and HistoryStore.onLinkLost are gone: DISCONNECTED marks when watching ended, and the last logged status holds until then. shouldLogStatus is unchanged; HistoryStore keeps a plain last-logged map, seeded on load as before.
  • ADR-0008, PRIVACY.md and the master plan are updated.

Review notes:

  • DISCONNECTED is also written when the app itself closes a ready connection (tracking switched off, a car that moved to a new address), which is why it is not called "lost". A killed app writes nothing, so a CONNECTED after a CONNECTED means an unclean end.
  • On connect the RSSI can be the advert's or the previous connection's last reading, since the controller polls it every 10 s. The ADR says so.
  • VehicleLink sits 2 lines under detekt's LargeClass cap (700), so the helpers (latestRssi, recordConnection) live next to updateConnection, and the recordStatus call stays compact.
  • HistoryStore reads the connection files on load only to refresh the record counts its 20k cap trims by; without it the cap would not hold across restarts.
  • The "newer payload kind" test used field 5, which rssi now owns; it uses field 7.
  • Names follow the owner's renames of 2026-10-08 (rssi_dbm to rssi, link to connection, LOST to DISCONNECTED). Field numbers and types are unchanged, and a unit test pins the wire tags.

Type

  • Bug fix
  • Feature
  • Protocol / crypto change
  • Docs / CI / tooling
  • Refactor (no behavior change)

Testing

  • ./gradlew :core:test (174 tests)
  • ./gradlew :app:testDebugUnitTest
  • ./gradlew :app:lintDebug
  • Real car: not done. The connection file should gain a record on each connect and each disconnect.

Also green: :app:assembleDebug, ktlintCheck, detekt (one run of the full command on the final commit).

New core tests in BleRecordMappingTest: the wire tags for fields 5 and 6 plus the ConnectionEvent state numbers; a ProtoLog round trip with connection events and rssi; a record without rssi reads it as absent (and 0 dBm stays 0).

HistoryStore and the controller wiring have no unit tests (they need an Android Context). I drove HistoryStore with a throwaway JVM harness, not committed, run on the final code: connection and status records land in the right files with the right RSSI, the status policy holds across a restart, and the 20k cap holds across restarts (that test fails without the load-time count refresh). The controller change is read-reviewed only; there is no emulator or car here.

Checklist

  • Protocol changes ship test vectors; expected.txt regenerated, not hand-edited (n/a: our own log envelope, not Tesla's protocol; a unit test pins the wire tags)
  • No VINs, keys, or decrypted payloads in logs
  • Docs/master-plan updated where relevant
  • New source files carry SPDX-License-Identifier: AGPL-3.0-only (no new source files)

🤖 Generated with Claude Code

https://claude.ai/code/session_0129RzhbEE2cboMcYyZMuxqX

Owner direction (2026-10-08): log the connection state as well, in the
envelope, together with the RSSI.

- BleRecord gains rssi_dbm (5, optional sint32): the phone's latest RSSI for
  the car when the record was acquired, absent when unknown. The controller
  passes the value it already holds for the car into every HistoryStore
  record call, so status, charge, drive and link records all carry it.
- New payload kind link_event (6, first in the oneof): LinkEvent.State
  CONNECTED when a link becomes ready and LOST when a link that had become
  ready ends. They go to <vehicleId>.link.pblog through VehicleLogs, with
  acquired_at as the event time and rssi_dbm as the last RSSI before it. A
  connection attempt that never became ready logs nothing, so a car out of
  range does not spam the log. LOST is also written when the app itself closes
  a ready link (tracking switched off, a car that moved to a new address); a
  killed app writes nothing. Log only: no read model or UI.
- The held-back status flush is gone: StatusLogGate, its test and
  HistoryStore.onLinkLost are removed. A LOST event marks when watching ended,
  and the last logged status holds until then. shouldLogStatus is unchanged;
  HistoryStore keeps a plain last-logged map, seeded on load as before.
- HistoryStore reads the link files on load only to refresh the record counts
  its 20k cap trims by, as it does for the other kinds; without it the cap
  would not hold across restarts.
- VehicleLink sits two lines under detekt's LargeClass cap, so the RSSI and
  link helpers live next to updateConnection in the controller, and the
  recordStatus call is a one-liner like the other two record calls.

The wire-order test pins tags 5 and 6, a ProtoLog round trip covers link
events with rssi_dbm, and a record without rssi_dbm reads it as absent. The
newer-payload test moves to field 7, since field 5 is now taken.

ADR-0008, PRIVACY.md and the master plan record the change.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0129RzhbEE2cboMcYyZMuxqX
@github-actions

github-actions Bot commented Oct 8, 2026

Copy link
Copy Markdown
Contributor

Screenshots

App screenshots: light and dark

Captured from the demo build at a8b5abb.

Debug APK: zip from Android CI (GitHub sign-in needed)

Owner renames for #154, asked for on 2026-10-08 before it merges. Field
numbers and types do not change, so the wire format is the same.

- BleRecord.rssi_dbm becomes rssi (still field 5, optional sint32; the proto
  comment says the value is in dBm). The Kotlin parameters are rssi, and the
  controller helper is latestRssi(address).
- "link" becomes "connection": LinkEvent is ConnectionEvent, link_event is
  connection_event (still field 6), <vehicleId>.link.pblog is
  <vehicleId>.connection.pblog, and recordLink is recordConnection in the
  controller and in HistoryStore. VehicleLink and ConnectionPhase keep their
  names.
- LinkEvent.State.LOST becomes ConnectionEvent.State.DISCONNECTED (still 2):
  the event is also logged when the app closes the connection itself, so
  "lost" was the wrong word. CONNECTED is unchanged.

The recordStatus call takes latestRssi(address) through a local, and the test
fixtures share connected/disconnected values, so no line passes 140 columns.
ADR-0008, PRIVACY.md and the master plan use the new names.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0129RzhbEE2cboMcYyZMuxqX
@dzid26 dzid26 changed the title Log link events and signal strength in the BLE envelope Log connection events and signal strength in the BLE envelope Oct 8, 2026
@github-actions

github-actions Bot commented Oct 8, 2026

Copy link
Copy Markdown
Contributor

Screenshots

App screenshots: light and dark

Captured from the demo build at efacbeb.

Debug APK: zip from Android CI (GitHub sign-in needed)

@dzid26
dzid26 merged commit 3fb8814 into main Oct 8, 2026
5 checks passed
@dzid26
dzid26 deleted the work/link-events-rssi branch October 8, 2026 14:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants