mirror of
https://github.com/XiaoMi/ha_xiaomi_home.git
synced 2025-03-31 14:55:31 +08:00
* test: add test case for mips * feat: change mips reconnect logic * fix: fix test_mdns type error
265 lines
9.9 KiB
Python
265 lines
9.9 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""Unit test for miot_mips.py.
|
|
NOTICE: When running this test case, you need to run test_cloud.py first to
|
|
obtain the token and certificate information, and at the same time avoid data
|
|
deletion.
|
|
"""
|
|
import ipaddress
|
|
from typing import Any, Tuple
|
|
import pytest
|
|
import asyncio
|
|
import logging
|
|
|
|
_LOGGER = logging.getLogger(__name__)
|
|
|
|
|
|
# pylint: disable = import-outside-toplevel, unused-argument
|
|
|
|
@pytest.mark.parametrize('central_info', [
|
|
('<Group id>', 'Gateway did', 'Gateway ip', 8883),
|
|
])
|
|
@pytest.mark.asyncio
|
|
async def test_mips_local_async(
|
|
test_cache_path: str,
|
|
test_domain_cloud_cache: str,
|
|
test_name_uid: str,
|
|
test_name_rd_did: str,
|
|
central_info: Tuple[str, str, str, int]
|
|
):
|
|
"""
|
|
NOTICE:
|
|
- Mips local is used to connect to the central gateway and is only
|
|
supported in the Chinese mainland region.
|
|
- Before running this test case, you need to run test_mdns.py first to
|
|
obtain the group_id, did, ip, and port of the hub, and then fill in this
|
|
information in the parametrize. you can enter multiple central connection
|
|
information items for separate tests.
|
|
- This test case requires running test_cloud.py first to obtain the
|
|
central connection certificate.
|
|
- This test case will control the indicator light switch of the central
|
|
gateway.
|
|
"""
|
|
from miot.miot_storage import MIoTStorage, MIoTCert
|
|
from miot.miot_mips import MipsLocalClient
|
|
|
|
central_group_id: str = central_info[0]
|
|
assert isinstance(central_group_id, str)
|
|
central_did: str = central_info[1]
|
|
assert central_did.isdigit()
|
|
central_ip: str = central_info[2]
|
|
assert ipaddress.ip_address(central_ip)
|
|
central_port: int = central_info[3]
|
|
assert isinstance(central_port, int)
|
|
|
|
miot_storage = MIoTStorage(test_cache_path)
|
|
uid = await miot_storage.load_async(
|
|
domain=test_domain_cloud_cache, name=test_name_uid, type_=str)
|
|
assert isinstance(uid, str)
|
|
random_did = await miot_storage.load_async(
|
|
domain=test_domain_cloud_cache, name=test_name_rd_did, type_=str)
|
|
assert isinstance(random_did, str)
|
|
miot_cert = MIoTCert(storage=miot_storage, uid=uid, cloud_server='CN')
|
|
assert miot_cert.ca_file
|
|
assert miot_cert.cert_file
|
|
assert miot_cert.key_file
|
|
_LOGGER.info(
|
|
'cert info, %s, %s, %s', miot_cert.ca_file, miot_cert.cert_file,
|
|
miot_cert.key_file)
|
|
|
|
mips_local = MipsLocalClient(
|
|
did=random_did,
|
|
host=central_ip,
|
|
group_id=central_group_id,
|
|
ca_file=miot_cert.ca_file,
|
|
cert_file=miot_cert.cert_file,
|
|
key_file=miot_cert.key_file,
|
|
port=central_port,
|
|
home_name='mips local test')
|
|
mips_local.enable_logger(logger=_LOGGER)
|
|
mips_local.enable_mqtt_logger(logger=_LOGGER)
|
|
|
|
async def on_mips_state_changed_async(key: str, state: bool):
|
|
_LOGGER.info('on mips state changed, %s, %s', key, state)
|
|
|
|
async def on_dev_list_changed_async(
|
|
mips: MipsLocalClient, did_list: list[str]
|
|
):
|
|
_LOGGER.info('dev list changed, %s', did_list)
|
|
|
|
def on_prop_changed(payload: dict, ctx: Any):
|
|
_LOGGER.info('prop changed, %s=%s', ctx, payload)
|
|
|
|
def on_event_occurred(payload: dict, ctx: Any):
|
|
_LOGGER.info('event occurred, %s=%s', ctx, payload)
|
|
|
|
# Reg mips state
|
|
mips_local.sub_mips_state(
|
|
key='mips_local', handler=on_mips_state_changed_async)
|
|
mips_local.on_dev_list_changed = on_dev_list_changed_async
|
|
# Connect
|
|
await mips_local.connect_async()
|
|
await asyncio.sleep(0.5)
|
|
# Get device list
|
|
device_list = await mips_local.get_dev_list_async()
|
|
assert isinstance(device_list, dict)
|
|
_LOGGER.info(
|
|
'get_dev_list, %d, %s', len(device_list), list(device_list.keys()))
|
|
# Sub Prop
|
|
mips_local.sub_prop(
|
|
did=central_did, handler=on_prop_changed,
|
|
handler_ctx=f'{central_did}.*')
|
|
# Sub Event
|
|
mips_local.sub_event(
|
|
did=central_did, handler=on_event_occurred,
|
|
handler_ctx=f'{central_did}.*')
|
|
# Get/set prop
|
|
test_siid = 3
|
|
test_piid = 1
|
|
# mips_local.sub_prop(
|
|
# did=central_did, siid=test_siid, piid=test_piid,
|
|
# handler=on_prop_changed,
|
|
# handler_ctx=f'{central_did}.{test_siid}.{test_piid}')
|
|
result1 = await mips_local.get_prop_async(
|
|
did=central_did, siid=test_siid, piid=test_piid)
|
|
assert isinstance(result1, bool)
|
|
_LOGGER.info('get prop.%s.%s, value=%s', test_siid, test_piid, result1)
|
|
result2 = await mips_local.set_prop_async(
|
|
did=central_did, siid=test_siid, piid=test_piid, value=not result1)
|
|
_LOGGER.info(
|
|
'set prop.%s.%s=%s, result=%s',
|
|
test_siid, test_piid, not result1, result2)
|
|
assert isinstance(result2, dict)
|
|
result3 = await mips_local.get_prop_async(
|
|
did=central_did, siid=test_siid, piid=test_piid)
|
|
assert isinstance(result3, bool)
|
|
_LOGGER.info('get prop.%s.%s, value=%s', test_siid, test_piid, result3)
|
|
# Action
|
|
test_siid = 4
|
|
test_aiid = 1
|
|
in_list = [{'piid': 1, 'value': 'hello world.'}]
|
|
result4 = await mips_local.action_async(
|
|
did=central_did, siid=test_siid, aiid=test_aiid,
|
|
in_list=in_list)
|
|
assert isinstance(result4, dict)
|
|
_LOGGER.info(
|
|
'action.%s.%s=%s, result=%s', test_siid, test_piid, in_list, result4)
|
|
# Disconnect
|
|
await mips_local.disconnect_async()
|
|
await mips_local.deinit_async()
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_mips_cloud_async(
|
|
test_cache_path: str,
|
|
test_name_uuid: str,
|
|
test_cloud_server: str,
|
|
test_domain_cloud_cache: str,
|
|
test_name_oauth2_info: str,
|
|
test_name_devices: str
|
|
):
|
|
"""
|
|
NOTICE:
|
|
- This test case requires running test_cloud.py first to obtain the
|
|
central connection certificate.
|
|
- This test case will control the indicator light switch of the central
|
|
gateway.
|
|
"""
|
|
from miot.const import OAUTH2_CLIENT_ID
|
|
from miot.miot_storage import MIoTStorage
|
|
from miot.miot_mips import MipsCloudClient
|
|
from miot.miot_cloud import MIoTHttpClient
|
|
|
|
miot_storage = MIoTStorage(test_cache_path)
|
|
uuid = await miot_storage.load_async(
|
|
domain=test_domain_cloud_cache, name=test_name_uuid, type_=str)
|
|
assert isinstance(uuid, str)
|
|
oauth_info = await miot_storage.load_async(
|
|
domain=test_domain_cloud_cache, name=test_name_oauth2_info, type_=dict)
|
|
assert isinstance(oauth_info, dict) and 'access_token' in oauth_info
|
|
access_token = oauth_info['access_token']
|
|
_LOGGER.info('connect info, %s, %s', uuid, access_token)
|
|
mips_cloud = MipsCloudClient(
|
|
uuid=uuid,
|
|
cloud_server=test_cloud_server,
|
|
app_id=OAUTH2_CLIENT_ID,
|
|
token=access_token)
|
|
mips_cloud.enable_logger(logger=_LOGGER)
|
|
mips_cloud.enable_mqtt_logger(logger=_LOGGER)
|
|
miot_http = MIoTHttpClient(
|
|
cloud_server=test_cloud_server,
|
|
client_id=OAUTH2_CLIENT_ID,
|
|
access_token=access_token)
|
|
|
|
async def on_mips_state_changed_async(key: str, state: bool):
|
|
_LOGGER.info('on mips state changed, %s, %s', key, state)
|
|
|
|
def on_prop_changed(payload: dict, ctx: Any):
|
|
_LOGGER.info('prop changed, %s=%s', ctx, payload)
|
|
|
|
def on_event_occurred(payload: dict, ctx: Any):
|
|
_LOGGER.info('event occurred, %s=%s', ctx, payload)
|
|
|
|
await mips_cloud.connect_async()
|
|
await asyncio.sleep(0.5)
|
|
|
|
# Sub mips state
|
|
mips_cloud.sub_mips_state(
|
|
key='mips_cloud', handler=on_mips_state_changed_async)
|
|
# Load devices
|
|
local_devices = await miot_storage.load_async(
|
|
domain=test_domain_cloud_cache, name=test_name_devices, type_=dict)
|
|
assert isinstance(local_devices, dict)
|
|
central_did = ''
|
|
for did, info in local_devices.items():
|
|
if info['model'] != 'xiaomi.gateway.hub1':
|
|
continue
|
|
central_did = did
|
|
break
|
|
if central_did:
|
|
# Sub Prop
|
|
mips_cloud.sub_prop(
|
|
did=central_did, handler=on_prop_changed,
|
|
handler_ctx=f'{central_did}.*')
|
|
# Sub Event
|
|
mips_cloud.sub_event(
|
|
did=central_did, handler=on_event_occurred,
|
|
handler_ctx=f'{central_did}.*')
|
|
# Get/set prop
|
|
test_siid = 3
|
|
test_piid = 1
|
|
# mips_cloud.sub_prop(
|
|
# did=central_did, siid=test_siid, piid=test_piid,
|
|
# handler=on_prop_changed,
|
|
# handler_ctx=f'{central_did}.{test_siid}.{test_piid}')
|
|
result1 = await miot_http.get_prop_async(
|
|
did=central_did, siid=test_siid, piid=test_piid)
|
|
assert isinstance(result1, bool)
|
|
_LOGGER.info('get prop.%s.%s, value=%s', test_siid, test_piid, result1)
|
|
result2 = await miot_http.set_prop_async(params=[{
|
|
'did': central_did, 'siid': test_siid, 'piid': test_piid,
|
|
'value': not result1}])
|
|
_LOGGER.info(
|
|
'set prop.%s.%s=%s, result=%s',
|
|
test_siid, test_piid, not result1, result2)
|
|
assert isinstance(result2, list)
|
|
result3 = await miot_http.get_prop_async(
|
|
did=central_did, siid=test_siid, piid=test_piid)
|
|
assert isinstance(result3, bool)
|
|
_LOGGER.info('get prop.%s.%s, value=%s', test_siid, test_piid, result3)
|
|
# Action
|
|
test_siid = 4
|
|
test_aiid = 1
|
|
in_list = [{'piid': 1, 'value': 'hello world.'}]
|
|
result4 = await miot_http.action_async(
|
|
did=central_did, siid=test_siid, aiid=test_aiid,
|
|
in_list=in_list)
|
|
assert isinstance(result4, dict)
|
|
_LOGGER.info(
|
|
'action.%s.%s=%s, result=%s',
|
|
test_siid, test_piid, in_list, result4)
|
|
await asyncio.sleep(1)
|
|
# Disconnect
|
|
await mips_cloud.disconnect_async()
|
|
await mips_cloud.deinit_async()
|
|
await miot_http.deinit_async()
|