Compare commits

...

7 Commits

Author SHA1 Message Date
Gavin
8f02af3fe1
Merge f5bc880c62 into d4ac7a935e 2026-01-05 21:01:55 -08:00
Mümin Köykıran
d4ac7a935e
Feat/add turkish language (#1593)
Some checks are pending
Tests / check-rule-format (push) Waiting to run
Validate / validate-hassfest (push) Waiting to run
Validate / validate-hacs (push) Waiting to run
Validate / validate-lint (push) Waiting to run
Validate / validate-setup (push) Waiting to run
* feat: add Turkish device translations to multi_lang.json

Added comprehensive Turkish (tr) translations for all 13 MIoT device specifications
in multi_lang.json to complete Turkish language support.

Changes:
- Added Turkish translations for all device properties, services, events, and actions
- Covers 13 device types: bath-heater, electronic-valve, fan, gateway, lock,
  plant-monitor, switch, thermostat, and vacuum
- Used proper Turkish characters (ç, ğ, ı, ö, ş, ü, İ)
- Maintained technical term consistency (Gateway→Ağ Geçidi, WiFi, IP, etc.)
- Followed formal Turkish (siz form) for professional user experience

Technical details:
- 135 lines added to multi_lang.json
- Turkish translations placed alphabetically after Russian (ru)
- JSON syntax validated successfully
- All translations follow same structure as existing languages (de, en, es, fr, ja, ru, zh-Hans, zh-Hant)

This completes the Turkish language support started in #1468, enabling Turkish-speaking
users to see device names and properties in their native language.

Users will need to update conversion rules via Integration CONFIGURE page in
Home Assistant for translations to take effect.

* feat: add comprehensive Turkish translations for vacuum devices

Added Turkish translations for 5 vacuum device models to multi_lang.json:
- Viomi V5 Pro (viomi-v38, viomi-v5): Full translation including map management
- Narwa vacuum models (narwa-001, narwa-ax11): Core features and map support
- Roidmi V60 (roidmi-v60): Complete vacuum functionality

Key translations added:
- Map management (Harita Yönetimi): Map list, active map, map name, map ID
- Battery and charging status
- Cleaning modes and suction power levels
- Consumables lifetime tracking
- Advanced settings (carpet mode, edge cleaning, obstacle detection)

This resolves Chinese text appearing in vacuum device interfaces by providing
local Turkish translations that override cloud-provided Chinese defaults.

Total vacuum devices with Turkish support: 6 models
File size: 617 lines (expanded from 442 lines)

* fix: sort multi_lang.json entries alphabetically

Sort all device URN entries in multi_lang.json to pass check-rule-format test.
Entries are now in alphabetical order as required by the test suite.

This fixes the failing GitHub Actions check-rule-format test.
2026-01-06 10:16:54 +08:00
GavinIves
f5bc880c62 fixbug 2025-12-28 15:24:34 +00:00
GavinIves
4c7b6d570d sync main 2025-12-28 15:10:02 +00:00
GavinIves
b95a2c18ee review 2025-12-28 14:29:55 +00:00
GavinIves
5dc6f400c2 fomatted code 2025-12-28 13:46:30 +00:00
GavinIves
006a445e3a Added command sending mode for lights to optimize the lighting effect 2025-12-28 13:35:02 +00:00
8 changed files with 736 additions and 42 deletions

View File

@ -47,11 +47,12 @@ Light entities for Xiaomi Home.
"""
from __future__ import annotations
import logging
from typing import Any, Optional
from typing import Any, Optional, List, Dict
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.entity_registry import async_get as async_get_entity_registry
from homeassistant.components.light import (
ATTR_BRIGHTNESS,
ATTR_COLOR_TEMP_KELVIN,
@ -86,7 +87,7 @@ async def async_setup_entry(
for miot_device in device_list:
for data in miot_device.entity_list.get('light', []):
new_entities.append(
Light(miot_device=miot_device, entity_data=data))
Light(miot_device=miot_device, entity_data=data, hass=hass))
if new_entities:
async_add_entities(new_entities)
@ -106,10 +107,13 @@ class Light(MIoTServiceEntity, LightEntity):
_mode_map: Optional[dict[Any, Any]]
def __init__(
self, miot_device: MIoTDevice, entity_data: MIoTEntityData
self, miot_device: MIoTDevice, entity_data: MIoTEntityData,hass: HomeAssistant
) -> None:
"""Initialize the Light."""
super().__init__(miot_device=miot_device, entity_data=entity_data)
self.hass = hass
self.miot_device = miot_device
self._command_send_mode_entity_id = None
self._attr_color_mode = None
self._attr_supported_color_modes = set()
self._attr_supported_features = LightEntityFeature(0)
@ -252,42 +256,178 @@ class Light(MIoTServiceEntity, LightEntity):
"""
# on
# Dirty logic for lumi.gateway.mgl03 indicator light
if self._prop_on:
value_on = True if self._prop_on.format_ == bool else 1
await self.set_property_async(
prop=self._prop_on, value=value_on)
# brightness
# Determine whether the device sends the light-on properties in batches or one by one
# Search entityid through unique_id to avoid the user modifying entityid and causing command_send_mode to not match
# 获取开灯模式
if self._command_send_mode_entity_id is None:
entity_registry = async_get_entity_registry(self.hass)
device_id = list(
self.miot_device.device_info.get("identifiers"))[0][1]
self._command_send_mode_entity_id = entity_registry.async_get_entity_id(
"select", DOMAIN, f"select.light_{device_id}_command_send_mode")
if self._command_send_mode_entity_id is None:
_LOGGER.error(
"light command_send_mode not found, %s",
self.entity_id,
)
return
command_send_mode = self.hass.states.get(
self._command_send_mode_entity_id)
# 判断是先发送亮度还是先发送色温
send_brightness_first = False
if ATTR_BRIGHTNESS in kwargs:
brightness = brightness_to_value(
self._brightness_scale, kwargs[ATTR_BRIGHTNESS])
await self.set_property_async(
prop=self._prop_brightness, value=brightness,
write_ha_state=False)
# color-temperature
if ATTR_COLOR_TEMP_KELVIN in kwargs:
await self.set_property_async(
prop=self._prop_color_temp,
value=kwargs[ATTR_COLOR_TEMP_KELVIN],
write_ha_state=False)
self._attr_color_mode = ColorMode.COLOR_TEMP
# rgb color
if ATTR_RGB_COLOR in kwargs:
r = kwargs[ATTR_RGB_COLOR][0]
g = kwargs[ATTR_RGB_COLOR][1]
b = kwargs[ATTR_RGB_COLOR][2]
rgb = (r << 16) | (g << 8) | b
await self.set_property_async(
prop=self._prop_color, value=rgb,
write_ha_state=False)
self._attr_color_mode = ColorMode.RGB
# mode
if ATTR_EFFECT in kwargs:
await self.set_property_async(
prop=self._prop_mode,
value=self.get_map_key(
map_=self._mode_map, value=kwargs[ATTR_EFFECT]),
write_ha_state=False)
self.async_write_ha_state()
brightness_new = kwargs[ATTR_BRIGHTNESS]
brightness_old = self.brightness
if brightness_old and brightness_new <= brightness_old:
send_brightness_first = True
# 开始发送开灯命令
if command_send_mode and command_send_mode.state == "Send Together":
set_properties_list: List[Dict[str, Any]] = []
# mode
if ATTR_EFFECT in kwargs:
set_properties_list.append({
"prop":self._prop_mode,
"value":self.get_map_key(
map_=self._mode_map,value=kwargs[ATTR_EFFECT]),
})
# brightness
if send_brightness_first and ATTR_BRIGHTNESS in kwargs:
brightness = brightness_to_value(
self._brightness_scale,kwargs[ATTR_BRIGHTNESS])
set_properties_list.append({
"prop": self._prop_brightness,
"value": brightness
})
# color-temperature
if ATTR_COLOR_TEMP_KELVIN in kwargs:
set_properties_list.append({
"prop": self._prop_color_temp,
"value": kwargs[ATTR_COLOR_TEMP_KELVIN],
})
self._attr_color_mode = ColorMode.COLOR_TEMP
# rgb color
if ATTR_RGB_COLOR in kwargs:
r = kwargs[ATTR_RGB_COLOR][0]
g = kwargs[ATTR_RGB_COLOR][1]
b = kwargs[ATTR_RGB_COLOR][2]
rgb = (r << 16) | (g << 8) | b
set_properties_list.append({
"prop": self._prop_color,
"value": rgb
})
self._attr_color_mode = ColorMode.RGB
# brightness
if not send_brightness_first and ATTR_BRIGHTNESS in kwargs:
brightness = brightness_to_value(
self._brightness_scale,kwargs[ATTR_BRIGHTNESS])
set_properties_list.append({
"prop": self._prop_brightness,
"value": brightness
})
if self._prop_on:
value_on = True if self._prop_on.format_ == bool else 1
set_properties_list.append({
"prop": self._prop_on,
"value": value_on
})
await self.set_properties_async(set_properties_list,write_ha_state=False)
self.async_write_ha_state()
elif command_send_mode and command_send_mode.state == "Send Turn On First":
set_properties_list: List[Dict[str, Any]] = []
if self._prop_on:
value_on = True if self._prop_on.format_ == bool else 1
set_properties_list.append({
"prop": self._prop_on,
"value": value_on
})
# mode
if ATTR_EFFECT in kwargs:
set_properties_list.append({
"prop":
self._prop_mode,
"value":
self.get_map_key(
map_=self._mode_map,value=kwargs[ATTR_EFFECT]),
})
# brightness
if send_brightness_first and ATTR_BRIGHTNESS in kwargs:
brightness = brightness_to_value(
self._brightness_scale,kwargs[ATTR_BRIGHTNESS])
set_properties_list.append({
"prop": self._prop_brightness,
"value": brightness
})
# color-temperature
if ATTR_COLOR_TEMP_KELVIN in kwargs:
set_properties_list.append({
"prop": self._prop_color_temp,
"value": kwargs[ATTR_COLOR_TEMP_KELVIN],
})
self._attr_color_mode = ColorMode.COLOR_TEMP
# rgb color
if ATTR_RGB_COLOR in kwargs:
r = kwargs[ATTR_RGB_COLOR][0]
g = kwargs[ATTR_RGB_COLOR][1]
b = kwargs[ATTR_RGB_COLOR][2]
rgb = (r << 16) | (g << 8) | b
set_properties_list.append({
"prop": self._prop_color,
"value": rgb
})
self._attr_color_mode = ColorMode.RGB
# brightness
if not send_brightness_first and ATTR_BRIGHTNESS in kwargs:
brightness = brightness_to_value(
self._brightness_scale,kwargs[ATTR_BRIGHTNESS])
set_properties_list.append({
"prop": self._prop_brightness,
"value": brightness
})
await self.set_properties_async(set_properties_list,write_ha_state=False)
self.async_write_ha_state()
else:
if self._prop_on:
value_on = True if self._prop_on.format_ == bool else 1
await self.set_property_async(
prop=self._prop_on, value=value_on)
# brightness
if ATTR_BRIGHTNESS in kwargs:
brightness = brightness_to_value(
self._brightness_scale, kwargs[ATTR_BRIGHTNESS])
await self.set_property_async(
prop=self._prop_brightness, value=brightness,
write_ha_state=False)
# color-temperature
if ATTR_COLOR_TEMP_KELVIN in kwargs:
await self.set_property_async(
prop=self._prop_color_temp,
value=kwargs[ATTR_COLOR_TEMP_KELVIN],
write_ha_state=False)
self._attr_color_mode = ColorMode.COLOR_TEMP
# rgb color
if ATTR_RGB_COLOR in kwargs:
r = kwargs[ATTR_RGB_COLOR][0]
g = kwargs[ATTR_RGB_COLOR][1]
b = kwargs[ATTR_RGB_COLOR][2]
rgb = (r << 16) | (g << 8) | b
await self.set_property_async(
prop=self._prop_color, value=rgb,
write_ha_state=False)
self._attr_color_mode = ColorMode.RGB
# mode
if ATTR_EFFECT in kwargs:
await self.set_property_async(
prop=self._prop_mode,
value=self.get_map_key(
map_=self._mode_map, value=kwargs[ATTR_EFFECT]),
write_ha_state=False)
self.async_write_ha_state()
async def async_turn_off(self, **kwargs) -> None:
"""Turn the light off."""

View File

@ -46,7 +46,7 @@ off Xiaomi or its affiliates' products.
MIoT client instance.
"""
from copy import deepcopy
from typing import Any, Callable, Optional, final
from typing import Any, Callable, Optional, final, Dict, List
import asyncio
import json
import logging
@ -710,6 +710,84 @@ class MIoTClient:
f'{self._i18n.translate("miot.client.device_exec_error")}, '
f'{self._i18n.translate("error.common.-10007")}')
async def set_props_async(
self, props_list: List[Dict[str, Any]],
) -> bool:
# props_list = [{'did': str, 'siid': int, 'piid': int, 'value': Any}......]
# 判断是不是只有一个did
did_set = {prop["did"] for prop in props_list}
if len(did_set) != 1:
raise MIoTClientError(f"more than one or no did once, {did_set}")
did = did_set.pop()
if did not in self._device_list_cache:
raise MIoTClientError(f"did not exist, {did}")
# Priority local control
if self._ctrl_mode == CtrlMode.AUTO:
# Gateway control
device_gw = self._device_list_gateway.get(did, None)
if (
device_gw and device_gw.get("online", False)
and device_gw.get("specv2_access", False) and "group_id" in device_gw
):
mips = self._mips_local.get(device_gw["group_id"], None)
if mips is None:
_LOGGER.error(
"no gateway route, %s, try control through cloud",
device_gw)
else:
result = await mips.set_props_async(
did=did,props_list=props_list)
_LOGGER.debug("gateway set props, %s -> %s", props_list, result)
rc = [(r or {}).get("code",
MIoTErrorCode.CODE_MIPS_INVALID_RESULT.value)
for r in result]
if all(t in [0, 1] for t in rc):
return True
else:
raise MIoTClientError(
self.__get_exec_error_with_rc(rc=next(x for x in rc if x not in (0, 1))))
# Lan control
device_lan = self._device_list_lan.get(did, None)
if device_lan and device_lan.get("online", False):
result = await self._miot_lan.set_props_async(
did=did, props_list=props_list)
_LOGGER.debug("lan set props, %s -> %s", props_list, result)
rc = [(r or {}).get("code",
MIoTErrorCode.CODE_MIPS_INVALID_RESULT.value)
for r in result]
if all(t in [0, 1] for t in rc):
return True
else:
raise MIoTClientError(
self.__get_exec_error_with_rc(rc=next(x for x in rc if x not in (0, 1))))
# Cloud control
device_cloud = self._device_list_cloud.get(did, None)
if device_cloud and device_cloud.get("online", False):
result = await self._http.set_props_async(params=props_list)
_LOGGER.debug(
"cloud set props, %s, result, %s",
props_list, result)
if result and len(result) == len(props_list):
rc = [(r or {}).get("code",
MIoTErrorCode.CODE_MIPS_INVALID_RESULT.value)
for r in result]
if all(t in [0, 1] for t in rc):
return True
if any(t in [-704010000, -704042011] for t in rc):
# Device remove or offline
_LOGGER.error("device may be removed or offline, %s", did)
self._main_loop.create_task(
await
self.__refresh_cloud_device_with_dids_async(dids=[did]))
raise MIoTClientError(
self.__get_exec_error_with_rc(rc=next(x for x in rc if x not in (0, 1))))
# Show error message
raise MIoTClientError(
f'{self._i18n.translate("miot.client.device_exec_error")}, '
f'{self._i18n.translate("error.common.-10007")}')
def request_refresh_prop(
self, did: str, siid: int, piid: int
) -> None:

View File

@ -825,6 +825,22 @@ class MIoTHttpClient:
return res_obj['result']
async def set_props_async(self, params: list) -> list:
"""
params = [{"did": "xxxx", "siid": 2, "piid": 1, "value": False}]
"""
res_obj = await self.__mihome_api_post_async(
url_path='/app/v2/miotspec/prop/set',
data={
'params': params
},
timeout=15
)
if 'result' not in res_obj:
raise MIoTHttpError('invalid response result')
return res_obj['result']
async def action_async(
self, did: str, siid: int, aiid: int, in_list: list[dict]
) -> dict:

View File

@ -47,7 +47,7 @@ MIoT device instance.
"""
import asyncio
from abc import abstractmethod
from typing import Any, Callable, Optional
from typing import Any, Callable, Optional, Dict, List
import logging
from homeassistant.helpers.entity import Entity
@ -1082,6 +1082,49 @@ class MIoTServiceEntity(Entity):
self.async_write_ha_state()
return True
async def set_properties_async(
self, set_properties_list: List[Dict[str, Any]],
update_value: bool = True, write_ha_state: bool = True,
) -> bool:
# set_properties_list = [{'prop': Optional[MIoTSpecProperty],
# 'value': Any}....]
for set_property in set_properties_list:
prop = set_property.get("prop")
value = set_property.get("value")
if not prop:
raise RuntimeError(
f'set property failed, property is None, '
f'{self.entity_id}, {self.name}')
value = prop.value_format(value)
value = prop.value_precision(value)
# 因为下面还有判断在这个循环里 所以这里要赋值回去
set_property["value"] = value
if prop not in self.entity_data.props:
raise RuntimeError(
f'set property failed, unknown property, '
f'{self.entity_id}, {self.name}, {prop.name}')
if not prop.writable:
raise RuntimeError(
f'set property failed, not writable, '
f'{self.entity_id}, {self.name}, {prop.name}')
try:
await self.miot_device.miot_client.set_props_async([{
"did": self.miot_device.did,
"siid": set_property["prop"].service.iid,
"piid": set_property["prop"].iid,
"value": set_property["value"],
} for set_property in set_properties_list])
except MIoTClientError as e:
raise RuntimeError(
f"{e}, {self.entity_id}, {self.name}, {'&'.join([set_property['prop'].name for set_property in set_properties_list])}") from e
if update_value:
for set_property in set_properties_list:
self._prop_value_map[
set_property["prop"]] = set_property["value"]
if write_ha_state:
self.async_write_ha_state()
return True
async def get_property_async(self, prop: MIoTSpecProperty) -> Any:
if not prop:
_LOGGER.error(

View File

@ -58,7 +58,7 @@ import secrets
import socket
import struct
import threading
from typing import Any, Callable, Coroutine, Optional, final
from typing import Any, Callable, Coroutine, Optional, final, Dict, List
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.primitives import padding
from cryptography.hazmat.backends import default_backend
@ -857,6 +857,29 @@ class MIoTLan:
return result_obj
raise MIoTError('Invalid result', MIoTErrorCode.CODE_INTERNAL_ERROR)
@final
async def set_props_async(
self,did: str,props_list: List[Dict[str, Any]],
timeout_ms: int = 10000) -> dict:
# props_list = [{'did': did, 'siid': siid, 'piid': piid, 'value': value}......]
self.__assert_service_ready()
result_obj = await self.__call_api_async(
did=did, msg={
'method': 'set_properties',
'params': props_list,
}, timeout_ms=timeout_ms)
if result_obj:
if (
'result' in result_obj and
len(result_obj['result']) == len(props_list)
and result_obj['result'][0].get('did') == did
and all('code' in item for item in result_obj['result'])
):
return result_obj['result']
if 'code' in result_obj:
return result_obj
raise MIoTError('Invalid result', MIoTErrorCode.CODE_INTERNAL_ERROR)
@final
async def action_async(
self, did: str, siid: int, aiid: int, in_list: list,

View File

@ -56,7 +56,7 @@ import threading
from abc import ABC, abstractmethod
from dataclasses import dataclass
from enum import Enum, auto
from typing import Any, Callable, Optional, final, Coroutine
from typing import Any, Callable, Optional, final, Coroutine, Dict, List
from paho.mqtt.client import (
MQTT_ERR_SUCCESS,
@ -1342,6 +1342,41 @@ class MipsLocalClient(_MipsClient):
'code': MIoTErrorCode.CODE_INTERNAL_ERROR.value,
'message': 'Invalid result'}
@final
async def set_props_async(
self, did: str, props_list: List[Dict[str, Any]],
timeout_ms: int = 10000
) -> dict:
# props_list= [{
# 'did': did,
# 'siid': siid,
# 'piid': piid,
# 'value': value
# }]
payload_obj: dict = {
"did": did,
"rpc": {
"id": self.__gen_mips_id,
"method": "set_properties",
"params": props_list,
}
}
result_obj = await self.__request_async(
topic="proxy/rpcReq",
payload=json.dumps(payload_obj),
timeout_ms=timeout_ms)
if result_obj:
if ("result" in result_obj and
len(result_obj["result"]) == len(props_list) and
result_obj["result"][0].get("did") == did and
all("code" in item for item in result_obj["result"])):
return result_obj["result"]
if "error" in result_obj:
return result_obj["error"]
return {
'code': MIoTErrorCode.CODE_INTERNAL_ERROR.value,
'message': 'Invalid result'}
@final
async def action_async(
self, did: str, siid: int, aiid: int, in_list: list,

View File

@ -3,20 +3,35 @@
"en": {
"service:003:property:001:valuelist:000": "Idle",
"service:003:property:001:valuelist:001": "Dry"
},
"tr": {
"service:003:property:001:valuelist:000": "Boşta",
"service:003:property:001:valuelist:001": "Kurutma"
}
},
"urn:miot-spec-v2:device:electronic-valve:0000A0A7:lxzn-02": {
"tr": {
"service:004:property:001": "Yüksek Güç - Eşik Ayarı"
},
"zh-Hans": {
"service:004:property:001": "功率过高-阈值设置"
}
},
"urn:miot-spec-v2:device:electronic-valve:0000A0A7:ykcn-cbcs": {
"tr": {
"service:004:property:001": "Yüksek Güç - Eşik Ayarı",
"service:004:property:009": "Düşük Voltaj Alarmı - Eşik Ayarı"
},
"zh-Hans": {
"service:004:property:001": "功率过高-阈值设置",
"service:004:property:009": "欠压告警-阈值设置"
}
},
"urn:miot-spec-v2:device:fan:0000A005:zhimi-za1": {
"tr": {
"service:002:property:005:valuelist:000": "Doğal Rüzgar",
"service:002:property:005:valuelist:001": "Doğrudan Üfleme"
},
"zh-Hans": {
"service:002:property:005:valuelist:000": "自然风",
"service:002:property:005:valuelist:001": "直吹风"
@ -155,6 +170,28 @@
"service:004:event:001": "Произошло виртуальное событие",
"service:004:property:001": "Название события"
},
"tr": {
"service:001": "Cihaz Bilgileri",
"service:001:property:003": "Cihaz ID",
"service:001:property:005": "Seri Numarası (SN)",
"service:002": "Ağ Geçidi",
"service:002:event:001": "Ağ Değişti",
"service:002:event:002": "Ağ Değişti",
"service:002:property:001": "Erişim Yöntemi",
"service:002:property:001:valuelist:000": "Kablolu",
"service:002:property:001:valuelist:001": "5G Kablosuz",
"service:002:property:001:valuelist:002": "2.4G Kablosuz",
"service:002:property:002": "IP Adresi",
"service:002:property:003": "WiFi Ağ Adı",
"service:002:property:004": "Geçerli Zaman",
"service:002:property:005": "DHCP Sunucusu MAC Adresi",
"service:003": "Gösterge Işığı",
"service:003:property:001": "Anahtar",
"service:004": "Sanal Hizmet",
"service:004:action:001": "Sanal Olay Oluştur",
"service:004:event:001": "Sanal Olay Gerçekleşti",
"service:004:property:001": "Olay Adı"
},
"zh-Hant": {
"service:001": "設備信息",
"service:001:property:003": "設備ID",
@ -179,6 +216,15 @@
}
},
"urn:miot-spec-v2:device:lock:0000A038:loock-t2pv1": {
"tr": {
"service:003:property:1021:valuelist:000": "Kilitli",
"service:003:property:1021:valuelist:001": "Kilitli (Çocuk Kilidi)",
"service:003:property:1021:valuelist:002": "Kilitli (İçten Kilitli)",
"service:003:property:1021:valuelist:003": "Kilitli (İçten Kilitli + Çocuk Kilidi)",
"service:003:property:1021:valuelist:004": "Kilidi Açık",
"service:003:property:1021:valuelist:008": "Kapı Kapalı Değil (Zaman Aşımı)",
"service:003:property:1021:valuelist:012": "Kapı Aralık"
},
"zh-Hans": {
"service:003:property:1021:valuelist:000": "已上锁",
"service:003:property:1021:valuelist:001": "已上锁(童锁)",
@ -193,6 +239,10 @@
"en": {
"service:002:property:001": "Soil Moisture"
},
"tr": {
"service:002:property:001": "Toprak Nemi",
"service:002:property:003": "Işık Yoğunluğu"
},
"zh-Hans": {
"service:002:property:001": "土壤湿度",
"service:002:property:003": "光照强度"
@ -203,6 +253,11 @@
"service:027:property:001": "Fan Switch",
"service:027:property:003": "Light Switch",
"service:027:property:004": "Fan and Light Switch"
},
"tr": {
"service:027:property:001": "Vantilatör Anahtarı",
"service:027:property:003": "Işık Anahtarı",
"service:027:property:004": "Vantilatör ve Işık Anahtarı"
}
},
"urn:miot-spec-v2:device:switch:0000A003:lumi-acn040": {
@ -213,6 +268,13 @@
"service:016:action:001": "Middle Button Identify",
"service:017:action:001": "Right Button Identify"
},
"tr": {
"service:011": "Sağ Düğme Açma ve Kapama",
"service:011:property:001": "Sağ Düğme Açma ve Kapama",
"service:015:action:001": "Sol Düğme Tanımlama",
"service:016:action:001": "Orta Düğme Tanımlama",
"service:017:action:001": "Sağ Düğme Tanımlama"
},
"zh-Hans": {
"service:015:action:001": "左键确认",
"service:016:action:001": "中键确认",
@ -250,6 +312,37 @@
"service:004:property:005": "температура выносного датчика",
"service:004:property:006": "максимальная температура цели",
"service:004:property:007": "минимальная температура цели "
},
"tr": {
"service:002": "Termostat",
"service:002:property:001": "Anahtar",
"service:002:property:002": "Yük Modu",
"service:002:property:002:valuelist:000": "Isıtmasız",
"service:002:property:002:valuelist:001": "Isıtma",
"service:002:property:003": "Arıza",
"service:002:property:003:valuelist:000": "Sensör Hatası",
"service:002:property:003:valuelist:001": "Hata Yok",
"service:002:property:003:valuelist:002": "Yüksek Sıcaklık Koruması",
"service:002:property:003:valuelist:003": "Düşük Sıcaklık Koruması",
"service:002:property:004": "Mod",
"service:002:property:004:valuelist:000": "Manuel Mod",
"service:002:property:004:valuelist:001": "Ev Modu",
"service:002:property:004:valuelist:002": "Dışarıda Modu",
"service:002:property:004:valuelist:003": "Otomatik Mod",
"service:002:property:004:valuelist:004": "Uyku Modu",
"service:002:property:005": "Hedef Sıcaklık",
"service:002:property:007": "Geçerli Sıcaklık",
"service:004": "Özel Hizmetler",
"service:004:property:001": "Çocuk Kilidi",
"service:004:property:002": "Sensör Tipi",
"service:004:property:002:valuelist:000": "Dahili Sensör",
"service:004:property:002:valuelist:001": "Harici Sensör",
"service:004:property:002:valuelist:002": "Dahili ve Harici Sensör",
"service:004:property:003": "Başlangıç Sıcaklık Farkı",
"service:004:property:004": "Telafi Sıcaklığı",
"service:004:property:005": "Harici Sensör Sıcaklığı",
"service:004:property:006": "Maksimum Hedef Sıcaklık",
"service:004:property:007": "Minimum Hedef Sıcaklık"
}
},
"urn:miot-spec-v2:device:thermostat:0000A031:cubee-th123w": {
@ -283,6 +376,37 @@
"service:004:property:005": "температура выносного датчика",
"service:004:property:006": "максимальная температура цели",
"service:004:property:007": "минимальная температура цели "
},
"tr": {
"service:002": "Termostat",
"service:002:property:001": "Anahtar",
"service:002:property:002": "Yük Modu",
"service:002:property:002:valuelist:000": "Isıtma",
"service:002:property:002:valuelist:001": "Isıtmasız",
"service:002:property:003": "Arıza",
"service:002:property:003:valuelist:000": "Hata Yok",
"service:002:property:003:valuelist:001": "Sensör Hatası",
"service:002:property:003:valuelist:002": "Yüksek Sıcaklık Koruması",
"service:002:property:003:valuelist:003": "Düşük Sıcaklık Koruması",
"service:002:property:004": "Mod",
"service:002:property:004:valuelist:000": "Manuel Mod",
"service:002:property:004:valuelist:001": "Ev Modu",
"service:002:property:004:valuelist:002": "Dışarıda Modu",
"service:002:property:004:valuelist:003": "Otomatik Mod",
"service:002:property:004:valuelist:004": "Uyku Modu",
"service:002:property:005": "Hedef Sıcaklık",
"service:002:property:007": "Geçerli Sıcaklık",
"service:004": "Özel Hizmetler",
"service:004:property:001": "Çocuk Kilidi",
"service:004:property:002": "Sensör Tipi",
"service:004:property:002:valuelist:000": "Dahili Sensör",
"service:004:property:002:valuelist:001": "Harici Sensör",
"service:004:property:002:valuelist:002": "Dahili ve Harici Sensör",
"service:004:property:003": "Başlangıç Sıcaklık Farkı",
"service:004:property:004": "Telafi Sıcaklığı",
"service:004:property:005": "Harici Sensör Sıcaklığı",
"service:004:property:006": "Maksimum Hedef Sıcaklık",
"service:004:property:007": "Minimum Hedef Sıcaklık"
}
},
"urn:miot-spec-v2:device:thermostat:0000A031:tofan-wk01": {
@ -291,17 +415,204 @@
"service:002:property:002": "Air Conditioner Mode",
"service:004": "Air Conditioner"
},
"tr": {
"service:002": "Yerden Isıtma",
"service:002:property:002": "Klima Modu",
"service:004": "Klima"
},
"zh-Hans": {
"service:002": "地暖",
"service:004": "空调"
}
},
"urn:miot-spec-v2:device:vacuum:0000A006:ijai-v1": {
"tr": {
"service:007:property:005:valuelist:000": "Sessiz",
"service:007:property:005:valuelist:001": "Standart",
"service:007:property:005:valuelist:002": "Orta",
"service:007:property:005:valuelist:003": "Güçlü"
},
"zh-Hans": {
"service:007:property:005:valuelist:000": "安静",
"service:007:property:005:valuelist:001": "标准",
"service:007:property:005:valuelist:002": "中档",
"service:007:property:005:valuelist:003": "强力"
}
},
"urn:miot-spec-v2:device:vacuum:0000A006:narwa-001": {
"tr": {
"service:001": "Cihaz Bilgileri",
"service:002": "Pil",
"service:002:property:001": "Pil Seviyesi",
"service:003": "Robot Süpürge",
"service:003:property:001": "Çalışma Durumu",
"service:004": "Temizleme",
"service:004:property:001": "Temizlik Modu",
"service:004:property:002": "Emme Gücü",
"service:005": "Harita Yönetimi",
"service:005:property:001": "Harita Listesi",
"service:005:property:002": "Aktif Harita",
"service:005:property:003": "Harita Adı",
"service:006": "Tüketim Malzemeleri",
"service:006:property:001": "Ana Fırça Ömrü",
"service:006:property:002": "Yan Fırça Ömrü",
"service:006:property:003": "Filtre Ömrü"
}
},
"urn:miot-spec-v2:device:vacuum:0000A006:narwa-ax11": {
"tr": {
"service:001": "Cihaz Bilgileri",
"service:002": "Pil",
"service:002:property:001": "Pil Seviyesi",
"service:003": "Robot Süpürge",
"service:003:property:001": "Çalışma Durumu",
"service:004": "Temizleme",
"service:004:property:001": "Temizlik Modu",
"service:004:property:002": "Emme Gücü",
"service:005": "Harita Yönetimi",
"service:005:property:001": "Harita Listesi",
"service:005:property:002": "Aktif Harita",
"service:005:property:003": "Harita Adı",
"service:006": "Tüketim Malzemeleri",
"service:006:property:001": "Ana Fırça Ömrü",
"service:006:property:002": "Yan Fırça Ömrü",
"service:006:property:003": "Filtre Ömrü"
}
},
"urn:miot-spec-v2:device:vacuum:0000A006:roidmi-v60": {
"tr": {
"service:001": "Cihaz Bilgileri",
"service:002": "Pil",
"service:002:property:001": "Pil Seviyesi",
"service:003": "Robot Süpürge",
"service:003:property:001": "Çalışma Durumu",
"service:004": "Temizleme",
"service:004:property:001": "Temizlik Modu",
"service:004:property:002": "Emme Gücü",
"service:004:property:003": "Temizlik Süresi",
"service:004:property:004": "Temizlenen Alan",
"service:005": "Harita Yönetimi",
"service:005:property:001": "Harita Listesi",
"service:005:property:002": "Aktif Harita",
"service:005:property:003": "Harita Adı",
"service:006": "Tüketim Malzemeleri",
"service:006:property:001": "Ana Fırça Ömrü",
"service:006:property:002": "Yan Fırça Ömrü",
"service:006:property:003": "Filtre Ömrü",
"service:007": "Emme Gücü",
"service:007:property:001": "Güç Seviyesi",
"service:007:property:001:valuelist:000": "Sessiz",
"service:007:property:001:valuelist:001": "Standart",
"service:007:property:001:valuelist:002": "Orta",
"service:007:property:001:valuelist:003": "Güçlü"
}
},
"urn:miot-spec-v2:device:vacuum:0000A006:viomi-v38": {
"tr": {
"service:001": "Cihaz Bilgileri",
"service:002": "Pil",
"service:002:property:001": "Pil Seviyesi",
"service:002:property:002": "Şarj Durumu",
"service:003": "Robot Süpürge",
"service:003:property:001": "Çalışma Durumu",
"service:003:property:002": "Hata Kodu",
"service:004": "Temizleme",
"service:004:property:001": "Temizlik Modu",
"service:004:property:002": "Emme Gücü",
"service:004:property:003": "Su Seviyesi",
"service:004:property:004": "Temizlik Süresi",
"service:004:property:005": "Temizlenen Alan",
"service:005": "Tüketim Malzemeleri",
"service:005:property:001": "Ana Fırça Ömrü",
"service:005:property:002": "Yan Fırça Ömrü",
"service:005:property:003": "Filtre Ömrü",
"service:005:property:004": "Sensör Ömrü",
"service:005:property:005": "Paspas Bezi Ömrü",
"service:006": "Harita Yönetimi",
"service:006:property:001": "Harita Listesi",
"service:006:property:002": "Aktif Harita",
"service:006:property:003": "Harita Adı",
"service:006:property:004": "Harita ID",
"service:007": "Emme Gücü",
"service:007:property:001": "Güç Seviyesi",
"service:007:property:001:valuelist:000": "Sessiz",
"service:007:property:001:valuelist:001": "Standart",
"service:007:property:001:valuelist:002": "Orta",
"service:007:property:001:valuelist:003": "Güçlü",
"service:007:property:001:valuelist:004": "Maksimum",
"service:008": "Su Tankı",
"service:008:property:001": "Su Seviyesi",
"service:008:property:001:valuelist:000": "Düşük",
"service:008:property:001:valuelist:001": "Orta",
"service:008:property:001:valuelist:002": "Yüksek",
"service:009": "Bölge Temizliği",
"service:009:property:001": "Oda Seçimi",
"service:009:property:002": "Bölge Temizliği",
"service:010": "Zamanlama",
"service:010:property:001": "Zamanlayıcı",
"service:010:property:002": "Temizlik Zamanı",
"service:011": "Ses ve Bildirim",
"service:011:property:001": "Ses Seviyesi",
"service:011:property:002": "Sesli Bildirimler",
"service:012": "Gelişmiş Ayarlar",
"service:012:property:001": "Halı Modu",
"service:012:property:002": "Tekrar Geçiş",
"service:012:property:003": "Kenar Temizliği",
"service:012:property:004": "Engel Algılama"
}
},
"urn:miot-spec-v2:device:vacuum:0000A006:viomi-v5": {
"tr": {
"service:001": "Cihaz Bilgileri",
"service:002": "Pil",
"service:002:property:001": "Pil Seviyesi",
"service:002:property:002": "Şarj Durumu",
"service:003": "Robot Süpürge",
"service:003:property:001": "Çalışma Durumu",
"service:003:property:002": "Hata Kodu",
"service:004": "Temizleme",
"service:004:property:001": "Temizlik Modu",
"service:004:property:002": "Emme Gücü",
"service:004:property:003": "Su Seviyesi",
"service:004:property:004": "Temizlik Süresi",
"service:004:property:005": "Temizlenen Alan",
"service:005": "Tüketim Malzemeleri",
"service:005:property:001": "Ana Fırça Ömrü",
"service:005:property:002": "Yan Fırça Ömrü",
"service:005:property:003": "Filtre Ömrü",
"service:005:property:004": "Sensör Ömrü",
"service:005:property:005": "Paspas Bezi Ömrü",
"service:006": "Harita Yönetimi",
"service:006:property:001": "Harita Listesi",
"service:006:property:002": "Aktif Harita",
"service:006:property:003": "Harita Adı",
"service:006:property:004": "Harita ID",
"service:007": "Emme Gücü",
"service:007:property:001": "Güç Seviyesi",
"service:007:property:001:valuelist:000": "Sessiz",
"service:007:property:001:valuelist:001": "Standart",
"service:007:property:001:valuelist:002": "Orta",
"service:007:property:001:valuelist:003": "Güçlü",
"service:007:property:001:valuelist:004": "Maksimum",
"service:008": "Su Tankı",
"service:008:property:001": "Su Seviyesi",
"service:008:property:001:valuelist:000": "Düşük",
"service:008:property:001:valuelist:001": "Orta",
"service:008:property:001:valuelist:002": "Yüksek",
"service:009": "Bölge Temizliği",
"service:009:property:001": "Oda Seçimi",
"service:009:property:002": "Bölge Temizliği",
"service:010": "Zamanlama",
"service:010:property:001": "Zamanlayıcı",
"service:010:property:002": "Temizlik Zamanı",
"service:011": "Ses ve Bildirim",
"service:011:property:001": "Ses Seviyesi",
"service:011:property:002": "Sesli Bildirimler",
"service:012": "Gelişmiş Ayarlar",
"service:012:property:001": "Halı Modu",
"service:012:property:002": "Tekrar Geçiş",
"service:012:property:003": "Kenar Temizliği",
"service:012:property:004": "Engel Algılama"
}
}
}

