feat(tessie): add set_roles command for payer role assignment - #123
Merged
Conversation
Verified full command parity against Tessie's live OpenAPI spec
(developer.tessie.com/openapi.yaml): every documented POST /command/*
and /wake endpoint was already implemented. The one gap was
POST /{vin}/roles ("Set Roles"), a Tesla-Business-only command to
assign the subscription/charging payer role, which had no library
method.
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 the Tessie class to full command parity with Tessie's documented command surface (developer.tessie.com), verified live rather than from memory. Enumerated every POST /{vin}/command/* and /{vin}/wake endpoint plus related action endpoints from the current openapi.yaml, then diffed against TessieVehicle's existing methods. Result: the class already implemented every documented vehicle command from a prior comprehensive-coverage pass; the only gap found was POST /{vin}/roles ('Set Roles'), a Tesla-Business-only command to assign the subscription/charging payer role, which had no library method (the sibling GET /{vin}/roles is a data/read endpoint and is intentionally out of scope). Added set_roles(role, account_id=None, federation_id=None) on TessieVehicle following the existing JSON-body command convention used by delete_driver/update_plate (POST with a json= payload, optional fields omitted when None, no wait_for_completion/max_attempts since the endpoint doesn't support them per the spec). No collision with any parent-class method name, so no tessie_ prefix was needed (that prefix convention is reserved for names already defined on VehicleFleet). No deprecated or beta-marked commands exist in the current spec, so there is nothing to exclude on that basis. Added unit tests mirroring the existing test_tessie_vehicle_params.py style (mocked _request, asserting the exact JSON body sent, including the omitted-optional-fields case) and a docs/tessie.md usage example in the same list-of-calls style as neighboring commands. Scope is intentionally narrow: Tessie command parity only - no data/telemetry endpoint work, no refactors, no version bump. Ruff, pyright (strict), and the full pytest suite (596 tests) are all green locally.
What Changed
TessieVehicle.set_roles(role, account_id=None, federation_id=None), a POST/{vin}/rolescommand that assigns the subscription/charging payer role on a Tesla Business account, following the same JSON-body command convention asdelete_driver/update_plate(optional fields omitted from the payload when unset).docs/tessie.mdusage example forset_rolesalongside the other vehicle command examples.tests/test_tessie_vehicle_params.pyasserting the exact JSON body sent, including the case where optional fields are omitted.Risk Assessment
✅ Low: Small, self-contained addition (one new method + doc line + two unit tests) that follows the existing delete_driver/update_plate JSON-body convention exactly, has no naming collision with VehicleFleet requiring a tessie_ prefix, and is fully covered by tests matching the documented endpoint and optional-field-omission behavior.
Testing
Ran the targeted test_tessie_vehicle_params.py suite (7/7 passed) covering the new set_roles unit tests, and separately drove TessieVehicle.set_roles() through a manual mocked-request script exercising all three field combinations to directly observe the exact POST /{vin}/roles JSON payload built — confirming required-only, full, and federation_id-variant calls all match the documented Tessie command convention with optional fields correctly omitted when unset. No issues found; working tree left clean (reverted incidental uv-generated egg-info/uv.lock churn from running the toolchain).
Evidence: Manual end-to-end verification of set_roles() request construction
Call 1 (role+account_id) -> request call: call(<Method.POST: 'POST'>, '5YJXCAE43LF123456/roles', json={'role': 'SUBSCRIPTION', 'account_id': '555555555'}) Call 2 (role only) -> request call: call(<Method.POST: 'POST'>, '5YJXCAE43LF123456/roles', json={'role': 'CHARGING'}) Call 3 (role+federation_id) -> request call: call(<Method.POST: 'POST'>, '5YJXCAE43LF123456/roles', json={'role': 'SUBSCRIPTION', 'federation_id': 'fed-123'})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_tessie_vehicle_params.py -v— all 7 tests pass (7 passed, 8 subtests), including the two new set_roles tests: test_set_roles_uses_documented_parameters and test_set_roles_omits_unset_optional_fieldsgrep -rn "def set_roles" tesla_fleet_api/— confirmed set_roles is defined only on TessieVehicle, no collision with VehicleFleet or other backendsManual scripted call to TessieVehicle.set_roles() with a mocked _request across three argument combinations (role+account_id, role only, role+federation_id) — verified the exact POST /{vin}/roles JSON body sent in each case, confirming optional fields are correctly omitted when None✅ **Document** - passed
✅ No issues found.
✅ **Lint** - passed
✅ No issues found.
✅ **Push** - passed
✅ No issues found.