feat(zap): opt-in read-only PV and battery ingest - #100
Conversation
P1/HAN stays the default. Sites where Zap is the only reader — closed inverter Modbus, or an RS-485 bus Zap already owns — can set read_pv or read_battery. The driver still never writes. Chargers stay out. Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 60021a0b07
ℹ️ 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".
| end | ||
| end | ||
|
|
||
| if any_power then |
There was a problem hiding this comment.
Suppress aggregates when any tracked source fails
When read_pv tracks multiple resources and one /data/json request fails or lacks a valid W, any_power can remain true because another resource succeeded, so this publishes a partial sum as the complete site PV value; the battery aggregate has the same behavior. Downstream consumers cannot distinguish that undercount from a real production or battery-power change, so suppress or explicitly invalidate the aggregate unless every tracked source contributes a current valid sample.
Useful? React with 👍 / 👎.
| notes: "P1/HAN site meter from a Sourceful Zap. PV and battery telemetry from devices on Zap are opt-in (read_pv / read_battery) and read-only. Prefer a native FTW driver; use Zap as the reader only when it already owns the bus." | ||
| min_driver_version: "3.1.0" |
There was a problem hiding this comment.
Record the Zap API in upstream_docs
The new PV and battery serializers are decoded from the Zap Local API referenced by the driver, but the updated manifest still has no upstream_docs entry. Consequently, the repository's weekly documentation watcher cannot detect when the payload contract changes or disappears; add that API URL and its metadata to this manifest.
AGENTS.md reference: AGENTS.md:L60-L66
Useful? React with 👍 / 👎.
|
Companion FTW PR: srcfl/ftw#974 — Settings → Devices opt-in, tests, docs, bundled pin. |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 2 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 60021a0. Configure here.
| else | ||
| host.log("warn", "Zap: site-meter fetch failed: " .. tostring(err)) | ||
| end | ||
| end |
There was a problem hiding this comment.
Duplicate meter fetch on failure
Medium Severity
After a successful discovery the site meter is always in tracked and already requested in the first loop of snapshot_map. When that request fails, the trailing fallback fetches the same URL again and logs the same warn a second time. Each failed poll therefore pays two HTTP round-trips and duplicate warnings before emit_meter also reports the gap.
Reviewed by Cursor Bugbot for commit 60021a0. Configure here.
| end | ||
| end | ||
|
|
||
| if not any_power then return end |
There was a problem hiding this comment.
Battery emit drops valid SoC
Medium Severity
emit_battery accumulates SoC and energy, then returns early unless sane_power accepted W. The driver comment notes Zap can return integer overflow sentinels when a unit is offline; with a known nameplate those values are rejected, so a still-valid SoC_nom_fract never reaches host.emit("battery", ...). Catalog guidance is to emit the battery DER when any answered field is usable, not only power.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 60021a0. Configure here.




Summary
Zap 3.1.0 keeps P1/HAN as the default and brings back opt-in, read-only ingest of PV and battery from devices Zap already talks to.
That matches the field case where a native inverter driver cannot be used (SolarEdge Modbus closed, no SetApp; or Zap already owns the RS-485 bus). Dual-Modbus sites stay on the 3.0 path: flags default off, so a native FTW driver is not doubled.
The driver still never writes. Chargers stay out — add those in FTW.
Config
FTW Settings → Devices will expose the same switches once the bundled pin moves.
Test plan
make test-driver ID=zappytest+ host-api + sandbox + baseline checkgo test ./internal/drivers -run Zapagainst this commit (companion PR)Note
Medium Risk
Core production driver now can emit extra PV/battery streams that affect site energy accounting if flags are enabled; still read-only and off by default.
Overview
Zap 3.1.0 keeps the P1/HAN site meter as the default path and restores opt-in, read-only ingest of PV and battery from devices Zap already talks to (
read_pv/read_battery, default off). Chargers stay out; the driver still never writes.Discovery now tracks per-serial meter/PV/battery records. When opted in, poll fetches those device snapshots, aggregates power/energy (PV generation forced negative; battery SoC capacity-weighted when possible), and drops overflow-looking power via a 10× nameplate guard. Extra DERs still warn the operator unless the matching flag is on.
Catalog/manifest
dersbecome[meter, pv, battery]; default behaviour is unchanged so a native FTW driver is not doubled.Reviewed by Cursor Bugbot for commit 60021a0. Bugbot is set up for automated code reviews on this repo. Configure here.