feat: update prop.format_ logic

This commit is contained in:
topsworld 2025-01-09 15:04:23 +08:00
parent d25d3f6a93
commit 93f04b1aee
5 changed files with 36 additions and 29 deletions

View File

@ -96,7 +96,7 @@ class Light(MIoTServiceEntity, LightEntity):
"""Light entities for Xiaomi Home.""" """Light entities for Xiaomi Home."""
# pylint: disable=unused-argument # pylint: disable=unused-argument
_VALUE_RANGE_MODE_COUNT_MAX = 30 _VALUE_RANGE_MODE_COUNT_MAX = 30
_prop_on: Optional[MIoTSpecProperty] _prop_on: MIoTSpecProperty
_prop_brightness: Optional[MIoTSpecProperty] _prop_brightness: Optional[MIoTSpecProperty]
_prop_color_temp: Optional[MIoTSpecProperty] _prop_color_temp: Optional[MIoTSpecProperty]
_prop_color: Optional[MIoTSpecProperty] _prop_color: Optional[MIoTSpecProperty]
@ -253,7 +253,7 @@ class Light(MIoTServiceEntity, LightEntity):
result: bool = False result: bool = False
# on # on
# Dirty logic for lumi.gateway.mgl03 indicator light # Dirty logic for lumi.gateway.mgl03 indicator light
value_on = True if self._prop_on.format_ == 'bool' else 1 value_on = True if self._prop_on.format_ == bool else 1
result = await self.set_property_async( result = await self.set_property_async(
prop=self._prop_on, value=value_on) prop=self._prop_on, value=value_on)
# brightness # brightness
@ -288,5 +288,5 @@ class Light(MIoTServiceEntity, LightEntity):
async def async_turn_off(self, **kwargs) -> None: async def async_turn_off(self, **kwargs) -> None:
"""Turn the light off.""" """Turn the light off."""
# Dirty logic for lumi.gateway.mgl03 indicator light # Dirty logic for lumi.gateway.mgl03 indicator light
value_on = False if self._prop_on.format_ == 'bool' else 0 value_on = False if self._prop_on.format_ == bool else 0
return await self.set_property_async(prop=self._prop_on, value=value_on) return await self.set_property_async(prop=self._prop_on, value=value_on)

View File

@ -513,7 +513,7 @@ class MIoTDevice:
if prop_access != (SPEC_PROP_TRANS_MAP[ if prop_access != (SPEC_PROP_TRANS_MAP[
'entities'][platform]['access']): 'entities'][platform]['access']):
return None return None
if prop.format_ not in SPEC_PROP_TRANS_MAP[ if prop.format_.__name__ not in SPEC_PROP_TRANS_MAP[
'entities'][platform]['format']: 'entities'][platform]['format']:
return None return None
if prop.unit: if prop.unit:
@ -566,9 +566,9 @@ class MIoTDevice:
# general conversion # general conversion
if not prop.platform: if not prop.platform:
if prop.writable: if prop.writable:
if prop.format_ == 'str': if prop.format_ == str:
prop.platform = 'text' prop.platform = 'text'
elif prop.format_ == 'bool': elif prop.format_ == bool:
prop.platform = 'switch' prop.platform = 'switch'
prop.device_class = SwitchDeviceClass.SWITCH prop.device_class = SwitchDeviceClass.SWITCH
elif prop.value_list: elif prop.value_list:

View File

