Skip to content

feat(tessie): add set_roles command for payer role assignment - #123

Merged
Bre77 merged 1 commit into
mainfrom
fm/pyfleet-tessie-command-parity
Aug 15, 2026
Merged

feat(tessie): add set_roles command for payer role assignment#123
Bre77 merged 1 commit into
mainfrom
fm/pyfleet-tessie-command-parity

Conversation

@Bre77

@Bre77 Bre77 commented Aug 15, 2026

Copy link
Copy Markdown
Member

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

  • Added TessieVehicle.set_roles(role, account_id=None, federation_id=None), a POST /{vin}/roles command that assigns the subscription/charging payer role on a Tesla Business account, following the same JSON-body command convention as delete_driver/update_plate (optional fields omitted from the payload when unset).
  • Added docs/tessie.md usage example for set_roles alongside the other vehicle command examples.
  • Added unit tests in tests/test_tessie_vehicle_params.py asserting 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'})

Call 1 (role+account_id) -> response: {'result': True}
Call 1 -> request call: call(<Method.POST: 'POST'>, '5YJXCAE43LF123456/roles', json={'role': 'SUBSCRIPTION', 'account_id': '555555555'})
Call 2 (role only) -> response: {'result': True}
Call 2 -> request call: call(<Method.POST: 'POST'>, '5YJXCAE43LF123456/roles', json={'role': 'CHARGING'})
Call 3 (role+federation_id) -> response: {'result': True}
Call 3 -> 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_fields
  • grep -rn &#34;def set_roles&#34; tesla_fleet_api/ — confirmed set_roles is defined only on TessieVehicle, no collision with VehicleFleet or other backends
  • Manual 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.

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.
@Bre77 Bre77 added the fm Opened by a Firstmate crewmate label Aug 15, 2026
@Bre77
Bre77 merged commit d5ec37a into main Aug 15, 2026
6 checks passed
@Bre77 Bre77 mentioned this pull request Aug 15, 2026
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