mirror of
https://github.com/XiaoMi/ha_xiaomi_home.git
synced 2025-04-02 07:45:31 +08:00
fix: merge conflicts
This commit is contained in:
commit
6d63975eba
@ -189,7 +189,7 @@ class FeaturePresetMode(MIoTServiceEntity, ClimateEntity):
|
||||
for prop in self.entity_data.props:
|
||||
if prop.name == prop_name and prop.service.name == service_name:
|
||||
if not prop.value_list:
|
||||
_LOGGER.error('invalid %s %s value_list, %s',service_name,
|
||||
_LOGGER.error('invalid %s %s value_list, %s', service_name,
|
||||
prop_name, self.entity_id)
|
||||
continue
|
||||
self._mode_map = prop.value_list.to_map()
|
||||
@ -229,7 +229,9 @@ class FeatureFanMode(MIoTServiceEntity, ClimateEntity):
|
||||
super().__init__(miot_device=miot_device, entity_data=entity_data)
|
||||
# properties
|
||||
for prop in entity_data.props:
|
||||
if prop.name == 'fan-level' and prop.service.name == 'fan-control':
|
||||
if (prop.name == 'fan-level' and
|
||||
(prop.service.name == 'fan-control' or
|
||||
prop.service.name == 'thermostat')):
|
||||
if not prop.value_list:
|
||||
_LOGGER.error('invalid fan-level value_list, %s',
|
||||
self.entity_id)
|
||||
@ -665,78 +667,31 @@ class PtcBathHeater(FeatureTargetTemperature, FeatureTemperature,
|
||||
|
||||
|
||||
class Thermostat(FeatureOnOff, FeatureTargetTemperature, FeatureTemperature,
|
||||
FeatureHumidity, FeatureFanMode):
|
||||
FeatureHumidity, FeatureFanMode, FeaturePresetMode):
|
||||
"""Thermostat"""
|
||||
_prop_mode: Optional[MIoTSpecProperty]
|
||||
_hvac_mode_map: Optional[dict[int, HVACMode]]
|
||||
|
||||
def __init__(self, miot_device: MIoTDevice,
|
||||
entity_data: MIoTEntityData) -> None:
|
||||
"""Initialize the thermostat."""
|
||||
self._prop_mode = None
|
||||
self._hvac_mode_map = None
|
||||
|
||||
super().__init__(miot_device=miot_device, entity_data=entity_data)
|
||||
|
||||
self._attr_icon = 'mdi:thermostat'
|
||||
# hvac modes
|
||||
self._attr_hvac_modes = None
|
||||
for prop in entity_data.props:
|
||||
if prop.name == 'mode':
|
||||
if not prop.value_list:
|
||||
_LOGGER.error('invalid mode value_list, %s', self.entity_id)
|
||||
continue
|
||||
self._hvac_mode_map = {}
|
||||
for item in prop.value_list.items:
|
||||
if item.name in {'off', 'idle'}:
|
||||
self._hvac_mode_map[item.value] = HVACMode.OFF
|
||||
elif item.name in {'auto'}:
|
||||
self._hvac_mode_map[item.value] = HVACMode.AUTO
|
||||
elif item.name in {'cool'}:
|
||||
self._hvac_mode_map[item.value] = HVACMode.COOL
|
||||
elif item.name in {'heat'}:
|
||||
self._hvac_mode_map[item.value] = HVACMode.HEAT
|
||||
elif item.name in {'dry'}:
|
||||
self._hvac_mode_map[item.value] = HVACMode.DRY
|
||||
elif item.name in {'fan'}:
|
||||
self._hvac_mode_map[item.value] = HVACMode.FAN_ONLY
|
||||
self._attr_hvac_modes = list(self._hvac_mode_map.values())
|
||||
self._prop_mode = prop
|
||||
|
||||
if self._attr_hvac_modes is None:
|
||||
self._attr_hvac_modes = [HVACMode.OFF, HVACMode.AUTO]
|
||||
elif HVACMode.OFF not in self._attr_hvac_modes:
|
||||
self._attr_hvac_modes.insert(0, HVACMode.OFF)
|
||||
self._attr_hvac_modes = [HVACMode.AUTO, HVACMode.OFF]
|
||||
# preset modes
|
||||
self._init_preset_modes('thermostat', 'mode')
|
||||
|
||||
async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:
|
||||
"""Set the target hvac mode."""
|
||||
# set the device off
|
||||
if hvac_mode == HVACMode.OFF:
|
||||
if not await self.set_property_async(prop=self._prop_on,
|
||||
value=False):
|
||||
raise RuntimeError(f'set climate prop.on failed, {hvac_mode}, '
|
||||
f'{self.entity_id}')
|
||||
return
|
||||
# set the device on
|
||||
elif self.get_prop_value(prop=self._prop_on) is False:
|
||||
await self.set_property_async(prop=self._prop_on, value=True)
|
||||
# set mode
|
||||
if self._prop_mode is None:
|
||||
return
|
||||
mode_value = self.get_map_key(map_=self._hvac_mode_map, value=hvac_mode)
|
||||
if mode_value is None or not await self.set_property_async(
|
||||
prop=self._prop_mode, value=mode_value):
|
||||
raise RuntimeError(
|
||||
f'set climate prop.mode failed, {hvac_mode}, {self.entity_id}')
|
||||
await self.set_property_async(
|
||||
prop=self._prop_on,
|
||||
value=False if hvac_mode == HVACMode.OFF else True)
|
||||
|
||||
@property
|
||||
def hvac_mode(self) -> Optional[HVACMode]:
|
||||
"""The current hvac mode."""
|
||||
if self.get_prop_value(prop=self._prop_on) is False:
|
||||
return HVACMode.OFF
|
||||
return (self.get_map_value(map_=self._hvac_mode_map,
|
||||
key=self.get_prop_value(
|
||||
prop=self._prop_mode))
|
||||
if self._prop_mode else None)
|
||||
return (HVACMode.AUTO if self.get_prop_value(
|
||||
prop=self._prop_on) else HVACMode.OFF)
|
||||
|
||||
|
||||
class ElectricBlanket(FeatureOnOff, FeatureTargetTemperature,
|
||||
|
@ -47,7 +47,7 @@ Cover entities for Xiaomi Home.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
import logging
|
||||
from typing import Optional
|
||||
from typing import Any, Optional
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant
|
||||
@ -107,7 +107,11 @@ class Cover(MIoTServiceEntity, CoverEntity):
|
||||
_prop_status_closed: Optional[list[int]]
|
||||
_prop_current_position: Optional[MIoTSpecProperty]
|
||||
_prop_target_position: Optional[MIoTSpecProperty]
|
||||
_prop_position_value_min: Optional[int]
|
||||
_prop_position_value_max: Optional[int]
|
||||
_prop_position_value_range: Optional[int]
|
||||
_prop_pos_closing: bool
|
||||
_prop_pos_opening: bool
|
||||
|
||||
def __init__(self, miot_device: MIoTDevice,
|
||||
entity_data: MIoTEntityData,
|
||||
@ -130,7 +134,11 @@ class Cover(MIoTServiceEntity, CoverEntity):
|
||||
self._prop_status_closed = []
|
||||
self._prop_current_position = None
|
||||
self._prop_target_position = None
|
||||
self._prop_position_value_min = None
|
||||
self._prop_position_value_max = None
|
||||
self._prop_position_value_range = None
|
||||
self._prop_pos_closing = False
|
||||
self._prop_pos_opening = False
|
||||
|
||||
self._close_threshold = close_threshold
|
||||
self._open_threshold = open_threshold
|
||||
@ -177,6 +185,8 @@ class Cover(MIoTServiceEntity, CoverEntity):
|
||||
'invalid current-position value_range format, %s',
|
||||
self.entity_id)
|
||||
continue
|
||||
self._prop_position_value_min = prop.value_range.min_
|
||||
self._prop_position_value_max = prop.value_range.max_
|
||||
self._prop_position_value_range = (prop.value_range.max_ -
|
||||
prop.value_range.min_)
|
||||
self._prop_current_position = prop
|
||||
@ -186,23 +196,52 @@ class Cover(MIoTServiceEntity, CoverEntity):
|
||||
'invalid target-position value_range format, %s',
|
||||
self.entity_id)
|
||||
continue
|
||||
self._prop_position_value_min = prop.value_range.min_
|
||||
self._prop_position_value_max = prop.value_range.max_
|
||||
self._prop_position_value_range = (prop.value_range.max_ -
|
||||
prop.value_range.min_)
|
||||
self._attr_supported_features |= CoverEntityFeature.SET_POSITION
|
||||
self._prop_target_position = prop
|
||||
# For the device that has the current position property but no status
|
||||
# property, the current position property will be used to determine the
|
||||
# opening and the closing status.
|
||||
if (self._prop_status is None) and (self._prop_current_position
|
||||
is not None):
|
||||
self.sub_prop_changed(self._prop_current_position,
|
||||
self._position_changed_handler)
|
||||
|
||||
def _position_changed_handler(self, prop: MIoTSpecProperty,
|
||||
ctx: Any) -> None:
|
||||
self._prop_pos_closing = False
|
||||
self._prop_pos_opening = False
|
||||
self.async_write_ha_state()
|
||||
|
||||
async def async_open_cover(self, **kwargs) -> None:
|
||||
"""Open the cover."""
|
||||
current = None if (self._prop_current_position
|
||||
is None) else self.get_prop_value(
|
||||
prop=self._prop_current_position)
|
||||
if (current is not None) and (current < self._prop_position_value_max):
|
||||
self._prop_pos_opening = True
|
||||
self._prop_pos_closing = False
|
||||
await self.set_property_async(self._prop_motor_control,
|
||||
self._prop_motor_value_open)
|
||||
|
||||
async def async_close_cover(self, **kwargs) -> None:
|
||||
"""Close the cover."""
|
||||
current = None if (self._prop_current_position
|
||||
is None) else self.get_prop_value(
|
||||
prop=self._prop_current_position)
|
||||
if (current is not None) and (current > self._prop_position_value_min):
|
||||
self._prop_pos_opening = False
|
||||
self._prop_pos_closing = True
|
||||
await self.set_property_async(self._prop_motor_control,
|
||||
self._prop_motor_value_close)
|
||||
|
||||
async def async_stop_cover(self, **kwargs) -> None:
|
||||
"""Stop the cover."""
|
||||
self._prop_pos_opening = False
|
||||
self._prop_pos_closing = False
|
||||
await self.set_property_async(self._prop_motor_control,
|
||||
self._prop_motor_value_pause)
|
||||
|
||||
@ -211,6 +250,10 @@ class Cover(MIoTServiceEntity, CoverEntity):
|
||||
pos = kwargs.get(ATTR_POSITION, None)
|
||||
if pos is None:
|
||||
return None
|
||||
current = self.current_cover_position
|
||||
if current is not None:
|
||||
self._prop_pos_opening = pos > current
|
||||
self._prop_pos_closing = pos < current
|
||||
pos = round(pos * self._prop_position_value_range / 100)
|
||||
await self.set_property_async(prop=self._prop_target_position,
|
||||
value=pos)
|
||||
@ -225,24 +268,14 @@ class Cover(MIoTServiceEntity, CoverEntity):
|
||||
# Assume that the current position is the same as the target
|
||||
# position when the current position is not defined in the device's
|
||||
# MIoT-Spec-V2.
|
||||
pos = None if (self._prop_target_position is None) else self.get_prop_value(
|
||||
prop=self._prop_target_position)
|
||||
else:
|
||||
pos = self.get_prop_value(prop=self._prop_current_position)
|
||||
|
||||
if pos is None:
|
||||
return None
|
||||
|
||||
# Convert the position to a percentage
|
||||
percentage = round(pos * 100 / self._prop_position_value_range)
|
||||
|
||||
# Adjust the position to 0 if it is below the close threshold
|
||||
if percentage <= self._close_threshold:
|
||||
return 0
|
||||
# Adjust the position to 0 if it is below the close threshold
|
||||
if percentage >= self._open_threshold:
|
||||
return 100
|
||||
return percentage
|
||||
if self._prop_target_position is None:
|
||||
return None
|
||||
self._prop_pos_opening = False
|
||||
self._prop_pos_closing = False
|
||||
return self.get_prop_value(prop=self._prop_target_position)
|
||||
pos = self.get_prop_value(prop=self._prop_current_position)
|
||||
return None if pos is None else round(pos * 100 /
|
||||
self._prop_position_value_range)
|
||||
|
||||
@property
|
||||
def is_opening(self) -> Optional[bool]:
|
||||
@ -250,14 +283,9 @@ class Cover(MIoTServiceEntity, CoverEntity):
|
||||
if self._prop_status and self._prop_status_opening:
|
||||
return (self.get_prop_value(prop=self._prop_status)
|
||||
in self._prop_status_opening)
|
||||
# The status is prior to the numerical relationship of the current
|
||||
# position and the target position when determining whether the cover
|
||||
# The status has higher priority when determining whether the cover
|
||||
# is opening.
|
||||
if (self._prop_target_position and
|
||||
self.current_cover_position is not None):
|
||||
return (self.current_cover_position
|
||||
< self.get_prop_value(prop=self._prop_target_position))
|
||||
return None
|
||||
return self._prop_pos_opening
|
||||
|
||||
@property
|
||||
def is_closing(self) -> Optional[bool]:
|
||||
@ -265,14 +293,9 @@ class Cover(MIoTServiceEntity, CoverEntity):
|
||||
if self._prop_status and self._prop_status_closing:
|
||||
return (self.get_prop_value(prop=self._prop_status)
|
||||
in self._prop_status_closing)
|
||||
# The status is prior to the numerical relationship of the current
|
||||
# position and the target position when determining whether the cover
|
||||
# The status has higher priority when determining whether the cover
|
||||
# is closing.
|
||||
if (self._prop_target_position and
|
||||
self.current_cover_position is not None):
|
||||
return (self.current_cover_position
|
||||
> self.get_prop_value(prop=self._prop_target_position))
|
||||
return None
|
||||
return self._prop_pos_closing
|
||||
|
||||
@property
|
||||
def is_closed(self) -> Optional[bool]:
|
||||
|
@ -172,7 +172,7 @@ class Fan(MIoTServiceEntity, FanEntity):
|
||||
self._attr_supported_features |= FanEntityFeature.OSCILLATE
|
||||
self._prop_horizontal_swing = prop
|
||||
elif prop.name == 'wind-reverse':
|
||||
if prop.format_ == 'bool':
|
||||
if prop.format_ == bool:
|
||||
self._prop_wind_reverse_forward = False
|
||||
self._prop_wind_reverse_reverse = True
|
||||
elif prop.value_list:
|
||||
@ -186,7 +186,7 @@ class Fan(MIoTServiceEntity, FanEntity):
|
||||
or self._prop_wind_reverse_reverse is None
|
||||
):
|
||||
# NOTICE: Value may be 0 or False
|
||||
_LOGGER.info(
|
||||
_LOGGER.error(
|
||||
'invalid wind-reverse, %s', self.entity_id)
|
||||
continue
|
||||
self._attr_supported_features |= FanEntityFeature.DIRECTION
|
||||
|
@ -20,7 +20,7 @@
|
||||
],
|
||||
"requirements": [
|
||||
"construct>=2.10.56",
|
||||
"paho-mqtt<2.0.0",
|
||||
"paho-mqtt",
|
||||
"numpy",
|
||||
"cryptography",
|
||||
"psutil"
|
||||
@ -29,4 +29,4 @@
|
||||
"zeroconf": [
|
||||
"_miot-central._tcp.local."
|
||||
]
|
||||
}
|
||||
}
|
||||
|
@ -549,6 +549,10 @@ class MIoTDevice:
|
||||
# Optional actions
|
||||
# Optional events
|
||||
miot_service.platform = platform
|
||||
# entity_category
|
||||
if entity_category := SPEC_SERVICE_TRANS_MAP[service_name].get(
|
||||
'entity_category', None):
|
||||
miot_service.entity_category = entity_category
|
||||
return entity_data
|
||||
|
||||
def parse_miot_property_entity(self, miot_prop: MIoTSpecProperty) -> bool:
|
||||
@ -899,6 +903,7 @@ class MIoTServiceEntity(Entity):
|
||||
self._attr_name = (
|
||||
f'{"* "if self.entity_data.spec.proprietary else " "}'
|
||||
f'{self.entity_data.spec.description_trans}')
|
||||
self._attr_entity_category = entity_data.spec.entity_category
|
||||
# Set entity attr
|
||||
self._attr_unique_id = self.entity_id
|
||||
self._attr_should_poll = False
|
||||
|
@ -56,7 +56,7 @@ from slugify import slugify
|
||||
|
||||
# pylint: disable=relative-beyond-top-level
|
||||
from .const import DEFAULT_INTEGRATION_LANGUAGE, SPEC_STD_LIB_EFFECTIVE_TIME
|
||||
from .common import MIoTHttp, load_yaml_file
|
||||
from .common import MIoTHttp, load_yaml_file, load_json_file
|
||||
from .miot_error import MIoTSpecError
|
||||
from .miot_storage import MIoTStorage
|
||||
|
||||
@ -465,7 +465,7 @@ class _MIoTSpecBase:
|
||||
iid: int
|
||||
type_: str
|
||||
description: str
|
||||
description_trans: str
|
||||
description_trans: Optional[str]
|
||||
proprietary: bool
|
||||
need_filter: bool
|
||||
name: str
|
||||
@ -476,6 +476,7 @@ class _MIoTSpecBase:
|
||||
device_class: Any
|
||||
state_class: Any
|
||||
external_unit: Any
|
||||
entity_category: Optional[str]
|
||||
|
||||
spec_id: int
|
||||
|
||||
@ -494,6 +495,7 @@ class _MIoTSpecBase:
|
||||
self.device_class = None
|
||||
self.state_class = None
|
||||
self.external_unit = None
|
||||
self.entity_category = None
|
||||
|
||||
self.spec_id = hash(f'{self.type_}.{self.iid}')
|
||||
|
||||
@ -837,6 +839,7 @@ class _MIoTSpecMultiLang:
|
||||
"""MIoT SPEC multi lang class."""
|
||||
# pylint: disable=broad-exception-caught
|
||||
_DOMAIN: str = 'miot_specs_multi_lang'
|
||||
_MULTI_LANG_FILE = 'specs/multi_lang.json'
|
||||
_lang: str
|
||||
_storage: MIoTStorage
|
||||
_main_loop: asyncio.AbstractEventLoop
|
||||
@ -892,6 +895,25 @@ class _MIoTSpecMultiLang:
|
||||
except Exception as err:
|
||||
trans_local = {}
|
||||
_LOGGER.info('get multi lang from local failed, %s, %s', urn, err)
|
||||
# Revert: load multi_lang.json
|
||||
try:
|
||||
trans_local_json = await self._main_loop.run_in_executor(
|
||||
None, load_json_file,
|
||||
os.path.join(
|
||||
os.path.dirname(os.path.abspath(__file__)),
|
||||
self._MULTI_LANG_FILE))
|
||||
urn_strs: list[str] = urn.split(':')
|
||||
urn_key: str = ':'.join(urn_strs[:6])
|
||||
if (
|
||||
isinstance(trans_local_json, dict)
|
||||
and urn_key in trans_local_json
|
||||
and self._lang in trans_local_json[urn_key]
|
||||
):
|
||||
trans_cache.update(trans_local_json[urn_key][self._lang])
|
||||
trans_local = trans_local_json[urn_key]
|
||||
except Exception as err: # pylint: disable=broad-exception-caught
|
||||
_LOGGER.error('multi lang, load json file error, %s', err)
|
||||
# Revert end
|
||||
# Default language
|
||||
if not trans_cache:
|
||||
if trans_cloud and DEFAULT_INTEGRATION_LANGUAGE in trans_cloud:
|
||||
@ -1205,6 +1227,13 @@ class _SpecModify:
|
||||
return None
|
||||
return value_range
|
||||
|
||||
def get_prop_value_list(self, siid: int, piid: int) -> Optional[list]:
|
||||
value_list = self.__get_prop_item(siid=siid, piid=piid,
|
||||
key='value-list')
|
||||
if not isinstance(value_list, list):
|
||||
return None
|
||||
return value_list
|
||||
|
||||
def __get_prop_item(self, siid: int, piid: int, key: str) -> Optional[str]:
|
||||
if not self._selected:
|
||||
return None
|
||||
@ -1444,10 +1473,12 @@ class MIoTSpecParser:
|
||||
key=':'.join(p_type_strs[:5]))
|
||||
or property_['description']
|
||||
or spec_prop.name)
|
||||
if 'value-range' in property_:
|
||||
spec_prop.value_range = property_['value-range']
|
||||
elif 'value-list' in property_:
|
||||
v_list: list[dict] = property_['value-list']
|
||||
# Modify value-list before translation
|
||||
v_list: list[dict] = self._spec_modify.get_prop_value_list(
|
||||
siid=service['iid'], piid=property_['iid'])
|
||||
if (v_list is None) and ('value-list' in property_):
|
||||
v_list = property_['value-list']
|
||||
if v_list is not None:
|
||||
for index, v in enumerate(v_list):
|
||||
if v['description'].strip() == '':
|
||||
v['description'] = f'v_{v["value"]}'
|
||||
@ -1461,6 +1492,8 @@ class MIoTSpecParser:
|
||||
f'{v["description"]}')
|
||||
or v['name'])
|
||||
spec_prop.value_list = MIoTSpecValueList.from_spec(v_list)
|
||||
if 'value-range' in property_:
|
||||
spec_prop.value_range = property_['value-range']
|
||||
elif property_['format'] == 'bool':
|
||||
v_tag = ':'.join(p_type_strs[:5])
|
||||
v_descriptions = (
|
||||
|
172
custom_components/xiaomi_home/miot/specs/multi_lang.json
Normal file
172
custom_components/xiaomi_home/miot/specs/multi_lang.json
Normal file
@ -0,0 +1,172 @@
|
||||
{
|
||||
"urn:miot-spec-v2:device:gateway:0000A019:xiaomi-hub1": {
|
||||
"de": {
|
||||
"service:001": "Geräteinformationen",
|
||||
"service:001:property:003": "Geräte-ID",
|
||||
"service:001:property:005": "Seriennummer (SN)",
|
||||
"service:002": "Gateway",
|
||||
"service:002:event:001": "Netzwerk geändert",
|
||||
"service:002:event:002": "Netzwerk geändert",
|
||||
"service:002:property:001": "Zugriffsmethode",
|
||||
"service:002:property:001:valuelist:000": "Kabelgebunden",
|
||||
"service:002:property:001:valuelist:001": "5G Drahtlos",
|
||||
"service:002:property:001:valuelist:002": "2.4G Drahtlos",
|
||||
"service:002:property:002": "IP-Adresse",
|
||||
"service:002:property:003": "WiFi-Netzwerkname",
|
||||
"service:002:property:004": "Aktuelle Zeit",
|
||||
"service:002:property:005": "DHCP-Server-MAC-Adresse",
|
||||
"service:003": "Anzeigelampe",
|
||||
"service:003:property:001": "Schalter",
|
||||
"service:004": "Virtueller Dienst",
|
||||
"service:004:action:001": "Virtuelles Ereignis erzeugen",
|
||||
"service:004:event:001": "Virtuelles Ereignis aufgetreten",
|
||||
"service:004:property:001": "Ereignisname"
|
||||
},
|
||||
"en": {
|
||||
"service:001": "Device Information",
|
||||
"service:001:property:003": "Device ID",
|
||||
"service:001:property:005": "Serial Number (SN)",
|
||||
"service:002": "Gateway",
|
||||
"service:002:event:001": "Network Changed",
|
||||
"service:002:event:002": "Network Changed",
|
||||
"service:002:property:001": "Access Method",
|
||||
"service:002:property:001:valuelist:000": "Wired",
|
||||
"service:002:property:001:valuelist:001": "5G Wireless",
|
||||
"service:002:property:001:valuelist:002": "2.4G Wireless",
|
||||
"service:002:property:002": "IP Address",
|
||||
"service:002:property:003": "WiFi Network Name",
|
||||
"service:002:property:004": "Current Time",
|
||||
"service:002:property:005": "DHCP Server MAC Address",
|
||||
"service:003": "Indicator Light",
|
||||
"service:003:property:001": "Switch",
|
||||
"service:004": "Virtual Service",
|
||||
"service:004:action:001": "Generate Virtual Event",
|
||||
"service:004:event:001": "Virtual Event Occurred",
|
||||
"service:004:property:001": "Event Name"
|
||||
},
|
||||
"es": {
|
||||
"service:001": "Información del dispositivo",
|
||||
"service:001:property:003": "ID del dispositivo",
|
||||
"service:001:property:005": "Número de serie (SN)",
|
||||
"service:002": "Puerta de enlace",
|
||||
"service:002:event:001": "Cambio de red",
|
||||
"service:002:event:002": "Cambio de red",
|
||||
"service:002:property:001": "Método de acceso",
|
||||
"service:002:property:001:valuelist:000": "Cableado",
|
||||
"service:002:property:001:valuelist:001": "5G inalámbrico",
|
||||
"service:002:property:001:valuelist:002": "2.4G inalámbrico",
|
||||
"service:002:property:002": "Dirección IP",
|
||||
"service:002:property:003": "Nombre de red WiFi",
|
||||
"service:002:property:004": "Hora actual",
|
||||
"service:002:property:005": "Dirección MAC del servidor DHCP",
|
||||
"service:003": "Luz indicadora",
|
||||
"service:003:property:001": "Interruptor",
|
||||
"service:004": "Servicio virtual",
|
||||
"service:004:action:001": "Generar evento virtual",
|
||||
"service:004:event:001": "Ocurrió un evento virtual",
|
||||
"service:004:property:001": "Nombre del evento"
|
||||
},
|
||||
"fr": {
|
||||
"service:001": "Informations sur l'appareil",
|
||||
"service:001:property:003": "ID de l'appareil",
|
||||
"service:001:property:005": "Numéro de série (SN)",
|
||||
"service:002": "Passerelle",
|
||||
"service:002:event:001": "Changement de réseau",
|
||||
"service:002:event:002": "Changement de réseau",
|
||||
"service:002:property:001": "Méthode d'accès",
|
||||
"service:002:property:001:valuelist:000": "Câblé",
|
||||
"service:002:property:001:valuelist:001": "Sans fil 5G",
|
||||
"service:002:property:001:valuelist:002": "Sans fil 2.4G",
|
||||
"service:002:property:002": "Adresse IP",
|
||||
"service:002:property:003": "Nom du réseau WiFi",
|
||||
"service:002:property:004": "Heure actuelle",
|
||||
"service:002:property:005": "Adresse MAC du serveur DHCP",
|
||||
"service:003": "Voyant lumineux",
|
||||
"service:003:property:001": "Interrupteur",
|
||||
"service:004": "Service virtuel",
|
||||
"service:004:action:001": "Générer un événement virtuel",
|
||||
"service:004:event:001": "Événement virtuel survenu",
|
||||
"service:004:property:001": "Nom de l'événement"
|
||||
},
|
||||
"ja": {
|
||||
"service:001": "デバイス情報",
|
||||
"service:001:property:003": "デバイスID",
|
||||
"service:001:property:005": "シリアル番号 (SN)",
|
||||
"service:002": "ゲートウェイ",
|
||||
"service:002:event:001": "ネットワークが変更されました",
|
||||
"service:002:event:002": "ネットワークが変更されました",
|
||||
"service:002:property:001": "アクセス方法",
|
||||
"service:002:property:001:valuelist:000": "有線",
|
||||
"service:002:property:001:valuelist:001": "5G ワイヤレス",
|
||||
"service:002:property:001:valuelist:002": "2.4G ワイヤレス",
|
||||
"service:002:property:002": "IPアドレス",
|
||||
"service:002:property:003": "WiFiネットワーク名",
|
||||
"service:002:property:004": "現在の時間",
|
||||
"service:002:property:005": "DHCPサーバーMACアドレス",
|
||||
"service:003": "インジケータライト",
|
||||
"service:003:property:001": "スイッチ",
|
||||
"service:004": "バーチャルサービス",
|
||||
"service:004:action:001": "バーチャルイベントを生成",
|
||||
"service:004:event:001": "バーチャルイベントが発生しました",
|
||||
"service:004:property:001": "イベント名"
|
||||
},
|
||||
"ru": {
|
||||
"service:001": "Информация об устройстве",
|
||||
"service:001:property:003": "ID устройства",
|
||||
"service:001:property:005": "Серийный номер (SN)",
|
||||
"service:002": "Шлюз",
|
||||
"service:002:event:001": "Сеть изменена",
|
||||
"service:002:event:002": "Сеть изменена",
|
||||
"service:002:property:001": "Метод доступа",
|
||||
"service:002:property:001:valuelist:000": "Проводной",
|
||||
"service:002:property:001:valuelist:001": "5G Беспроводной",
|
||||
"service:002:property:001:valuelist:002": "2.4G Беспроводной",
|
||||
"service:002:property:002": "IP Адрес",
|
||||
"service:002:property:003": "Название WiFi сети",
|
||||
"service:002:property:004": "Текущее время",
|
||||
"service:002:property:005": "MAC адрес DHCP сервера",
|
||||
"service:003": "Световой индикатор",
|
||||
"service:003:property:001": "Переключатель",
|
||||
"service:004": "Виртуальная служба",
|
||||
"service:004:action:001": "Создать виртуальное событие",
|
||||
"service:004:event:001": "Произошло виртуальное событие",
|
||||
"service:004:property:001": "Название события"
|
||||
},
|
||||
"zh-Hant": {
|
||||
"service:001": "設備信息",
|
||||
"service:001:property:003": "設備ID",
|
||||
"service:001:property:005": "序號 (SN)",
|
||||
"service:002": "網關",
|
||||
"service:002:event:001": "網路發生變化",
|
||||
"service:002:event:002": "網路發生變化",
|
||||
"service:002:property:001": "接入方式",
|
||||
"service:002:property:001:valuelist:000": "有線",
|
||||
"service:002:property:001:valuelist:001": "5G 無線",
|
||||
"service:002:property:001:valuelist:002": "2.4G 無線",
|
||||
"service:002:property:002": "IP地址",
|
||||
"service:002:property:003": "WiFi網路名稱",
|
||||
"service:002:property:004": "當前時間",
|
||||
"service:002:property:005": "DHCP伺服器MAC地址",
|
||||
"service:003": "指示燈",
|
||||
"service:003:property:001": "開關",
|
||||
"service:004": "虛擬服務",
|
||||
"service:004:action:001": "產生虛擬事件",
|
||||
"service:004:event:001": "虛擬事件發生",
|
||||
"service:004:property:001": "事件名稱"
|
||||
}
|
||||
},
|
||||
"urn:miot-spec-v2:device:switch:0000A003:lumi-acn040": {
|
||||
"en": {
|
||||
"service:011": "Right Button On and Off",
|
||||
"service:011:property:001": "Right Button On and Off",
|
||||
"service:015:action:001": "Left Button Identify",
|
||||
"service:016:action:001": "Middle Button Identify",
|
||||
"service:017:action:001": "Right Button Identify"
|
||||
},
|
||||
"zh-Hans": {
|
||||
"service:015:action:001": "左键确认",
|
||||
"service:016:action:001": "中键确认",
|
||||
"service:017:action:001": "右键确认"
|
||||
}
|
||||
}
|
||||
}
|
@ -49,3 +49,12 @@ urn:miot-spec-v2:device:airer:0000A00D:hyd-znlyj5:1:
|
||||
- 1
|
||||
- 1
|
||||
urn:miot-spec-v2:device:airer:0000A00D:hyd-znlyj5:2: urn:miot-spec-v2:device:airer:0000A00D:hyd-znlyj5:1
|
||||
urn:miot-spec-v2:device:bath-heater:0000A028:opple-acmoto:1:
|
||||
prop.5.2:
|
||||
value-list:
|
||||
- value: 1
|
||||
description: low
|
||||
- value: 128
|
||||
description: medium
|
||||
- value: 255
|
||||
description: high
|
||||
|
@ -51,6 +51,7 @@ from homeassistant.components.event import EventDeviceClass
|
||||
|
||||
from homeassistant.const import (
|
||||
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
EntityCategory,
|
||||
LIGHT_LUX,
|
||||
UnitOfEnergy,
|
||||
UnitOfPower,
|
||||
@ -330,7 +331,8 @@ SPEC_DEVICE_TRANS_MAP: dict = {
|
||||
'events': set<event instance name: str>,
|
||||
'actions': set<action instance name: str>
|
||||
},
|
||||
'entity': str
|
||||
'entity': str,
|
||||
'entity_category'?: str
|
||||
}
|
||||
}
|
||||
"""
|
||||
@ -348,10 +350,23 @@ SPEC_SERVICE_TRANS_MAP: dict = {
|
||||
},
|
||||
'entity': 'light'
|
||||
},
|
||||
'indicator-light': 'light',
|
||||
'ambient-light': 'light',
|
||||
'night-light': 'light',
|
||||
'white-light': 'light',
|
||||
'indicator-light': {
|
||||
'required': {
|
||||
'properties': {
|
||||
'on': {'read', 'write'}
|
||||
}
|
||||
},
|
||||
'optional': {
|
||||
'properties': {
|
||||
'mode', 'brightness',
|
||||
}
|
||||
},
|
||||
'entity': 'light',
|
||||
'entity_category': EntityCategory.CONFIG
|
||||
},
|
||||
'fan': {
|
||||
'required': {
|
||||
'properties': {
|
||||
|
Loading…
x
Reference in New Issue
Block a user