Skip to content

feat(teslamate_vehicle): read Tesla charge state from TeslaMate MQTT - #139

Merged
frahlg merged 2 commits into
mainfrom
feat/teslamate-vehicle
Sep 26, 2026
Merged

frahlg merged 2 commits into
mainfrom
feat/teslamate-vehicle

Conversation

@frahlg

@frahlg frahlg commented Sep 26, 2026 •

Copy link
Copy Markdown
Member

Adds teslamate_vehicle, a read-only driver that reads a Tesla's charge state from the owner's TeslaMate MQTT broker. It is one of three vehicle drivers for srcfl/ftw#1442, next to #140 (Tesla Fleet API) and #141 (VW Group).

What it does

  • Subscribes to teslamate/cars/{car_id}/# and emits vehicle (DerVehicle): soc, charge_limit_pct, charging_state, time_to_full_min, charge_amps, charger_actual_current, stale and soc_fresh.
  • Takes the VIN from YAML, because TeslaMate does not publish it. Identity is Tesla plus that VIN.
  • Counts a reading as fresh only when TeslaMate reports the car awake (online, charging, driving, updating) and has just read it: a changed charge field, or the healthy message TeslaMate sends with every update. Retained values from a sleeping car emit nothing at subscribe.
  • Between updates it replays the last reading with soc_fresh=false, so Core ages it from the observation. It stops emitting 15 minutes after the last fresh reading.
  • Never publishes on MQTT, wakes the car or starts a charge. read_only = true, verification_status = "experimental". Leaves tesla_vehicle (BLE proxy) untouched.

Where it came from

A Cursor cloud agent wrote the first commit against main at 92adaf0. The Cursor GitHub App can only reach srcfl/ftw, so its push here failed with 403, and the patch was applied unchanged from Fredrik's machine. The second commit fixes what review found.

Fixed in review

  • Every replay was marked stale=true. Core skips a stale vehicle reading, so the car would have dropped out of Core between two TeslaMate messages. Replays now carry soc_fresh=false only; stale=true is left for when TeslaMate reports itself unhealthy.
  • TeslaMate publishes a topic only when it changes, so a parked, awake car sent nothing and went stale. It does send healthy with every update (not retained; see vehicle_subscriber.ex in TeslaMate), which now counts as a fresh reading while the car is awake.
  • When charging ends, TeslaMate sends an empty time_to_full_charge and charger_actual_current. The old values used to linger; they now clear.
  • starting is not a TeslaMate state and left the awake set.
  • The changelog no longer says FTW never talks to Tesla's cloud, which stops being true if feat(tesla_cloud): read Tesla charge state from the Fleet API #140 merges. The catalog notes say no car has run the driver.

Evidence

  • make test-driver ID=teslamate_vehicle: 38 passed, 14 skipped
  • make check: 4641 passed, 881 skipped
  • Mocks only. No TeslaMate broker or car has run this driver, so support status stays not_recorded.

Still open

  • Relies on TeslaMate sending healthy with every update. That is true in TeslaMate's source today but not documented. If it changes, the driver falls back to fresh-on-change only.
  • While the car sleeps, the driver goes quiet after 15 minutes and FTW shows it offline until the car wakes.
  • Settings still scaffolds vehicles as {ip, vin}, so owners must write the YAML by hand.

How to test

Enable MQTT in TeslaMate (MQTT_HOST), then:

drivers:
  - name: teslamate
    lua: drivers/teslamate_vehicle.lua
    capabilities:
      mqtt:
        host: 192.168.1.10   # TeslaMate's broker
        port: 1883
    config:
      vin: "<your VIN>"
      car_id: 1

After merge the driver is in the signed drivers-beta channel. Until an FTW release bundles it, put the Lua file on the box as a local override at the path the YAML names. Check that the vehicle shows the SoC while the car is awake, and report what happens when it sleeps and wakes.

Merge notes

🤖 Generated with Claude Code

…iver

Optional TeslaMate SoC next to tesla_vehicle (BLE proxy) and tesla_cloud
(Fleet API). Emits DerVehicle, binds Tesla+VIN, ages vendor data, and
never wakes or starts a charge.

Signed-off-by: Cursor Agent <cursoragent@cursor.com>
Every replay was marked stale, so Core dropped the car between two
TeslaMate messages. A replay now carries soc_fresh=false and lets Core
age it; stale=true is left for when TeslaMate reports itself unhealthy.

TeslaMate publishes a topic only when its value changes, but sends
`healthy` with every update. A healthy=true while the car is awake now
counts as a fresh reading of the retained values. An empty
time_to_full_charge or charger_actual_current, which TeslaMate sends
when charging ends, now clears the old value. `starting` is not a
TeslaMate state and leaves the awake set.

The changelog no longer says FTW never talks to Tesla's cloud, which
stops being true once tesla_cloud lands, and the catalog notes say no
car has run the driver yet.

Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@frahlg
frahlg marked this pull request as ready for review September 26, 2026 11:07
@frahlg
frahlg merged commit ebfc591 into main Sep 26, 2026
5 checks passed
@frahlg
frahlg deleted the feat/teslamate-vehicle branch September 26, 2026 11:08
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 26, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-09-26T11:10:41.949176Z 22b417f Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 22b417fe6f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +350 to +351
local err = host.mqtt_subscribe(base_topic .. "/#")
if type(err) == "string" and err ~= "" then

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Handle a false subscription result as failure

When host.mqtt_subscribe rejects the subscription and returns false, this condition treats it as success because it only recognizes nonempty strings. The repository contract in spec/host-api.md states that this API returns true/false, so the driver will misleadingly log that it subscribed and then remain permanently silent because it never retries the failed subscription.

Useful? React with 👍 / 👎.

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