Skip to content

feat: accept externally sourced events via TeslemetryStream.ingest - #41

Merged
Bre77 merged 1 commit into
mainfrom
fm/funnel-stream-ingest
Aug 26, 2026
Merged

feat: accept externally sourced events via TeslemetryStream.ingest#41
Bre77 merged 1 commit into
mainfrom
fm/funnel-stream-ingest

Conversation

@Bre77

@Bre77 Bre77 commented Aug 26, 2026

Copy link
Copy Markdown
Member

Intent

  • Observations about a vehicle can arrive from somewhere other than the SSE connection - a Bluetooth broadcast read locally is the case in hand - and there was no way to hand one to this library. A consumer holding both sources had to run a second, differently shaped subscription alongside its listen_* callbacks and merge the two itself.
    • Added TeslemetryStream.ingest(data, vin, metadata, created_at), plus TeslemetryStreamVehicle.ingest as the same call with the VIN filled in. It builds the event in the wire format the connection already sends (vin/data/createdAt) and fans it out through the same dispatch, so existing listen_* callbacks receive it untranslated. It holds no client and opens no connection: an observation is delivered whether or not the stream is connected, which is the point when the other source is a local radio.
    • metadata is a plain dict carried on the event and never acted on - source keeps provenance visible, raw keeps the untranslated wire value a boolean collapse discards (any unlocked state reads as unlocked, but which one is still worth having). Metadata in const.py names both, and the dict stays open ended so a source can add keys without a format break.
    • Ordering and deduplication are deliberate: every event, native or ingested, is dispatched in arrival order exactly as given, and the stream keeps no per-field value to compare against. Two sources reporting one field therefore call listeners twice, later report last, neither dropped. There is deliberately no source ranking, precedence, or preferred source - which report to believe is the consumer's decision, made on metadata.
    • listen()'s per-event dispatch moved unchanged into _dispatch() so both paths share it. Native events are otherwise untouched, which is the first thing tests/test_external_ingest.py asserts, along with a BLE-shaped and a stream-shaped event for the same field being indistinguishable to a consumer apart from metadata.
  • Nothing here depends on tesla-fleet-api, in either direction. The shim that shapes a VCSEC broadcast into this format belongs there, and the consumer wires the two together - the same duck-typed composition EnergySiteRouter already uses for aiopowerwall.

Worth noting for later, not encoded here: a real-vehicle run has Bluetooth leading the stream on every lock transition by ~1s, because the stream emits on a ~1Hz aligned tick rather than because of network latency. That is an argument a precedence rule could be justified one day; it is a separate decision, and this surface takes no position on it.

Ran uv run --with ruff ruff check teslemetry_stream and uv run --with mypy mypy teslemetry_stream clean, and every tests/test_*.py script directly.

An observation the library did not read off its own SSE connection - a
Bluetooth broadcast, today - can now be handed in as a stream-shaped dict
and reaches the same listeners a native event does, with no translation
and no second subscription.

Events carry an open-ended metadata dict (source, raw) that is recorded
but never acted on: dispatch stays arrival-ordered with no per-field
state, no deduplication, and no source ranking.
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@Bre77
Bre77 merged commit 098c67e into main Aug 26, 2026
14 checks passed
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.

1 participant