Skip to content

feat(teslemetry): add custom_command routes and align method names with BLE Commands - #124

Merged
Bre77 merged 3 commits into
mainfrom
fm/pyfleet-teslemetry-command-parity
Aug 15, 2026
Merged

feat(teslemetry): add custom_command routes and align method names with BLE Commands#124
Bre77 merged 3 commits into
mainfrom
fm/pyfleet-teslemetry-command-parity

Conversation

@Bre77

@Bre77 Bre77 commented Aug 15, 2026

Copy link
Copy Markdown
Member

Intent

Bring TeslemetryVehicle/TeslemetryEnergySite to command parity with Teslemetry's API surface, checked against both the live OpenAPI spec and a source-verified, file:line-cited command inventory of Teslemetry's own (private) API repo.

For custom_command/* routes specifically: the live OpenAPI under-publishes them (see discrepancy record below), and the standing decision for this in-house API is that the source-verified inventory outranks the served spec, with the spec gap tracked as a separate defect rather than treated as evidence the routes don't exist.

What Changed

  • Added navigation_waypoints_request to VehicleFleet (tesla_fleet_api/tesla/vehicle/fleet.py) - it already had a signed BLE sibling in Commands but no REST counterpart. Standard vehicle commands are now 66/66.
  • Added 37 custom_command/* methods to TeslemetryVehicle (tesla_fleet_api/teslemetry/vehicle.py), closing the gap identified by the source inventory - set_keep_accessory_power_mode, Cybertruck outlet/power-feed/lightbar/suspension controls, parental controls, unit/display preferences, set_recirculation, auto_secure_vehicle, navigation-to-named-destination, and a few read/query routes (get_nearby_charging_sites, get_rate_tariff, get_charge_on_solar). Each mirrors the field names and semantics of this library's own BLE Commands methods for the same underlying tesla-protocol actions, following existing method-naming/typing/docstring conventions.
  • Post-review: renamed 4 of the new methods (set_front_zone_lights, set_rear_zone_lights, set_recirculation, navigation_gps_destination_request) to match their existing BLE Commands siblings' names exactly, and renamed the new no-arg set_rate_tariff to trigger_rate_tariff_update to avoid colliding with the pre-existing BLE set_rate_tariff(seasons, tariff) of the same name - VehicleRouter dispatches by exact attribute name, so a name or signature mismatch between backends breaks failover for that command. See "Naming fixes" below.
  • Tests: tests/test_teslemetry_vehicle_custom_commands.py (new - one assertion per method on the REST call shape) and a navigation_waypoints_request case in tests/test_cross_transport_parity.py.
  • No refactors, no data-endpoint work, no version bump.

Spec discrepancy record

The live OpenAPI (https://api.teslemetry.com/openapi.json, v2.0.0) publishes only 10 of the 52 custom_command/* routes the source inventory cites from Teslemetry's own API repo (src/routes/api/vehicles/custom_command.ts, file:line-cited per route) - set_keep_accessory_power_mode among the unpublished ones. Verified this wasn't a fetch artifact before treating the spec as incomplete: 6 independent fetches (plain, openapi.yaml, /docs/openapi.json, the na/eu regional mirrors, with a bogus Authorization header, and with a browser User-Agent) all hash-identical (sha256 2b75d593...), plus a case-insensitive full-text search of the spec for accessory/keep/power turning up nothing related.

Coverage: route → library method

Standard vehicle commands — 66/66

Route (command/<name>) Status
All 66, e.g. actuate_trunk, door_lock, set_charge_limit, trigger_homelink, ... pre-existing
navigation_waypoints_request added

Custom signed commands — 47/52 (10 pre-existing, 37 added, 5 excluded)

Route (custom_command/<name>) Status
closure, seat_heater, charge_on_solar [POST], dashcam_save, ping, play_video, stop_light_show, start_light_show, clear_pin_to_drive, remove_key pre-existing
get_charge_on_solar [GET, public] added
set_front_zone_lights (route front_zone_light), set_rear_zone_lights (route rear_zone_light), set_outlets, set_outlet_soc_limit, set_power_feed, set_power_feed_soc_limit, set_lightbar_brightness, set_lightbar_middle, set_lightbar_ditch, set_trailer_light_test, set_truck_bed_light_auto, set_truck_bed_light_brightness, set_powershare_feature, set_powershare_request, set_powershare_discharge_limit, set_recirculation (route hvac_recirculation), set_tent_mode, set_suspension_level, set_low_power_mode, set_keep_accessory_power_mode, set_temperature_unit, set_distance_unit, set_time_display_format, set_tire_pressure_unit, set_energy_display_format, parental_controls, parental_controls_clear_pin, parental_controls_clear_pin_admin, parental_controls_enable_setting, parental_controls_set_speed_limit, navigation_gps_destination_request (route navigation_gps_destination), auto_secure_vehicle, cancel_soh_test, get_nearby_charging_sites, get_rate_tariff, trigger_rate_tariff_update (route set_rate_tariff) added (37 total)
set_discharge_limit, set_outlet_timer, set_power_feed_timer, batch_remove_charge_schedules, batch_remove_precondition_schedules, drivenote excluded, see below

Special vehicle endpoints — 2/2

wake_up, signed_command — pre-existing.

Energy site commands (public) — 6/7

backup, grid_import_export, off_grid_vehicle_charging_reserve, operation, storm_mode, time_of_use_settings — pre-existing. vehicle_charging_settings — excluded, see below.

Naming fixes (post-review)

Codex's review flagged that VehicleRouter dispatches by exact Python attribute name across backends, so a name or signature mismatch between the BLE and Teslemetry implementations of the "same" command silently breaks failover instead of raising a clear error. Since these are all new, unpublished methods, the new (Teslemetry) side was renamed to match in every case:

Route (custom_command/<name>) Old method name New method name Reason
front_zone_light front_zone_light set_front_zone_lights match BLE Commands.set_front_zone_lights
rear_zone_light rear_zone_light set_rear_zone_lights match BLE Commands.set_rear_zone_lights
hvac_recirculation hvac_recirculation set_recirculation match BLE Commands.set_recirculation
navigation_gps_destination navigation_gps_destination navigation_gps_destination_request match BLE Commands.navigation_gps_destination_request
set_rate_tariff set_rate_tariff trigger_rate_tariff_update BLE Commands.set_rate_tariff(seasons, tariff) is a pre-existing, published method with a required nested-schedule signature; a same-named, payload-free method here would raise TypeError if VehicleRouter failover forwarded those arguments to it, so this one keeps its own name instead

REST paths are unchanged - only the Python method names moved, so this doesn't touch the wire contract.

Exclusions, with reasons

  • set_discharge_limit - the inventory itself flags this hidden pending firmware validation; no confirmed schema to implement against.
  • set_outlet_timer, set_power_feed_timer - marked [UNTESTED] in Teslemetry's own source per the inventory.
  • batch_remove_charge_schedules, batch_remove_precondition_schedules - VehicleFleet already has methods of these exact names at the standard command/ path; a same-named custom_command/* method would collide/override rather than add coverage.
  • drivenote - VehicleFleet.take_drivenote() already covers this at the standard command/take_drivenote path; same collision concern.
  • vehicle_charging_settings (energy) - not in the public OpenAPI, and the inventory calls it an undocumented raw passthrough with no schema.
  • Energy-device gRPC-envelope family (system_info, networking_status, authorized_clients, signed_commands_public_key, device_cert, wifi_scan, schedule_backup_event, cancel_backup_event, set_local_site_config, set_island_mode, add_authorized_client, remove_authorized_client, generic command) - out of scope for this PR.

Uncertainty flagged for review

Request-body field names for the 37 added custom_command/* methods are inferred from the matching BLE Commands proto field names, following the one confirmed shape (set_keep_accessory_power_mode's {on: bool}) rather than a raw 1:1 proto-field mapping - both transports build on the same tesla-protocol actions, but the REST body key names aren't independently confirmed against Teslemetry's documentation (unpublished for these routes). trigger_rate_tariff_update takes no arguments: Teslemetry's own backend forwards an empty request object for this route today regardless of caller input, so it's implemented as a trigger rather than a speculative nested-schema setter.

Risk Assessment

✅ Low: additive command-parity PR - a new REST method with a verified BLE-sibling field match, and 37 new Teslemetry custom_command/* methods whose field names/paths were cross-checked against the equivalent BLE Commands implementations. Exclusions were verified correct against existing code. No version bump, no refactors, and tests pin the exact request shape for every new method.

Testing

Ran the new and pre-existing targeted test files (48 tests) covering all 37 new custom_command/* TeslemetryVehicle methods and the new navigation_waypoints_request REST↔BLE parity case — all passed; the pre-existing proto coverage lock test also still passes. Manually verified via a mocked-request CLI transcript that the motivating set_keep_accessory_power_mode call and the new navigation_waypoints_request REST command each produce the exact method/path/JSON body described above, and confirmed by grep that the 5 explicitly excluded routes are not present in TeslemetryVehicle.

Evidence: request-shape transcript, post-rename
set_keep_accessory_power_mode: call(<Method.POST: 'POST'>, 'api/1/vehicles/5YJ3E1EA1JF000001/custom_command/set_keep_accessory_power_mode', json={'on': True})
set_front_zone_lights: call(<Method.POST: 'POST'>, 'api/1/vehicles/5YJ3E1EA1JF000001/custom_command/front_zone_light', json={'level': 2})
set_recirculation: call(<Method.POST: 'POST'>, 'api/1/vehicles/5YJ3E1EA1JF000001/custom_command/hvac_recirculation', json={'on': True})
navigation_gps_destination_request: call(<Method.POST: 'POST'>, 'api/1/vehicles/5YJ3E1EA1JF000001/custom_command/navigation_gps_destination', json={'lat': 37.323, 'lon': -122.0322, 'destination': 'Tesla HQ', 'order': 1})
trigger_rate_tariff_update: call(<Method.POST: 'POST'>, 'api/1/vehicles/5YJ3E1EA1JF000001/custom_command/set_rate_tariff')
navigation_waypoints_request (VehicleFleet): call(<Method.POST: 'POST'>, 'api/1/vehicles/5YJ3E1EA1JF000001/command/navigation_waypoints_request', json={'waypoints': '47.6062,-122.3321;47.7,-122.2'})

Confirms the renamed methods still hit the unchanged REST paths, and that trigger_rate_tariff_update takes no arguments (no TypeError risk from a VehicleRouter failover call carrying seasons/tariff).

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_teslemetry_vehicle_custom_commands.py tests/test_cross_transport_parity.py -v
  • uv run pytest tests/test_proto_coverage_lock.py -q
  • grep -c for '^\+ async def ' in the vehicle.py diff to confirm exactly 37 new custom_command/* methods were added
  • grep for batch_remove_charge_schedules/batch_remove_precondition_schedules/set_discharge_limit/set_outlet_timer/set_power_feed_timer to confirm the 5 stated exclusions are genuinely absent from TeslemetryVehicle
  • Manual CLI transcript exercising set_keep_accessory_power_mode, navigation_waypoints_request, and set_suspension_level against a mocked _request to confirm exact HTTP method/path/JSON body sent
✅ **Document** - passed

✅ No issues found.

✅ **Lint** - passed

✅ No issues found.

✅ **Push** - passed

✅ No issues found.

@Bre77 Bre77 added the fm Opened by a Firstmate crewmate label Aug 15, 2026

@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: e4f4cba939

ℹ️ 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 thread tesla_fleet_api/teslemetry/vehicle.py Outdated
Comment thread tesla_fleet_api/teslemetry/vehicle.py Outdated
@Bre77
Bre77 marked this pull request as draft August 15, 2026 09:31
Bre77 added 3 commits August 15, 2026 19:36
Closes the one real gap found auditing TeslemetryVehicle against the
live Teslemetry OpenAPI spec: navigation_waypoints_request already had
a signed BLE sibling but no REST counterpart. Every other route the
audit flagged as missing (52 custom_command/* routes, one energy
route, the energy gRPC-envelope family) isn't in the published
OpenAPI, so it's out of scope for this library.
…tory

The published Teslemetry OpenAPI under-publishes custom_command/* -
only 10 of 52 routes a source-verified, file:line-cited inventory of
Teslemetry's own API repo confirms exist, set_keep_accessory_power_mode
among the unpublished ones. Verified this wasn't a fetch artifact (6
independent fetches, all hash-identical, plus a full-text search of the
spec) before treating the served spec's gap as a defect to file
separately rather than a signal these routes don't exist.

Adds the 37 routes the inventory confirms and this class doesn't yet
cover, mirroring the field names and semantics of the equivalent BLE
Commands methods (same underlying tesla-protocol actions). Excludes
5 routes: 3 the inventory itself flags as unverified/hidden, and 2
that would collide with pre-existing VehicleFleet methods of the same
name at a different path.
…siblings

VehicleRouter dispatches by exact attribute name across backends, so a
name or signature mismatch between the BLE and Teslemetry
implementations of the same command silently breaks failover instead
of raising a clear error.

Renames the new (unpublished) Teslemetry side to match its BLE
Commands sibling in every case: front_zone_light -> set_front_zone_lights,
rear_zone_light -> set_rear_zone_lights, hvac_recirculation ->
set_recirculation, navigation_gps_destination ->
navigation_gps_destination_request. set_rate_tariff is instead renamed
to trigger_rate_tariff_update, since the BLE side already has a
published set_rate_tariff(seasons, tariff) with a required nested
schedule - keeping that name here with no arguments would raise
TypeError on a failed-over call. REST paths are unchanged.
@Bre77
Bre77 force-pushed the fm/pyfleet-teslemetry-command-parity branch from e4f4cba to 18880ff Compare August 15, 2026 09:39
@Bre77 Bre77 changed the title feat(teslemetry): add custom_command routes and navigation_waypoints_request for command parity feat(teslemetry): add custom_command routes and align method names with BLE Commands Aug 15, 2026
@Bre77
Bre77 marked this pull request as ready for review August 15, 2026 09:41
@Bre77
Bre77 merged commit 16ef230 into main Aug 15, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

fm Opened by a Firstmate crewmate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant