Skip to content

Implement sliding-window smoothing for production, consumption, and battery with battery recharge reserve - #177

Open
HAuser1234 wants to merge 63 commits into
jmcollin78:mainfrom
HAuser1234:main
Open

Implement sliding-window smoothing for production, consumption, and battery with battery recharge reserve#177
HAuser1234 wants to merge 63 commits into
jmcollin78:mainfrom
HAuser1234:main

Conversation

@HAuser1234

Copy link
Copy Markdown

This pull request introduces configurable sliding-window smoothing for solar production, consumption, and battery charge power readings, as well as a new option to reserve a portion of solar production for battery charging when the battery is not full. These changes make the optimizer more robust against short-term fluctuations and help prioritize battery charging when desired.

The most important changes include:

Smoothing and Reserve Features:

  • Added configuration options for sliding-window smoothing of solar production, consumption, and battery charge power, with user-defined window lengths in minutes. These options allow the system to average readings over a specified period, reducing the impact of short-term spikes or drops. (config_schema.py, const.py, coordinator.py, strings.json) [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11]
  • Implemented a new configuration option to reserve a specified number of watts from solar production for battery charging when the battery state of charge is below 100%. This ensures battery charging is prioritized over other loads when needed. (config_schema.py, const.py, coordinator.py, strings.json) [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11]

Implementation and Code Structure:

  • Refactored the coordinator to use a new _apply_smoothing_window method, which manages the sliding window for each smoothed value using a deque, and updated the update logic to use this method for production, consumption, and battery charge power. (coordinator.py) [1] [2] [3] [4] [5]
  • Updated the configuration schema, constants, and localization files to support the new options, including default values, user-facing strings, and descriptions for each new setting. (config_schema.py, const.py, strings.json) [1] [2] [3] [4] [5] [6] [7]
  • Added german translation

These enhancements provide users with more control over data smoothing and battery management, improving the stability and flexibility of the solar optimizer.

Copilot AI and others added 5 commits October 24, 2025 16:21
Co-authored-by: HAuser1234 <122117318+HAuser1234@users.noreply.github.com>
Co-authored-by: HAuser1234 <122117318+HAuser1234@users.noreply.github.com>
Co-authored-by: HAuser1234 <122117318+HAuser1234@users.noreply.github.com>
…battery with battery recharge reserve

Implement sliding-window smoothing for production, consumption, and battery with battery recharge reserve
@HAuser1234

Copy link
Copy Markdown
Author
image It seems to be able to hold a steady battery charging offset (when battery < 100%) and helping to ignore temporary swings in production helping the optimizer to get a more persistant solution.

Copilot AI and others added 23 commits October 25, 2025 09:17
Co-authored-by: HAuser1234 <122117318+HAuser1234@users.noreply.github.com>
Co-authored-by: HAuser1234 <122117318+HAuser1234@users.noreply.github.com>
Co-authored-by: HAuser1234 <122117318+HAuser1234@users.noreply.github.com>
…riptions

Co-authored-by: HAuser1234 <122117318+HAuser1234@users.noreply.github.com>
…wer_production sensor

Co-authored-by: HAuser1234 <122117318+HAuser1234@users.noreply.github.com>
…recharge

Add option to apply battery reserve before smoothing
Added a new translation key for battery recharge reserve before smoothing.
Co-authored-by: HAuser1234 <122117318+HAuser1234@users.noreply.github.com>
Co-authored-by: HAuser1234 <122117318+HAuser1234@users.noreply.github.com>
Co-authored-by: HAuser1234 <122117318+HAuser1234@users.noreply.github.com>
Co-authored-by: HAuser1234 <122117318+HAuser1234@users.noreply.github.com>
- Calculate base household by subtracting currently distributed power from total consumption
- Add protection against negative values during smoothing transients
- Add diagnostic sensors: household_consumption, available_excess_power, total_current_distributed_power
- Update algorithm comments to clarify household_consumption excludes managed devices

Co-authored-by: HAuser1234 <122117318+HAuser1234@users.noreply.github.com>
The algorithm was incorrectly using diff from initial power, causing it to think there was excess power when devices were already active. Since household_consumption already excludes currently active managed devices, we should add solution devices directly, not the difference.

Example: Wallbox at 4830W, household base 670W, production 3000W
- OLD (buggy): total = 670 + (4830 - 4830) = 670W → thinks exporting 2330W
- NEW (fixed): total = 670 + 4830 = 5500W → correctly shows importing 2500W

