feat(teslemetry): add custom_command routes and align method names with BLE Commands - #124
Merged
Merged
Conversation
There was a problem hiding this comment.
💡 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".
Bre77
marked this pull request as draft
August 15, 2026 09:31
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
force-pushed
the
fm/pyfleet-teslemetry-command-parity
branch
from
August 15, 2026 09:39
e4f4cba to
18880ff
Compare
Bre77
marked this pull request as ready for review
August 15, 2026 09:41
This was referenced Aug 15, 2026
Merged
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
Bring
TeslemetryVehicle/TeslemetryEnergySiteto 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
navigation_waypoints_requesttoVehicleFleet(tesla_fleet_api/tesla/vehicle/fleet.py) - it already had a signed BLE sibling inCommandsbut no REST counterpart. Standard vehicle commands are now 66/66.custom_command/*methods toTeslemetryVehicle(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 BLECommandsmethods for the same underlyingtesla-protocolactions, following existing method-naming/typing/docstring conventions.set_front_zone_lights,set_rear_zone_lights,set_recirculation,navigation_gps_destination_request) to match their existing BLECommandssiblings' names exactly, and renamed the new no-argset_rate_tarifftotrigger_rate_tariff_updateto avoid colliding with the pre-existing BLEset_rate_tariff(seasons, tariff)of the same name -VehicleRouterdispatches by exact attribute name, so a name or signature mismatch between backends breaks failover for that command. See "Naming fixes" below.tests/test_teslemetry_vehicle_custom_commands.py(new - one assertion per method on the REST call shape) and anavigation_waypoints_requestcase intests/test_cross_transport_parity.py.Spec discrepancy record
The live OpenAPI (
https://api.teslemetry.com/openapi.json, v2.0.0) publishes only 10 of the 52custom_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_modeamong 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, thena/euregional mirrors, with a bogusAuthorizationheader, and with a browser User-Agent) all hash-identical (sha2562b75d593...), plus a case-insensitive full-text search of the spec foraccessory/keep/powerturning up nothing related.Coverage: route → library method
Standard vehicle commands — 66/66
command/<name>)actuate_trunk,door_lock,set_charge_limit,trigger_homelink, ...navigation_waypoints_requestCustom signed commands — 47/52 (10 pre-existing, 37 added, 5 excluded)
custom_command/<name>)closure,seat_heater,charge_on_solar[POST],dashcam_save,ping,play_video,stop_light_show,start_light_show,clear_pin_to_drive,remove_keyget_charge_on_solar[GET, public]set_front_zone_lights(routefront_zone_light),set_rear_zone_lights(routerear_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(routehvac_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(routenavigation_gps_destination),auto_secure_vehicle,cancel_soh_test,get_nearby_charging_sites,get_rate_tariff,trigger_rate_tariff_update(routeset_rate_tariff)set_discharge_limit,set_outlet_timer,set_power_feed_timer,batch_remove_charge_schedules,batch_remove_precondition_schedules,drivenoteSpecial 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
VehicleRouterdispatches 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:custom_command/<name>)front_zone_lightfront_zone_lightset_front_zone_lightsCommands.set_front_zone_lightsrear_zone_lightrear_zone_lightset_rear_zone_lightsCommands.set_rear_zone_lightshvac_recirculationhvac_recirculationset_recirculationCommands.set_recirculationnavigation_gps_destinationnavigation_gps_destinationnavigation_gps_destination_requestCommands.navigation_gps_destination_requestset_rate_tariffset_rate_tarifftrigger_rate_tariff_updateCommands.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 raiseTypeErrorifVehicleRouterfailover forwarded those arguments to it, so this one keeps its own name insteadREST 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-VehicleFleetalready has methods of these exact names at the standardcommand/path; a same-namedcustom_command/*method would collide/override rather than add coverage.drivenote-VehicleFleet.take_drivenote()already covers this at the standardcommand/take_drivenotepath; same collision concern.vehicle_charging_settings(energy) - not in the public OpenAPI, and the inventory calls it an undocumented raw passthrough with no schema.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, genericcommand) - 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 BLECommandsproto 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 sametesla-protocolactions, but the REST body key names aren't independently confirmed against Teslemetry's documentation (unpublished for these routes).trigger_rate_tariff_updatetakes 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 BLECommandsimplementations. 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/*TeslemetryVehiclemethods and the newnavigation_waypoints_requestREST↔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 motivatingset_keep_accessory_power_modecall and the newnavigation_waypoints_requestREST command each produce the exact method/path/JSON body described above, and confirmed by grep that the 5 explicitly excluded routes are not present inTeslemetryVehicle.Evidence: request-shape transcript, post-rename
Confirms the renamed methods still hit the unchanged REST paths, and that
trigger_rate_tariff_updatetakes no arguments (noTypeErrorrisk from aVehicleRouterfailover call carryingseasons/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 -vuv run pytest tests/test_proto_coverage_lock.py -qgrep -c for '^\+ async def ' in the vehicle.py diff to confirm exactly 37 new custom_command/* methods were addedgrep 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 TeslemetryVehicleManual 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.