Skip to content

Commit d7ffb89

Browse files
author
david
committed
Permit setting aqi_realtime_update_duration and do not override the value of aqi_realtime_update_duration if it is set for the Mi Air Purifier 3/3H (zhimi.airpurifier.mb3).
Tested against a 3H. Signed-off-by: david <db@d1b.org>
1 parent c5cc0f2 commit d7ffb89

File tree

2 files changed

+81
-9
lines changed

2 files changed

+81
-9
lines changed

miio/integrations/zhimi/airpurifier/airpurifier_miot.py

Lines changed: 38 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,8 @@ class AirPurifierMiotStatus(DeviceStatus):
334334
{'did': 'average_aqi', 'siid': 13, 'piid': 2, 'code': 0, 'value': 2},
335335
{'did': 'filter_rfid_tag', 'siid': 14, 'piid': 1, 'code': 0, 'value': '81:6b:3f:32:84:4b:4'},
336336
{'did': 'filter_rfid_product_id', 'siid': 14, 'piid': 3, 'code': 0, 'value': '0:0:31:31'},
337-
{'did': 'app_extra', 'siid': 15, 'piid': 1, 'code': 0, 'value': 0}
337+
{'did': 'app_extra', 'siid': 15, 'piid': 1, 'code': 0, 'value': 0},
338+
{'did': 'aqi_realtime_update_duration', 'siid': 13, 'piid': 9, 'code': 0, 'value': 0}
338339
]
339340
"""
340341

@@ -520,6 +521,11 @@ def gestures(self) -> Optional[bool]:
520521
"""Return True if gesture control is on."""
521522
return self.data.get("gestures")
522523

524+
@property
525+
def aqi_realtime_update_duration(self) -> Optional[int]:
526+
"""Return the aqi_realtime_update_duration in use."""
527+
return self.data.get("aqi_realtime_update_duration")
528+
523529

524530
class AirPurifierMiot(MiotDevice):
525531
"""Main class representing the air purifier which uses MIoT protocol."""
@@ -555,24 +561,30 @@ class AirPurifierMiot(MiotDevice):
555561
"Motor speed: {result.motor_speed} rpm\n"
556562
"Filter RFID product id: {result.filter_rfid_product_id}\n"
557563
"Filter RFID tag: {result.filter_rfid_tag}\n"
558-
"Filter type: {result.filter_type}\n",
564+
"Filter type: {result.filter_type}\n"
565+
"AQI Update Duration: {result.aqi_realtime_update_duration}\n",
559566
)
560567
)
561568
def status(self) -> AirPurifierMiotStatus:
562569
"""Retrieve properties."""
563-
# Some devices update the aqi information only every 30min.
564-
# This forces the device to poll the sensor for 5 seconds,
565-
# so that we get always the most recent values. See #1281.
566-
if self.model == "zhimi.airpurifier.mb3":
567-
self.set_property("aqi_realtime_update_duration", 5)
568-
569-
return AirPurifierMiotStatus(
570+
status = AirPurifierMiotStatus(
570571
{
571572
prop["did"]: prop["value"] if prop["code"] == 0 else None
572573
for prop in self.get_properties_for_mapping()
573574
},
574575
self.model,
575576
)
577+
if (
578+
self.model == "zhimi.airpurifier.mb3"
579+
and not status.aqi_realtime_update_duration
580+
):
581+
# Some devices update the aqi information only every 30min.
582+
# This forces the device to poll the sensor for 5 seconds,
583+
# so that we get always the most recent values. See #1281.
584+
self.set_aqi_realtime_update_duration(5)
585+
status.data["aqi_realtime_update_duration"] = 5
586+
587+
return status
576588

577589
@command(default_output=format_output("Powering on"))
578590
def on(self):
@@ -764,3 +776,20 @@ def set_led_brightness_level(self, level: int):
764776
raise ValueError("Invalid brightness level: %s" % level)
765777

766778
return self.set_property("led_brightness_level", level)
779+
780+
@command(
781+
click.argument("duration", type=int),
782+
default_output=format_output(
783+
"Setting AQI Realtime update duration to {duration}"
784+
),
785+
)
786+
def set_aqi_realtime_update_duration(self, duration: int):
787+
"""Set the AQI Realtime update duration."""
788+
if "aqi_realtime_update_duration" not in self._get_mapping():
789+
raise UnsupportedFeatureException(
790+
"Unsupported aqi_realtime_update_duration for model '%s'" % self.model
791+
)
792+
793+
if duration < 0:
794+
raise ValueError("Invalid aqi realtime update duration: %s" % duration)
795+
return self.set_property("aqi_realtime_update_duration", duration)

miio/integrations/zhimi/airpurifier/tests/test_airpurifier_miot.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,10 @@
3131
"filter_rfid_product_id": "0:0:41:30",
3232
"filter_rfid_tag": "10:20:30:40:50:60:7",
3333
"button_pressed": "power",
34+
"aqi_realtime_update_duration": 0,
3435
}
3536

37+
3638
_INITIAL_STATE_MB4 = {
3739
"power": True,
3840
"aqi": 10,
@@ -91,6 +93,9 @@ def __init__(self, *args, **kwargs):
9193
),
9294
"set_act_det": lambda x: self._set_state("act_det", x),
9395
"set_app_extra": lambda x: self._set_state("app_extra", x),
96+
"set_aqi_realtime_update_duration": lambda x: self._set_state(
97+
"aqi_realtime_update_duration", x
98+
),
9499
}
95100
super().__init__(*args, **kwargs)
96101

@@ -236,6 +241,44 @@ def test_set_anion(self):
236241
self.device.set_anion(True)
237242

238243

244+
class DummyAirPurifierMiotMB3(DummyAirPurifierMiot):
245+
def __init__(self, *args, **kwargs):
246+
self._model = "zhimi.airpurifier.mb3"
247+
super().__init__(*args, **kwargs)
248+
249+
250+
@pytest.fixture(scope="function")
251+
def airpurifierMB3(request):
252+
request.cls.device = DummyAirPurifierMiotMB3()
253+
254+
255+
@pytest.mark.usefixtures("airpurifierMB3")
256+
class TestAirPurifierMB3(TestCase):
257+
def test_status(self):
258+
default_adjusted_value = 5
259+
specific_value = 10
260+
status = self.device.status()
261+
assert _INITIAL_STATE["aqi_realtime_update_duration"] == 0
262+
assert status.aqi_realtime_update_duration == default_adjusted_value
263+
264+
# Set a specific value
265+
266+
self.device.set_aqi_realtime_update_duration(specific_value)
267+
268+
# Check that we do not override a specific set value
269+
status = self.device.status()
270+
271+
assert status.aqi_realtime_update_duration == specific_value
272+
273+
def test_set_aqi_realtime_update_duration_negative_value(self):
274+
with pytest.raises(ValueError):
275+
self.device.set_aqi_realtime_update_duration(-1)
276+
277+
def test_set_aqi_realtime_update_duration(self):
278+
self.device.set_aqi_realtime_update_duration(12)
279+
assert self.device.status().aqi_realtime_update_duration == 12
280+
281+
239282
class DummyAirPurifierMiotMB4(DummyAirPurifierMiot):
240283
def __init__(self, *args, **kwargs):
241284
self._model = "zhimi.airpurifier.mb4"

0 commit comments

Comments
 (0)