@ -48,7 +48,7 @@ MIoT-Spec-V2 parser.
import asyncio import asyncio
import platform import platform
import time import time
from typing import Any, Optional, Union from typing import Any, Optional, Type, Union
import logging import logging
from slugify import slugify from slugify import slugify
@ -506,10 +506,10 @@ class _MIoTSpecBase:
class MIoTSpecProperty(_MIoTSpecBase): class MIoTSpecProperty(_MIoTSpecBase):
"""MIoT SPEC property class.""" """MIoT SPEC property class."""
format_: str
unit: Optional[str] unit: Optional[str]
precision: int precision: int
_format_: Type
_value_range: Optional[MIoTSpecValueRange] _value_range: Optional[MIoTSpecValueRange]
_value_list: Optional[MIoTSpecValueList] _value_list: Optional[MIoTSpecValueList]
@ -543,6 +543,19 @@ class MIoTSpecProperty(_MIoTSpecBase):
self.spec_id = hash( self.spec_id = hash(
f'p.{self.name}.{self.service.iid}.{self.iid}') f'p.{self.name}.{self.service.iid}.{self.iid}')
@property
def format_(self) -> Type:
return self._format_
@format_.setter
def format_(self, value: str) -> None:
self._format_ = {
'string': str,
'str': str,
'bool': bool,
'float': float}.get(
value, int)
@property @property
def access(self) -> list: def access(self) -> list:
return self._access return self._access
@ -601,11 +614,11 @@ class MIoTSpecProperty(_MIoTSpecBase):
def value_format(self, value: Any) -> Any: def value_format(self, value: Any) -> Any:
if value is None: if value is None:
return None return None
if self.format_ == 'int': if self.format_ == int:
return int(value) return int(value)
if self.format_ == 'float': if self.format_ == float:
return round(value, self.precision) return round(value, self.precision)
if self.format_ == 'bool': if self.format_ == bool:
return bool(value in [True, 1, 'True', 'true', '1']) return bool(value in [True, 1, 'True', 'true', '1'])
return value return value
@ -618,7 +631,7 @@ class MIoTSpecProperty(_MIoTSpecBase):
'description_trans': self.description_trans, 'description_trans': self.description_trans,
'proprietary': self.proprietary, 'proprietary': self.proprietary,
'need_filter': self.need_filter, 'need_filter': self.need_filter,
'format': self.format_, 'format': self.format_.__name__,
'access': self._access, 'access': self._access,
'unit': self.unit, 'unit': self.unit,
'value_range': ( 'value_range': (
@ -1048,12 +1061,6 @@ class MIoTSpecParser:
return await self._storage.save_async( return await self._storage.save_async(
domain=self._DOMAIN, name=f'{urn}_{self._lang}', data=data) domain=self._DOMAIN, name=f'{urn}_{self._lang}', data=data)
def __spec_format2dtype(self, format_: str) -> str:
# 'string'|'bool'|'uint8'|'uint16'|'uint32'|
# 'int8'|'int16'|'int32'|'int64'|'float'
return {'string': 'str', 'bool': 'bool', 'float': 'float'}.get(
format_, 'int')
async def __get_instance(self, urn: str) -> Optional[dict]: async def __get_instance(self, urn: str) -> Optional[dict]:
return await MIoTHttp.get_json_async( return await MIoTHttp.get_json_async(
url='https://miot-spec.org/miot-spec-v2/instance', url='https://miot-spec.org/miot-spec-v2/instance',
@ -1124,7 +1131,7 @@ class MIoTSpecParser:
spec_prop: MIoTSpecProperty = MIoTSpecProperty( spec_prop: MIoTSpecProperty = MIoTSpecProperty(
spec=property_, spec=property_,
service=spec_service, service=spec_service,
format_=self.__spec_format2dtype(property_['format']), format_=property_['format'],
access=property_['access'], access=property_['access'],
unit=property_.get('unit', None)) unit=property_.get('unit', None))
spec_prop.name = p_type_strs[3] spec_prop.name = p_type_strs[3]

View File

@ -90,7 +90,7 @@ class Notify(MIoTActionEntity, NotifyEntity):
super().__init__(miot_device=miot_device, spec=spec) super().__init__(miot_device=miot_device, spec=spec)
self._attr_extra_state_attributes = {} self._attr_extra_state_attributes = {}
action_in: str = ', '.join([ action_in: str = ', '.join([
f'{prop.description_trans}({prop.format_})' f'{prop.description_trans}({prop.format_.__name__})'
for prop in self.spec.in_]) for prop in self.spec.in_])
self._attr_extra_state_attributes['action params'] = f'[{action_in}]' self._attr_extra_state_attributes['action params'] = f'[{action_in}]'
@ -122,24 +122,24 @@ class Notify(MIoTActionEntity, NotifyEntity):
return return
in_value: list[dict] = [] in_value: list[dict] = []
for index, prop in enumerate(self.spec.in_): for index, prop in enumerate(self.spec.in_):
if prop.format_ == 'str': if prop.format_ == str:
if isinstance(in_list[index], (bool, int, float, str)): if isinstance(in_list[index], (bool, int, float, str)):
in_value.append( in_value.append(
{'piid': prop.iid, 'value': str(in_list[index])}) {'piid': prop.iid, 'value': str(in_list[index])})
continue continue
elif prop.format_ == 'bool': elif prop.format_ == bool:
if isinstance(in_list[index], (bool, int)): if isinstance(in_list[index], (bool, int)):
# yes, no, on, off, true, false and other bool types # yes, no, on, off, true, false and other bool types
# will also be parsed as 0 and 1 of int. # will also be parsed as 0 and 1 of int.
in_value.append( in_value.append(
{'piid': prop.iid, 'value': bool(in_list[index])}) {'piid': prop.iid, 'value': bool(in_list[index])})
continue continue
elif prop.format_ == 'float': elif prop.format_ == float:
if isinstance(in_list[index], (int, float)): if isinstance(in_list[index], (int, float)):
in_value.append( in_value.append(
{'piid': prop.iid, 'value': in_list[index]}) {'piid': prop.iid, 'value': in_list[index]})
continue continue
elif prop.format_ == 'int': elif prop.format_ == int:
if isinstance(in_list[index], int): if isinstance(in_list[index], int):
in_value.append( in_value.append(
{'piid': prop.iid, 'value': in_list[index]}) {'piid': prop.iid, 'value': in_list[index]})

View File

@ -111,7 +111,7 @@ class ActionText(MIoTActionEntity, TextEntity):
self._attr_extra_state_attributes = {} self._attr_extra_state_attributes = {}
self._attr_native_value = '' self._attr_native_value = ''
action_in: str = ', '.join([ action_in: str = ', '.join([
f'{prop.description_trans}({prop.format_})' f'{prop.description_trans}({prop.format_.__name__})'
for prop in self.spec.in_]) for prop in self.spec.in_])
self._attr_extra_state_attributes['action params'] = f'[{action_in}]' self._attr_extra_state_attributes['action params'] = f'[{action_in}]'
# For action debug # For action debug
@ -141,24 +141,24 @@ class ActionText(MIoTActionEntity, TextEntity):
f'invalid action params, {value}') f'invalid action params, {value}')
in_value: list[dict] = [] in_value: list[dict] = []
for index, prop in enumerate(self.spec.in_): for index, prop in enumerate(self.spec.in_):
if prop.format_ == 'str': if prop.format_ == str:
if isinstance(in_list[index], (bool, int, float, str)): if isinstance(in_list[index], (bool, int, float, str)):
in_value.append( in_value.append(
{'piid': prop.iid, 'value': str(in_list[index])}) {'piid': prop.iid, 'value': str(in_list[index])})
continue continue
elif prop.format_ == 'bool': elif prop.format_ == bool:
if isinstance(in_list[index], (bool, int)): if isinstance(in_list[index], (bool, int)):
# yes, no, on, off, true, false and other bool types # yes, no, on, off, true, false and other bool types
# will also be parsed as 0 and 1 of int. # will also be parsed as 0 and 1 of int.
in_value.append( in_value.append(
{'piid': prop.iid, 'value': bool(in_list[index])}) {'piid': prop.iid, 'value': bool(in_list[index])})
continue continue
elif prop.format_ == 'float': elif prop.format_ == float:
if isinstance(in_list[index], (int, float)): if isinstance(in_list[index], (int, float)):
in_value.append( in_value.append(
{'piid': prop.iid, 'value': in_list[index]}) {'piid': prop.iid, 'value': in_list[index]})
continue continue
elif prop.format_ == 'int': elif prop.format_ == int:
if isinstance(in_list[index], int): if isinstance(in_list[index], int):
in_value.append( in_value.append(
{'piid': prop.iid, 'value': in_list[index]}) {'piid': prop.iid, 'value': in_list[index]})