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

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.
@Bre77Bre77 added the fm Opened by a Firstmate crewmate label Aug 15, 2026
@Bre77
Bre77 merged commit d5ec37a into mainAug 15, 2026
6 checks passed
@Bre77Bre77 mentioned this pull request Aug 15, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

fmOpened by a Firstmate crewmate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@Bre77