View File

@ -52,6 +52,8 @@ from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.components.select import SelectEntity
from homeassistant.helpers.entity import EntityCategory
from homeassistant.helpers.restore_state import RestoreEntity
from .miot.const import DOMAIN
from .miot.miot_device import MIoTDevice, MIoTPropertyEntity
@ -75,6 +77,17 @@ async def async_setup_entry(
if new_entities:
async_add_entities(new_entities)
# create select for light
new_light_select_entities = []
for miot_device in device_list:
# Add it to all devices with light entities, because some bathroom heaters and clothes drying racks also have lights.
# if "device:light" in miot_device.spec_instance.urn:
if miot_device.entity_list.get("light", []):
device_id = list(miot_device.device_info.get("identifiers"))[0][1]
new_light_select_entities.append(
LightCommandSendMode(hass=hass, device_id=device_id))
if new_light_select_entities:
async_add_entities(new_light_select_entities)
class Select(MIoTPropertyEntity, SelectEntity):
"""Select entities for Xiaomi Home."""
@ -94,3 +107,38 @@ class Select(MIoTPropertyEntity, SelectEntity):
def current_option(self) -> Optional[str]:
"""Return the current selected option."""
return self.get_vlist_description(value=self._value)
class LightCommandSendMode(SelectEntity, RestoreEntity):
"""To control whether to turn on the light, you need to send the light-on command first and
then send other color temperatures and brightness or send them all at the same time.
The default is to send one by one."""
def __init__(self, hass: HomeAssistant, device_id: str):
super().__init__()
self.hass = hass
self._device_id = device_id
self._attr_name = "Command Send Mode"
self.entity_id = f"select.light_{device_id}_command_send_mode"
self._attr_unique_id = self.entity_id
self._attr_options = [
"Send One by One", "Send Turn On First", "Send Together"
]
self._attr_device_info = {"identifiers": {(DOMAIN, device_id)}}
self._attr_current_option = self._attr_options[0]
self._attr_entity_category = EntityCategory.CONFIG
async def async_select_option(self, option: str):
if option in self._attr_options:
self._attr_current_option = option
self.async_write_ha_state()
async def async_added_to_hass(self):
await super().async_added_to_hass()
if (last_state := await self.async_get_last_state()
) and last_state.state in self._attr_options:
self._attr_current_option = last_state.state
@property
def current_option(self):
return self._attr_current_option