diff --git a/custom_components/dreo/pydreo/pydreoheater.py b/custom_components/dreo/pydreo/pydreoheater.py index 14c8d93..81c3e1f 100644 --- a/custom_components/dreo/pydreo/pydreoheater.py +++ b/custom_components/dreo/pydreo/pydreoheater.py @@ -173,6 +173,7 @@ def preset_mode(self, level: str) -> None: _LOGGER.error("Preset mode %s is not in the acceptable list: %s", level, self._device_definition.preset_modes) + raise ValueError(f"preset_mode must be one of: {self.preset_modes}") @mode.setter def mode(self, mode: str) -> None: @@ -224,7 +225,8 @@ def oscon(self, value: bool) -> None: self._send_command(OSCON_KEY, value) else: _LOGGER.error("Attempting to set oscillation on on a device that doesn't support it.") - return + raise ValueError(f"Attempting to set oscillation on on a device that doesn't support it.") + return @property def oscangle(self) -> HeaterOscillationAngles: diff --git a/tests/pydreo/api_responses/get_device_state_HSH004S_1.json b/tests/pydreo/api_responses/get_device_state_HSH004S_1.json new file mode 100644 index 0000000..f9dbb9c --- /dev/null +++ b/tests/pydreo/api_responses/get_device_state_HSH004S_1.json @@ -0,0 +1,153 @@ +{ + "code": 0, + "msg": "OK", + "data": { + "currentPage": 1, + "pageSize": 100, + "totalNum": 2, + "totalPage": 1, + "familyRooms": null, + "list": [ + { + "deviceId": "4456", + "sn": "HSH004S_1", + "brand": "Dreo", + "model": "DR-HSH004S", + "productId": "1536529638074978306", + "productName": "Heater", + "deviceName": "Heater 1", + "shared": false, + "series": null, + "seriesName": "Atom One S", + "type": 0, + "owner": true, + "familyId": null, + "familyName": null, + "roomId": null, + "roomName": null, + "roomNameI18Key": "", + "color": "b", + "controlsConf": { + "template": "DR-HSH004S", + "lottie": { + "key": "poweron", + "frames": [ + { + "value": 0, + "frame": [ + 0 + ] + }, + { + "value": 1, + "frame": [ + 2 + ] + } + ] + }, + "instructions": { + "en": "https://fe.dreo.com/en/safety-protection-instructions/", + "zh": "https://fe.dreo.com/zh/safety-protection-instructions/" + }, + "cards": [ + { + "type": 2, + "title": "device_control_temp", + "icon": "", + "image": "", + "url": "", + "show": true + }, + { + "type": 6, + "title": "device_settings_title", + "icon": "ic_setting", + "image": "", + "url": "dreo://nav/device/setting?deviceSn=${sn}", + "show": true, + "key": "setting" + } + ], + "preference": [ + { + "id": "200", + "type": "Panel Sound", + "title": "device_control_panelsound", + "image": "ic_mute", + "reverse": true, + "cmd": "muteon" + }, + { + "id": "210", + "type": "Display Auto Off", + "title": "device_fans_mode_auto_display", + "image": "ic_display", + "reverse": true, + "cmd": "lighton" + }, + { + "id": "220", + "type": "Child Lock", + "title": "device_control_childlock", + "image": "ic_child_lock", + "reverse": false, + "cmd": "childlockon" + }, + { + "id": "230", + "type": "Temperature Unit", + "title": "device_control_temp_unit", + "image": "ic_temp_unit" + }, + { + "id": "240", + "type": "Temperature Calibration", + "title": "device_control_temp_calibration", + "image": "ic_temp_cal" + } + ], + "control": [ + { + "swingtype": false, + "hideSafeMode": false + } + ], + "category": "Space Heater" + }, + "mainConf": { + "isSmart": true, + "isWifi": true, + "isBluetooth": true, + "isVoiceControl": true + }, + "resourcesConf": { + "imageSmallSrc": "https://resources.dreo-cloud.com/app/preSigned202406/285c6f0e219a6f40b5a2b79a053cf6d3cb.png", + "imageFullSrc": "https://resources.dreo-cloud.com/app/preSigned202406/288eb1e27a155b4b4c875393b04313706a.zip", + "imageSmallDarkSrc": "", + "imageFullDarkSrc": "" + }, + "servicesConf": [ + { + "key": "user_manual", + "value": "https://resources.dreo-cloud.com/app/202310/12056ea09c80d5455f9aa4e713ca8bd84e.pdf" + } + ], + "userManuals": [ + { + "url": "https://resources.dreo-cloud.com/app/preSigned202407/2b5ae671ab4f64b05a03cb3d4ba3527b4.pdf", + "icon": null, + "desc": "Smart PTC Fan Heater (US)", + "lang": "en" + }, + { + "url": "https://resources.dreo-cloud.com/app/preSigned202407/24bc6a0c439f348ca9a73d5108a82c9be.pdf", + "icon": null, + "desc": "Smart PTC Fan Heater (EU)", + "lang": "en" + } + ] + } + ] + } +} diff --git a/tests/pydreo/test_pydreoheater.py b/tests/pydreo/test_pydreoheater.py new file mode 100644 index 0000000..8650287 --- /dev/null +++ b/tests/pydreo/test_pydreoheater.py @@ -0,0 +1,48 @@ +"""Tests for Dreo Fans""" +# pylint: disable=used-before-assignment +import logging +from typing import TYPE_CHECKING +from unittest.mock import patch, call +import pytest + +if TYPE_CHECKING: + from .imports import * # pylint: disable=W0401,W0614 + from . import call_json + from .testbase import TestBase +else: + from imports import * # pylint: disable=W0401,W0614 + import call_json + from testbase import TestBase + +logger = logging.getLogger(__name__) +logger.setLevel(logging.DEBUG) + +LOGIN_RESPONSE = call_json.LOGIN_RET_BODY + + +class TestPyDreoHeater(TestBase): + """Test PyDreoHeater class.""" + def test_heater_load_and_send_commands(self): + """Load heater and test sending commands.""" + + self.get_devices_file_name = "get_device_state_HSH004S_1.json" + self.manager.load_devices() + assert len(self.manager.heaters) == 1 + heater = self.manager.heaters[0] + + assert heater.heat_range == (1, 3) + assert heater.preset_modes == ['H1', 'H2', 'H3'] + + with patch('pydreo.PyDreo.send_command') as mock_send_command: + heater.poweron = True + mock_send_command.assert_called_once_with(heater, {POWERON_KEY: True}) + + with (patch('pydreo.PyDreo.send_command') as mock_send_command): + heater.preset_mode = 'H1' + mock_send_command.assert_has_calls([call(heater, {HTALEVEL_KEY: 1})], True) + + with pytest.raises(ValueError): + heater.preset_mode = 'not_a_mode' + + +