Skip to content

Add MQTT battery dispatch controls and Home Assistant inputs - #184

Merged
jasonacox merged 5 commits into
jasonacox:mainfrom
longzheng:codex/mqtt-battery-dispatch
Nov 11, 2026
Merged

jasonacox merged 5 commits into
jasonacox:mainfrom
longzheng:codex/mqtt-battery-dispatch

Conversation

@longzheng

Copy link
Copy Markdown
Contributor

Follow-up to #180: MQTT clients and Home Assistant can now start a timed local battery dispatch and resume normal operation using a separate MQTT_CONTROLS bit 32. Existing 15/31 masks keep their previous behavior; 63 enables all controls.

Home Assistant discovers power and duration inputs plus Start Dispatch and Resume buttons. Input changes only prepare the next command, with defaults of -500 W for 30 seconds; prepared values are per gateway, survive broker reconnects and reset on server restart. Automations can send {"power_watts":-500,"duration_seconds":30,"confirm":true} to {prefix}/{gateway}/control/dispatch/set, or {} to .../control/resume/set.

Dispatch and discovery follow each gateway's live v1r connection, including hybrid configurations. Commands reuse the HTTP write lock and timeout handling, never fall back to cloud or retry, and retain the existing payload limits, burst coalescing and retained-command rejection/clearing. HTTP and MQTT share parameter validation. Logs report acknowledgements without claiming actual battery power.

Dispatch requires confirm:true; the Home Assistant Start button sends it when pressed. Documentation explains that discharge can export despite Grid Export settings and drain below Backup Reserve, that Home Assistant has no extra confirmation dialog, and that prepared values are not active-dispatch telemetry. API.md, MQTT.md, the setup guides and upcoming release notes are updated.

Validation:

  • Full pytest -q: 1,215 passed against pypowerwall 0.22.1.
  • Regression coverage includes legacy masks, per-gateway live capability and discovery removal/restoration, prepared inputs, atomic payload validation, retained commands, burst ordering, failure logging and cross-API serialization after worker timeouts.
  • git diff --check passes; changed Python sections follow Black formatting.
  • MQTT message handling uses aiomqtt's real iterator in tests. No live Home Assistant, broker or hardware validation was performed.

Copilot AI balanced review requested due to automatic review settings October 27, 2026 05:53

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Command coalescing can dispatch with stale prepared values, and concurrent state publications can show values different from those Start uses.

2 open issues
What changed in this PR

Extends the existing local battery dispatch API to MQTT and Home Assistant, with a separate opt-in control bit that preserves existing masks.

Changes:

  • Adds per-gateway prepared power/duration inputs and dispatch/resume commands using local v1r connections.
  • Shares HTTP/MQTT parameter validation and adds discovery, command-handling and write-lock regression coverage.
  • Documents configuration, command payloads, safety warnings and release notes.
File Description
tests/​test_mqtt_controls.py Tests dispatch configuration, discovery, validation and message handling.
tests/​test_battery_dispatch.py Tests shared HTTP/MQTT write locking across timeouts.
RELEASE.md Adds upcoming MQTT dispatch release notes.
README.md Introduces dispatch controls and safety guidance.
MQTT.md Documents dispatch topics, prepared inputs and risks.
mqtt-tools/​README.md Updates Home Assistant setup guidance.
app/​utils/​control.py Adds shared dispatch parameter validation.
app/​mqtt/​publisher.py Handles prepared inputs and local dispatch/resume commands.
app/​mqtt/​ha_discovery.py Adds dispatch input and button discovery payloads.
app/​config.py Adds dispatch bit 32 and expands supported masks.
app/​api/​legacy.py Reuses shared dispatch validation.
API.md Documents MQTT dispatch configuration and cross-references.

Review effort: Balanced

Comment thread app/mqtt/publisher.py Resolved
Comment thread app/mqtt/publisher.py Resolved
@BJReplay

Copy link
Copy Markdown

