Skip to content

feat(energysite): wire list_authorized_clients over local TEDAPI v1r - #4

Merged
Bre77 merged 1 commit into
mainfrom
fm/apw-authclients-local-first
Jul 17, 2026
Merged

feat(energysite): wire list_authorized_clients over local TEDAPI v1r#4
Bre77 merged 1 commit into
mainfrom
fm/apw-authclients-local-first

Conversation

@Bre77

@Bre77 Bre77 commented Jul 17, 2026

Copy link
Copy Markdown
Member

Intent

Wire PowerwallEnergySite.list_authorized_clients up to the local TEDAPI v1r path instead of leaving it as a NotImplementedError placeholder, so a primary/secondary router (tesla_fleet_api.tesla.router.Router / EnergySiteRouter in the sibling python-tesla-fleet-api project) can run the authorized-clients check against the gateway directly over the LAN and only fall back to the cloud EnergySite when the local RSA key isn't paired. This repo's checked-in tedapi_combined.proto only ports the message oneofs an implemented command actually needs — AuthorizationMessages had never been ported beyond a bytes placeholder = 1 stub, unlike TEGMessages (backup events, islanding). Ported the real field numbers/shapes from Tesla's published energy_device/v1 schema (Matthew1471/Tesla-API), which the checked-in proto already matches exactly wherever both define the same message (TEGMessages, MessageEnvelope, Participant), giving high confidence the ported AuthorizationMessages/AuthorizationRecord fields are correct too.

No router changes were needed for the fallback behavior itself: Router._dispatch already treats any exception raised by the primary — including the PowerwallAuthenticationError an unregistered/unpaired local RSA key produces — as a signal to fail over to the next backend, the same way it already does for every other implemented PowerwallEnergySite command.

What Changed

  • src/aiopowerwall/proto/tedapi_combined.proto: replaced the AuthorizationMessages placeholder with the real oneof (only list_authorized_clients_request/_response uncommented — matches how TEGMessages leaves unimplemented commands commented out), plus AuthorizationRecord and its enums (AuthorizedState, AuthorizedKeyType, AuthorizationRole, AuthorizedVerificationType). Regenerated tedapi_combined_pb2.py.
  • PowerwallClient._send_teg_request generalized to _send_command_request(category=..., message_cls=..., ...) so any MessageEnvelope oneof category can reuse it, not just teg. All four existing TEG call sites (schedule_max_backup, cancel_max_backup, get_backup_events) updated to pass category="teg" explicitly; behavior is unchanged.
  • PowerwallClient.list_authorized_clients(): issues the local command and maps each AuthorizationRecord into a plain dict (base64-encoded public key, enum values as their name with the common prefix stripped, e.g. "VERIFIED" not AUTHORIZED_STATE_VERIFIED).
  • PowerwallEnergySite.list_authorized_clients(): moved out of the placeholder section, wraps the payload under response.clients — one of the two keys the cloud envelope is observed to use (the other is authorized_clients), so a caller parsing either shape works unchanged against this local read.
  • Added AuthorizedClient/AuthorizedClientsPayload TypedDicts in models.py.
  • Tests: tests/test_client.py (new) exercises the protobuf parsing directly — response mapping, optional-field absence, empty-list, and the outbound request shape. tests/test_energysite.py moves list_authorized_clients out of the placeholder-raises-NotImplementedError table into its own response-wrapping test.

Testing

uv run ruff check ., uv run mypy, and uv run pytest (87 passed) all pass. This has not been exercised against real Powerwall 3 hardware — the ported field numbers are verified against Tesla's published proto schema and by protobuf round-trip in tests, not by a live gateway call.

Implements the AuthorizationMessages command (list_authorized_clients
oneof, field numbers verified against Tesla's published energy_device/v1
proto schema) so PowerwallEnergySite.list_authorized_clients reads the
gateway's registered-client list directly over the local RSA-signed
channel instead of only being a NotImplementedError placeholder.

Generalizes PowerwallClient._send_teg_request into
_send_command_request(category=...) so it can drive any MessageEnvelope
oneof, not just teg, and reuses it for the new authorization category.

No router changes needed: a router with per-command failover already
treats any exception (including an unregistered/unpaired local key) as
a signal to fall through to the cloud EnergySite, so an unset-up local
key degrades the same way other implemented commands do.
@Bre77
Bre77 merged commit 3949ca1 into main Jul 17, 2026
8 checks passed
@Bre77 Bre77 mentioned this pull request Jul 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant