Skip to content

feat(control): show command limits and measured response tiers - #1474

Draft
frahlg wants to merge 11 commits into
masterfrom
feat/control-feedback
Draft

frahlg wants to merge 11 commits into
masterfrom
feat/control-feedback

Conversation

@frahlg

@frahlg frahlg commented Sep 29, 2026 •

Copy link
Copy Markdown
Member

Problem and result

A successful driver call can hide an unchanged device, an overwritten setpoint or a charger limit below the user's request. FTW now separates the request, sent command, device setpoint and measured power for each controlled function.

Tier 0 records driver acceptance. Tier 1 requires distinct, fresh device power across a measured window. Tier 2 compares its actual change with a separate physical site meter. Target fulfilment is separate: 4.4 kW against a 5 kW command can reach Tier 2 while the shortfall stays visible. A plateau alone does not establish a device limit. Wrong direction, no power and excess power keep their own warnings, even when the readings are confirmed. Solar normally provides context; curtailment makes it a controlled function. Low sunshine alone cannot prove that a ceiling took effect.

Each device keeps its own tier. An offline charger can remain in the unknown background while a battery reaches Tier 2. The site meter and target device must supply fresh, aligned readings. Other flows correct the comparison only when both windows support them; missing readings never mean zero power. Corrections are selected by timing and availability, never by whether their watts make the result pass. Every aligned point must agree, so an unexplained household pulse cannot disappear into an average. Unknown background may include generation as well as load.

The overview uses a small dot for device measurement, a dot with a ring for site confirmation and an amber warning for shortfalls or known limits, and a red warning for faults. Tier 1 and Tier 2 share one quiet colour; tier text stays in the detail view. Normal command-response waits have a neutral mark, with no mark for inactive commands. A tap opens the existing device controls directly. A collapsed ‘Are we in control?’ section below the controls contains that device's reasons, request, readings and comparison curves. It keeps its open state and keyboard focus through updates. Scope changes select matching evidence. Combined bubbles retain alarms. Offline controlled devices remain visible beside healthy siblings, without displaying old watts as current. Values mode opens the same device view. VISION.md and the roadmap define the evidence standard and the digital-twin goal: keep kW, kWh, reported limits and learned estimates distinct, retain source and uncertainty, and never use a model prediction to confirm itself or raise safety limits. This PR does not change the existing battery learning or planning algorithms.

Scope and limits

  • Record Lua and OCPP results for battery, EV, PV and V2X power commands across modes. Show limits, changed setpoints, missing response, failed calls/defaults and stale data. Non-power commands remain outside this implementation.
  • Tier 1 needs distinct post-command samples over 10 seconds. Tier 2 uses a before-command baseline, up to 20-second windows, at least three aligned samples across eight seconds, at most two seconds of skew, and at least 500 W of change. Tolerance is the larger of 150 W and 15%. These initial thresholds still need more site traces.
  • Recognize a physical meter relayed through an inverter when the driver identifies its source from the register map. Shared transport does not make two physical sensors one. Derived readings do not qualify. The paired Sungrow driver reports its active forced setpoint.
  • Keep confirmed control loss visible as an alarm. Normal response waits, intentional release and unplugging do not trigger a false loss alarm. Fresh proof clears it. This is current UI/API evidence held in memory, not durable alarm history or a push-notification workflow.
  • Tier 2 supports an observed response; it cannot prove exclusive control or identify every unmetered load. A reduced command can be followed while the user's request remains limited. Core's precise battery clamp cause is still unavailable and the UI says so.
  • Dispatch, safety limits, smoothing and polling cadence remain unchanged. Configured controllable batteries show a neutral “No command” row before their first command after restart.

Paired with srcfl/device-drivers#149 (pinned at aa9099e9b985cbfb657c53576a12a5778910a75a) and srcfl/ftw-webapp#75. Optional JSON fields use existing status/loadpoint endpoints. Registry and design tokens stay unchanged.

Overlap reviewed: preserve #1470's vehicle decorators, #1337's charging helper, #888's dispatch changes, #1449's driver-list work and #1292's other vision sections. #1337 may need its loadpoint helper composed with this response wrapper. The source-inventory callback is separate from #1003's Modbus work and #1364's flag-copy change. Bubble rendering and click routing leave #1177's animation/polling lifecycle intact.

Validation

Passed: make verify, 632 Core web tests, targeted API/telemetry race checks, and paired app verification (1,051 passed, one skipped; clean type check and production build). The full Core and app suites need local listening sockets and passed outside the sandbox.

Replay tests cover 250 changing-solar sites and 250 matching cases with an unexplained load pulse that must prevent confirmation. Regressions cover stale/missing optional flows, fresh conflicting corrections, required-meter failures, cached samples, control modes, current limits, overwritten setpoints, release/restart, proof-loss grace and recovery. Fake-clock API regressions cover battery charge/discharge, EV and V2X shortfalls, missing response, wrong direction, overshoot, idle, PV ceilings, changing background, stale samples and recovery. A failed call does not masquerade as lost measurements. UI tests cover confirmed partial delivery, direct battery/EV entry, scoped evidence, disclosure state and focus across updates, fresh-to-lost proof, aggregate alarms and stale watts.

Rendered Core and Svelte views on desktop and at 390 px, including Tier 2 beside an offline Tier 0 device, mixed tiers and alarm details. These are labelled fixtures, not physical Tier 2 evidence. Agent browser checks do not replace human UI review.

The owner's private box reached physical Tier 2 using the separate meter relayed through Sungrow, while Easee stayed in the unmeasured background. A new power command briefly returned its current evidence to Tier 0 during response, then recovered Tier 2; the overview now shows this as a quiet wait rather than a tier badge. The pre-command flows_changing explanation now names the baseline rather than blaming a current background device.

Browser checks on the owner’s box confirm that battery and EV taps open their existing control modals directly, with evidence collapsed below. These checks sent no device commands. The new private build v0.138.2-dev.79518637 is installed and healthy. At the post-install check, Sungrow requested and measured 0 W, showing Tier 1 with no shortfall alarm. The 5-to-4.4 kW case passed telemetry-to-API regressions and browser fixtures; it has not recurred physically on this new build. No merge or beta. Pixii hardware checks, live remote-client validation and human UI review remain before readiness. An earlier private build logged a history timeout and SQLITE_BUSY with retained retries; storage code is outside this PR.

Checklist

  • The change follows VISION.md and one selected scope.
  • Overlapping PRs and shared contracts were checked.
  • Relevant checks cover changed behaviour and failure paths.
  • A human reviewed changed UI in a browser.
  • A Changeset is included.
  • Every commit has a DCO sign-off.

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