-
-
Notifications
You must be signed in to change notification settings - Fork 568
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
- Loading branch information
Showing
3 changed files
with
243 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,145 @@ | ||
from unittest import TestCase | ||
from miio import WifiRepeater | ||
from miio.wifirepeater import WifiRepeaterConfiguration, WifiRepeaterStatus | ||
import pytest | ||
|
||
|
||
class DummyWifiRepeater(WifiRepeater): | ||
def __init__(self, *args, **kwargs): | ||
self.state = { | ||
'sta': {'count': 2, 'access_policy': 0}, | ||
'mat': [ | ||
{'mac': 'aa:aa:aa:aa:aa:aa', 'ip': '192.168.1.133', | ||
'last_time': 54371873}, | ||
{'mac': 'bb:bb:bb:bb:bb:bb', 'ip': '192.168.1.156', | ||
'last_time': 54371496} | ||
], | ||
'access_list': {'mac': ''} | ||
} | ||
self.config = {'ssid': 'SSID', 'pwd': 'PWD', 'hidden': 0} | ||
self.device_info = { | ||
'life': 543452, 'cfg_time': 543452, | ||
'token': 'ffffffffffffffffffffffffffffffff', | ||
'fw_ver': '2.2.14', 'hw_ver': 'R02', | ||
'uid': 1583412143, 'api_level': 2, | ||
'mcu_fw_ver': '1000', 'wifi_fw_ver': '1.0.0', | ||
'mac': 'FF:FF:FF:FF:FF:FF', | ||
'model': 'xiaomi.repeater.v2', | ||
'ap': {'rssi': -63, 'ssid': 'SSID', | ||
'bssid': 'EE:EE:EE:EE:EE:EE', | ||
'rx': 136695922, 'tx': 1779521233}, | ||
'sta': {'count': 2, 'ssid': 'REPEATER-SSID', | ||
'hidden': 0, | ||
'assoclist': 'cc:cc:cc:cc:cc:cc;bb:bb:bb:bb:bb:bb;'}, | ||
'netif': {'localIp': '192.168.1.170', | ||
'mask': '255.255.255.0', | ||
'gw': '192.168.1.1'}, | ||
'desc': {'wifi_explorer': 1, | ||
'sn': '14923 / 20191356', 'color': 101, | ||
'channel': 'release'} | ||
} | ||
|
||
self.return_values = { | ||
'miIO.get_repeater_sta_info': self._get_state, | ||
'miIO.get_repeater_ap_info': self._get_configuration, | ||
'miIO.switch_wifi_explorer': self._set_wifi_explorer, | ||
'miIO.switch_wifi_ssid': self._set_configuration, | ||
'miIO.info': self._get_info, | ||
} | ||
self.start_state = self.state.copy() | ||
self.start_config = self.config.copy() | ||
self.start_device_info = self.device_info.copy() | ||
|
||
def send(self, command: str, parameters=None, retry_count=3): | ||
"""Overridden send() to return values from `self.return_values`.""" | ||
return self.return_values[command](parameters) | ||
|
||
def _reset_state(self): | ||
"""Revert back to the original state.""" | ||
self.state = self.start_state.copy() | ||
self.config = self.start_config.copy() | ||
self.device_info = self.start_device_info.copy() | ||
|
||
def _get_state(self, param): | ||
return self.state | ||
|
||
def _get_configuration(self, param): | ||
return self.config | ||
|
||
def _get_info(self, param): | ||
return self.device_info | ||
|
||
def _set_wifi_explorer(self, data): | ||
self.device_info['desc']['wifi_explorer'] = data[0]['wifi_explorer'] | ||
|
||
def _set_configuration(self, data): | ||
self.config = { | ||
'ssid': data[0]['ssid'], | ||
'pwd': data[0]['pwd'], | ||
'hidden': data[0]['hidden'] | ||
} | ||
|
||
self.device_info['desc']['wifi_explorer'] = data[0]['wifi_explorer'] | ||
return True | ||
|
||
|
||
@pytest.fixture(scope="class") | ||
def wifirepeater(request): | ||
request.cls.device = DummyWifiRepeater() | ||
# TODO add ability to test on a real device | ||
|
||
|
||
@pytest.mark.usefixtures("wifirepeater") | ||
class TestWifiRepeater(TestCase): | ||
def state(self): | ||
return self.device.status() | ||
|
||
def configuration(self): | ||
return self.device.configuration() | ||
|
||
def info(self): | ||
return self.device.info() | ||
|
||
def test_status(self): | ||
self.device._reset_state() | ||
|
||
assert repr(self.state()) == repr(WifiRepeaterStatus(self.device.start_state)) | ||
|
||
assert self.state().access_policy == self.device.start_state['sta']['access_policy'] | ||
assert self.state().associated_stations == self.device.start_state['mat'] | ||
|
||
def test_set_wifi_roaming(self): | ||
self.device.set_wifi_roaming(True) | ||
assert self.info().raw['desc']['wifi_explorer'] == 1 | ||
|
||
self.device.set_wifi_roaming(False) | ||
assert self.info().raw['desc']['wifi_explorer'] == 0 | ||
|
||
def test_configuration(self): | ||
self.device._reset_state() | ||
|
||
assert repr(self.configuration()) == repr(WifiRepeaterConfiguration(self.device.start_config)) | ||
|
||
assert self.configuration().ssid == self.device.start_config['ssid'] | ||
assert self.configuration().password == self.device.start_config['pwd'] | ||
assert self.configuration().ssid_hidden is (self.device.start_config['hidden'] == 1) | ||
|
||
def test_set_configuration(self): | ||
def configuration(): | ||
return self.device.configuration() | ||
|
||
dummy_configuration = { | ||
'ssid': 'SSID2', | ||
'password': 'PASSWORD2', | ||
'hidden': True, | ||
'wifi_explorer': False | ||
} | ||
|
||
self.device.set_configuration( | ||
dummy_configuration['ssid'], | ||
dummy_configuration['password'], | ||
dummy_configuration['hidden'], | ||
dummy_configuration['wifi_explorer']) | ||
assert configuration().ssid == dummy_configuration['ssid'] | ||
assert configuration().password == dummy_configuration['password'] | ||
assert configuration().ssid_hidden is dummy_configuration['hidden'] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
import logging | ||
from .device import Device | ||
|
||
_LOGGER = logging.getLogger(__name__) | ||
|
||
|
||
class WifiRepeaterStatus: | ||
def __init__(self, data): | ||
""" | ||
Response of a xiaomi.repeater.v2: | ||
{ | ||
'sta': {'count': 2, 'access_policy': 0}, | ||
'mat': [ | ||
{'mac': 'aa:aa:aa:aa:aa:aa', 'ip': '192.168.1.133', 'last_time': 54371873}, | ||
{'mac': 'bb:bb:bb:bb:bb:bb', 'ip': '192.168.1.156', 'last_time': 54371496} | ||
], | ||
'access_list': {'mac': ''} | ||
} | ||
""" | ||
self.data = data | ||
|
||
@property | ||
def access_policy(self) -> int: | ||
"""Access policy of the associated stations.""" | ||
return self.data['sta']['access_policy'] | ||
|
||
@property | ||
def associated_stations(self) -> dict: | ||
"""List of associated stations.""" | ||
return self.data['mat'] | ||
|
||
def __repr__(self) -> str: | ||
s = "<WifiRepeaterStatus access_policy=%s, " \ | ||
"associated_stations=%s>" % \ | ||
(self.access_policy, | ||
len(self.associated_stations)) | ||
return s | ||
|
||
|
||
class WifiRepeaterConfiguration: | ||
def __init__(self, data): | ||
""" | ||
Response of a xiaomi.repeater.v2: | ||
{'ssid': 'SSID', 'pwd': 'PWD', 'hidden': 0} | ||
""" | ||
self.data = data | ||
|
||
@property | ||
def ssid(self) -> str: | ||
return self.data['ssid'] | ||
|
||
@property | ||
def password(self) -> str: | ||
return self.data['pwd'] | ||
|
||
@property | ||
def ssid_hidden(self) -> bool: | ||
return self.data['hidden'] == 1 | ||
|
||
def __repr__(self) -> str: | ||
s = "<WifiRepeaterConfiguration ssid=%s, " \ | ||
"password=%s, " \ | ||
"ssid_hidden=%s>" % \ | ||
(self.ssid, | ||
self.password, | ||
self.ssid_hidden) | ||
return s | ||
|
||
|
||
class WifiRepeater(Device): | ||
"""Device class for Xiaomi Mi WiFi Repeater 2.""" | ||
def status(self) -> WifiRepeaterStatus: | ||
"""Return the associated stations.""" | ||
return WifiRepeaterStatus(self.send("miIO.get_repeater_sta_info", [])) | ||
|
||
def configuration(self) -> WifiRepeaterConfiguration: | ||
"""Return the configuration of the accesspoint.""" | ||
return WifiRepeaterConfiguration( | ||
self.send("miIO.get_repeater_ap_info", [])) | ||
|
||
def set_wifi_roaming(self, wifi_roaming: bool): | ||
"""Turn the WiFi roaming on/off.""" | ||
return self.send("miIO.switch_wifi_explorer", [{ | ||
'wifi_explorer': int(wifi_roaming) | ||
}]) | ||
|
||
def set_configuration(self, ssid: str, password: str, hidden: bool = False, | ||
wifi_roaming: bool = False): | ||
"""Update the configuration of the accesspoint.""" | ||
return self.send("miIO.switch_wifi_ssid", [{ | ||
'ssid': ssid, | ||
'pwd': password, | ||
'hidden': int(hidden), | ||
'wifi_explorer': int(wifi_roaming) | ||
}]) |