Skip to content

feat(zap): opt-in read-only PV and battery ingest - #100

Open
frahlg wants to merge 1 commit into
mainfrom
zap-opt-in-read
Open

feat(zap): opt-in read-only PV and battery ingest#100
frahlg wants to merge 1 commit into
mainfrom
zap-opt-in-read

Conversation

@frahlg

@frahlg frahlg commented Aug 23, 2026

Copy link
Copy Markdown
Member

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

config:
  host: zap.local
  read_pv: true        # default false
  read_battery: true   # default false

FTW Settings → Devices will expose the same switches once the bundled pin moves.

Test plan

  • make test-driver ID=zap
  • catalog generate (index, devices, support-status, manifests sha)
  • full pytest + host-api + sandbox + baseline check
  • FTW go test ./internal/drivers -run Zap against 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 ders become [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.

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>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 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".

Comment thread drivers/lua/zap.lua
end
end

if any_power then

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge 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 👍 / 👎.

Comment thread manifests/zap.yaml
Comment on lines +15 to +16
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"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge 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 👍 / 👎.

@frahlg

frahlg commented Aug 23, 2026

Copy link
Copy Markdown
Member Author

Companion FTW PR: srcfl/ftw#974 — Settings → Devices opt-in, tests, docs, bundled pin.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes using high effort and found 2 potential issues.

Fix All in Cursor

❌ 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.

Comment thread drivers/lua/zap.lua
else
host.log("warn", "Zap: site-meter fetch failed: " .. tostring(err))
end
end

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 60021a0. Configure here.

Comment thread drivers/lua/zap.lua
end
end

if not any_power then return end

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 60021a0. Configure here.

@cursor
cursor Bot requested review from Leitet and davmoz August 23, 2026 16:59

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Left a non-blocking comment: Cursor Bugbot found two unresolved medium-severity issues, so this is not approved. Assigned Leitet and davmoz for human review.

Open in Web View Automation 

Sent by Cursor Approval Agent: Pull Request Router and Approver

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.

1 participant