refactor: Extract thermal learning into utils/thermal_learning.py#1947
Open
cl445 wants to merge 2 commits intoKartoffelToby:developfrom
Open
refactor: Extract thermal learning into utils/thermal_learning.py#1947cl445 wants to merge 2 commits intoKartoffelToby:developfrom
cl445 wants to merge 2 commits intoKartoffelToby:developfrom
Conversation
Add 63 regression tests covering the 6 most important methods in climate.py before refactoring begins. Uses the unbound-method pattern with MagicMock fixtures, consistent with existing test conventions. Classes: - TestShouldHeatWithTolerance (10 tests) - TestComputeHvacAction (15 tests) - TestCalculateHeatingPower (12 tests, async) - TestCalculateHeatLoss (9 tests, async) - TestAsyncSetPresetMode (7 tests, async) - TestAsyncSetTemperature (10 tests, async)
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
bb3d939 to
fbe82cf
Compare
fbe82cf to
8b15e57
Compare
…ase 1) Extract calculate_heating_power() (253 lines) and calculate_heat_loss() (131 lines) from climate.py into typed, mypy-strict-clean dataclass state machines (HeatingPowerTracker, HeatLossTracker). climate.py shrinks by ~282 lines (3729 → 3447). The two methods become thin wrappers (~25 and ~15 lines) that delegate to the trackers and handle HA side-effects via frozen Result dataclasses. - New: utils/thermal_learning.py (~490 lines) with full type annotations - New: tests/unit/test_thermal_learning.py (54 tests) - Updated baseline tests to use real tracker objects - Updated events/window.py for tracker API - All 991 tests pass, mypy --strict clean on thermal_learning.py
8b15e57 to
6f0324d
Compare
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.
Motivation
climate.pyis by far the largest file in the project at 3729 lines.calculate_heating_power()(253 lines) andcalculate_heat_loss()(131 lines) are self-contained state machines scattered across ~20 looseself.*attributes. This causes three concrete problems:BetterThermostatmock just to verify an EMA calculation.heating_start_temp,loss_end_timestamp, …) are error-prone. There is no guarantee they are set/reset consistently.This PR addresses all three by extracting the logic into typed dataclass state machines that are testable without Home Assistant.
Summary
calculate_heating_power()(253 LOC) andcalculate_heat_loss()(131 LOC) fromclimate.pyinto typed dataclass state machines in newutils/thermal_learning.pyclimate.pyby ~282 lines (3729 → 3447) — both methods become thin wrappers (~25 + ~15 lines)Details
New:
utils/thermal_learning.py(~490 lines)HeatingPowerTracker/HeatLossTracker— stateful dataclasses withupdate()returning frozen result objectsCycleResult,HeatingPowerUpdate,HeatLossUpdate— frozen result dataclasses (no HA side-effects)ema_smooth(),clamp(),compute_weight_factor(),compute_env_factor()HVACActionviaTYPE_CHECKINGonly)mypy --strictcleanChanges in
climate.pyself.*thermal attributes replaced byself._heating_tracker+self._loss_trackerheating_power,heat_loss_rate,heating_cycles, etc.) — documented with TODO for future elimination_get_outdoor_temp()helper method (6 lines)Other changes
events/window.py: 1-line update for tracker API (self._heating_tracker.start_temp = None)tests/unit/test_climate_baseline.py: Updated fixture to use real tracker objectsTest plan
test_thermal_learning.pytests passtest_climate_baseline.pytests passmypy --strictclean onthermal_learning.py(0 errors)