I'm testing this because I'm a cowboy... (and I remembered that I could git clone your working branch, build -t somethingsomething . and then run that image)

pypowerwall-server  | 2026-10-27 06:31:04,274 - app.mqtt.publisher - INFO - MQTT controls subscribed to pypowerwall/+/control/+/set (enabled: reserve, mode, grid_charging, grid_export, dispatch)
pypowerwall-server  | 2026-10-27 06:31:04,274 - app.mqtt.publisher - WARNING - MQTT BATTERY DISPATCH control is enabled: discharge may export despite Grid Export settings and drain below Backup Reserve. Restrict broker access and ACL pypowerwall/+/control/#
pypowerwall-server  | 2026-10-27 06:31:05,298 - httpx - INFO - HTTP Request: GET https://fleet-api.prd.na.vn.cloud.tesla.com/api/1/products "HTTP/2 200 OK"
pypowerwall-server  | 2026-10-27 06:31:05,541 - app.core.gateway_manager - INFO - Connected to gateway default - TEDAPI v1r mode (192.168.1.30)
pypowerwall-server  | 2026-10-27 06:31:05,618 - httpx - INFO - HTTP Request: GET https://fleet-api.prd.na.vn.cloud.tesla.com/api/1/energy_sites/2252189176170857/site_info "HTTP/2 200 OK"
pypowerwall-server  | 2026-10-27 06:31:05,620 - app.core.gateway_manager - INFO - Cloud control connection established for write operations
pypowerwall-server  | 2026-10-27 06:31:06,629 - app.core.gateway_manager - INFO - Gateway default firmware: 26.34.1 dcee474d
pypowerwall-server  | 2026-10-27 06:31:06,629 - app.core.gateway_manager - INFO - Successfully connected to gateway default (192.168.1.30) - Site: BLAH
pypowerwall-server  | 2026-10-27 06:31:06,704 - app.mqtt.publisher - INFO - MQTT HA discovery published for gateway 'default' (35 entities)
pypowerwall-server  | 2026-10-27 06:32:10,551 - app.mqtt.publisher - INFO - MQTT control 'dispatch_power' for 'default' prepared (value=500; battery unchanged)
pypowerwall-server  | 2026-10-27 06:32:40,092 - app.mqtt.publisher - INFO - MQTT control 'dispatch_power' for 'default' prepared (value=200; battery unchanged)
pypowerwall-server  | 2026-10-27 06:32:45,082 - app.core.gateway_manager - INFO - [default] local_control(dispatch_battery_power) completed successfully
pypowerwall-server  | 2026-10-27 06:32:45,082 - app.mqtt.publisher - INFO - MQTT control 'dispatch' for 'default' acknowledged (power_watts=200, duration_seconds=30 via local v1r); check actual battery power
image image

@jasonacox jasonacox left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, @longzheng! You've already thought about safety carefully here:

  • a separate MQTT_CONTROLS bit (32), so existing 15/31 masks don't change;
  • confirm:true;
  • retained commands are rejected;
  • no fallback to cloud;
  • the shared write lock across both APIs;
  • shared validation.

That's thoughtful work, and the test coverage is excellent.

Before this goes in, I want MQTT dispatch to get the same treatment as the Console and HTTP API in #185. We aren't trying to be pedantic, but we want to be clear about how serious this control is. A dispatch takes direct control of the battery through an undocumented Tesla command and overrides the backup reserve and export settings. We have no idea whether incorrect use could damage someone's home, Powerwall system or the grid. MQTT makes it easier still to run unattended from automations, so it should only be used by people who know what they're doing, and the docs should say so loudly.

