Summary
Code review of the peak shaving feature revealed several areas for improvement. None are critical bugs, but they affect robustness, user experience, and code quality.
1. combined mode silently disabled when price_limit is not set
File: src/batcontrol/logic/next.py (lines ~237-239)
When mode: combined is configured but price_limit is omitted (defaults to None), _apply_peak_shaving() returns early and skips both the time-based and price-based components. This is surprising because the time component does not need a price_limit at all.
Suggestion: Fall back to time-only behaviour when price_limit is None in combined mode, or at least log a warning so users know why peak shaving is not active.
2. No validation in PeakShavingConfig dataclass
File: src/batcontrol/core.py (lines ~57-74)
PeakShavingConfig has no __post_init__ validation. Invalid values (e.g. mode: 'invalid', allow_full_battery_after: 99) are only caught later when CalculationParameters.__post_init__ fires. The resulting error message references CalculationParameters, not the config key, making debugging harder.
Suggestion: Add a __post_init__ validator to PeakShavingConfig that checks:
mode in ('time', 'price', 'combined')
0 <= allow_full_battery_after <= 23
price_limit is numeric or None
3. Incomplete MQTT runtime control (undocumented limitation)
enabled and allow_full_battery_after are settable via MQTT at runtime, but mode and price_limit are not. This asymmetry is not documented. Users may expect all peak shaving parameters to be changeable without restart.
Suggestion: Either add MQTT set-callbacks for mode and price_limit, or document this as a known limitation. An MQTT discovery entity for price_limit (as a number) would be a useful addition for HA users.
4. Incorrect test comment
File: tests/batcontrol/logic/test_peak_shaving.py (around line 341)
The comment in test_currently_in_cheap_slot_surplus_overflow states:
"Time-based (mode=combined): 6 slots to target, 6*3000=18000>5000 -> 5000/6=833 W"
This describes flat division, but the actual algorithm uses a counter-linear ramp: 2*5000/(6*7) = 238 W, raised to 500 W by the minimum charge rate. The test assertion (500) is correct -- only the comment is wrong.
Suggestion: Fix the comment to reflect the counter-linear formula.
5. Minor: MODE 8 reference in logic layer
File: src/batcontrol/logic/next.py (line ~293)
A comment says "MODE 8" which is an inverter implementation detail. The logic layer should ideally not reference mode numbers.
Suggestion: Replace with a descriptive comment like "limit_battery_charge_rate mode".
Summary
Code review of the peak shaving feature revealed several areas for improvement. None are critical bugs, but they affect robustness, user experience, and code quality.
1.
combinedmode silently disabled whenprice_limitis not setFile:
src/batcontrol/logic/next.py(lines ~237-239)When
mode: combinedis configured butprice_limitis omitted (defaults toNone),_apply_peak_shaving()returns early and skips both the time-based and price-based components. This is surprising because the time component does not need aprice_limitat all.Suggestion: Fall back to time-only behaviour when
price_limitisNoneincombinedmode, or at least log a warning so users know why peak shaving is not active.2. No validation in
PeakShavingConfigdataclassFile:
src/batcontrol/core.py(lines ~57-74)PeakShavingConfighas no__post_init__validation. Invalid values (e.g.mode: 'invalid',allow_full_battery_after: 99) are only caught later whenCalculationParameters.__post_init__fires. The resulting error message referencesCalculationParameters, not the config key, making debugging harder.Suggestion: Add a
__post_init__validator toPeakShavingConfigthat checks:mode in ('time', 'price', 'combined')0 <= allow_full_battery_after <= 23price_limitis numeric orNone3. Incomplete MQTT runtime control (undocumented limitation)
enabledandallow_full_battery_afterare settable via MQTT at runtime, butmodeandprice_limitare not. This asymmetry is not documented. Users may expect all peak shaving parameters to be changeable without restart.Suggestion: Either add MQTT set-callbacks for
modeandprice_limit, or document this as a known limitation. An MQTT discovery entity forprice_limit(as a number) would be a useful addition for HA users.4. Incorrect test comment
File:
tests/batcontrol/logic/test_peak_shaving.py(around line 341)The comment in
test_currently_in_cheap_slot_surplus_overflowstates:This describes flat division, but the actual algorithm uses a counter-linear ramp:
2*5000/(6*7) = 238 W, raised to 500 W by the minimum charge rate. The test assertion (500) is correct -- only the comment is wrong.Suggestion: Fix the comment to reflect the counter-linear formula.
5. Minor: MODE 8 reference in logic layer
File:
src/batcontrol/logic/next.py(line ~293)A comment says "MODE 8" which is an inverter implementation detail. The logic layer should ideally not reference mode numbers.
Suggestion: Replace with a descriptive comment like "limit_battery_charge_rate mode".