feat(ble): add BleBroadcastStreamGlue for teslemetry-stream ingest() - #139
Merged
Merged
Conversation
Feeds VCSEC broadcast listeners (lock state, charge port, front trunk) into any duck-typed sink shaped like python-teslemetry-stream's ingest(data, metadata) - no import of teslemetry_stream, same structural-Protocol pattern EnergySiteRouter uses for aiopowerwall. Promotes funnel.py's LOCK_STATES/CLOSURE_STATES decode maps to module-level so the glue can reuse them without a pyright reportPrivateUsage violation.
…ehavioral tomllib assertions
Bre77
commented
Aug 28, 2026
Co-authored-by: Brett Adams <Bre77@users.noreply.github.com>
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
Build BleBroadcastStreamGlue in python-tesla-fleet-api, per the approved design report (captain approved 2026-08-28). Takes BLE broadcast observations from the existing broadcast listener (tesla_fleet_api/tesla/vehicle/broadcast.py) and publishes them into teslemetry-stream's already-shipped ingest() surface, so BLE observations reach the same stream listeners a native SSE event does, with no translation and no second subscription.
Hard design constraints from the approved report:
What was built:
Explicitly out of scope (a separate parked task): the BLE-POLLED "Merge" class that merges polled BLE data with cloud vehicle_data - this PR is broadcasts-only. The HA integration migration that consumes this glue is a separate follow-on task.
Full test suite (749 tests), ruff check, ruff format, and pyright strict all pass locally.
What Changed
BleBroadcastStreamGlue(tesla_fleet_api/tesla/vehicle/stream_glue.py) which wires the existinglisten_vehicle_lock_state/listen_charge_port/listen_front_trunkbroadcast listeners to a duck-typedStreamSink(ingest(data, metadata=None)), so BLE broadcasts push into ateslemetry-streamsink in the same shape a native SSE event would, tagged withmetadata={"source": "bluetooth", "raw": <proto enum name>}; includes an idempotentstop()lifecycle method and no import ofteslemetry_stream.LOCK_STATES/CLOSURE_STATESintesla_fleet_api/funnel.pyfrom module-private to module-level sostream_glue.pycan reuse the same decode maps (visibility rename only, no behavior change); exportBleBroadcastStreamGluefromtesla_fleet_api/__init__.py.tests/test_ble_stream_glue.pycovering broadcast-to-ingest()translation for all three fields, ambiguous/absent states producing no call, the no-import/duck-typed contract, andstop()/idempotency; document the new glue indocs/bluetooth_vehicles.mdandAGENTS.md.Risk Assessment
✅ Low: The change matches the approved design exactly (duck-typed StreamSink Protocol, no teslemetry_stream import, zero new dependency, correct translation logic reusing funnel.py's decode maps), both prior test-quality findings were properly fixed with genuine behavioral assertions (sys.modules check, tomllib-based semantic parse), and no other functional or structural issues were found in the implementation, exports, or docs.
Testing
Ran the focused test_ble_stream_glue.py suite plus the funnel/broadcast-listener tests it depends on — all 67 tests pass, and manual diff inspection confirms both flagged AST/substring test-quality issues were replaced with genuine behavioral assertions (sys.modules check after exercising the glue; tomllib-parsed dependency list check) as decided in review round 1.
Pipeline
Updates from git push no-mistakes
✅ **intent** - passed
✅ No issues found.
✅ **Rebase** - passed
✅ No issues found.
tests/test_ble_stream_glue.py:238-test_module_source_never_references_teslemetry_streamproves nothing about runtime behavior: it callsinspect.getsourceonstream_glueand walks the parsed AST forImport/ImportFromnodes namingteslemetry_stream. This is a source-content-only assertion (an AST-shape check) — a behavior-preserving refactor (e.g. a differently-shaped conditional import, or an import hidden inside a string built dynamically) could dodge the exact AST pattern checked while a legitimate rewrite that changes unrelated code structure could break it for no behavioral reason. A behavioral replacement is available and cheap: assert'teslemetry_stream' not in sys.modulesafter importing and exercisingstream_glue, which proves the module was never actually imported rather than that its source text happens not to contain an import statement matching a string.tests/test_ble_stream_glue.py:270-test_zero_net_new_dependencyreadspyproject.tomlas raw text and doesassertNotIn("teslemetry-stream", text)/assertNotIn("teslemetry_stream", text). This is exactly the anti-pattern the test-quality rule calls out for machine-consumed declarative config: a raw substring search over the file rather than parsing it into a semantic model. It would false-negative on a match hiding in an unrelated comment/URL, and false-positive-pass if the string appeared only in, say, a# see teslemetry_streamcomment while a real dependency was actually added under a different alias. Parse withtomlliband assert the string is absent from the actualproject.dependencies(and[tool.uv.sources]/optional-dependencies as applicable) list instead.🔧 Fix: Replace AST/substring test-quality checks with behavioral tomllib assertions
1 info still open:
tests/test_ble_stream_glue.py:273-_names()'s dependency-spec parser only strips>=and==operators before comparing names. A dependency spec using another PEP 508 operator (~=,<=,<,>,!=) or an extras marker (pkg[extra]) would leave the operator/version attached to the parsed name, soassertNotIn("teslemetry-stream", dependency_names)would still pass even if such a spec were added, since the set element would be the unparsed string rather than the bare name. Minor gap in an otherwise fixed semantic-parse test; not a blocker.✅ **Test** - passed
✅ No issues found.
uv run pytest tests/test_ble_stream_glue.py -v(12 passed)uv run pytest tests/test_funnel.py tests/test_ble_broadcast_listeners.py -q(55 passed) — sanity check on funnel.py's LOCK_STATES/CLOSURE_STATES visibility rename that stream_glue.py depends onmanual diff review ofgit show HEAD -- tests/test_ble_stream_glue.pyconfirming the AST/inspect-based check was replaced with a behavioralassertNotIn("teslemetry_stream", sys.modules)around realBleBroadcastStreamGlueusage, and the raw-text pyproject.toml substring check was replaced with atomllib.loadparse checked against actual dependency/source name setsconfirmed the now-unusedfrom tesla_fleet_api.tesla.vehicle import stream_gluemodule import was removed alongside the AST check that used it✅ **Document** - passed
✅ No issues found.
✅ **Lint** - passed
✅ No issues found.
✅ **Push** - passed
✅ No issues found.