Conversation
Users confused "Eff. kW" (effective power from the DP schedule after hybrid/commitment resolution) with an efficiency metric, and were puzzled to see it pinned at 0 while the battery was visibly charging. This is expected: in zero_grid mode there's no fixed schedule power, it's recalculated continuously by the real-time zero-grid controller instead, and shown in "Setpoint kW" / the Real-time Setpoint Log. Add a note and a column tooltip explaining this.
effective_power_kw is always 0 during zero_grid mode by design (the real-time controller determines power dynamically, not the DP schedule), so comparing it to setpoint_kw unconditionally made the "SoC/power limited" warning tip and red row-highlight fire on nearly every normal zero_grid charge/discharge cycle -- a false positive unrelated to any actual SoC or power constraint. Skip the comparison when effective_mode is zero_grid, in both the tip generator (analyzer.js) and the run-log table highlighting (index.html). The setpoint_log's own soc_limited flag (computed in coordinator_optimization.py by comparing dp_schedule_w vs raw_target_w) is unaffected: it already requires dp_schedule_w > 50W, which is never true during zero_grid (controller_schedule_w is 0 there too), so it doesn't share this false-positive.
…grid fix: clarify Eff. kW and stop false "SoC/power limited" warnings during zero_grid
…rice forecast Hybrid mode charges the battery as soon as PV surplus appears, even when the forecast shows abundant cheaper surplus later in the day (e.g. the midday PV peak at low prices). The new hybrid+ mode behaves like hybrid, but only stores surplus when the DP shadow price says the stored energy is worth more than exporting it: capture requires lambda x sqrt(RTE) >= current feed-in price, with a +/-5% hysteresis band to prevent oscillation. When capture is blocked the surplus is exported at the current feed-in price and the battery charges later from the cheaper surplus via the regular DP schedule. The realtime idle->zero_grid upgrade respects the same block so surplus appearing between optimizer runs is not captured anyway. Discharge decisions, self-consumption on grid import, and negative feed-in handling (always capture) are unchanged from hybrid.
Community forum questions (community.home-assistant.io/t/re-custom-integration-battery-controller/1016849) showed users were confused why Hybrid mode charges the battery via zero-grid even at a positive feed-in price, and why the schedule can look different between two closely-timed screenshots.
…run deviations The README and ALGORITHM.md described the shadow price as feeding forward into the next run's terminal condition. optimizer.py no longer does this (deliberately, to avoid a circular self-suppression bug at peak prices) — the terminal value comes from a tail-average of the feed-in forecast every run. Replaced with an accurate explanation of why the DP's full-horizon re-solve (a global allocation of limited capacity across price opportunities) can make two runs a few minutes apart look meaningfully different, which is what triggered the community forum question this addresses.
Same fix as the README/ALGORITHM.md correction: the DP terminal condition comes from the feed-in forecast tail, not the previous run's shadow price. Fixed the misleading comment in diagnostics.py, the print text in simulate_diagnostics.py, and a stale label plus dead empty if-block in docs/index.html. No behavior change — text/comments only.
…osdoip docs: clarify Hybrid mode trade-off and rolling-horizon re-optimization
…ce-forecast-jzltzl # Conflicts: # README.md
Two independent bugs were causing the erratic behavior: - The feed-in price sensor was never tracked for state changes when it's a separate entity from the buy price sensor, so current_feed_in_price (and PVCurtailmentSensor) only refreshed on buy-price events, the mid-period timer, or the 60-min base update_interval — lagging the actual feed-in price by up to an hour. - Condition B (battery absorption limiting) compared live, noisy battery power against a single threshold on every real-time zero_grid update (every ~5-10s), flapping the sensor independent of any price change. Added an entry/recovery hysteresis band, matching the pattern already used for hybrid zero_grid/charging transitions.
…-bxvwup fix: PV Curtailment Suggested lagging feed-in price and flapping mid-period
…-jzltzl feat: add hybrid+ control mode that gates PV-surplus capture on the price forecast
When the user switches control mode (e.g. hybrid → follow_schedule), the real-time loop previously continued using the cached _effective_mode from the previous mode (e.g. "zero_grid") until the re-optimization triggered by async_request_refresh() completed. This caused a brief window where the old mode's setpoint was still applied, and made the transition non-atomic. Changes: - control_mode setter now resets _effective_mode = ACTION_IDLE and _controller_schedule_w = 0.0 so the real-time loop immediately applies a safe idle setpoint while the re-optimization is running. - Added _optimization_trigger_source tracking: each trigger site now labels the run (mode_change, price_boundary, price_spike, price_available, mid_period, feed_in_price_change, soc_available, forecast_available, pending_rerun). The label appears in the optimizer_run_log for diagnostics. - Extended test_mode_switch_resets_commitment to cover the new resets. Closes #88 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
When the user switches control mode (e.g. hybrid → follow_schedule), the real-time loop previously continued using the cached _effective_mode from the previous mode (e.g. "zero_grid") until the re-optimization triggered by async_request_refresh() completed. This caused a brief window where the old mode's setpoint was still applied, and made the transition non-atomic. Changes: - control_mode setter now resets _effective_mode = ACTION_IDLE and _controller_schedule_w = 0.0 so the real-time loop immediately applies a safe idle setpoint while the re-optimization is running. - Added _optimization_trigger_source tracking: each trigger site now labels the run (mode_change, price_boundary, price_spike, price_available, mid_period, feed_in_price_change, soc_available, forecast_available, pending_rerun). The label appears in the optimizer_run_log for diagnostics. - Extended test_mode_switch_resets_commitment to cover the new resets. Closes #88 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… control mode The control_mode setter resets the commitment filter and (since #88) also forces the cached setpoint to idle so the real-time loop stops applying the previous mode's schedule while the mode-change re-optimization runs. Both resets also fired when the selected mode was already active: HA's select entity calls async_select_option on every service call, so an automation (or voice assistant) that periodically re-asserts the current mode would wipe the commitment filter and drop the battery to an idle setpoint until the next optimization completed — churn for a no-op. Guard the setter: when the requested mode equals the current mode there is no stale state to clear, so return without touching anything. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XJ1durpbByC5PtwhFkiHzm
The sensor was intended to signal the price condition only: feed-in price negative = curtailment suggested. The battery-absorption conditions (SoC near maximum, actual charge power below the setpoint) second-guessed that intent and made the sensor state depend on live battery power, which also required hysteresis to keep it from flapping between DP re-optimizations. is_on is now simply current_feed_in_price < 0. The absorption conditions, the condition-B hysteresis latch, and the now-unused ABSORPTION_THRESHOLD constant are removed. The battery/setpoint diagnostic attributes on the sensor are kept unchanged. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XJ1durpbByC5PtwhFkiHzm
…-mode-reselect fix: don't reset commitment and setpoint when re-selecting the active control mode
fix: make PV Curtailment Suggested purely price-based
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.
No description provided.