fix(ble): verify charging commands over BLE#52
Merged
Conversation
added 2 commits
July 9, 2026 21:13
Live-verified snapshot->act->verify->restore->confirm against the test car (plugged in throughout) for the full charging group: charge_start, charge_stop, charge_standard, charge_max_range, set_charge_limit, set_charging_amps, set_scheduled_charging, set_scheduled_departure, add/remove_charge_schedule, add/remove_precondition_schedule, and the two batch_remove_* commands (exercised with all-False, the only safe live case since they're destructive). The car's six real charge schedules and five real precondition schedules were confirmed present and unchanged before and after every schedule test, and the car ended the session restored exactly to its original charge_limit_soc, charge_current_request, and scheduled_charging_mode. charge_port_door_open/close are excluded from live testing per the charge-cable rule (unlatching a plugged-in cable doesn't re-engage without a physical reseat) and ship mocked-transport-only. Documents three real vehicle-side/library-boundary behaviors found live: charge_standard() rejects "already_standard" rather than no-op succeeding; scheduled_charging_mode is a tri-state shared by both set_scheduled_charging and set_scheduled_departure; and set_scheduled_departure's preconditioning_enabled/off_peak_charging_enabled args are accepted but never wired into the proto. Also documents that TeslaFleetError subclasses BaseException, not Exception, which silently breaks naive `except Exception` retry loops around BLE reads.
5a73655 to
89e2fa4
Compare
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
PR-5 of the BLE production-readiness program: live-verify the charging command group (§1.3 in the master plan) over the VehicleBluetooth signed-command transport, and lock the result with mocked-transport regression tests since the inherited Commands surface had never been exercised over BLE for these methods. Scope: charge_start, charge_stop, charge_standard, charge_max_range, set_charge_limit, set_charging_amps, set_scheduled_charging, set_scheduled_departure, add_charge_schedule, remove_charge_schedule, batch_remove_charge_schedules, add_precondition_schedule, remove_precondition_schedule, batch_remove_precondition_schedules - all live-verified snapshot->act->verify->restore->confirm in a single BLE session against the real test car (VIN LRW3F7EK4NC716336, m5-btproxy proxy), which stayed plugged in throughout per a standing safety rule. charge_port_door_open/close were deliberately EXCLUDED from live testing per a captain-approved rule: unlatching a plugged-in charge cable does not re-engage without a physical reseat, so it is captain-present-only; they ship as mocked-transport-only tests instead (proto construction verified, never live-actuated). The two batch_remove_* commands are destructive by nature, so the only safe live exercise was calling them with home=work=other=False (removes nothing in any category) after snapshotting all real schedules - this proves the ACK and wire path without risking the car owner's real charge/precondition schedules; the six real charge schedules and five real precondition schedules present on the car were confirmed present and byte-identical (by id set) before and after every schedule-mutating test, and the whole car (charge_limit_soc, charge_current_request, scheduled_charging_mode) was confirmed restored to its exact original snapshot at the end of the session. Along the way I discovered and deliberately worked around one real vehicle-side behavior rather than treating it as a bug: charge_standard() rejects with {result: False, reason: already_standard} if the current limit already equals the std preset, so the test chain routes through charge_max_range() first to give charge_standard() a real transition to prove (this conveniently also serves as the restore back to the original limit, since charge_limit_soc_std equals the car's original limit). I also documented two other real, load-bearing findings in AGENTS.md (not fixed, since they reflect genuine protocol/vehicle-firmware constraints, not library defects): scheduled_charging_mode is a tri-state enum (Off/StartAt/DepartBy) shared by both set_scheduled_charging and set_scheduled_departure, so toggling one can clobber the other's active configuration unless the caller snapshots and restores the full mode+fields; and set_scheduled_departure's preconditioning_enabled/off_peak_charging_enabled Python parameters are accepted by the signature but never wired into the ScheduledDepartureAction proto (confirmed live - passing preconditioning_enabled=False had no effect on the vehicle's observed state), because that proto message has no such fields upstream. Separately, while writing retry-with-backoff logic for the live BLE session, I hit and documented a real, generally-applicable trap: this library's exceptions all inherit from BaseException, not Exception (by design, per the existing Error Handling section), which silently defeats a naive 'except Exception' retry loop around BLE reads - added a one-line gotcha to AGENTS.md's Error Handling section since this affects any future BLE work using retry/backoff. No behavior changes were made to tesla_fleet_api itself in this PR - it is purely live-verification plus regression tests plus documentation, matching the master plan's framing that BLE command support already exists via inheritance from Commands and the deliverable here is verification, not new implementation.
What Changed
Risk Assessment
✅ Low: The branch is limited to documentation plus mocked BLE transport regression coverage for existing command paths, and the added assertions line up with the current command/protobuf behavior without introducing production-code risk.
Testing
Inspected the target diff, ran the focused BLE charging tests and adjacent mocked BLE regression tests, generated reviewer-visible decoded signed-command payload evidence, then removed transient
.venv, pytest cache, pycache, and generated egg-info changes; all exercised checks passed and the worktree was clean afterward.Evidence: Decoded BLE charging payload evidence
Pipeline
Updates from git push no-mistakes
✅ **intent** - passed
✅ No issues found.
🔧 **Rebase** - 1 issue found → auto-fixed ✅
AGENTS.md- merge conflict rebasing onto origin/main🔧 Fix applied.
✅ Re-checked - no issues remain.
✅ **Review** - passed
✅ No issues found.
✅ **Test** - passed
✅ No issues found.
git status --short --branchgit diff --stat 3659f00a69b15cb23d0037d7733451630ae156b7..5a70ac23eb62fc3025eac3f9422402e5c4285697git diff --name-only 3659f00a69b15cb23d0037d7733451630ae156b7..5a70ac23eb62fc3025eac3f9422402e5c4285697uv run pytest tests/test_ble_charging_commands.pyuv run python - <<'PY' ...to decode signed BLE charging command payloads into/tmp/no-mistakes-evidence/01KX37W5NWP8RXJK6VJQ4HJW5B/ble_charging_decoded_payloads.jsonuv run pytest tests/test_ble_mocked_commands.py tests/test_ble_charging_commands.pygit status --shortafter cleanup✅ **Document** - passed
✅ No issues found.
✅ **Lint** - passed
✅ No issues found.
✅ **Push** - passed
✅ No issues found.