Skip to content

Commit bb85312

Browse files
committed
fix: raise when async_set_low_voltage_state has no mode to send
If neither the mode argument nor the device's reported mode was available, Thermostat24VMode silently dropped out of the payload (filtered as None) and the request sent only the setpoints -- exactly the partial write this method exists to prevent. Raise ValueError instead of sending it. Also tighten payload's type from dict[str, Any] to dict[str, str | int | float | None], mirroring HiloDevice.set_attributes()'s own signature.
1 parent 184a002 commit bb85312

2 files changed

Lines changed: 27 additions & 3 deletions

File tree

pyhilo/device/climate.py

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -216,9 +216,21 @@ async def async_set_low_voltage_state(
216216
have to be sent in one request even when only one of them changed.
217217
Arguments left out keep their current value; values the device does
218218
not report at all are omitted from the payload.
219-
"""
220-
payload: dict[str, Any] = {
221-
"Thermostat24VMode": mode if mode is not None else self.low_voltage_mode,
219+
220+
Raises:
221+
ValueError: The mode isn't given and the device hasn't reported
222+
one either. Silently dropping Thermostat24VMode from the
223+
payload in that case would send setpoints without a mode,
224+
exactly the partial write this method exists to prevent.
225+
"""
226+
resolved_mode = mode if mode is not None else self.low_voltage_mode
227+
if resolved_mode is None:
228+
raise ValueError(
229+
f"{self._tag} Cannot set low voltage state: no mode was given "
230+
"and the device has not reported one. Pass mode explicitly."
231+
)
232+
payload: dict[str, str | int | float | None] = {
233+
"Thermostat24VMode": resolved_mode,
222234
"TargetTemperature": (
223235
target_temperature
224236
if target_temperature is not None

tests/test_climate.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
from unittest.mock import AsyncMock, MagicMock
22

3+
import pytest
4+
35
from pyhilo.const import HILO_READING_TYPES, STATE_UNKNOWN
46
from pyhilo.device import DeviceAttribute, DeviceReading, get_device_attributes
57
from pyhilo.device.climate import Climate, as_list
@@ -182,3 +184,13 @@ async def test_absent_values_are_not_sent(self):
182184
device.set_attributes.assert_awaited_once_with(
183185
{"Thermostat24VMode": "HEAT", "TargetTemperature": 22}
184186
)
187+
188+
async def test_unreported_mode_without_explicit_mode_raises(self):
189+
"""A device that hasn't reported Thermostat24VMode can't be written to
190+
without an explicit mode: silently dropping the key would send only
191+
the setpoints, the exact partial write this method must prevent."""
192+
device = _climate(TargetTemperature=19, CoolTemperatureSet=24)
193+
device.set_attributes = AsyncMock()
194+
with pytest.raises(ValueError):
195+
await device.async_set_low_voltage_state(cool_setpoint=22)
196+
device.set_attributes.assert_not_awaited()

0 commit comments

Comments
 (0)