fix(planner): pin Energyplan 0.4.3 and land EV duty-cycle support - #1225
Conversation
Drivers, probes and an optional LAN listener now go through one engine keyed by host:port, so two Lua drivers can poll the same inverter (or different unit IDs behind one gateway) without each taking a socket the device will not accept. modbus_proxy is off by default. When on, other integrations talk to FTW instead of the device. Writes stay blocked unless allow_write is set — they would bypass the control loop. Enabling it needs a restart. Signed-off-by: Cursor Agent <cursoragent@cursor.com>
Plan, heating, settings, history/savings/price cards, loadpoints and twins now follow the same visibilitychange rule as status polling: clear the timer while document.hidden, then one fetch and one timer on return. Settings EV and System timers also stop when the modal closes. Energy-flow particles skip rAF while hidden. Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com>
Keep master's shared Modbus session (#987) and graft the LAN proxy onto it instead of a second pool. Resolve config/UI overlap with OCPP; drop the retired CalDAV comments. Signed-off-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Fredrik Ahlgren <fredrik@sourceful-labs.com>
Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com>
Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com>
Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com>
Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com>
Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com>
Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com>
Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com>
Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com>
…ation-20260913 # Conflicts: # go/internal/config/restart_required.go # go/internal/config/restart_required_test.go
…ntegration-20260913
…pport-integration-20260913
Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com>
…pport-integration-20260913
Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com>
Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com>
The worker can finish a last interval below a full charger step, reports on-power and remaining shortfall, and prices on/off pulses so Core accepts the plan. Best-effort deadlines pass the wire gate when shortfall is present.
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_c0605e03-afe1-49a0-915b-c051888352c8) |
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. |
A fleet solve can leave 1e-9 W on an EV after the deadline. Core was rejecting that as an on-power of 0 W with a positive mean.
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_50c44104-ee83-4816-901a-875d4c65a462) |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9e348317f1
ℹ️ 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".
| energy += wh | ||
| } | ||
| } | ||
| return energy / hours |
There was a problem hiding this comment.
Reserve duty-cycle peak wattage at the fuse
For a partial duty-cycle action, this returns the slot-average demand (LoadpointEnergyWh / hours), while the loadpoint controller intentionally commands LoadpointMaxPowerW whenever the pulse is on. For example, a 100 Wh final interval can reserve only 400 W here but switch the charger on at 11 kW, allowing the battery allocator to consume the remaining fuse headroom and potentially exceed the site import ceiling until telemetry catches up. Use the directive's simultaneous on-power when calculating the fuse reservation.
AGENTS.md reference: AGENTS.md:L65-L68
Useful? React with 👍 / 👎.
| first = err | ||
| } | ||
| } | ||
| p.wg.Wait() |
There was a problem hiding this comment.
Close accepted clients before waiting for proxy shutdown
When any Home Assistant or Node-RED client keeps an accepted proxy connection idle, closing only the listeners does not interrupt handleClient's read, so this wait blocks shutdown or an API-requested restart for up to the 90-second idle timeout. Track and close accepted connections, or otherwise cancel their reads, before waiting for the goroutines.
AGENTS.md reference: AGENTS.md:L24-L25
Useful? React with 👍 / 👎.
| proxy, err := modbusEngine.Listen(mbBinds, cfg.ModbusProxy.AllowWrite) | ||
| if err != nil { | ||
| slog.Error("modbus proxy listen failed", "err", err) |
There was a problem hiding this comment.
Report a failed proxy listener to the operator
If the configured port is occupied or cannot be bound, startup continues after only writing this log entry. A repository-wide search shows no Modbus-proxy runtime/status endpoint, so Settings continues to show the proxy as enabled without exposing that it is unavailable; operators will troubleshoot downstream integrations with no normal UI indication of the actual failure. Preserve the safe optional-module behavior, but publish the listener failure through status/config diagnostics.
AGENTS.md reference: AGENTS.md:L22-L23
Useful? React with 👍 / 👎.
Pins Energyplan 0.4.3 and the Core decoder work needed to run it.
Energyplan can now finish a last interval below a full charger step, report on-power and remaining shortfall, and price on/off pulses so Core accepts the plan. This branch also carries the EV reliability, forecast-view, and battery-priority work that the pin depends on.
Local
make verifypassed in Energyplan. Core native testsTestNativePartialFleetAndOldResponseRejected,TestNativeRestoreFuturePVDependencyRequiresNewPlan, andTestNativeAllPhysicalTopologiespassed against the pinned worker.Source commit:
1dd3f01b09134d69f13b3100996ac9e1f915e061(srcfl/energyplan#22).Note
High Risk
Changes core dispatch, EV/fuse allocation, and planner validation paths where small logic errors affect grid import and charging deadlines; the Modbus proxy also exposes unauthenticated LAN access when enabled.
Overview
Pins Energyplan 0.4.3 and extends Core to accept EV duty-cycle plans: per-slot on-power (
LoadpointMaxPowerW), measured-energy budgets, pulse pricing validation, and shortfall reporting when a deadline cannot be met. A newcoreReservePlanpath targets the same contract when the external worker is unavailable.EV charging and fuse sharing get a substantial rework: configured phase/amp planning steps feed the MPC, session energy is tracked from meter/counter readings (not slot-averaged power), failed ev_resume retries stay scoped to the plug session, and scheduled EV demand is reserved before optional battery charge under the site limit.
Dispatch behavior shifts for arbitrage-family idle slots: batteries no longer reactively discharge to cover forecast misses (energy is held for later slots; idle plans can withdraw prior discharge). A live PV export guard adds reactive curtail caps when solar-attributable export exceeds the site ceiling, with explicit residual when caps cannot safely clear the overage.
Adds an optional Modbus TCP proxy (off by default, read-only unless opted in) on FTW’s shared inverter sessions, plus a background forecast scoring worker that pages archived issues so scoring does not block sampling.
Reviewed by Cursor Bugbot for commit 5efb386. Bugbot is set up for automated code reviews on this repo. Configure here.