Skip to content

Commit

Permalink
Tests for the Xiaomi Air Conditioning Companion (#182)
Browse files Browse the repository at this point in the history
* Tests for optional return values added.

* Blank line removed.

* Catch a TypError. It cannot be a ValueError in this case.

* Open loop tests added and bugs fixed.

* Additional cases added.

* Typo fixed.
  • Loading branch information
syssi authored and rytilahti committed Jan 27, 2018
1 parent e9ce9e0 commit b281845
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 23 deletions.
46 changes: 25 additions & 21 deletions miio/airconditioningcompanion.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ class Power(enum.Enum):
},
'0100010727': {
'deviceType': 'gree_2',
'base': '[po][mo][wi][sw][tt]1100190[tt1]205002102000t7t0190[tt1]207002000000[tt4]0',
'base': '[po][mo][wi][sw][tt]1100190[tt1]205002102000[tt7]0190[tt1]207002000000[tt4]0',
'off': '01011101004000205002112000D04000207002000000A0'
},
'0100004795': {
Expand Down Expand Up @@ -101,9 +101,12 @@ def is_on(self) -> bool:
return self.power == 'on'

@property
def temperature(self) -> int:
def temperature(self) -> Optional[int]:
"""Current temperature."""
return int(self.data[1][6:8], 16)
try:
return int(self.data[1][6:8], 16)
except TypeError:
return None

@property
def swing_mode(self) -> bool:
Expand All @@ -113,20 +116,20 @@ def swing_mode(self) -> bool:
@property
def fan_speed(self) -> Optional[FanSpeed]:
"""Current fan speed."""
speed = int(self.data[1][4:5])
if speed is not None:
try:
speed = int(self.data[1][4:5])
return FanSpeed(speed)

return None
except TypeError:
return None

@property
def mode(self) -> Optional[OperationMode]:
"""Current operation mode."""
mode = int(self.data[1][3:4])
if mode is not None:
try:
mode = int(self.data[1][3:4])
return OperationMode(mode)

return None
except TypeError:
return None


class AirConditioningCompanion(Device):
Expand All @@ -137,17 +140,17 @@ def status(self) -> AirConditioningCompanionStatus:
status = self.send("get_model_and_state", [])
return AirConditioningCompanionStatus(status)

def learn(self):
def learn(self, slot: int=STORAGE_SLOT_ID):
"""Learn an infrared command."""
return self.send("start_ir_learn", [STORAGE_SLOT_ID])
return self.send("start_ir_learn", [slot])

def learn_result(self):
"""Read the learned command."""
return self.send("get_ir_learn_result", [])

def learn_stop(self):
def learn_stop(self, slot: int=STORAGE_SLOT_ID):
"""Stop learning of a infrared command."""
return self.send("end_ir_learn", [STORAGE_SLOT_ID])
return self.send("end_ir_learn", [slot])

def send_ir_code(self, command: str):
"""Play a captured command.
Expand Down Expand Up @@ -175,18 +178,19 @@ def send_configuration(self, model: str, power: Power,
if model in DEVICE_COMMAND_TEMPLATES:
configuration = model + DEVICE_COMMAND_TEMPLATES[model]['base']
else:
configuration = model + DEVICE_COMMAND_TEMPLATES['fallback']['base']
configuration = \
model + DEVICE_COMMAND_TEMPLATES['fallback']['base']

configuration = configuration.replace('[po]', power.value)
configuration = configuration.replace('[mo]', operation_mode.value)
configuration = configuration.replace('[wi]', fan_speed.value)
configuration = configuration.replace('[sw]', swing_mode.value)
configuration = configuration.replace('[po]', str(power.value))
configuration = configuration.replace('[mo]', str(operation_mode.value))
configuration = configuration.replace('[wi]', str(fan_speed.value))
configuration = configuration.replace('[sw]', str(swing_mode.value))
configuration = configuration.replace(
'[tt]', hex(int(target_temperature))[2:])

temperature = (1 + int(target_temperature) - 17) % 16
temperature = hex(temperature)[2:].upper()
configuration = configuration.replace('[[tt1]]', temperature)
configuration = configuration.replace('[tt1]', temperature)

temperature = (4 + int(target_temperature) - 17) % 16
temperature = hex(temperature)[2:].upper()
Expand Down
78 changes: 76 additions & 2 deletions miio/tests/test_airconditioningcompanion.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import string
from unittest import TestCase
from miio import AirConditioningCompanion
from miio.airconditioningcompanion import OperationMode, FanSpeed
from miio.airconditioningcompanion import OperationMode, FanSpeed, Power, \
SwingMode, STORAGE_SLOT_ID
import pytest


Expand All @@ -9,7 +11,12 @@ def __init__(self, *args, **kwargs):
self.state = ['010500978022222102', '010201190280222221', '2']

self.return_values = {
'get_model_and_state': self._get_state
'get_model_and_state': self._get_state,
'start_ir_learn': lambda x: True,
'end_ir_learn': lambda x: True,
'get_ir_learn_result': lambda x: True,
'send_ir_code': lambda x: True,
'send_cmd': self._send_cmd_input_validation,
}
self.start_state = self.state.copy()

Expand All @@ -25,6 +32,9 @@ def _get_state(self, props):
"""Return the requested data"""
return self.state

def _send_cmd_input_validation(self, props):
return all(c in string.hexdigits for c in props[0])


@pytest.fixture(scope="class")
def airconditioningcompanion(request):
Expand All @@ -50,3 +60,67 @@ def test_status(self):
assert self.state().swing_mode is False
assert self.state().fan_speed == FanSpeed.Low
assert self.state().mode == OperationMode.Auto

def test_status_without_temperature(self):
self.device._reset_state()
self.device.state[1] = None
assert self.state().temperature is None

def test_status_without_mode(self):
self.device._reset_state()
self.device.state[1] = None
assert self.state().mode is None

def test_status_without_fan_speed(self):
self.device._reset_state()
self.device.state[1] = None
assert self.state().fan_speed is None

def test_learn(self):
assert self.device.learn(STORAGE_SLOT_ID) is True
assert self.device.learn() is True

def test_learn_result(self):
assert self.device.learn_result() is True

def test_learn_stop(self):
assert self.device.learn_stop(STORAGE_SLOT_ID) is True
assert self.device.learn_stop() is True

def test_send_ir_code(self):
assert self.device.send_ir_code('0000000') is True

def test_send_command(self):
assert self.device.send_command('0000000') is True

def test_send_configuration(self):
def send_configuration_known_aircondition():
return self.device.send_configuration(
'0100010727',
Power.On,
OperationMode.Auto,
22.5,
FanSpeed.Low,
SwingMode.On)

def send_configuration_known_aircondition_turn_off():
return self.device.send_configuration(
'0100010727',
Power.Off,
OperationMode.Auto,
22.5,
FanSpeed.Low,
SwingMode.On)

def send_configuration_unknown_aircondition():
return self.device.send_configuration(
'01000fffff',
Power.On,
OperationMode.Auto,
22.5,
FanSpeed.Low,
SwingMode.On)

assert send_configuration_known_aircondition() is True
assert send_configuration_known_aircondition_turn_off() is True
assert send_configuration_unknown_aircondition() is True

0 comments on commit b281845

Please sign in to comment.