From c97c1e5e64df272c22a8dacd1f4776adeee5e08f Mon Sep 17 00:00:00 2001 From: Alex van den Hoogen Date: Wed, 13 Mar 2024 15:09:32 +0100 Subject: [PATCH] Set zhimi.fan.za4 countdown timer to minutes (#1787) --- miio/integrations/zhimi/fan/fan.py | 20 ++++++++ miio/integrations/zhimi/fan/test_fan.py | 64 +++++++++++++++++++++++++ 2 files changed, 84 insertions(+) diff --git a/miio/integrations/zhimi/fan/fan.py b/miio/integrations/zhimi/fan/fan.py index e30f35d73..4e6aec324 100644 --- a/miio/integrations/zhimi/fan/fan.py +++ b/miio/integrations/zhimi/fan/fan.py @@ -226,6 +226,18 @@ def button_pressed(self) -> Optional[str]: return None +class FanStatusZA4(FanStatus): + """Container for status reports from the Xiaomi Mi Smart Pedestal Fan Zhimi ZA4.""" + + def __init__(self, data: Dict[str, Any]) -> None: + self.data = data + + @property + def delay_off_countdown(self) -> int: + """Countdown until turning off in minutes.""" + return self.data["poweroff_time"] / 60 + + class Fan(Device): """Main class representing the Xiaomi Mi Smart Pedestal Fan.""" @@ -246,6 +258,10 @@ def status(self) -> FanStatus: values = self.get_properties(properties, max_properties=_props_per_request) + # The ZA4 has a countdown timer in minutes + if self.model in [MODEL_FAN_ZA4]: + return FanStatusZA4(dict(zip(properties, values))) + return FanStatus(dict(zip(properties, values))) @command(default_output=format_output("Powering on")) @@ -390,4 +406,8 @@ def delay_off(self, seconds: int): if seconds < 0: raise ValueError("Invalid value for a delayed turn off: %s" % seconds) + # Set delay countdown in minutes for model ZA4 + if self.model in [MODEL_FAN_ZA4]: + return self.send("set_poweroff_time", [seconds * 60]) + return self.send("set_poweroff_time", [seconds]) diff --git a/miio/integrations/zhimi/fan/test_fan.py b/miio/integrations/zhimi/fan/test_fan.py index d9bfabfd6..a0a7ac1dd 100644 --- a/miio/integrations/zhimi/fan/test_fan.py +++ b/miio/integrations/zhimi/fan/test_fan.py @@ -8,6 +8,7 @@ MODEL_FAN_SA1, MODEL_FAN_V2, MODEL_FAN_V3, + MODEL_FAN_ZA4, Fan, FanStatus, LedBrightness, @@ -737,3 +738,66 @@ def delay_off_countdown(): with pytest.raises(ValueError): self.device.delay_off(-1) + + +class DummyFanZA4(DummyDevice, Fan): + def __init__(self, *args, **kwargs): + self._model = MODEL_FAN_ZA4 + self.state = { + "angle": 120, + "speed": 277, + "poweroff_time": 0, + "power": "on", + "ac_power": "on", + "angle_enable": "off", + "speed_level": 1, + "natural_level": 2, + "child_lock": "off", + "buzzer": 0, + "led_b": 0, + "use_time": 2318, + } + + self.return_values = { + "get_prop": self._get_state, + "set_power": lambda x: self._set_state("power", x), + "set_speed_level": lambda x: self._set_state("speed_level", x), + "set_natural_level": lambda x: self._set_state("natural_level", x), + "set_move": lambda x: True, + "set_angle": lambda x: self._set_state("angle", x), + "set_angle_enable": lambda x: self._set_state("angle_enable", x), + "set_led_b": lambda x: self._set_state("led_b", x), + "set_buzzer": lambda x: self._set_state("buzzer", x), + "set_child_lock": lambda x: self._set_state("child_lock", x), + "set_poweroff_time": lambda x: self._set_state("poweroff_time", x), + } + super().__init__(args, kwargs) + + +@pytest.fixture(scope="class") +def fanza4(request): + request.cls.device = DummyFanZA4() + # TODO add ability to test on a real device + + +@pytest.mark.usefixtures("fanza4") +class TestFanZA4(TestCase): + def is_on(self): + return self.device.status().is_on + + def state(self): + return self.device.status() + + def test_delay_off(self): + def delay_off_countdown(): + return self.device.status().delay_off_countdown + + self.device.delay_off(100) + assert delay_off_countdown() == 100 + self.device.delay_off(200) + assert delay_off_countdown() == 200 + self.device.delay_off(0) + assert delay_off_countdown() == 0 + + with pytest.raises(ValueError): + self.device.delay_off(-1)