1. Require the PW_BATTERY_DISPATCH opt-in as well (#185). Please rebase onto #185 once it lands. Bit 32 alone shouldn't enable dispatch: commands need both PW_BATTERY_DISPATCH=yes and bit 32. Without the opt-in, please:

  • don't announce the dispatch entities;
  • reject dispatch commands with a log line that names PW_BATTERY_DISPATCH;
  • have the startup log say why.

Resume can stay available, as it is over HTTP, so turning dispatch off never strands a running dispatch.

2. "Use at your own risk" everywhere it's documented. Please add the same "⚠️ WARNING: USE AT YOUR OWN RISK" block from #185's README/API.md to the MQTT.md dispatch section and mqtt-tools/README.md. Also add a line to the existing MQTT controls warning in README naming bit 32: it can drain below the reserve, export despite Grid Export, and charge from the grid.

3. Home Assistant entities off by default. The Start button dispatches with one tap, with no confirmation in Home Assistant. Please announce the dispatch entities with "enabled_by_default": false, so a user has to enable them deliberately in Home Assistant, and say so in MQTT.md.

4. Copilot's two findings.

  • The first can make Start charge instead of discharge: in a burst of dispatch_power=500, then Start, then dispatch_power=-1000, coalescing drops the first input and Start runs with the previous power. Please make Start a coalescing barrier for its gateway's prepared inputs, and add the message-loop regression test Copilot describes.
  • The second is a stale display: please serialize the prepared-state publications per gateway, so Home Assistant always shows the values Start will use.

5. One "dispatch running" state. #185 records the dispatch the server last sent and shows it in the Console banner (dispatch_active in /control/status). Please move that into a shared helper (app/utils/control.py fits) and record MQTT dispatches and resumes there too, so the Console shows a dispatch started from Home Assistant.

6. A short live run. Please run start, resume, a retained-message rejection and the opt-in off through a real broker and Home Assistant, on your system or with @BJReplay's help. Short durations are fine.

Thanks again, Long. MQTT dispatch is a natural next step, and with these guardrails it'll be something people can use with confidence.

@jasonacox

Copy link
Copy Markdown
Owner

@longzheng, thank you for raising jasonacox/pypowerwall#450! The warranty catch is exactly the kind of thing that protects our users, and I really appreciate you flagging it right away. 🙏

Battery dispatch now warns that it could void or limit your Tesla Powerwall warranty (jasonacox/pypowerwall#451, #190). Please add the same warning here before this merges:

  • MQTT.md, in the battery dispatch (bit 32) warning: the bold warranty paragraph from docs(dispatch): warn that battery dispatch could void your warranty #190's README/API.md.
  • README.md and mqtt-tools/README.md, on the bit 32 rows: "use at your own risk; could void your warranty".
  • The startup WARNING ("MQTT BATTERY DISPATCH control is enabled: …"): add "could void your Tesla warranty".

Please copy #190's wording ("could void or limit", and "the Powerwall warranty quoted in #450"), so we don't claim more than that warranty shows. If #190 merges first, a rebase brings the shared docs along.

Thanks again for all your work on this. MQTT dispatch is going to be a great addition for Home Assistant users.

@jasonacox

Copy link
Copy Markdown
Owner

Hi @longzheng, checking in on this one! The MQTT dispatch controls are a great follow-up to #180, and the careful safety design (a separate bit 32, confirm:true, no retained commands) is exactly right. @BJReplay's early test run was really helpful too.

Three things are left before it can merge:

  • Warranty warning: the "could void or limit your Tesla Powerwall warranty" line in MQTT.md and on the Home Assistant inputs, matching docs(dispatch): warn that battery dispatch could void your warranty #190 (details in my last comment).
  • Two open Copilot threads, both real races:
    • a command burst can start a dispatch with stale prepared power or duration;
    • a concurrent input change can publish state that differs from what Start will use.
  • Merge conflicts with main: 0.15.0 just shipped new MQTT alert and stale-topic code next to yours.

If you're busy, I'm happy to finish it on this branch: rebase, add the warning, fix both races with tests, and keep you credited as the author. Just let me know which you'd prefer. If I don't hear back by Nov 15, I'll go ahead and push the changes here. Thank you!

@longzheng

Copy link
Copy Markdown
Contributor Author

@jasonacox sorry I'm a bit busy, if you can finish off that would be great.

jasonacox and others added 2 commits November 10, 2026 20:40
Conflicts:
- publisher.py: keep both the prepared dispatch parameters and the
  retained-topic tracking; announce state uses main's
  _gateway_can_v1r_write plus this branch's _gateway_can_dispatch.
- API.md: main's dispatch warranty/opt-in block, then the MQTT paragraph.
- RELEASE.md: the MQTT dispatch note moves to a new [0.16.0] - Upcoming.
- tests/test_battery_dispatch.py: keep both sets of tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Finishes jasonacox#184 on top of 0.15.1 (thanks @longzheng):

- PW_BATTERY_DISPATCH=yes is required for MQTT dispatch and the prepared
  inputs, like HTTP dispatch; resume works without it so turning it off
  can't strand a running dispatch. Home Assistant only gets the dispatch
  entities when it's on, and the startup log says when bit 32 is set but
  the opt-in is off.
- Warranty warning (could void or limit your Tesla Powerwall warranty,
  the warranty quoted in pypowerwall#450) in MQTT.md, README.md,
  mqtt-tools/README.md and the startup WARNING, matching jasonacox#190.
- Burst ordering: dispatch and resume are coalescing barriers, so a burst
  of "power 500, Start, power -1000" dispatches at 500 instead of the
  previous prepared power. Each Start/Resume in a burst runs in order;
  repeated presses with nothing between them still collapse to one.
- Prepared-input publishing takes a per-gateway lock and snapshots under
  it, so a poll that started earlier can't publish a stale duration after
  an accepted input.

Tests: regression tests for both races, the barrier coalescing, the
opt-in (commands, discovery, startup log) and the warranty log line; all
fail on the previous code. 1360 tests pass.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

MQTT publishing logs false or mismatched dispatch acknowledgements as successful without confirming the requested operation, requiring method-specific validation and regression coverage.

1 open issue
2 resolved since last review

Review effort: Balanced

Comment thread app/mqtt/publisher.py Resolved
MQTT logged any non-error dict as acknowledged, including
{"resume_battery_operation": false} or a dispatch reply with another
power or duration (Copilot on jasonacox#184). HTTP already checks these, so the
check moves to app/utils/control.dispatch_acknowledged() and both paths
use it: matching power and duration for a dispatch (bools are not
numbers here), resume_battery_operation True for a resume.

Tests: false and mismatched replies log as failed, matching replies as
acknowledged; the old {"ok": true} mock in the stay-local test now
returns real library replies.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Battery dispatch via MQTT/Home Assistant can bypass reserve and export protections, warranting hardware-aware human review because broker, Home Assistant, and hardware behavior have not been validated live.

No open issues 🎉

1 resolved since last review

Review effort: Balanced

@jasonacox

Copy link
Copy Markdown
Owner

Thanks @longzheng, happy to! You built a careful, well-tested feature here: the separate bit 32, confirm:true, prepared inputs that never touch the battery, the shared write lock across timeouts, and retained-command clearing were all already right. I pushed three commits on your branch to finish it, with you staying the author:

  • 1ee0b68: merged main (0.15.1). It resolves the conflicts with the MQTT alert and stale-topic code. The release note moves to a new [0.16.0] - Upcoming.
  • bbd7087: opt-in, warranty warning, and both Copilot races.
    • PW_BATTERY_DISPATCH=yes is now required for MQTT dispatch and the prepared inputs, the same opt-in as HTTP dispatch (from docs(dispatch): warn that battery dispatch could void your warranty #190). Resume works without it, so turning it off can't strand a running dispatch. Home Assistant only gets the dispatch entities when it's on. If bit 32 is set without the opt-in, the startup log says so.
    • The warranty warning ("could void or limit your Tesla Powerwall warranty", the warranty quoted in Manual dispatch changes warranty terms pypowerwall#450) is in MQTT.md, README.md, mqtt-tools/README.md and the startup WARNING, matching docs(dispatch): warn that battery dispatch could void your warranty #190.
    • Burst ordering: dispatch and resume are coalescing barriers, so "power 500, Start, power -1000" in one burst dispatches at 500. Every Start and Resume in a burst runs in order, and repeated presses with nothing between them still collapse to one.
    • Stale publish: publishing the prepared inputs takes a per-gateway lock and snapshots under it, so an older poll can't publish a stale duration after an accepted input.
  • 0a5db17: acknowledgements. MQTT logs a dispatch or resume as acknowledged only when the reply confirms that exact command. This uses the same dispatch_acknowledged() check as HTTP, now shared in app/utils/control.py.

Every new test fails on the previous code. All 1,366 tests pass, CI is green, and Copilot has no open issues. On our 2x Powerwall 3 (v1r, read-only), the branch serves every endpoint and publishes 63 Home Assistant entities to a test broker. We don't run control writes in our hardware checks, so the dispatch path itself hasn't been exercised on hardware since these changes.

@BJReplay, your earlier test run was really helpful. If you're up for another, a quick check of this build would be great: set PW_BATTERY_DISPATCH=yes, prepare a small dispatch from Home Assistant, press Start, then Resume, and post the log lines. Entirely optional, and thank you!

@jasonacox
jasonacox merged commit 85044ee into jasonacox:main Nov 11, 2026
10 checks passed
@BJReplay

Copy link
Copy Markdown

On it, @jasonacox

jasonacox added a commit that referenced this pull request Nov 11, 2026
- MQTT / Home Assistant battery dispatch and resume, opt-in with
  MQTT_CONTROLS bit 32 plus PW_BATTERY_DISPATCH=yes (#184)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
@BJReplay

BJReplay commented Nov 11, 2026 •

Copy link
Copy Markdown

Testing:

git pulled my existing clone of https://github.com/longzheng/pypowerwall-server branch codex/mqtt-battery-dispatch
Updating e937e67..0a5db17
built the docker image
restarted my docker stack with this image, and the MQTT_CONTROL changed from 15 to 47.

Ran a dispatch (with the value first changed from -500 to 500).

pypowerwall-server  | 2026-11-11 05:35:04,504 - app.mqtt.publisher - INFO - MQTT control 'dispatch_power' for 'default' prepared (value=500; battery unchanged)
pypowerwall-server  | 2026-11-11 05:35:04,866 - pypowerwall.tedapi.tedapi_v1r - WARNING - Battery dispatch accepted: discharge 500 W for 30 s. A dispatch overrides the backup reserve and grid export settings and could void your warranty - use at your own risk.
pypowerwall-server  | 2026-11-11 05:35:04,867 - app.core.gateway_manager - INFO - [default] local_control(dispatch_battery_power) completed successfully
pypowerwall-server  | 2026-11-11 05:35:04,867 - app.mqtt.publisher - INFO - MQTT control 'dispatch' for 'default' acknowledged (power_watts=500, duration_seconds=30 via local v1r); check actual battery power

Confirmed in the pypowerwall-server web console that the battery commenced a 500W dispatch (was idle as it was fully charged, it commenced discharging, and increased total discharge to the grid).

Confirmed working.

The hash 0a5db17 should be the same hash that you've used for the release build merged back into main.

@BJReplay

Copy link
Copy Markdown

@jasonacox @jasonacox-sam @longzheng just successfully tested with the jasonacox/pypowerwall-server:latest docker image (v0.16.0).

Confirmed working. Nice work all around.

pypowerwall-server  | INFO:     Started server process [7]
pypowerwall-server  | INFO:     Waiting for application startup.
pypowerwall-server  | 2026-11-11 05:43:25,195 - app.main - INFO - Starting PyPowerwall Server v0.16.0...
pypowerwall-server  | 2026-11-11 05:43:25,195 - app.main - INFO - Configured for 1 gateway(s)
pypowerwall-server  | 2026-11-11 05:43:25,195 - app.main - INFO - Polling interval (PW_CACHE_EXPIRE): 5s
pypowerwall-server  | 2026-11-11 05:43:25,195 - app.main - INFO - Timeout (PW_TIMEOUT): 10s
pypowerwall-server  | 2026-11-11 05:43:25,195 - app.main - INFO - Server listening on 0.0.0.0:8675
pypowerwall-server  | 2026-11-11 05:43:25,195 - app.main - WARNING - Battery dispatch is ON (PW_BATTERY_DISPATCH=yes). USE AT YOUR OWN RISK: a dispatch overrides the backup reserve and grid export settings, could void your Tesla warranty, and its effects on your home, system and the grid are not fully known.
pypowerwall-server  | 2026-11-11 05:43:25,195 - app.core.gateway_manager - INFO - Thread pool initialized with 10 workers for 1 gateway(s)
pypowerwall-server  | 2026-11-11 05:43:25,195 - app.core.gateway_manager - WARNING - Gateway default: PW_HOST + PW_GW_PWD + PW_RSA_KEY_PATH are all set — TEDAPI v1r mode is active but follower Powerwall data will be limited to the primary unit only. To see all Powerwalls, either: (a) set PW_WIFI_HOST to the gateway's WiFi access point (normally 192.168.91.1, which this host must be able to reach) for follower queries while keeping v1r, or (b) remove PW_RSA_KEY_PATH to use TEDAPI WiFi mode.
pypowerwall-server  | 2026-11-11 05:43:25,195 - app.core.gateway_manager - INFO - Registered gateway: default (Default Gateway) - TEDAPI mode - connection pending
pypowerwall-server  | 2026-11-11 05:43:25,195 - app.core.gateway_manager - INFO - TEDAPI probe/recovery task started for gateway default (interval=30s, threshold=3)
pypowerwall-server  | 2026-11-11 05:43:25,195 - app.core.gateway_manager - INFO - Gateway manager ready - 1 gateway(s) will connect on first poll
pypowerwall-server  | 2026-11-11 05:43:25,196 - app.core.timeseries - INFO - TimeSeriesStore enabled — raw retention 86400s, daily retention 0s, db: /data/timeseries.db
pypowerwall-server  | 2026-11-11 05:43:25,196 - app.main - INFO - Initialized 1 gateway(s)
pypowerwall-server  | 2026-11-11 05:43:25,196 - app.main - INFO -   - default: Default Gateway (192.168.1.30)
pypowerwall-server  | 2026-11-11 05:43:25,213 - app.mqtt.publisher - INFO - MQTT publisher starting...
pypowerwall-server  | 2026-11-11 05:43:25,213 - app.main - INFO - MQTT publisher enabled — broker: mqtt.mymqttserver:8883
pypowerwall-server  | 2026-11-11 05:43:25,217 - app.core.gateway_manager - INFO - Attempting lazy initialization of gateway default
pypowerwall-server  | 2026-11-11 05:43:25,832 - app.mqtt.publisher - INFO - MQTT connecting to mqtt.mymqttserver:8883
pypowerwall-server  | INFO:     Application startup complete.
pypowerwall-server  | INFO:     Uvicorn running on http://0.0.0.0:8675 (Press CTRL+C to quit)
pypowerwall-server  | 2026-11-11 05:43:25,987 - app.mqtt.publisher - INFO - MQTT connected to mqtt.mymqttserver:8883
pypowerwall-server  | 2026-11-11 05:43:25,992 - app.mqtt.publisher - INFO - MQTT controls subscribed to pypowerwall/+/control/+/set (enabled: reserve, mode, grid_charging, grid_export, dispatch)
pypowerwall-server  | 2026-11-11 05:43:25,992 - app.mqtt.publisher - WARNING - MQTT BATTERY DISPATCH control is enabled. USE AT YOUR OWN RISK: it could void your Tesla warranty, and discharge may export despite Grid Export settings and drain below Backup Reserve. Restrict broker access and ACL pypowerwall/+/control/#
pypowerwall-server  | 2026-11-11 05:43:27,066 - httpx - INFO - HTTP Request: GET https://fleet-api.prd.na.vn.cloud.tesla.com/api/1/products "HTTP/2 200 OK"
pypowerwall-server  | 2026-11-11 05:43:27,394 - httpx - INFO - HTTP Request: GET https://fleet-api.prd.na.vn.cloud.tesla.com/api/1/energy_sites/mysiteid/site_info "HTTP/2 200 OK"
pypowerwall-server  | 2026-11-11 05:43:27,395 - app.core.gateway_manager - INFO - Cloud connection established (control/read bindings available)
pypowerwall-server  | 2026-11-11 05:43:27,755 - app.core.gateway_manager - INFO - Connected to gateway default - TEDAPI v1r mode (192.168.1.30)
pypowerwall-server  | 2026-11-11 05:43:28,057 - pypowerwall.tedapi.pypowerwall_tedapi - WARNING - This API [get_api_unimplemented_timeout] is using mock data in tedapi mode. This message will be printed only once at the warning level.
pypowerwall-server  | 2026-11-11 05:43:28,058 - pypowerwall.tedapi.pypowerwall_tedapi - WARNING - This API [get_api_powerwalls] is using mock data in tedapi mode. This message will be printed only once at the warning level.
pypowerwall-server  | 2026-11-11 05:43:28,058 - app.core.gateway_manager - INFO - Gateway default firmware: 26.34.2 56d7ba06
pypowerwall-server  | 2026-11-11 05:43:28,058 - app.core.gateway_manager - INFO - Successfully connected to gateway default (192.168.1.30) - Site: BLAH
pypowerwall-server  | 2026-11-11 05:43:28,136 - app.mqtt.publisher - INFO - MQTT HA discovery published for gateway 'default' (36 entities)
pypowerwall-server  | 2026-11-11 05:43:55,877 - app.mqtt.publisher - INFO - MQTT control 'dispatch_power' for 'default' prepared (value=500; battery unchanged)
pypowerwall-server  | 2026-11-11 05:44:02,555 - pypowerwall.tedapi.tedapi_v1r - WARNING - Battery dispatch accepted: discharge 500 W for 30 s. A dispatch overrides the backup reserve and grid export settings and could void your warranty - use at your own risk.
pypowerwall-server  | 2026-11-11 05:44:02,556 - app.core.gateway_manager - INFO - [default] local_control(dispatch_battery_power) completed successfully
pypowerwall-server  | 2026-11-11 05:44:02,556 - app.mqtt.publisher - INFO - MQTT control 'dispatch' for 'default' acknowledged (power_watts=500, duration_seconds=30 via local v1r); check actual battery power

@jasonacox

Copy link
Copy Markdown
Owner

Awesome! Thanks @BJReplay !

@BJReplay

Copy link
Copy Markdown

@jasonacox Sorry, didn't notice the request for resume until now. PC shut down, but have tested resume from my phone, and confirmed that the battery started discharging, and then stopped quicker than 30 seconds, so I'm going to call that a pass, too. I can read logs from my phone, but it is way too hard.

@jasonacox

Copy link
Copy Markdown
Owner

Thank you so much @BJReplay! You tested the final build, then the published 0.16.0 image, and even tested Resume from your phone. Seeing a 500 W dispatch acknowledged and the battery actually discharging on your system was exactly the live check this feature needed. That's now in the 0.16.0 release credits, and reading logs on a phone is above and beyond. 🙏

And thanks again @longzheng for building MQTT dispatch so carefully in the first place. It's out in 0.16.0!

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.

4 participants