Source code for miio.integrations.dmaker.airfresh.airfresh_t2017

import enum
import logging
from collections import defaultdict
from typing import Any, Dict, Optional

import click

from miio import Device, DeviceStatus
from miio.click_common import EnumType, command, format_output

_LOGGER = logging.getLogger(__name__)

MODEL_AIRFRESH_A1 = "dmaker.airfresh.a1"
MODEL_AIRFRESH_T2017 = "dmaker.airfresh.t2017"

AVAILABLE_PROPERTIES_COMMON = [
    "power",
    "mode",
    "pm25",
    "co2",
    "temperature_outside",
    "favourite_speed",
    "control_speed",
    "ptc_on",
    "ptc_status",
    "child_lock",
    "sound",
    "display",
]

AVAILABLE_PROPERTIES = {
    MODEL_AIRFRESH_T2017: AVAILABLE_PROPERTIES_COMMON
    + [
        "filter_intermediate",
        "filter_inter_day",
        "filter_efficient",
        "filter_effi_day",
        "ptc_level",
        "screen_direction",
    ],
    MODEL_AIRFRESH_A1: AVAILABLE_PROPERTIES_COMMON
    + [
        "filter_rate",
        "filter_day",
    ],
}


[docs] class OperationMode(enum.Enum): Off = "off" Auto = "auto" Sleep = "sleep" Favorite = "favourite"
[docs] class PtcLevel(enum.Enum): Low = "low" Medium = "medium" High = "high"
[docs] class DisplayOrientation(enum.Enum): Portrait = "forward" LandscapeLeft = "left" LandscapeRight = "right"
[docs] class AirFreshStatus(DeviceStatus): """Container for status reports from the air fresh t2017.""" def __init__(self, data: Dict[str, Any]) -> None: """ Response of a Air Fresh A1 (dmaker.airfresh.a1): { 'power': True, 'mode': 'auto', 'pm25': 2, 'co2': 554, 'temperature_outside': 12, 'favourite_speed': 150, 'control_speed': 60, 'filter_rate': 45, 'filter_day': 81, 'ptc_on': False, 'ptc_status': False, 'child_lock': False, 'sound': False, 'display': False, } Response of a Air Fresh T2017 (dmaker.airfresh.t2017): { 'power': True, 'mode': 'favourite', 'pm25': 1, 'co2': 550, 'temperature_outside': 24, 'favourite_speed': 241, 'control_speed': 241, 'filter_intermediate': 100, 'filter_inter_day': 90, 'filter_efficient': 100, 'filter_effi_day': 180, 'ptc_on': False, 'ptc_level': 'low', 'ptc_status': False, 'child_lock': False, 'sound': True, 'display': False, 'screen_direction': 'forward', } """ self.data = data @property def power(self) -> str: """Power state.""" return "on" if self.data["power"] else "off" @property def is_on(self) -> bool: """Return True if device is on.""" return self.data["power"] @property def mode(self) -> OperationMode: """Current operation mode.""" return OperationMode(self.data["mode"]) @property def pm25(self) -> int: """Fine particulate patter (PM2.5).""" return self.data["pm25"] @property def co2(self) -> int: """Carbon dioxide.""" return self.data["co2"] @property def temperature(self) -> int: """Current temperature in degree celsions.""" return self.data["temperature_outside"] @property def favorite_speed(self) -> int: """Favorite speed.""" return self.data["favourite_speed"] @property def control_speed(self) -> int: """Control speed.""" return self.data["control_speed"] @property def dust_filter_life_remaining(self) -> Optional[int]: """Remaining dust filter life in percent.""" return self.data.get("filter_intermediate", self.data.get("filter_rate")) @property def dust_filter_life_remaining_days(self) -> Optional[int]: """Remaining dust filter life in days.""" return self.data.get("filter_inter_day", self.data.get("filter_day")) @property def upper_filter_life_remaining(self) -> Optional[int]: """Remaining upper filter life in percent.""" return self.data.get("filter_efficient") @property def upper_filter_life_remaining_days(self) -> Optional[int]: """Remaining upper filter life in days.""" return self.data.get("filter_effi_day") @property def ptc(self) -> bool: """Return True if PTC is on.""" return self.data["ptc_on"] @property def ptc_level(self) -> Optional[PtcLevel]: """PTC level.""" try: return PtcLevel(self.data["ptc_level"]) except (KeyError, ValueError): return None @property def ptc_status(self) -> bool: """Return true if PTC status is on.""" return self.data["ptc_status"] @property def child_lock(self) -> bool: """Return True if child lock is on.""" return self.data["child_lock"] @property def buzzer(self) -> bool: """Return True if sound is on.""" return self.data["sound"] @property def display(self) -> bool: """Return True if the display is on.""" return self.data["display"] @property def display_orientation(self) -> Optional[DisplayOrientation]: """Display orientation.""" try: return DisplayOrientation(self.data["screen_direction"]) except (KeyError, ValueError): return None
[docs] class AirFreshA1(Device): """Main class representing the air fresh a1.""" _supported_models = list(AVAILABLE_PROPERTIES.keys())
[docs] @command( default_output=format_output( "", "Power: {result.power}\n" "Mode: {result.mode}\n" "PM2.5: {result.pm25}\n" "CO2: {result.co2}\n" "Temperature: {result.temperature}\n" "Favorite speed: {result.favorite_speed}\n" "Control speed: {result.control_speed}\n" "Dust filter life: {result.dust_filter_life_remaining} %, " "{result.dust_filter_life_remaining_days} days\n" "PTC: {result.ptc}\n" "PTC status: {result.ptc_status}\n" "Child lock: {result.child_lock}\n" "Buzzer: {result.buzzer}\n" "Display: {result.display}\n", ) ) def status(self) -> AirFreshStatus: """Retrieve properties.""" properties = AVAILABLE_PROPERTIES.get( self.model, AVAILABLE_PROPERTIES[MODEL_AIRFRESH_A1] ) values = self.get_properties(properties, max_properties=15) return AirFreshStatus(defaultdict(lambda: None, zip(properties, values)))
[docs] @command(default_output=format_output("Powering on")) def on(self): """Power on.""" return self.send("set_power", [True])
[docs] @command(default_output=format_output("Powering off")) def off(self): """Power off.""" return self.send("set_power", [False])
[docs] @command( click.argument("mode", type=EnumType(OperationMode)), default_output=format_output("Setting mode to '{mode.value}'"), ) def set_mode(self, mode: OperationMode): """Set mode.""" return self.send("set_mode", [mode.value])
[docs] @command( click.argument("display", type=bool), default_output=format_output( lambda led: "Turning on display" if led else "Turning off display" ), ) def set_display(self, display: bool): """Turn led on/off.""" return self.send("set_display", [display])
[docs] @command( click.argument("ptc", type=bool), default_output=format_output( lambda ptc: "Turning on ptc" if ptc else "Turning off ptc" ), ) def set_ptc(self, ptc: bool): """Turn ptc on/off.""" return self.send("set_ptc_on", [ptc])
[docs] @command( click.argument("buzzer", type=bool), default_output=format_output( lambda buzzer: "Turning on buzzer" if buzzer else "Turning off buzzer" ), ) def set_buzzer(self, buzzer: bool): """Set sound on/off.""" return self.send("set_sound", [buzzer])
[docs] @command( click.argument("lock", type=bool), default_output=format_output( lambda lock: "Turning on child lock" if lock else "Turning off child lock" ), ) def set_child_lock(self, lock: bool): """Set child lock on/off.""" return self.send("set_child_lock", [lock])
[docs] @command(default_output=format_output("Resetting dust filter")) def reset_dust_filter(self): """Resets filter lifetime of the dust filter.""" return self.send("set_filter_rate", [100])
[docs] @command( click.argument("speed", type=int), default_output=format_output("Setting favorite speed to {speed}"), ) def set_favorite_speed(self, speed: int): """Sets the fan speed in favorite mode.""" if speed < 0 or speed > 150: raise ValueError("Invalid favorite speed: %s" % speed) return self.send("set_favourite_speed", [speed])
[docs] @command() def set_ptc_timer(self): """Set PTC timer (not implemented) Value construction:: value = time.index + '-' + time.hexSum + '-' + time.startTime + '-' + time.ptcTimer.endTime + '-' + time.level + '-' + time.status; return self.send("set_ptc_timer", [value]) """ raise NotImplementedError()
[docs] @command() def get_ptc_timer(self): """Returns a list of PTC timers. Response unknown. """ return self.send("get_ptc_timer")
[docs] @command() def get_timer(self): """Response unknown.""" return self.send("get_timer")
[docs] class AirFreshT2017(AirFreshA1): """Main class representing the air fresh t2017."""
[docs] @command( default_output=format_output( "", "Power: {result.power}\n" "Mode: {result.mode}\n" "PM2.5: {result.pm25}\n" "CO2: {result.co2}\n" "Temperature: {result.temperature}\n" "Favorite speed: {result.favorite_speed}\n" "Control speed: {result.control_speed}\n" "Dust filter life: {result.dust_filter_life_remaining} %, " "{result.dust_filter_life_remaining_days} days\n" "Upper filter life remaining: {result.upper_filter_life_remaining} %, " "{result.upper_filter_life_remaining_days} days\n" "PTC: {result.ptc}\n" "PTC level: {result.ptc_level}\n" "PTC status: {result.ptc_status}\n" "Child lock: {result.child_lock}\n" "Buzzer: {result.buzzer}\n" "Display: {result.display}\n" "Display orientation: {result.display_orientation}\n", ) ) @command( click.argument("speed", type=int), default_output=format_output("Setting favorite speed to {speed}"), ) def set_favorite_speed(self, speed: int): """Sets the fan speed in favorite mode.""" if speed < 60 or speed > 300: raise ValueError("Invalid favorite speed: %s" % speed) return self.send("set_favourite_speed", [speed])
[docs] @command(default_output=format_output("Resetting dust filter")) def reset_dust_filter(self): """Resets filter lifetime of the dust filter.""" return self.send("set_filter_reset", ["intermediate"])
[docs] @command(default_output=format_output("Resetting upper filter")) def reset_upper_filter(self): """Resets filter lifetime of the upper filter.""" return self.send("set_filter_reset", ["efficient"])
[docs] @command( click.argument("orientation", type=EnumType(DisplayOrientation)), default_output=format_output("Setting orientation to '{orientation.value}'"), ) def set_display_orientation(self, orientation: DisplayOrientation): """Set display orientation.""" return self.send("set_screen_direction", [orientation.value])
[docs] @command( click.argument("level", type=EnumType(PtcLevel)), default_output=format_output("Setting ptc level to '{level.value}'"), ) def set_ptc_level(self, level: PtcLevel): """Set PTC level.""" return self.send("set_ptc_level", [level.value])