From 1a6906f9f779bf11a9112fc30d74a1aac6191cea Mon Sep 17 00:00:00 2001 From: Sebastian Muszynski Date: Thu, 23 Nov 2017 11:18:35 +0100 Subject: [PATCH] First draft of the Xiaomi Mi Home Air Conditioner Companion supported. Fixes #76. --- miio/__init__.py | 1 + miio/airconditioningcompanion.py | 102 +++++++++++++++++++++++++++++++ 2 files changed, 103 insertions(+) create mode 100644 miio/airconditioningcompanion.py diff --git a/miio/__init__.py b/miio/__init__.py index 8350244d1..a551ebc1a 100644 --- a/miio/__init__.py +++ b/miio/__init__.py @@ -16,6 +16,7 @@ from miio.fan import Fan from miio.wifispeaker import WifiSpeaker from miio.airqualitymonitor import AirQualityMonitor +from miio.airconditioningcompanion import AirConditioningCompanion from miio.yeelight import Yeelight from miio.device import Device, DeviceException from miio.discovery import Discovery diff --git a/miio/airconditioningcompanion.py b/miio/airconditioningcompanion.py new file mode 100644 index 000000000..4de0a4e58 --- /dev/null +++ b/miio/airconditioningcompanion.py @@ -0,0 +1,102 @@ +import logging +import enum +from typing import Any, Dict, Optional +from collections import defaultdict +from .device import Device, DeviceException + + +class AirConditioningCompanionStatus: + """Container for status reports of the Xiaomi AC Companion.""" + + def __init__(self, data): + self.data = data + + @property + def ac_power(self): + """Current power state of the air conditioner.""" + return self.data[2] + + @property + def ac_model(self): + """Model of the air conditioner.""" + return str(self.data[0][0:2] + self.data[0][8:16]) + + @property + def power(self): + """Current power state.""" + return self.data[1][2:3] + + # FIXME: Introduce a container class + @property + def wind_force(self): + """Current wind force.""" + if self.data[1][4:5] == '0': + return 'low' + elif self.data[1][4:5] == '1': + return 'medium' + elif self.data[1][4:5] == '2': + return 'high' + else: + return 'auto' + + @property + def sweep(self) -> bool: + """True if sweep is turned on.""" + return self.data[1][5:6] == '0' + + @property + def temp(self) -> int: + """Current temperature.""" + return int(self.data[1][6:8], 16) + + # FIXME: Merge both properties + @property + def mode(self): + """Current mode.""" + return self.data[1][3:4] + + # FIXME: Introduce a container class + @property + def operation(self): + if self.data[1][2:3] == '0': + return 'off' + else: + if self.data[1][3:4] == '0': + return 'heat' + elif self.data[1][3:4] == '1': + return 'cool' + else: + return 'auto' + + +class AirConditioningCompanion(Device): + """Main class representing Xiaomi Air Conditioning Companion.""" + + def status(self) -> AirConditioningCompanionStatus: + """Return device status.""" + status = self.send("get_model_and_state", []) + return AirConditioningCompanionStatus(status) + + def learn(self): + """Learn an infrared command.""" + return self.send("start_ir_learn", [30]) + + def learn_result(self): + """Read the learned command.""" + return self.send("get_ir_learn_result", []) + + def learn_stop(self): + """Stop learning of a infrared command.""" + return self.send("end_ir_learn", [30]) + + def send_ir_code(self, command: str): + """Play a captured command. + + :param str command: Command to execute""" + return self.send("send_ir_code", [str(command)]) + + def send_command(self, command: str): + """Send a command to the air conditioner. + + :param str command: Command to execute""" + return self.send("send_cmd", [str(command)])