This prevents the algorithm from increasing device power when already importing from grid.

Co-authored-by: HAuser1234 <122117318+HAuser1234@users.noreply.github.com>
1. Add household consumption smoothing (smoothing_household_window_min):
   - Smooths only base household consumption (excluding managed devices)
   - Helps compensate for short spikes from fridges, kettles, etc.
   - Never allows base consumption to go negative

2. Add minimum export margin at 100% SOC (min_export_margin_w):
   - Reserves watts from optimization when battery is full
   - Positive values keep battery topped up by always exporting
   - Negative values allow slight import
   - Prevents battery discharge when at 100%

Updated config schema and all translations (en, fr, de, strings.json) with descriptions for both new features.

Co-authored-by: HAuser1234 <122117318+HAuser1234@users.noreply.github.com>
1. Fix available excess power calculation when deficit occurs:
   - When household_consumption - devices goes negative (power deficit due to reporting lag)
   - Set available_excess to 0 instead of jumping to full PV production
   - Add explicit deficit detection and logging

2. Improve household smoothing:
   - Add extra protection to ensure smoothed value stays non-negative
   - Properly track raw vs smoothed values

3. Remove all battery smoothing references:
   - Remove CONF_SMOOTHING_BATTERY_WINDOW_MIN from const.py
   - Remove from config_schema.py
   - Remove battery_window deque and related code from coordinator.py
   - Battery charge power now recorded for diagnostics only (no smoothing)

Co-authored-by: HAuser1234 <122117318+HAuser1234@users.noreply.github.com>
…wer-distribution

Refactor power distribution to use household consumption with enhanced battery management
When devices are turned on/off, there's a lag between sending the command and HA state updating. The algorithm was reading device states that hadn't updated yet, causing it to underestimate power consumption and turn on too many devices.

Fix: Use requested_power (from previous cycle) when it's higher than actual state power, to account for state lag during device transitions. This prevents the algorithm from thinking a newly-activated device is using 0W.

Co-authored-by: HAuser1234 <122117318+HAuser1234@users.noreply.github.com>
Co-authored-by: HAuser1234 <122117318+HAuser1234@users.noreply.github.com>
- Changed from vol.Coerce(float) to selector.NumberSelector widget
- Added proper UI controls: min=0.0, max=5.0, step=0.1, mode=BOX
- Ensures field appears correctly in Home Assistant config flow UI
- Allows users to adjust the value via slider/number input

Co-authored-by: HAuser1234 <122117318+HAuser1234@users.noreply.github.com>

@jmcollin78 jmcollin78 left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello, thank you for this. There is already smoothing function in SO and battry threshold so it is not clear what this PR improve considering the existing features. I will have a look but I'm on a big change on the Versatile Thermostat and I will not be available soon.

@HAuser1234

HAuser1234 commented Oct 27, 2025

Copy link
Copy Markdown
Author

@jmcollin78 No worries, totally understand! 😊
Just to clarify — the PR isn’t final yet, since I currently don’t have enough sun to properly test a small part of the new code I added yesterday. I’ll update it once I can validate everything under real conditions.

Thanks for taking the time to have a look whenever you can, and good luck with the Versatile Thermostat work!

@jmcollin78
jmcollin78 marked this pull request as draft October 27, 2025 20:29
@jmcollin78

Copy link
Copy Markdown
Owner

I convert it to draft while waiting for completion.

HAuser1234 and others added 23 commits October 28, 2025 11:48
…g-algorithm

Add switching penalty to reduce device churn from marginal power changes
…wer-distribution-bug

Revert "Fix device power tracking during HA state lag causing overconsumption"
…tigate-power-distribution-bug

Revert "Revert "Fix device power tracking during HA state lag causing overconsumption""
…ilot/investigate-power-distribution-bug

Revert "Revert "Revert "Fix device power tracking during HA state lag causing overconsumption"""
Co-authored-by: HAuser1234 <122117318+HAuser1234@users.noreply.github.com>
Co-authored-by: HAuser1234 <122117318+HAuser1234@users.noreply.github.com>
…lation

Fix household deficit zeroing available excess power despite sufficient production
- Remove current_power <= 0 force-off condition in simulated_annealing_algo.py
- Add was_active tracking to equipment dict for initial device state
- Update switching penalty to use was_active instead of current_power > 0
- Add _last_non_zero_power tracking in managed_device.py
- Implement debounce in set_current_power_with_device_state to use requested_power or last_non_zero_power during grace window

