Repository navigation
feat(sungrow): read live values once a second (1.6.0) - #179
Conversation
driver_poll returns 1000 ms. Power, SoC, per-phase values and the EMS readback are read on every poll; counters, nameplate, temperature, frequency and fault bits keep the five-second rate and ride along on the polls between, only when that poll's own power read succeeded. A read FTW refused during a reconnect wait no longer counts toward treating a register as absent. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com>
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 265d909328
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| else | ||
| battery.charge_wh, battery.discharge_wh = slow.charge_wh, slow.discharge_wh |
There was a problem hiding this comment.
Stop re-emitting cached slow values as fresh
Between full reads, this copies the previous battery counters into a new one-second host.emit without preserving their observation time or marking them stale; the analogous PV and meter caches do the same. Whenever live power continues but a slow field has not been reread, consumers therefore receive that old measurement as part of a fresh sample, contrary to the repository requirement not to emit stale cached telemetry as fresh. Keep the original sample age explicitly or avoid replaying these fields.
AGENTS.md reference: AGENTS.md:L71-L75
Useful? React with 👍 / 👎.
driver_poll returned 1000 ms, which FTW ignored until srcfl/ftw#1616. An SDM630 often shares an RS485 bus with an inverter, and its one 76-register read takes about 0.18 s at 9600 baud. Return 5000 until hardware shows one second is safe. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com>
driver_poll returned 1000 ms, which FTW ignored until srcfl/ftw#1616. Hold it at the five seconds it has run at until hardware shows one second works. It reads MQTT, so the hold is about unproven behaviour, not bus load. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com>
…(0.3.3)" pixii_pv reads Core's local MQTT queue, so the bus-load reason for the hold does not apply. The owner chose to let it run at one second like ferroamp. This reverts commit b5af185. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com>
….0.3)" The owner says an SDM630 easily reads at one second, so it runs at the 1000 ms its driver asks for. This reverts commit 48cae6c. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com>
Summary
FTW sends live frames once a second, but the home box reads its Sungrow
site meter every 5 s, so the phone's figures jump every 5 s
(srcfl/ftw-app#33). sungrow 1.6.0 returns 1000 ms from
driver_pollandsplits its reads:
(13019), EMS readback (13049 holding, for
setpoint_w), PV power (5016)and MPPT (5010), grid power (5600), per-phase W, V and A (5602, 5740,
5743).
rated power (5000), heatsink temperature (5007), grid frequency (5241),
fault bits (13049 input), battery and grid energy counters (13040, 13026,
13036, 13045). Diagnostic metrics keep this rate too.
Between full reads, each blob carries the last slow values. FTW stores each
emit whole, and its energy ledger starts over (
counter_resumed) whenever acounter drops out of a reading. The carried values ride only on a poll whose
own power read succeeded, so they never outlive the device. Each is at most
one full cycle old, the age it reaches between polls today.
Per-phase current is read every second as well, because FTW's fuse guard
reads it from the meter blob.
A read FTW refused while it waited to reconnect ("modbus reconnect
backoff") no longer counts toward treating a register as absent. FTW's
first reconnect wait is 2 s, which spans two polls at one per second.
Counted, one dropped packet could mark a whole block absent until restart.
Other bundled drivers. With srcfl/ftw#1616, sdm630 and pixii_pv also
move to the 1 s they already return. The owner accepted both: an SDM630
easily reads at 1 s, and pixii_pv reads MQTT, so it adds no bus traffic.
Paired with srcfl/ftw#1616. Core ignores the return value until that
merges. On an older Core this driver still polls every 5 s, and then every
poll is a full read, as before. The FTW pin moves in a separate PR after
both merge.
Driver evidence
(device type 0x0E0E), Modbus TCP
Hardware, 14 Oct 2026, owner's home box. Sungrow SH hybrid (device type
0x0E0E), Modbus TCP on the LAN, FTW v0.142.1-beta.1. The owner approved a
30-minute driver draft (
POST /api/drivers/sungrow/draft), which reverted byitself at 06:45. The draft was this driver plus two lines for the test:
host.set_poll_interval(1000), because that Core ignores the return, and atimer around each Modbus read that logged a summary each minute.
/api/drivers/sungrow, sampled 4 times a secondJournal, 06:10–06:55: no warning during the run. Two
modbus reconnectedlines, one at each driver restart. One
site dispatch inhibited (site_meter_stale)for 3 s at 06:45:04, after the revert: the bundled 1.5.10waits 5 s for its first poll after a restart, and the same line appears at
every restart in the 24 h before. The draft start, which polled after 1 s,
had none.
Limits: 30 minutes on one site, early morning, battery full and mostly idle,
so few control writes shared the Modbus session. A WiNet-S dongle answers
more slowly than this LAN port.
Verdict: 1 s is safe for this Sungrow. Modbus traffic takes about 17 ms of
each second, and nothing failed.
Safety
Control evidence
required: not applicable, read path only.Checks
Signed-off-by.make test-driver ID=sungrowmake check(4908 passed)New tests in
test_sungrow_poll_cadence.py: the 1000 ms return, whichregisters each poll reads, full reads on a 5 s host, carried values, no
carried values without this poll's power read, reconnect waits not counted,
refused registers still given up. Five of them fail on 1.5.10.
test_fault_clears_on_a_running_state_of_zeronow steps the clock 5 s perpoll, because the running state is read on full polls.
Also run, not committed: this driver under FTW's gopher-lua with the
srcfl/ftw#1616 run loop and a fake Modbus, 12 s. Polls 1 s apart, 9 reads
each, 19 every 5 s, counters kept in the meter blob.
🤖 Generated with Claude Code