feat(ble): wire 8 more BLE broadcast fields into BleBroadcastStreamGlue - #141
Merged
Merged
Conversation
Extends BleBroadcastStreamGlue from 3 to 11 wired fields: rear trunk,
all 4 side doors, gear, tonneau position, and tonneau open percent -
every BLE-derivable field the current teslemetry-stream 0.13.0 API can
carry. Gear and tonneau position translate through new GEAR_STATES/
TONNEAU_POSITION_STATES maps into the <Prefix><Option>-shaped wire
strings ("ShiftStateP", "TonneauPositionStateClosed") that package's
own TeslemetryEnum-based listeners expect, verified against its actual
installed source rather than guessed.
Vehicle sleep status, user presence, and UI desire stay unwired:
ingest() unconditionally nests its payload under the data (signal-topic)
key of a wire event and has no way to produce a state-topic-shaped
event for sleep status, and user presence/UI desire have no Signal
entry or listener in teslemetry-stream 0.13.0 at all.
Claude-Session: https://claude.ai/code/session_01B6Jgdgk52WL4KWP57hYyyF
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.
Intent
Extend BleBroadcastStreamGlue so every field derivable from a BLE broadcast is glued into teslemetry-stream's ingest() path, per captain's ruling: any field we can derive from a Bluetooth broadcast should be glued into the ingest method for teslemetry stream so local broadcasts and the hundreds-of-fields stream can both be consumed downstream.
Before this change, BleBroadcastStreamGlue wired only 3 of the 14 BLE-derivable fields (lock state, charge port, front trunk). This change wires 8 more (11 total): rear trunk, all 4 side doors (front/rear driver/passenger), gear, tonneau position, and tonneau open percent - all via the DoorState dict leaves and the Gear/TonneauPosition/TonneauOpenPercent Signal names.
I installed the real teslemetry-stream 0.13.0 package into a scratch venv and read its actual TeslemetryStreamVehicle listener source (not the local funnel.py maps) to verify wire shapes rather than guessing:
Three of the 14 fields are deliberately left unwired, each because of a genuine teslemetry-stream API gap rather than something I could work around:
These three should be called out in the PR body as named follow-ups (the specific teslemetry-stream addition each needs), not hacked around with a guessed field name.
I discovered along the way that VCSEC's gear field is a scalar enum with no proto3 presence (like vehicleLockState), so it fires - with GEAR_UNKNOWN as a legitimate reading - on every VCSEC status broadcast, not just gear changes. This matches the existing established pattern for vehicleLockState/vehicleSleepStatus/userPresence in broadcast.py, so I updated the pre-existing (and already slightly stale) AGENTS.md line describing that scalar-field set to also list gear and uiDesire. I updated existing tests in tests/test_ble_stream_glue.py to filter per-field (matching the pattern the charge-port test already used) since Locked and Gear now both fire on most single-field test broadcasts, rather than asserting an exact single-call list. I added new tests for every newly-wired mapping, each citing the exact teslemetry-stream field/Signal name it targets, plus tests for the two unmapped-state cases (ambiguous closures, unmapped tonneau positions).
Full test suite (759 tests), ruff check, ruff format, and pyright strict all pass. Only files touched: tesla_fleet_api/tesla/vehicle/stream_glue.py, tests/test_ble_stream_glue.py, docs/bluetooth_vehicles.md, AGENTS.md.
What Changed
BleBroadcastStreamGlue(tesla_fleet_api/tesla/vehicle/stream_glue.py) now wires 11 of the 14 BLE-derivable broadcast fields intosink.ingest()(up from 3): rear trunk and all 4 side doors via a new shared_ingest_door_state()helper over theDoorStatedict leaves, plus gear and tonneau position/open-percent via newGEAR_STATESandTONNEAU_POSITION_STATESwire-string maps (<Prefix><Option>-shaped strings matching teslemetry-stream's own listener output, e.g."ShiftStateP","TonneauPositionStateClosed");TONNEAU_POSITION_STATESonly maps CLOSED/OPEN/AJAR, leaving OPENING/CLOSING/UNKNOWN/FAILED_UNLATCH unmapped.tests/test_ble_stream_glue.pygains coverage for every newly-wired mapping and the two unmapped-state cases, and switches existing assertions to per-field filtering (matching the prior charge-port test pattern) sinceLockedandGearnow both fire on most single-field test broadcasts.AGENTS.mdanddocs/bluetooth_vehicles.mdare updated to describe the glue's new 11-field coverage, listgear/uiDesirealongside the other no-proto3-presence scalar broadcast fields, and document vehicle sleep status, user presence, and UI desire as fields deliberately left unwired pending specific teslemetry-stream API gaps (nostate-topic-shapedingest()path for sleep status; noSignal/listen_*entry at all for user presence or UI desire in teslemetry-stream 0.13.0).Risk Assessment
✅ Low: The change is a well-bounded, additive extension of an existing glue module; every new field mapping (Gear/TonneauPosition wire strings, DoorState leaf keys) was independently verified against the real installed teslemetry-stream 0.13.0 package source and matches exactly, tests exercise real observable ingest() behavior rather than source-string matching, and the diff introduces no changes to command paths, proto handling, or other higher-risk BLE machinery.
Testing
Ran the targeted
test_ble_stream_glue.py/test_proto_coverage_lock.pysuite (22 tests, all passing) and, since unit tests alone only prove internal consistency against a mocked sink, went further and drove the change end-to-end against the real, unmodifiedteslemetry-stream0.13.0 package installed in a scratch venv — confirming its actuallisten_Gear/listen_TonneauPosition/listen_TonneauOpenPercent/listen_FrontDriverDoor/listen_FrontPassengerDoor/listen_RearDriverDoor/listen_RearPassengerDoorcallbacks correctly decode a real BLE broadcast routed throughBleBroadcastStreamGlue. This also verified the PR's central factual claim (theShiftState/TonneauPositionStatewire-string shapes) directly against the dependency's own source rather than trusting the description. An initial-looking anomaly (per-door DoorState events arriving fragmented, one key at a time) was traced to the real package's own documented no-mergeingest()semantics andbool | None-typed listeners, not a defect in this change. No actionable findings; all scratch/verification artifacts were removed from outside the evidence directory.Evidence: End-to-end verification output against real teslemetry-stream 0.13.0
Values received by REAL teslemetry-stream 0.13.0 listen_* callbacks: ChargePortDoorOpen: [False] FrontDriverDoor: [None, None, False, None, None, None] FrontPassengerDoor: [None, None, None, True, None, None] Gear: ['Unknown', 'D', 'Unknown'] Locked: [False, False, False] RearDriverDoor: [None, None, None, None, False, None] RearPassengerDoor: [None, None, None, None, None, True] TonneauOpenPercent: [37.0] TonneauPosition: ['PartiallyOpen'] ALL ASSERTIONS PASSED against the real teslemetry-stream package.Evidence: End-to-end verification script (drives real teslemetry-stream package)
Pipeline
Updates from git push no-mistakes
✅ **intent** - passed
✅ No issues found.
✅ **Rebase** - passed
✅ No issues found.
✅ **Review** - passed
✅ No issues found.
✅ **Test** - passed
✅ No issues found.
uv run pytest tests/test_ble_stream_glue.py tests/test_proto_coverage_lock.py -v(22 tests, all pass)Installed realteslemetry-stream==0.13.0(matching worktree's Python 3.14 ABI) into a scratch venv and read itsconst.py/vehicle.pyto confirmShiftState/TonneauPositionStateTeslemetryEnum prefixes and option lists exactly match the newGEAR_STATES/TONNEAU_POSITION_STATESmaps instream_glue.pyManual end-to-end script: drove a real VCSEC status broadcast (vehicle._on_message) throughBleBroadcastStreamGlueinto the REAL (unmodified)teslemetry_stream.TeslemetryStream.get_vehicle().ingest(), and asserted the real package's ownlisten_Gear/listen_TonneauPosition/listen_TonneauOpenPercent/listen_FrontDriverDoor/listen_FrontPassengerDoor/listen_RearDriverDoor/listen_RearPassengerDoorcallbacks decoded every newly-wired field to the expected valueReviewed full diff (git diffbase..target) forstream_glue.py,tests/test_ble_stream_glue.py,docs/bluetooth_vehicles.md,AGENTS.mdagainst the stated intent and file scopeConfirmed alllisten_*methods referenced by the new glue code (listen_rear_trunk,listen_front_driver_door, etc.) pre-exist inbroadcast.pyConfirmed working tree is clean after testing (no residual scratch files in the worktree)✅ **Document** - passed
✅ No issues found.
✅ **Lint** - passed
✅ No issues found.
✅ **Push** - passed
✅ No issues found.