github jasonacox/pypowerwall v0.21.0
v0.21.0 - Powerwall 2 Per-Unit Vitals, Battery Power Limits, PW_FAILOVER and TEDAPI Recovery Fix

3 hours ago

Library Changes

  • feat(tedapi): Powerwall 2 per-Powerwall vitals from the DeviceController msa components. The V2024_06 device_controller_full request now appends 14 more signal names to its unsigned msaSignals variable, after #419's SYNC_Uptime (PW2_MSA_SIGNAL_NAMES, via EXTRA_SIGNAL_NAMES; the capture, its signature and its msaComp component types are unchanged). They fill PW2 vitals keys that mirror the original /api/devices/vitals and were hard-coded None:

    • on each TEPINV block: PINV_EnergyCharged and PINV_EnergyDischarged (lifetime Wh), PINV_HardwareEnableLine, PINV_PllFrequency, PINV_PllLocked, PINV_PowerLimiter, PINV_Qout and PINV_ReadyForGridForming
    • THC_State on each TETHC block
    • SYNC_ExternallyPowered and SYNC_SiteSwitchEnabled on TESYNC

    Three new keys join each TEPINV block: PINV_HeatsinkTemp, PINV_LifetimeEnergyCharged and PINV_LifetimeEnergyDischarged. Values pass through as the gateway delivers them, None included. The boolValue/textValue fields are read as well as value, so a False or an enum is not lost.

    • The TETHC and TESYNC values join on serial.
    • The TEPINV values come from the msa component of the battery module, whose serial is not the package serial the block is named by. Nothing in the payload links the two, so _pw2_msa_module_pairing() pairs each package's TETHC with the TEPINV that follows it. Serial-less slots are skipped, even ones carrying a live signal. If the layout is irregular in any way, every module value stays None rather than risk giving one Powerwall another's counters.
    • Hardware-validated on 4x Powerwall 2 behind a Backup Gateway 1 (firmware 26.34.0, v1r LAN), and with this request on a second Backup Gateway 1 site with 4x Powerwall 2 (firmware 26.18.3, one warranty-replacement unit with different part numbers). The module counters' sum matched the Fleet API cumulative battery discharge to 0.12%. Over 5.9 hours of charging, the charged counters' rise matched the gateway's own battery meter, integrated, to 0.07%. The component order was identical in every read over 46 hours, and again after a gateway restart (no firmware change).
    • temps(), /temps, msaComp and every existing key are unchanged. SYNC_ExternallyPowered / SYNC_SiteSwitchEnabled also fill on Powerwall 3 sites that report a SYNC device (esCan.bus.SYNC with a serial, e.g. behind a Backup Gateway 2): they were None there and now carry the gateway's value (False on 2x PW3, firmware 26.26.11, over WiFi TEDAPI and v1r), matching the original /api/devices/vitals. Nothing else in Powerwall 3 vitals changes: the other 12 names come back null on PW3 and are not read there (hardware-checked by @jasonacox). The TEPOD POD_* placeholders stay None, because they need TEPOD in msaComp. Under V2026_06 the signed DeviceControllerQuery can't carry extras, so these keys stay None there. Thanks @jcl-bit (#416, #409).
  • feat(tedapi): /api/system_status max_charge_power, max_discharge_power and max_apparent_power are filled (they were always null) the way the gateway's local API reports them: the site's nominal system power from the gateway config (site_info.nominal_system_power_ac, in kW, converted to W), capped at the inverters' usable power where the inverters report it. A site whose wiring derates its Powerwalls below nameplate reports the derated value, as its local API does (2x Powerwall 2 at 4600 W each on single-phase wiring: 9200, not the 10000 nameplate). Powerwall 3 reports the nameplate, since it has no per-inverter values here. Cloud and FleetAPI report the nameplate. Thanks @erikgieseler (#423).

  • feat(tedapi): /api/system_status inverter_nominal_usable_power is filled (it was hard-coded 0) with the sum of the active inverters' esCan.bus.PINV[].PINV_PowerCapability.PINV_Pnom, matching the local API. It stays 0 when no inverter reports one (Powerwall 3) (#423).

  • feat(proxy): new PW_FAILOVER setting (default yes) exposes the library's failover option (#395) in the proxy. Set PW_FAILOVER=no to pin the configured transports: the v1r leader stays on the wired LAN instead of switching to PW_WIFI_HOST, a failed request returns no data instead of being rerouted, and the proxy never falls back from local to FleetAPI or Cloud mode (at startup it retries the configured mode until it connects). Only no turns it off. /stats reports it under config, and /health shows failover per transport. Requested by @BJReplay (#427, #402).

  • fix: TEDAPI recovery no longer gets stuck on Tesla cloud after a gateway outage. With failover on (the default) and cloud credentials available, the proxy's recovery connect() could succeed by falling back to cloud. The proxy counted that as recovered (cloud answers version() too), then stopped probing because pw.tedapi was off, and stayed on cloud with no TEDAPI data until restart. Now Powerwall.connect() always starts from the mode set at construction, as its docstring says, instead of where an earlier failover left it, and a successful cloud or FleetAPI connect clears any TEDAPI state left from an earlier failover to local. The proxy counts recovery only when the connection is back in TEDAPI mode, and treats a connection that has left TEDAPI mode as a failed probe. Cloud data keeps flowing while recovery runs. (#425, #424)

  • docs: README, proxy README and AGENTS.md say which TEDAPI query set to use. Keep the default V2024_06 unless you need bearer mode: both sets are pre-signed query payloads, but only V2024_06 takes its signal names as unsigned variables, so it is the only set pypowerwall can extend, and PW3 temperatures, fans and battery health and the gateway uptime are null under V2026_06. V2026_06 stays for bearer mode on solar-only gateways. The docs now describe V2026_06 as a pre-signed query set rather than a Tesla-signed or Tesla-provided one. (#422)

  • docs: README v1r key registration covers the Powerwall 2 physical proof (one unit's On/Off switch off for about 15 seconds). (#416)

  • tests: new test_pw2_msa_signals.py, with a redacted raw PW2 device-controller response (tests/tedapi/fixtures/pw2_device_controller_full.json, made with this request). It covers the request (signature and msaComp unchanged, names appended), value fields, the pairing rule and its failure cases, the vitals fills, ambiguous pairing, and that every other vitals key is unchanged. test_pw3_fans.py and test_pw3_temperatures.py no longer assume the device-controller request is the untouched capture object. (#416)

  • Library version bumped to 0.21.0

Proxy t107

  • Upgraded to pyPowerwall v0.21.0 - see the library release notes. Proxy-visible changes:
    • /vitals and /pw/vitals: Powerwall 2 per-Powerwall values that were null (lifetime charged/discharged energy, inverter state and heatsink temperature on each TEPINV-- block, THC_State on TETHC--, and SYNC_ExternallyPowered / SYNC_SiteSwitchEnabled on TESYNC--). Powerwall 3 sites with a SYNC device report those two TESYNC-- values too (false instead of null). (#416)
    • /api/system_status in TEDAPI mode: max_charge_power, max_discharge_power and max_apparent_power are filled the way the gateway's local API reports them (the site nameplate, capped at the inverters' usable power), and inverter_nominal_usable_power reports the inverters' usable power instead of 0 where the inverters report it. (#423)
  • New PW_FAILOVER setting (default yes). Set PW_FAILOVER=no to pin the configured transports: the v1r leader stays on the wired LAN instead of switching to PW_WIFI_HOST, a failed request returns no data instead of being rerouted, and the proxy never falls back from local to FleetAPI or Cloud mode. Reported in /stats under config. Requested by @BJReplay (#427, #402).
  • TEDAPI recovery no longer gets stuck on Tesla cloud after a gateway outage: with cloud credentials present, recovery could fall back to cloud, report "recovered" and stop probing until restart. It now counts recovery only when the connection is back in TEDAPI mode (#425, #424).

Upgrade

pip install --upgrade pypowerwall==0.21.0

PyPI: https://pypi.org/project/pypowerwall/0.21.0/

Docker proxy image: jasonacox/pypowerwall:0.21.0t107 (also tagged :latest), built for linux/amd64, arm64, arm/v7 and arm/v8.

docker pull jasonacox/pypowerwall:0.21.0t107

Changes in this Release

  • #416 — Powerwall 2 per-unit vitals (msa signals)
  • #423 — /api/system_status battery power limits (max_*, inverter_nominal_usable_power)
  • #427 — proxy PW_FAILOVER setting (server counterpart jasonacox/pypowerwall-server#160 still in review)
  • #425 — TEDAPI recovery fix (#424)
  • #422 — query-set documentation
  • #426 — housekeeping

Test Hardware

Validated on 2x Powerwall 3 + Backup Gateway 2, no expansion packs.


Contributors

Thanks to the community members who made this release possible:

  • @jcl-bit — #416 Powerwall 2 msa signals, plus hardware validation on two Powerwall 2 sites and the restart check (#409)
  • @erikgieseler — #423 PINV discovery, and the local, cloud and TEDAPI captures that settled the semantics
  • @BJReplay — requested PW_FAILOVER (#402)
  • @jasonacox-sam — review and PW3 hardware testing on #423 and #416

Don't miss a new pypowerwall release

NewReleases is sending notifications on new releases.