feat: completely remove filtered spec

This commit is contained in:
LiShuzhen 2025-03-28 09:09:27 +08:00
parent 19ed04f2f5
commit 51e5ef4153
3 changed files with 118 additions and 0 deletions

View File

@ -1156,6 +1156,59 @@ class _SpecFilter:
return False return False
class _SpecAdd:
"""MIoT-Spec-V2 add for entity conversion."""
_SPEC_ADD_FILE = 'specs/spec_add.yaml'
_main_loop: asyncio.AbstractEventLoop
_data: Optional[dict]
_selected: Optional[dict]
def __init__(
self, loop: Optional[asyncio.AbstractEventLoop] = None
) -> None:
self._main_loop = loop or asyncio.get_running_loop()
self._data = None
async def init_async(self) -> None:
if isinstance(self._data, dict):
return
add_data = None
self._data = {}
self._selected = None
try:
add_data = await self._main_loop.run_in_executor(
None, load_yaml_file,
os.path.join(
os.path.dirname(os.path.abspath(__file__)),
self._SPEC_ADD_FILE))
except Exception as err: # pylint: disable=broad-exception-caught
_LOGGER.error('spec add, load file error, %s', err)
return
if not isinstance(add_data, dict):
_LOGGER.error('spec add, invalid spec add content')
return
for key, value in add_data.items():
if not isinstance(key, str) or not isinstance(value, (dict, str)):
_LOGGER.error('spec add, invalid spec modify data')
return
self._data = add_data
async def deinit_async(self) -> None:
self._data = None
self._selected = None
async def set_spec_async(self, urn: str) -> None:
if not self._data:
return
self._selected = self._data.get(urn, None)
if isinstance(self._selected, str):
return await self.set_spec_async(urn=self._selected)
def get_spec_add(self) -> Optional[dict]:
return self._selected
class _SpecModify: class _SpecModify:
"""MIoT-Spec-V2 modify for entity conversion.""" """MIoT-Spec-V2 modify for entity conversion."""
_SPEC_MODIFY_FILE = 'specs/spec_modify.yaml' _SPEC_MODIFY_FILE = 'specs/spec_modify.yaml'
@ -1259,6 +1312,7 @@ class MIoTSpecParser:
_multi_lang: _MIoTSpecMultiLang _multi_lang: _MIoTSpecMultiLang
_bool_trans: _SpecBoolTranslation _bool_trans: _SpecBoolTranslation
_spec_filter: _SpecFilter _spec_filter: _SpecFilter
_spec_add: _SpecAdd
_spec_modify: _SpecModify _spec_modify: _SpecModify
_init_done: bool _init_done: bool
@ -1434,6 +1488,8 @@ class MIoTSpecParser:
# Filter spec service # Filter spec service
spec_service.need_filter = self._spec_filter.filter_service( spec_service.need_filter = self._spec_filter.filter_service(
siid=service['iid']) siid=service['iid'])
if spec_service.need_filter:
continue
if type_strs[1] != 'miot-spec-v2': if type_strs[1] != 'miot-spec-v2':
spec_service.proprietary = True spec_service.proprietary = True
spec_service.description_trans = ( spec_service.description_trans = (
@ -1467,6 +1523,8 @@ class MIoTSpecParser:
spec_service.need_filter spec_service.need_filter
or self._spec_filter.filter_property( or self._spec_filter.filter_property(
siid=service['iid'], piid=property_['iid'])) siid=service['iid'], piid=property_['iid']))
if spec_prop.need_filter:
continue
if p_type_strs[1] != 'miot-spec-v2': if p_type_strs[1] != 'miot-spec-v2':
spec_prop.proprietary = spec_service.proprietary or True spec_prop.proprietary = spec_service.proprietary or True
spec_prop.description_trans = ( spec_prop.description_trans = (
@ -1543,6 +1601,8 @@ class MIoTSpecParser:
spec_service.need_filter spec_service.need_filter
or self._spec_filter.filter_event( or self._spec_filter.filter_event(
siid=service['iid'], eiid=event['iid'])) siid=service['iid'], eiid=event['iid']))
if spec_event.need_filter:
continue
if e_type_strs[1] != 'miot-spec-v2': if e_type_strs[1] != 'miot-spec-v2':
spec_event.proprietary = spec_service.proprietary or True spec_event.proprietary = spec_service.proprietary or True
spec_event.description_trans = ( spec_event.description_trans = (
@ -1579,6 +1639,8 @@ class MIoTSpecParser:
spec_service.need_filter spec_service.need_filter
or self._spec_filter.filter_action( or self._spec_filter.filter_action(
siid=service['iid'], aiid=action['iid'])) siid=service['iid'], aiid=action['iid']))
if spec_action.need_filter:
continue
if a_type_strs[1] != 'miot-spec-v2': if a_type_strs[1] != 'miot-spec-v2':
spec_action.proprietary = spec_service.proprietary or True spec_action.proprietary = spec_service.proprietary or True
spec_action.description_trans = ( spec_action.description_trans = (

View File

@ -0,0 +1,13 @@
urn:miot-spec-v2:device:airer:0000A00D:hyd-lyjpro:1:
3:
name: light
description: Moon Light
properties:
2:
name: true
description: Switch Status
format: bool
access:
- read
- write
- notify

View File

@ -20,6 +20,9 @@ SPEC_BOOL_TRANS_FILE = path.join(
SPEC_FILTER_FILE = path.join( SPEC_FILTER_FILE = path.join(
ROOT_PATH, ROOT_PATH,
'../custom_components/xiaomi_home/miot/specs/spec_filter.yaml') '../custom_components/xiaomi_home/miot/specs/spec_filter.yaml')
SPEC_ADD_FILE = path.join(
ROOT_PATH,
'../custom_components/xiaomi_home/miot/specs/spec_add.yaml')
SPEC_MODIFY_FILE = path.join( SPEC_MODIFY_FILE = path.join(
ROOT_PATH, ROOT_PATH,
'../custom_components/xiaomi_home/miot/specs/spec_modify.yaml') '../custom_components/xiaomi_home/miot/specs/spec_modify.yaml')
@ -139,6 +142,29 @@ def bool_trans(d: dict) -> bool:
return True return True
def spec_add(data: dict) -> bool:
"""dict[str, str | dict[str, dict[str, str | dict]]]"""
if not isinstance(data, dict):
return False
for urn, content in data.items():
if not isinstance(urn, str) or not isinstance(content, (dict, str)):
return False
if isinstance(content, str):
continue
for key, value in content.items():
if not isinstance(key, int) or not isinstance(value, dict):
return False
for k, v in value.items():
if not isinstance(k, str):
return False
if k in ['properties', 'actions', 'events']:
if not isinstance(v, dict):
return False
elif not isinstance(v, str):
return False
return True
def spec_modify(data: dict) -> bool: def spec_modify(data: dict) -> bool:
"""dict[str, str | dict[str, dict]]""" """dict[str, str | dict[str, dict]]"""
if not isinstance(data, dict): if not isinstance(data, dict):
@ -200,6 +226,12 @@ def sort_spec_filter(file_path: str):
return filter_data return filter_data
def sort_spec_add(file_path: str):
filter_data = load_yaml_file(file_path=file_path)
assert isinstance(filter_data, dict), f'{file_path} format error'
return dict(sorted(filter_data.items()))
def sort_spec_modify(file_path: str): def sort_spec_modify(file_path: str):
filter_data = load_yaml_file(file_path=file_path) filter_data = load_yaml_file(file_path=file_path)
assert isinstance(filter_data, dict), f'{file_path} format error' assert isinstance(filter_data, dict), f'{file_path} format error'
@ -222,6 +254,14 @@ def test_spec_filter():
assert spec_filter(data), f'{SPEC_FILTER_FILE} format error' assert spec_filter(data), f'{SPEC_FILTER_FILE} format error'
@pytest.mark.github
def test_spec_add():
data = load_yaml_file(SPEC_ADD_FILE)
assert isinstance(data, dict)
assert data, f'load {SPEC_ADD_FILE} failed'
assert spec_add(data), f'{SPEC_ADD_FILE} format error'
@pytest.mark.github @pytest.mark.github
def test_spec_modify(): def test_spec_modify():
data = load_yaml_file(SPEC_MODIFY_FILE) data = load_yaml_file(SPEC_MODIFY_FILE)
@ -319,6 +359,9 @@ def test_sort_spec_data():
sort_data = sort_spec_filter(file_path=SPEC_FILTER_FILE) sort_data = sort_spec_filter(file_path=SPEC_FILTER_FILE)
save_yaml_file(file_path=SPEC_FILTER_FILE, data=sort_data) save_yaml_file(file_path=SPEC_FILTER_FILE, data=sort_data)
_LOGGER.info('%s formatted.', SPEC_FILTER_FILE) _LOGGER.info('%s formatted.', SPEC_FILTER_FILE)
sort_data = sort_spec_add(file_path=SPEC_ADD_FILE)
save_yaml_file(file_path=SPEC_ADD_FILE, data=sort_data)
_LOGGER.info('%s formatted.', SPEC_ADD_FILE)
sort_data = sort_spec_modify(file_path=SPEC_MODIFY_FILE) sort_data = sort_spec_modify(file_path=SPEC_MODIFY_FILE)
save_yaml_file(file_path=SPEC_MODIFY_FILE, data=sort_data) save_yaml_file(file_path=SPEC_MODIFY_FILE, data=sort_data)
_LOGGER.info('%s formatted.', SPEC_MODIFY_FILE) _LOGGER.info('%s formatted.', SPEC_MODIFY_FILE)