Repository navigation
fix(drivers): honour the interval driver_poll returns - #1616
Conversation
Core discarded driver_poll's return value and polled every driver every five seconds unless it called host.set_poll_interval. The returned wait now sets the next poll, between one second and thirty seconds. A driver that calls host.set_poll_interval keeps that interval, unbounded, as before. Registry.PollInterval reports the wait the run loop armed, so driver repository activation waits long enough for a driver on a returned interval. 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: ab87ceb347
ℹ️ 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".
| // sets it with host.set_poll_interval, as the vehicle drivers do. | ||
| const ( | ||
| minReturnedPollInterval = time.Second | ||
| maxReturnedPollInterval = 30 * time.Second |
There was a problem hiding this comment.
Cap returned waits below the configured watchdog
When site.watchdog_timeout_s is configured below 30 seconds—config.go accepts any nonnegative value—a driver that emits successfully and then returns a longer interval is now left idle past its watchdog deadline. For example, a 10-second watchdog with a 30-second returned wait makes WatchdogScan repeatedly mark the driver offline and send its autonomous default between otherwise successful polls; the previous five-second cadence did not. Derive this cap from the effective site/per-driver watchdog or otherwise ensure the scheduled wait remains below it.
AGENTS.md reference: AGENTS.md:L66-L67
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>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com>
The owner dropped the hold: an SDM630 easily reads at one second, and pixii_pv reads MQTT. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com>
* feat(sungrow): read live values once a second (1.6.0) 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> * fix(sdm630): stay at five seconds until seen at one second (2.0.3) 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> * fix(pixii_pv): stay at five seconds until seen at one second (0.3.3) 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> * Revert "fix(pixii_pv): stay at five seconds until seen at one second (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> * Revert "fix(sdm630): stay at five seconds until seen at one second (2.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> --------- Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Problem and result
Core threw away the number a driver returns from
driver_poll(
_, err := rd.driver.Poll(...)inregistry.go). Onlyhost.set_poll_intervalcounted, so every other driver was read everyfive seconds. The driver contract in srcfl/device-drivers says the return
is "milliseconds until the next call". Ferroamp asks for 1000 ms and gets
5 s. The Sungrow site meter on the home box is read every 5 s, so the
phone's live figures move every 5 s even though Lane 0 and FTW Cloud send
once a second (srcfl/ftw-app#33).
second and thirty seconds.
host.set_poll_intervalwins. Once a driver calls it, Core keepsthat interval, unbounded, as before, and ignores what
driver_pollreturns. Every driver that sets its own cadence today keeps it exactly.
before.
Registry.PollIntervalreports the wait the run loop armed, so driverrepository activation waits long enough.
time.Duration, so itcannot overflow.
Why these bounds:
2 s by default. A faster read reaches nothing but the device's bus. Some
catalog drivers return 200 ms (P1) or 50 ms.
wait cannot make a driver stale on its own. myuplink returns 60 s after a
good read; at 60 s plus the fetch it would go offline every minute.
Drivers that need longer waits (vag_vehicle 300 s, tesla_cloud 60 s)
already set them with
host.set_poll_interval, which this does not bound.A "return wins" rule would have cut their waits to 30 s and raised their
cloud API calls, which is why
set_poll_intervalwins here.Scope and safety
Bundled drivers at the current pin that only return an interval:
None of these has hardware evidence at 1 s in FTW. The owner chose to run
all seven at 1 s. The owner's evidence for sdm630: "SDM630 kan LÄTT läsa på 1 s så
inga problem" (an SDM630 easily reads at 1 s). pixii_pv reads Core's local
MQTT queue, so 1 s adds no bus traffic. An earlier version of this text
called pixii_pv Modbus; that was wrong.
Unchanged: every driver that calls
host.set_poll_interval(esphome_dsmr,nibe_local, tesla_vehicle, tibber, zuidwijk_p1 and the vehicle drivers),
and every driver that returns 5000.
Paired PR
srcfl/device-drivers#179 — sungrow 1.6.0 returns 1000 ms and reads only
what the live view needs every second. It needs this PR to run at 1 s; on
an older Core it still reads everything every 5 s. The FTW pin moves in a
separate PR after both merge.
Verification
go test ./internal/drivers/ ./internal/api/ ./cmd/ftw/, thenmake verify: green.poll_interval_test.go: the bounds,set_poll_intervalwinning in both directions, a fake runtime polled at the returned second
instead of the default, a Lua driver at
set_poll_interval(10)thatreturns 60000 still polled every 10 ms.
fake Modbus for 12 s. 9 reads per poll each second, all 19 every 5 s, and
the meter blob kept its counters between full reads.
Core ignores the return, so the test driver set the same 1 s with
host.set_poll_interval; bus traffic is the same as this PR gives.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.
This PR keeps one thing: after a driver restart, a driver on a returned
interval still waits the 5 s default for its first poll, and a site meter
shows stale for a few seconds, as it does today.
Checklist
🤖 Generated with Claude Code