Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 38 additions & 9 deletions miio/integrations/zhimi/airpurifier/airpurifier_miot.py
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,8 @@ class AirPurifierMiotStatus(DeviceStatus):
{'did': 'average_aqi', 'siid': 13, 'piid': 2, 'code': 0, 'value': 2},
{'did': 'filter_rfid_tag', 'siid': 14, 'piid': 1, 'code': 0, 'value': '81:6b:3f:32:84:4b:4'},
{'did': 'filter_rfid_product_id', 'siid': 14, 'piid': 3, 'code': 0, 'value': '0:0:31:31'},
{'did': 'app_extra', 'siid': 15, 'piid': 1, 'code': 0, 'value': 0}
{'did': 'app_extra', 'siid': 15, 'piid': 1, 'code': 0, 'value': 0},
{'did': 'aqi_realtime_update_duration', 'siid': 13, 'piid': 9, 'code': 0, 'value': 0}
]
"""

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

@property
def aqi_realtime_update_duration(self) -> Optional[int]:
"""Return the aqi_realtime_update_duration in use."""
return self.data.get("aqi_realtime_update_duration")


class AirPurifierMiot(MiotDevice):
"""Main class representing the air purifier which uses MIoT protocol."""
Expand Down Expand Up @@ -555,24 +561,30 @@ class AirPurifierMiot(MiotDevice):
"Motor speed: {result.motor_speed} rpm\n"
"Filter RFID product id: {result.filter_rfid_product_id}\n"
"Filter RFID tag: {result.filter_rfid_tag}\n"
"Filter type: {result.filter_type}\n",
"Filter type: {result.filter_type}\n"
"AQI Update Duration: {result.aqi_realtime_update_duration}\n",
)
)
def status(self) -> AirPurifierMiotStatus:
"""Retrieve properties."""
# Some devices update the aqi information only every 30min.
# This forces the device to poll the sensor for 5 seconds,
# so that we get always the most recent values. See #1281.
if self.model == "zhimi.airpurifier.mb3":
self.set_property("aqi_realtime_update_duration", 5)

return AirPurifierMiotStatus(
status = AirPurifierMiotStatus(
{
prop["did"]: prop["value"] if prop["code"] == 0 else None
for prop in self.get_properties_for_mapping()
},
self.model,
)
if (
self.model == "zhimi.airpurifier.mb3"
and not status.aqi_realtime_update_duration
):
# Some devices update the aqi information only every 30min.
# This forces the device to poll the sensor for 5 seconds,
# so that we get always the most recent values. See #1281.
self.set_aqi_realtime_update_duration(5)
status.data["aqi_realtime_update_duration"] = 5

return status

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

return self.set_property("led_brightness_level", level)

@command(
click.argument("duration", type=int),
default_output=format_output(
"Setting AQI Realtime update duration to {duration}"
),
)
def set_aqi_realtime_update_duration(self, duration: int):
"""Set the AQI Realtime update duration."""
if "aqi_realtime_update_duration" not in self._get_mapping():
raise UnsupportedFeatureException(
"Unsupported aqi_realtime_update_duration for model '%s'" % self.model
)

if duration < 0:
raise ValueError("Invalid aqi realtime update duration: %s" % duration)
return self.set_property("aqi_realtime_update_duration", duration)
43 changes: 43 additions & 0 deletions miio/integrations/zhimi/airpurifier/tests/test_airpurifier_miot.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,10 @@
"filter_rfid_product_id": "0:0:41:30",
"filter_rfid_tag": "10:20:30:40:50:60:7",
"button_pressed": "power",
"aqi_realtime_update_duration": 0,
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The default value for my 3H for this setting is 0. I can move this change to device specific init state if that is desired.

}


_INITIAL_STATE_MB4 = {
"power": True,
"aqi": 10,
Expand Down Expand Up @@ -91,6 +93,9 @@ def __init__(self, *args, **kwargs):
),
"set_act_det": lambda x: self._set_state("act_det", x),
"set_app_extra": lambda x: self._set_state("app_extra", x),
"set_aqi_realtime_update_duration": lambda x: self._set_state(
"aqi_realtime_update_duration", x
),
}
super().__init__(*args, **kwargs)

Expand Down Expand Up @@ -236,6 +241,44 @@ def test_set_anion(self):
self.device.set_anion(True)


class DummyAirPurifierMiotMB3(DummyAirPurifierMiot):
def __init__(self, *args, **kwargs):
self._model = "zhimi.airpurifier.mb3"
super().__init__(*args, **kwargs)


@pytest.fixture(scope="function")
def airpurifierMB3(request):
request.cls.device = DummyAirPurifierMiotMB3()


@pytest.mark.usefixtures("airpurifierMB3")
class TestAirPurifierMB3(TestCase):
def test_status(self):
default_adjusted_value = 5
specific_value = 10
status = self.device.status()
assert _INITIAL_STATE["aqi_realtime_update_duration"] == 0
assert status.aqi_realtime_update_duration == default_adjusted_value

# Set a specific value

self.device.set_aqi_realtime_update_duration(specific_value)

# Check that we do not override a specific set value
status = self.device.status()

assert status.aqi_realtime_update_duration == specific_value

def test_set_aqi_realtime_update_duration_negative_value(self):
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure what other models have or do not have the ability to set and or provide information on aqi_realtime_update_duration_negative_value are there other changes that I should do in relation to this change and the related tests ?

with pytest.raises(ValueError):
self.device.set_aqi_realtime_update_duration(-1)

def test_set_aqi_realtime_update_duration(self):
self.device.set_aqi_realtime_update_duration(12)
assert self.device.status().aqi_realtime_update_duration == 12


class DummyAirPurifierMiotMB4(DummyAirPurifierMiot):
def __init__(self, *args, **kwargs):
self._model = "zhimi.airpurifier.mb4"
Expand Down
Loading