Co-authored-by: HAuser1234 <122117318+HAuser1234@users.noreply.github.com>
- Add auto_switching_penalty option to automatically calculate optimal penalty based on conditions
- Add clamp_price_step option to reduce price volatility (e.g., 0.05 for 5-cent steps)
- Implement _calculate_optimal_switching_penalty method considering production, consumption, and active devices
- Implement _clamp_price method to round prices to configured steps
- Update algorithm initialization to accept new parameters

Co-authored-by: HAuser1234 <122117318+HAuser1234@users.noreply.github.com>
- Add suggested_penalty property to algorithm to expose last calculated value
- Update coordinator to track and expose suggested penalty
- Add new sensor entity for suggested_penalty in sensor.py
- Configure sensor with appropriate icon, device_class, and state_class
- Update coordinator configure method to read and apply auto_switching_penalty and clamp_price_step from config

Co-authored-by: HAuser1234 <122117318+HAuser1234@users.noreply.github.com>
- Add English translations for new config options
- Add French translations for auto penalty and price clamping
- Add German translations for auto penalty and price clamping
- Translations include both field names and detailed descriptions

Co-authored-by: HAuser1234 <122117318+HAuser1234@users.noreply.github.com>
- Add auto_switching_penalty boolean option to config schema
- Add clamp_price_step number option to config schema (0.0-1.0, step 0.01)
- Always calculate suggested penalty even when auto mode is off (for monitoring/tuning)
- This fixes the suggested_penalty sensor showing as unknown

Co-authored-by: HAuser1234 <122117318+HAuser1234@users.noreply.github.com>
- When a device was off but solution turns it on, check if there's still excess power
- If turning on the device would still leave excess power being exported, apply a reward (negative penalty)
- Reward is 50% of penalty factor to encourage using available solar without being too aggressive
- This solves the issue where devices stay off even with abundant excess power
- Devices will now be more likely to turn back on when plenty of solar is available

Co-authored-by: HAuser1234 <122117318+HAuser1234@users.noreply.github.com>
…power

- Low-priority devices (priority > 8) get additional reward boost when abundant excess power (>20%)
- Boost scales with both priority level (higher priority number = more boost) and excess ratio
- Boost is weighted by priority_weight to counteract the priority penalty that keeps them off
- This ensures low-priority devices turn on when there's plenty of solar available
- Addresses issue where devices with LOW priority stay off despite 5kW+ excess power

Co-authored-by: HAuser1234 <122117318+HAuser1234@users.noreply.github.com>
Fix standby/0W device handling, add auto-penalty, price clamping, and excess power rewards
…rdinator

Co-authored-by: HAuser1234 <122117318+HAuser1234@users.noreply.github.com>
…or-error

Fix config flow device type selector after coordinator setup
@HAuser1234
HAuser1234 marked this pull request as ready for review December 14, 2025 19:04

@jmcollin78 jmcollin78 left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You change too many things in one PR:

  1. smoothing: seems fine,
  2. change the meaning of power_consumption_entity_id (really needed ?)
  3. add debounce (I understand this can be necessary),
  4. switching penalty factor

This is almost a new integration you made and therefore it is very hard to see all eventual impacts.
But this is really a hard work (I guess IA helps...).

What do you think ?

# if a device was running, which correctly handles standby/0W devices.
# For variable power devices, changing power (up or down) is NOT penalized.
# Only turning the device completely OFF/ON incurs a penalty/reward.
switching_penalty = 0

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This block of code is very hard to read and understand. There is too much complexity (imbricated if).

"data_description": {
"refresh_period_sec": "Période de rafraichissement en secondes. Attention des calculs lourds sont effectués à chaque période. Ne pas rafraichir trop souvent",
"power_consumption_entity_id": "l'entity_id du capteur de consommation nette. La consommation nette doit être négative si l'énergie est exportée vers le réseau.",
"power_consumption_entity_id": "L'entity_id du capteur de consommation électrique de la maison (en watts positifs). Cela devrait représenter la consommation de base de la maison. Si vous utilisez un capteur de compteur net, envisagez de créer un capteur template qui fournit des valeurs de consommation positives.",

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a major breaking change if I understand correctly. All current installation will no more work. What we need here: is the grid import/export net value. If you change this, the algorithm should change. I see you change also the algorithm.

Don't know what to think about that. Was it really necessary to change this ? I guess not.

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.

3 participants