Validate freeze protection temperature against device limits - #116
Conversation
set_freeze_protection_temperature documented a 35-45°F valid range but never enforced it, unlike set_dhw_temperature which validates against device feature limits. Now validates temperature against features.freeze_protection_temp_min/_max before sending, raising RangeValidationError out of range and DeviceCapabilityError if device features aren't available yet. Fixes #112
There was a problem hiding this comment.
Pull request overview
This PR brings set_freeze_protection_temperature in src/nwp500/mqtt/control.py in line with other temperature-setting commands by validating the requested freeze-protection threshold against device-reported feature limits before publishing the MQTT command, addressing issue #112.
Changes:
- Added device-feature-based range validation for
set_freeze_protection_temperature, raisingRangeValidationErrorwhen out of range. - Added an explicit
DeviceCapabilityErrorpath when device features are unavailable for validation. - Added protocol correctness tests covering in-range publish, out-of-range rejection (no publish), and missing-features behavior.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
src/nwp500/mqtt/control.py |
Fetches device features and validates freeze-protection temperature against freeze_protection_temp_min/max before sending command. |
tests/test_protocol_correctness.py |
Adds async regression tests to ensure validation behavior and “no publish on failure” semantics. |
| @@ -831,7 +831,30 @@ async def set_freeze_protection_temperature( | |||
|
|
|||
| Returns: | |||
| Publish packet ID | |||
|
|
|||
There was a problem hiding this comment.
Fixed in 3caebbf — reworded to describe validation against the device's own reported freeze_protection_temp_min/_max limits instead of a hard-coded range.
| features = await self._get_device_features(device) | ||
| if features is None: | ||
| raise DeviceCapabilityError( | ||
| "freeze_protection_use", | ||
| ( | ||
| "Device features not available. " | ||
| "Unable to validate temperature range." | ||
| ), | ||
| ) | ||
|
|
There was a problem hiding this comment.
Good catch — fixed in 3caebbf. Added freeze_protection_use to _CAPABILITY_MAP and decorated the method with @requires_capability("freeze_protection_use"), matching the pattern used everywhere else. Added a regression test (test_blocked_when_device_lacks_freeze_protection).
Review feedback on #116 (Copilot): - Range validation alone let the command through to devices that report freeze_protection_use=False; add the capability to _CAPABILITY_MAP and decorate set_freeze_protection_temperature with @requires_capability("freeze_protection_use"), consistent with every other controllable feature. - The docstring hard-coded a fixed 35-45°F range even though validation is against the device's own reported limits; reworded to describe device-specific validation instead.
Resolves conflicts with #115 (docstring fix) and #116 (freeze protection validation), both merged to main after this branch was cut. Conflicts were purely additive: dr_setting_use and freeze_protection_use both added to _CAPABILITY_MAP, and their respective test classes both added to test_protocol_correctness.py / test_device_capabilities.py. Combined capability count is now 10.
Summary
set_freeze_protection_temperature(src/nwp500/mqtt/control.py) documented a 35–45°F valid range but sent the value straight through with no validation, unlikeset_dhw_temperature, which validates against device feature limits before sending.temperatureagainstfeatures.freeze_protection_temp_min/features.freeze_protection_temp_max(mirrors theset_dhw_temperaturepattern), raisingRangeValidationErrorfor out-of-range values andDeviceCapabilityErrorif features aren't cached/available yet.Fixes #112
Test plan
TestFreezeProtectionTemperatureValidationintests/test_protocol_correctness.py:DeviceCapabilityErrorwhen device features are unavailable607 passed, 4 skipped.