feat: add grid charge blackout windows - #119
Conversation
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. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 14ca9f2d53
ℹ️ 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".
| if force_state.get("scope") == "optimizer": | ||
| self._clear_optimizer_force_state() | ||
| elif self._force_state_clearer: | ||
| self._force_state_clearer() |
There was a problem hiding this comment.
Preserve force state until blackout restoration succeeds
When restore_normal() or set_self_consumption_mode() returns False, these lines have already cleared the optimizer/shared force state even though the inverter may still be force-charging. The failure branch then claims the state is retained for retry, but status and subsequent ownership checks can report no optimizer force, making cleanup unreliable during the blackout. Clear the state only after a successful restore, or snapshot and restore it on failure as the adjacent SOC-cap path does.
Useful? React with 👍 / 👎.
| return [ | ||
| self._time_is_in_grid_charge_blackout( | ||
| localize(timestamp) if callable(localize) else timestamp, | ||
| windows, | ||
| ) | ||
| for timestamp in self._price_timestamps(n) |
There was a problem hiding this comment.
Block slots that overlap minute-level blackout windows
For valid windows whose boundaries are not aligned to the fixed five-minute optimizer interval, the mask tests only each slot's start timestamp. A window such as 22:01–22:04 therefore matches no schedule slot, and the runtime gate is likewise only reached when an action is executed, so a planned charge spanning that entire window can continue unchanged. Either reject/round non-aligned times or mark every slot whose execution interval overlaps a blackout window.
Useful? React with 👍 / 👎.
| except ValueError: | ||
| # Do not persist malformed legacy/text-client input during | ||
| # setup. The options form also shows the field-specific error. | ||
| return await self.async_step_ml_options() |
There was a problem hiding this comment.
Surface setup validation errors instead of resetting the form
When a user enters malformed blackout JSON during initial setup, this exception path recursively renders the step with user_input=None, so no field error is shown and all submitted values are replaced by defaults. The user only sees that Continue did nothing, despite the new invalid_grid_charge_blackout_windows translation being available. Re-render the form with the field-specific error and preserve the submitted values, as the options-flow path does.
Useful? React with 👍 / 👎.
Summary
Adds site-local Smart Optimization grid-charge blackout windows with setup, options, and optimizer-settings support.
Validation