Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Air purifier 3/3H support (remastered) #634

Merged
merged 14 commits into from
Mar 15, 2020
Merged
1 change: 1 addition & 0 deletions miio/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from miio.airhumidifier import AirHumidifier, AirHumidifierCA1, AirHumidifierCB1
from miio.airhumidifier_mjjsq import AirHumidifierMjjsq
from miio.airpurifier import AirPurifier
from miio.airpurifier_miot import AirPurifierMiot
from miio.airqualitymonitor import AirQualityMonitor
from miio.aqaracamera import AqaraCamera
from miio.ceil import Ceil
Expand Down
36 changes: 36 additions & 0 deletions miio/airfilter_util.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import enum
import re


class FilterType(enum.Enum):
Regular = "regular"
AntiBacterial = "anti-bacterial"
AntiFormaldehyde = "anti-formaldehyde"
Unknown = "unknown"


FILTER_TYPE_RE = (
(re.compile(r"^\d+:\d+:41:30$"), FilterType.AntiBacterial),
(re.compile(r"^\d+:\d+:(30|0|00):31$"), FilterType.AntiFormaldehyde),
(re.compile(r".*"), FilterType.Regular),
)


class FilterTypeUtil:
"""Utility class for determining xiaomi air filter type."""

_filter_type_cache = {}

def determine_filter_type(self, product_id: str) -> FilterType:
"""
Determine Xiaomi air filter type based on its product ID.

:param product_id: Product ID such as "0:0:30:33"
"""
ft = self._filter_type_cache.get(product_id, None)
if ft is None:
for filter_re, filter_type in FILTER_TYPE_RE:
if filter_re.match(product_id):
ft = self._filter_type_cache[product_id] = filter_type
break
return ft
31 changes: 4 additions & 27 deletions miio/airpurifier.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import enum
import logging
import re
from collections import defaultdict
from typing import Any, Dict, Optional

import click

from .airfilter_util import FilterType, FilterTypeUtil
from .click_common import EnumType, command, format_output
from .device import Device
from .exceptions import DeviceException
Expand Down Expand Up @@ -42,20 +42,6 @@ class LedBrightness(enum.Enum):
Off = 2


class FilterType(enum.Enum):
Regular = "regular"
AntiBacterial = "anti-bacterial"
AntiFormaldehyde = "anti-formaldehyde"
Unknown = "unknown"


FILTER_TYPE_RE = (
(re.compile(r"^\d+:\d+:41:30$"), FilterType.AntiBacterial),
(re.compile(r"^\d+:\d+:(30|0|00):31$"), FilterType.AntiFormaldehyde),
(re.compile(r".*"), FilterType.Regular),
)


class AirPurifierStatus:
"""Container for status reports from the air purifier."""

Expand Down Expand Up @@ -102,6 +88,7 @@ def __init__(self, data: Dict[str, Any]) -> None:
A request is limited to 16 properties.
"""

self.filter_type_util = FilterTypeUtil()
self.data = data

@property
Expand Down Expand Up @@ -245,7 +232,7 @@ def filter_type(self) -> Optional[FilterType]:
return FilterType.Unknown
if self.filter_rfid_product_id is None:
return FilterType.Regular
return self._get_filter_type(self.filter_rfid_product_id)
return self.filter_type_util.determine_filter_type(self.filter_rfid_product_id)

@property
def learn_mode(self) -> bool:
Expand Down Expand Up @@ -284,16 +271,6 @@ def button_pressed(self) -> Optional[str]:
"""Last pressed button."""
return self.data["button_pressed"]

@classmethod
def _get_filter_type(cls, product_id: str) -> FilterType:
ft = cls._filter_type_cache.get(product_id, None)
if ft is None:
for filter_re, filter_type in FILTER_TYPE_RE:
if filter_re.match(product_id):
ft = cls._filter_type_cache[product_id] = filter_type
break
return ft

def __repr__(self) -> str:
s = (
"<AirPurifierStatus power=%s, "
Expand Down Expand Up @@ -538,7 +515,7 @@ def set_child_lock(self, lock: bool):

@command(
click.argument("volume", type=int),
default_output=format_output("Setting favorite level to {volume}"),
default_output=format_output("Setting sound volume to {volume}"),
)
def set_volume(self, volume: int):
"""Set volume of sound notifications [0-100]."""
Expand Down
Loading