Fix: Graceful Startup Config Retries & ML Load Fallback#4216
Open
rholligan wants to merge 17 commits into
Open
Fix: Graceful Startup Config Retries & ML Load Fallback#4216rholligan wants to merge 17 commits into
rholligan wants to merge 17 commits into
Conversation
…ecast fallback when model is invalid
…cuting >10 minutes after startup to prevent permanent dummy regex strings
…retaining original strings instead of replacing with None
… to crlf line endings
Contributor
There was a problem hiding this comment.
Pull request overview
This PR targets Predbat startup resilience by (1) improving auto_config handling of regex-based entity configuration during slow Home Assistant startups, and (2) hardening ML load forecasting publication/consumption against non-JSON-compliant floats, alongside several cross-platform test-output cleanups.
Changes:
- Add
safe_float()and apply it to ML load stats publishing to avoid crashes when values becomeNaN/Inf. - Rework regex resolution and startup retry timing for
auto_config, plus add new tests intended to cover the retry/fallback paths. - Normalize many unit-test prints/comments to avoid Unicode/CRLF issues on Windows.
Reviewed changes
Copilot reviewed 52 out of 53 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| apps/predbat/utils.py | Adds safe_float() helper for sanitizing floats. |
| apps/predbat/userinterface.py | Changes regex resolution and auto_config retry bookkeeping. |
| apps/predbat/unit_test.py | Registers new test modules in the test runner. |
| apps/predbat/tests/test_temperature.py | Replaces Unicode status markers with ASCII text. |
| apps/predbat/tests/test_storage.py | Comment-only ASCII normalization. |
| apps/predbat/tests/test_solis.py | Comment-only ASCII normalization. |
| apps/predbat/tests/test_solcast.py | Comment-only ASCII normalization. |
| apps/predbat/tests/test_sigenergy.py | Comment/docstring ASCII normalization. |
| apps/predbat/tests/test_rate_replicate_missing_slots.py | Replaces Unicode status markers with ASCII text. |
| apps/predbat/tests/test_rate_min_forward_calc.py | Comment-only ASCII normalization. |
| apps/predbat/tests/test_rate_add_io_slots.py | Comment-only ASCII normalization. |
| apps/predbat/tests/test_open_meteo.py | Docstring/comment ASCII normalization. |
| apps/predbat/tests/test_ohme.py | Replaces Unicode status markers with ASCII text. |
| apps/predbat/tests/test_octopus_url.py | Replaces Unicode status markers with ASCII text. |
| apps/predbat/tests/test_octopus_read_response_retry.py | Replaces Unicode status markers with ASCII text. |
| apps/predbat/tests/test_octopus_misc.py | Replaces Unicode status markers with ASCII text. |
| apps/predbat/tests/test_octopus_download_rates.py | Replaces Unicode status markers with ASCII text. |
| apps/predbat/tests/test_octopus_day_night_rates.py | Docstring/comment ASCII normalization + status text changes. |
| apps/predbat/tests/test_ml_load_fallback.py | New tests for ML load fallback behaviour. |
| apps/predbat/tests/test_minute_data.py | Comment-only ASCII normalization. |
| apps/predbat/tests/test_minute_array.py | Comment-only ASCII normalization. |
| apps/predbat/tests/test_load_ml.py | Test output ASCII normalization (and some comment tweaks). |
| apps/predbat/tests/test_kraken.py | Comment-only ASCII normalization. |
| apps/predbat/tests/test_integer_config.py | Replaces Unicode status markers with ASCII text. |
| apps/predbat/tests/test_hainterface_websocket.py | Replaces Unicode status markers with ASCII text. |
| apps/predbat/tests/test_hainterface_state.py | Replaces Unicode status markers with ASCII text. |
| apps/predbat/tests/test_hainterface_service.py | Replaces Unicode status markers with ASCII text. |
| apps/predbat/tests/test_hainterface_lifecycle.py | Replaces Unicode status markers with ASCII text. |
| apps/predbat/tests/test_hainterface_api.py | Replaces Unicode status markers with ASCII text. |
| apps/predbat/tests/test_ge_cloud.py | Replaces Unicode status markers with ASCII text. |
| apps/predbat/tests/test_gateway.py | Docstring/comment ASCII normalization. |
| apps/predbat/tests/test_futurerate_auto.py | Docstring ASCII normalization. |
| apps/predbat/tests/test_find_charge_window.py | Docstring/comment ASCII normalization. |
| apps/predbat/tests/test_find_battery_size.py | Comment-only ASCII normalization. |
| apps/predbat/tests/test_fill_load_from_power.py | Replaces Unicode status markers with ASCII text. |
| apps/predbat/tests/test_fetch_pv_forecast.py | Replaces Unicode status markers with ASCII text. |
| apps/predbat/tests/test_fetch_config_options.py | Replaces Unicode status markers with ASCII text. |
| apps/predbat/tests/test_download.py | Fixes temp file writing to be bytes-mode (Windows-friendly). |
| apps/predbat/tests/test_db_manager.py | Replaces Unicode status markers with ASCII text. |
| apps/predbat/tests/test_component_base.py | Comment-only ASCII normalization. |
| apps/predbat/tests/test_compare.py | Comment-only ASCII normalization. |
| apps/predbat/tests/test_carbon.py | Replaces Unicode status markers with ASCII text. |
| apps/predbat/tests/test_battery_curve_keys.py | Replaces Unicode status markers with ASCII text. |
| apps/predbat/tests/test_balance_inverters.py | Replaces Unicode status markers with ASCII text. |
| apps/predbat/tests/test_auto_config.py | New tests for auto_config regex retry behaviour. |
| apps/predbat/tests/open_meteo_live.py | Comment-only ASCII normalization. |
| apps/predbat/predbat.py | Changes startup auto_config finalization and adds a 10-minute retry window. |
| apps/predbat/load_ml_component.py | Uses safe_float() for ML stats publishing to avoid JSON serialization crashes. |
| apps/predbat/fetch.py | Adds “inactive ML forecast” early return fallback to historical data. |
Comments suppressed due to low confidence (1)
apps/predbat/userinterface.py:1099
- auto_config(final=False) does nothing when an arg doesn’t match (it neither disables the arg nor records it in unmatched_args). Since predbat.py only retries auto_config when unmatched_args is non-empty, unmatched regex args won’t be retried during startup, which contradicts the intended “retry for 10 minutes then final-disable” behaviour.
Comment on lines
1045
to
+1049
| for item_value in arg_value: | ||
| item_matched, item_value = self.resolve_arg_re(arg, item_value, state_keys) | ||
| if not item_matched: | ||
| self.log("Warn: Regular argument {} expression {} failed to match - disabling this item".format(arg, item_value)) | ||
| new_list.append(None) | ||
| else: | ||
| new_list.append(item_value) | ||
| self.log("Warn: Regular argument {} expression {} failed to match - will retry".format(arg, item_value)) | ||
| new_list.append(item_value) |
Comment on lines
1054
to
+1058
| item_value = arg_value[item_name] | ||
| item_matched, item_value = self.resolve_arg_re(arg, item_value, state_keys) | ||
| if not item_matched: | ||
| self.log("Warn: Regular argument {} expression {} failed to match - disabling this item".format(arg, item_value)) | ||
| new_dict[item_name] = None | ||
| else: | ||
| new_dict[item_name] = item_value | ||
| self.log("Warn: Regular argument {} expression {} failed to match - will retry".format(arg, item_value)) | ||
| new_dict[item_name] = item_value |
Comment on lines
24
to
26
| from datetime import datetime, timezone, timedelta | ||
| import math | ||
| from component_base import ComponentBase |
Comment on lines
+38
to
+60
| # Test 1: Active status proceeds | ||
| fetch.prefix = "active_test" | ||
| try: | ||
| fetch.fetch_ml_load_forecast(now_utc) | ||
| print("FAIL: ML Load forecast should have raised AttributeError on active path") | ||
| failed = True | ||
| except AttributeError: | ||
| # It bypassed the early return and hit unmocked attributes, which means it works | ||
| print("PASS: ML Load forecast active status proceeds past early return") | ||
|
|
||
| # Test 2: Inactive status falls back | ||
| fetch.prefix = "inactive_test" | ||
| fetch.load_ml_forecast = {} | ||
| try: | ||
| fetch.fetch_ml_load_forecast(now_utc) | ||
| if fetch.load_ml_forecast: | ||
| print("FAIL: ML Load forecast should NOT be populated when inactive") | ||
| failed = True | ||
| else: | ||
| print("PASS: ML Load forecast ignored when inactive (fallback)") | ||
| except AttributeError: | ||
| print("FAIL: ML Load forecast did NOT fall back early and hit AttributeError") | ||
| failed = True |
…an generation output from main
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.
This PR resolves several startup initialization bugs when dealing with slower Home Assistant environments and unexpected ML model outputs.
Changes:
re:sensor...) inapps.yamllists/dicts were destructively overwritten withNone. They now retain their original string and are cleanly retried.predbat.pynow waits 10 minutes from startup before finalizingauto_config(hard-disabling unmatched entities), allowing slower HA environments time to load all integrations.NaNSafety: Addedsafe_floattoutils.pyand applied it to the ML component to preventInvalidJSONErrorcrashes when the ML model occasionally outputsNaNorInf.unit_test.pyto crash on Windows environments.