Repository navigation
support for pixii control, solaredge (w/o meter) + some UI improvements - #32
Merged
Merged
Conversation
erikarenhill
commented
Apr 15, 2026
Collaborator
- Support for controlling Pixii
- Support for SolarEdges without meter
- Removed hard coded sungrow & ferroamp from live charts, reading configured devices instead
The driver assumed Pixii's native meter reported negative=import and negated W/A at the emit boundary. On current firmware the Model 203 meter block already uses the site convention (+import / -export), so the negation flipped the sign backward — the UI showed 'importing' while the meter was actually exporting. Pass W and per-phase W/A through unchanged.
Clone of drivers/solaredge.lua with the SunSpec Model 203 meter block stripped out. Use this when the grid meter comes from a different driver (e.g. Pixii Model 203) and only PV generation is wanted from the SolarEdge inverter. Reads FC 0x03 (holding) instead of FC 0x04 (input): the commercial SolarEdge gateway tested here only serves holding registers — the residential input-register mirror documented in the stock driver times out. Keeps the SunSpec common + inverter (Model 103) reads: AC power (with sign flip → site convention), frequency, lifetime Wh, heat-sink temp, MPPT1/MPPT2 A/V, SN + make for device identity.
Implement the control path alongside the existing read-only telemetry,
following Pixii PowerShaper Modbus Mapping doc 13300 rev 2.0 page 15.
- Heartbeat: tick register 39903 on every poll so the system never
times out to idle after 60 s of silence.
- Setpoint: write registers 39905/39906 atomically via write-multiple
(FC 0x10). The Pixii uses generator reference frame on this path
(positive = discharge), so negate power_w at the boundary to match
the project-wide EMS convention (positive = charge).
- Command handlers: driver_command("battery") writes the setpoint,
driver_default_mode and driver_cleanup reset to 0 so the watchdog
rolls the battery back to idle on telemetry loss.
Verified end-to-end: /api/target -> PI loop -> driver_command ->
modbus_write_multi -> Pixii actual power follows within one tick.
The config-reload applier rebuilt driverCapacitiesFrom(newCfg.Drivers) and assigned it to the local capacities variable. But api.Deps.Capacities holds a separate reference captured at startup, so the reassignment orphaned the new map and every downstream consumer kept reading stale data until the next process restart. Two consequences were visible: - /api/status.bat_soc is weighted by capacity, so a driver that gained battery_capacity_wh via hot-reload still contributed zero weight and avg_soc stayed at 0 while the driver card showed the correct per- driver value (dashboard mismatch). - control.ComputeDispatch also filters by capacities, so the affected driver was silently excluded from battery dispatch - no setpoint was ever sent to it, making it look like the driver's control path was broken when the real issue was eligibility. Mutate the existing map in place (delete + repopulate) so every holder of the original reference sees the update on the next read.
The live chart had hardcoded series for 'ferroamp' and 'sungrow', which were invisible when either driver wasn't configured and wrong when any other battery driver was active. Rebuild the chart around a chartBatteries map keyed by driver name, populated from /api/status and /api/history as drivers appear. - Any driver in data.drivers that exposes bat_w is treated as battery- capable and gets its own actual/target series pair. - ensureBatteryDriver(name) backfills a new driver's arrays with zeros up to chartHistory.timestamps.length so index alignment stays intact for the hover tooltip. - Drivers that stop reporting for a cycle push 0 into their slot so lines stay contiguous and no prior points get shifted. - batteryColor(name) hashes the driver name to a stable palette slot so reload doesn't reshuffle colors. - syncBatteryLegend() appends a <span class="legend-item" data-toggle="bat:<name>"> for each discovered driver; the existing delegated click handler on #chart-legend picks it up for free and legendHidden persistence via localStorage covers new entries. - loadHistory resets chartBatteries and rediscovers from each history item's drivers + targets maps. - Static Ferroamp/Sungrow legend items removed from index.html; a comment marks where the dynamic entries land.
erikarenhill
added a commit
to erikarenhill/forty-two-watts
that referenced
this pull request
Apr 15, 2026
The success step of @semantic-release/github walks every commit
included in the release, parses `(#N)` references out of merge commit
subjects via issue-parser, and then calls GitHub API to annotate each
referenced PR with a "Released in vX.Y.Z" comment, labels, etc. The
v1.0.0 run of this workflow successfully published the tag + GitHub
release, then crashed in that success step with
AggregateError: HttpError: Not Found
- /repos/{owner}/{repo}/pulls/{pull_number}/commits
because most of the referenced PR numbers (srcfl#32, srcfl#33, srcfl#34, srcfl#35, srcfl#36,
srcfl#39) come from UPSTREAM frahlg/forty-two-watts PRs, not from this
fork. In the fork, those PR numbers either don't exist or refer to
unrelated PRs, so the lookup 404s and the whole job fails. The
release itself is fine — the tag, CHANGELOG.md, and GitHub Release
for v1.0.0 all got created — but because the job exit code is
non-zero, the docker build dependency evaluates `needs: release` as
failed and skips.
Disable every feature on @semantic-release/github that walks PR
references. The plugin's only remaining job is to POST to
/repos/{owner}/{repo}/releases once per release, which is what we
actually care about. Explicitly turned off:
successComment — no "released in" comments on PRs/issues
failComment — no failure report issues
failTitle — no fail-report titles
labels — no labeling of PRs on failure
releasedLabels — no "released" labels on PRs
addReleases — no "next release" section on the GitHub Release
These options map 1:1 to the GitHub API calls the plugin makes;
with all six off, the plugin no longer touches /pulls/* endpoints
and the 404 can't happen. Tested locally via config shape only;
correctness will be visible on the next workflow run.
github-actions Bot
pushed a commit
to erikarenhill/forty-two-watts
that referenced
this pull request
Apr 15, 2026
## [1.0.1](v1.0.0...v1.0.1) (2026-04-15) ### Bug Fixes * **ci:** disable @semantic-release/github PR annotation features ([51eb9e2](51eb9e2)), closes [srcfl#32](https://github.com/erikarenhill/forty-two-watts/issues/32) [srcfl#33](https://github.com/erikarenhill/forty-two-watts/issues/33) [srcfl#34](https://github.com/erikarenhill/forty-two-watts/issues/34) [srcfl#35](https://github.com/erikarenhill/forty-two-watts/issues/35) [srcfl#36](https://github.com/erikarenhill/forty-two-watts/issues/36) [srcfl#39](https://github.com/erikarenhill/forty-two-watts/issues/39)
Contributor
|
🎉 This PR is included in version 2.0.1 🎉 The release is available on GitHub release Your semantic-release bot 📦🚀 |
erikarenhill
added a commit
that referenced
this pull request
Apr 16, 2026
The success step of @semantic-release/github walks every commit
included in the release, parses `(#N)` references out of merge commit
subjects via issue-parser, and then calls GitHub API to annotate each
referenced PR with a "Released in vX.Y.Z" comment, labels, etc. The
v1.0.0 run of this workflow successfully published the tag + GitHub
release, then crashed in that success step with
AggregateError: HttpError: Not Found
- /repos/{owner}/{repo}/pulls/{pull_number}/commits
because most of the referenced PR numbers (#32, #33, #34, #35, #36,
#39) come from UPSTREAM frahlg/forty-two-watts PRs, not from this
fork. In the fork, those PR numbers either don't exist or refer to
unrelated PRs, so the lookup 404s and the whole job fails. The
release itself is fine — the tag, CHANGELOG.md, and GitHub Release
for v1.0.0 all got created — but because the job exit code is
non-zero, the docker build dependency evaluates `needs: release` as
failed and skips.
Disable every feature on @semantic-release/github that walks PR
references. The plugin's only remaining job is to POST to
/repos/{owner}/{repo}/releases once per release, which is what we
actually care about. Explicitly turned off:
successComment — no "released in" comments on PRs/issues
failComment — no failure report issues
failTitle — no fail-report titles
labels — no labeling of PRs on failure
releasedLabels — no "released" labels on PRs
addReleases — no "next release" section on the GitHub Release
These options map 1:1 to the GitHub API calls the plugin makes;
with all six off, the plugin no longer touches /pulls/* endpoints
and the 404 can't happen. Tested locally via config shape only;
correctness will be visible on the next workflow run.
github-actions Bot
pushed a commit
that referenced
this pull request
Apr 16, 2026
## [2.2.1](v2.2.0...v2.2.1) (2026-04-16) ### Bug Fixes * **ci:** disable @semantic-release/github PR annotation features ([4020d46](4020d46)), closes [#32](#32) [#33](#33) [#34](#34) [#35](#35) [#36](#36) [#39](#39) * **ci:** switch semantic-release to conventionalcommits preset ([7e0bb89](7e0bb89)) * **ci:** upgrade GitHub Actions to Node.js 24 (drop deprecated Node 20) ([4005bd8](4005bd8)) ### UI * remove manual EV charging slider ([063174c](063174c))
github-actions Bot
pushed a commit
that referenced
this pull request
Apr 16, 2026
## [0.4.0](v0.3.0...v0.4.0) (2026-04-16) ### Features * config/UI improvements — kWh display, secure EV password, planner tab ([#65](#65)) ([35ab03d](35ab03d)) * Easee Cloud driver + host.http_get/post for Lua drivers ([#56](#56)) ([4cdc942](4cdc942)) * EV charger config + credential masking in API responses ([#58](#58)) ([c22cb80](c22cb80)) ### Bug Fixes * 5 Go-side P1 bugs from Codex review ([#46](#46)) ([0cd2885](0cd2885)) * 5 Go-side P1 bugs from Codex review ([#47](#47)) ([4f2eaf6](4f2eaf6)) * address P2 review comments across control, MPC, drivers, and UI ([#64](#64)) ([fcafa88](fcafa88)) * **ci:** disable @semantic-release/github PR annotation features ([4020d46](4020d46)), closes [#32](#32) [#33](#33) [#34](#34) [#35](#35) [#36](#36) [#39](#39) * **ci:** switch semantic-release to conventionalcommits preset ([7e0bb89](7e0bb89)) * **ci:** upgrade GitHub Actions to Node.js 24 (drop deprecated Node 20) ([4005bd8](4005bd8)) * Lua driver Command() reading wrong field — Sungrow ignored targets ([9237156](9237156)) * populate EV Charger tab from driver config when ev_charger is empty ([5e6b116](5e6b116)) * remove dead evSlider event listeners that crash app.js ([8ae76c7](8ae76c7)) * replace wonky Catmull-Rom spline with simple linear forecast ([abea431](abea431)) * show '...' instead of stale v0.1.0 while JS loads version ([dc65065](dc65065)) * **solaredge_pv:** read SunSpec scale factors every poll, not cached ([#38](#38)) ([26f8793](26f8793)) ### Drivers * add Eastron SDM630 Lua driver ([#18](#18)) ([d5ad806](d5ad806)) * add Ferroamp Modbus driver (alt transport to ferroamp.lua) ([#31](#31)) ([03b802c](03b802c)) * fix 9 P1 bugs flagged by Codex review ([#44](#44)) ([b20e485](b20e485)) * port Deye SUN-SG hybrid inverter to 42W v2.1 Lua host ([#29](#29)) ([df8fbc0](df8fbc0)) * port Fronius GEN24 (SunSpec) to Lua ([#19](#19)) ([c1fc875](c1fc875)) * port Fronius Smart Meter (SunSpec Modbus, read-only) ([#24](#24)) ([575895c](575895c)) * port GoodWe hybrid inverter (ET-Plus / EH) to Lua v2.1 ([#28](#28)) ([e43d2d9](e43d2d9)) * port Growatt hybrid inverter driver (read-only) ([#20](#20)) ([92524ac](92524ac)) * port Huawei SUN2000 hybrid inverter ([#15](#15)) ([09a8855](09a8855)) * port Kostal Plenticore / Piko IQ (Lua, read-only) ([#21](#21)) ([bdeca96](bdeca96)) * port Pixii PowerShaper battery driver to v2.1 Lua host ([#22](#22)) ([70a96d1](70a96d1)) * port SMA hybrid inverter Lua driver ([#23](#23)) ([dd34555](dd34555)) * port Sofar HYD-ES/HYD-EP from hugin to Lua v2.1 ([#26](#26)) ([14f6131](14f6131)) * port SolarEdge SunSpec inverter + meter to Lua (read-only) ([#30](#30)) ([1007e63](1007e63)) * port Solis hybrid inverter ([#27](#27)) ([98b2a50](98b2a50)) * port Victron Energy GX Modbus driver ([#25](#25)) ([ad71db2](ad71db2)) ### UI * add status bar with driver health indicators ([b048d60](b048d60)) * EV status card + Easee control commands ([#59](#59)) ([b03749a](b03749a)) * fix summary cards grid for 7 cards + raise side-by-side breakpoint ([6e19973](6e19973)) * inline target on hover + driver card + collapsible model cards ([de88f43](de88f43)) * legend wrap + nice-tick y-axis + cleaner chart labels ([#33](#33)) ([aeb1d1c](aeb1d1c)) * remove manual EV charging slider ([063174c](063174c)) * show mode band in plan chart + grid target on status card ([877e0bd](877e0bd)) * smooth Catmull-Rom spline for forecast + 15min forecast zone ([dba51a5](dba51a5)) ### Control loop * fold live DerEV readings into the EV clamp ([#36](#36)) ([5d57d68](5d57d68)) * slew-rate anchors on actual battery power, not stale command ([#41](#41)) ([4f73f19](4f73f19)) ### MPC planner * fall back to forecast when learned PV twin collapses ([#39](#39)) ([f3062ac](f3062ac)) * log optimize params + ems_mode per action for plan chart ([9e8c14b](9e8c14b)) * value SoC at import−export spread in self-consumption modes ([#40](#40)) ([a90d525](a90d525)) ### Telemetry * add DerEV type for EV charger readings ([#34](#34)) ([65c9e2c](65c9e2c)) ### TSDB * long-format SQLite (14d) + Parquet rolloff for older ([c53c964](c53c964)) ### Safety * watchdog marks stale drivers offline + reverts to autonomous ([519196c](519196c))
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.