Source code for miio.integrations.shuii.humidifier.airhumidifier_jsq

import enum
import logging
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__)


# Xiaomi Zero Fog Humidifier
MODEL_HUMIDIFIER_JSQ001 = "shuii.humidifier.jsq001"

# Array of properties in same order as in humidifier response
AVAILABLE_PROPERTIES = {
    MODEL_HUMIDIFIER_JSQ001: [
        "temperature",  # (degrees, int)
        "humidity",  # (percentage, int)
        "mode",  # ( 0: Intelligent, 1: Level1, ..., 5:Level4)
        "buzzer",  # (0: off, 1: on)
        "child_lock",  # (0: off, 1: on)
        "led_brightness",  # (0: off, 1: low, 2: high)
        "power",  # (0: off, 1: on)
        "no_water",  # (0: enough, 1: add water)
        "lid_opened",  # (0: ok, 1: lid is opened)
    ]
}


[docs] class OperationMode(enum.Enum): Intelligent = 0 Level1 = 1 Level2 = 2 Level3 = 3 Level4 = 4
[docs] class LedBrightness(enum.Enum): Off = 0 Low = 1 High = 2
[docs] class AirHumidifierStatus(DeviceStatus): """Container for status reports from the air humidifier jsq.""" def __init__(self, data: Dict[str, Any]) -> None: """Status of an Air Humidifier (shuii.humidifier.jsq001): [24, 30, 1, 1, 0, 2, 0, 0, 0] Parsed by AirHumidifierJsq device as: {'temperature': 24, 'humidity': 29, 'mode': 1, 'buzzer': 1, 'child_lock': 0, 'led_brightness': 2, 'power': 0, 'no_water': 0, 'lid_opened': 0} """ self.data = data @property def power(self) -> str: """Power state.""" return "on" if self.data["power"] == 1 else "off" @property def is_on(self) -> bool: """True if device is turned on.""" return self.power == "on" @property def mode(self) -> OperationMode: """Operation mode. Can be either low, medium, high or humidity. """ try: mode = OperationMode(self.data["mode"]) except ValueError as e: _LOGGER.exception("Cannot parse mode: %s", e) return OperationMode.Intelligent return mode @property def temperature(self) -> int: """Current temperature in degree celsius.""" return self.data["temperature"] @property def humidity(self) -> int: """Current humidity in percent.""" return self.data["humidity"] @property def buzzer(self) -> bool: """True if buzzer is turned on.""" return self.data["buzzer"] == 1 @property def led_brightness(self) -> LedBrightness: """Buttons illumination Brightness level.""" try: brightness = LedBrightness(self.data["led_brightness"]) except ValueError as e: _LOGGER.exception("Cannot parse brightness: %s", e) return LedBrightness.Off return brightness @property def led(self) -> bool: """True if LED is turned on.""" return self.led_brightness is not LedBrightness.Off @property def child_lock(self) -> bool: """Return True if child lock is on.""" return self.data["child_lock"] == 1 @property def no_water(self) -> bool: """True if the water tank is empty.""" return self.data["no_water"] == 1 @property def lid_opened(self) -> bool: """True if the water tank is detached.""" return self.data["lid_opened"] == 1 @property def use_time(self) -> Optional[int]: """How long the device has been active in seconds. Not supported by the device, so we return none here. """ return None
[docs] class AirHumidifierJsq(Device): """Implementation of Xiaomi Zero Fog Humidifier: shuii.humidifier.jsq001.""" _supported_models = [MODEL_HUMIDIFIER_JSQ001]
[docs] @command( default_output=format_output( "", "Power: {result.power}\n" "Mode: {result.mode}\n" "Temperature: {result.temperature} °C\n" "Humidity: {result.humidity} %\n" "Buzzer: {result.buzzer}\n" "LED brightness: {result.led_brightness}\n" "Child lock: {result.child_lock}\n" "No water: {result.no_water}\n" "Lid opened: {result.lid_opened}\n", ) ) def status(self) -> AirHumidifierStatus: """Retrieve properties.""" values = self.send("get_props") # Response of an Air Humidifier (shuii.humidifier.jsq001): # [24, 37, 3, 1, 0, 2, 0, 0, 0] # # status[0] : temperature (degrees, int) # status[1]: humidity (percentage, int) # status[2]: mode ( 0: Intelligent, 1: Level1, ..., 5:Level4) # status[3]: buzzer (0: off, 1: on) # status[4]: lock (0: off, 1: on) # status[5]: brightness (0: off, 1: low, 2: high) # status[6]: power (0: off, 1: on) # status[7]: water level state (0: ok, 1: add water) # status[8]: lid state (0: ok, 1: lid is opened) properties = AVAILABLE_PROPERTIES.get( self.model, AVAILABLE_PROPERTIES[MODEL_HUMIDIFIER_JSQ001] ) if len(properties) != len(values): _LOGGER.error( "Count (%s) of requested properties (%s) does not match the " "count (%s) of received values (%s).", len(properties), properties, len(values), values, ) return AirHumidifierStatus({k: v for k, v in zip(properties, values)})
[docs] @command(default_output=format_output("Powering on")) def on(self): """Power on.""" return self.send("set_start", [1])
[docs] @command(default_output=format_output("Powering off")) def off(self): """Power off.""" return self.send("set_start", [0])
[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.""" value = mode.value if value not in (om.value for om in OperationMode): raise ValueError(f"{value} is not a valid OperationMode value") return self.send("set_mode", [value])
[docs] @command( click.argument("brightness", type=EnumType(LedBrightness)), default_output=format_output("Setting LED brightness to {brightness}"), ) def set_led_brightness(self, brightness: LedBrightness): """Set led brightness.""" value = brightness.value if value not in (lb.value for lb in LedBrightness): raise ValueError(f"{value} is not a valid LedBrightness value") return self.send("set_brightness", [value])
[docs] @command( click.argument("led", type=bool), default_output=format_output( lambda led: "Turning on LED" if led else "Turning off LED" ), ) def set_led(self, led: bool): """Turn led on/off.""" brightness = LedBrightness.High if led else LedBrightness.Off return self.set_led_brightness(brightness)
[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 buzzer on/off.""" return self.send("set_buzzer", [int(bool(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_lock", [int(bool(lock))])