Compare commits

...

22 Commits

Author SHA1 Message Date
topsworld
8cc917807d feat: update device list changed notify logic 2025-01-17 18:08:35 +08:00
topsworld
bfb6a96477 fix: fix some type error 2025-01-17 15:44:29 +08:00
topsworld
af3c4572f9 fix: github actions add dependencies lib 2025-01-17 15:23:41 +08:00
topsworld
ee1a910205 feat: update test case logic 2025-01-17 15:19:46 +08:00
topsworld
a79fe144ab merge: merge main 2025-01-17 13:29:09 +08:00
wilds
bf116e13a4
feat: support italian translation (#183)
* added italian translation

* feat: updated translation/it.json

* feat: add missing key in Italian translation

* feat: fix missing key in Italian translation
2025-01-17 13:17:05 +08:00
topsworld
b16d158dc2 fix: fix __init__ type error 2025-01-17 12:00:15 +08:00
topsworld
22f843d7ff fix: fix sensor entity type error 2025-01-17 11:54:06 +08:00
topsworld
e7564b0152 feat: set default sensor state_class 2025-01-17 11:04:20 +08:00
topsworld
d5e243caf0 feat: support binary display mode configure 2025-01-17 10:54:54 +08:00
topsworld
cebd48355f fix: miot storage type error 2025-01-17 09:41:01 +08:00
topsworld
37492438e8 fix: fix pylint warning 2025-01-16 22:48:43 +08:00
topsworld
bc62891576 style: ignore i18n tranlate type error 2025-01-16 22:44:29 +08:00
topsworld
64d5ff41f6 feat: change miot spec name type define 2025-01-16 22:34:01 +08:00
topsworld
14766466ca feat: support binary mode 2025-01-16 22:33:37 +08:00
topsworld
37a446f2d1 feat: ignore normal disconnect log 2025-01-16 21:54:50 +08:00
topsworld
93905a10ee feat: update action debug logic 2025-01-16 21:51:46 +08:00
topsworld
6b49d07140 fix: fix multi lang error 2025-01-16 20:58:10 +08:00
topsworld
e07b90dd7a feat: add func slugify_did 2025-01-16 19:23:06 +08:00
topsworld
8a1b38ef56 fix: fix device remove error 2025-01-16 11:24:47 +08:00
topsworld
69f1d38a19 feat: same event supports multiple sub 2025-01-16 10:30:43 +08:00
topsworld
da4cdc47d1 feat: same prop supports multiple sub 2025-01-16 10:11:12 +08:00
41 changed files with 1025 additions and 420 deletions

View File

@ -19,7 +19,7 @@ jobs:
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install pytest pytest-asyncio pytest-dependency zeroconf paho.mqtt psutil cryptography
pip install pytest pytest-asyncio pytest-dependency zeroconf paho.mqtt psutil cryptography slugify
- name: Check rule format with pytest
run: |

View File

@ -54,6 +54,7 @@ from homeassistant.core import HomeAssistant
from homeassistant.components import persistent_notification
from homeassistant.helpers import device_registry, entity_registry
from .miot.common import slugify_did
from .miot.miot_storage import (
DeviceManufacturer, MIoTStorage, MIoTCert)
from .miot.miot_spec import (
@ -92,7 +93,7 @@ async def async_setup_entry(
"""Send messages in Notifications dialog box."""
if title:
persistent_notification.async_create(
hass=hass, message=message,
hass=hass, message=message or '',
title=title, notification_id=notify_id)
else:
persistent_notification.async_dismiss(
@ -125,9 +126,8 @@ async def async_setup_entry(
miot_devices: list[MIoTDevice] = []
er = entity_registry.async_get(hass=hass)
for did, info in miot_client.device_list.items():
spec_instance: MIoTSpecInstance = await spec_parser.parse(
urn=info['urn'])
if spec_instance is None:
spec_instance = await spec_parser.parse(urn=info['urn'])
if not isinstance(spec_instance, MIoTSpecInstance):
_LOGGER.error('spec content is None, %s, %s', did, info)
continue
device: MIoTDevice = MIoTDevice(
@ -155,7 +155,8 @@ async def async_setup_entry(
for entity in filter_entities:
device.entity_list[platform].remove(entity)
entity_id = device.gen_service_entity_id(
ha_domain=platform, siid=entity.spec.iid)
ha_domain=platform,
siid=entity.spec.iid) # type: ignore
if er.async_get(entity_id_or_uuid=entity_id):
er.async_remove(entity_id=entity_id)
if platform in device.prop_list:
@ -208,12 +209,7 @@ async def async_setup_entry(
if er.async_get(entity_id_or_uuid=entity_id):
er.async_remove(entity_id=entity_id)
# Action debug
if miot_client.action_debug:
if 'notify' in device.action_list:
# Add text entity for debug action
device.action_list['action_text'] = (
device.action_list['notify'])
else:
if not miot_client.action_debug:
# Remove text entity for debug action
for action in device.action_list.get('notify', []):
entity_id = device.gen_action_entity_id(
@ -221,6 +217,21 @@ async def async_setup_entry(
siid=action.service.iid, aiid=action.iid)
if er.async_get(entity_id_or_uuid=entity_id):
er.async_remove(entity_id=entity_id)
# Binary sensor display
if not miot_client.display_binary_bool:
for prop in device.prop_list.get('binary_sensor', []):
entity_id = device.gen_prop_entity_id(
ha_domain='binary_sensor', spec_name=prop.name,
siid=prop.service.iid, piid=prop.iid)
if er.async_get(entity_id_or_uuid=entity_id):
er.async_remove(entity_id=entity_id)
if not miot_client.display_binary_text:
for prop in device.prop_list.get('binary_sensor', []):
entity_id = device.gen_prop_entity_id(
ha_domain='sensor', spec_name=prop.name,
siid=prop.service.iid, piid=prop.iid)
if er.async_get(entity_id_or_uuid=entity_id):
er.async_remove(entity_id=entity_id)
hass.data[DOMAIN]['devices'][config_entry.entry_id] = miot_devices
await hass.config_entries.async_forward_entry_setups(
@ -237,7 +248,7 @@ async def async_setup_entry(
device_entry = dr.async_get_device(
identifiers={(
DOMAIN,
MIoTDevice.gen_did_tag(
slugify_did(
cloud_server=config_entry.data['cloud_server'],
did=did))},
connections=None)
@ -330,21 +341,10 @@ async def async_remove_config_entry_device(
'remove device failed, invalid domain, %s, %s',
device_entry.id, device_entry.identifiers)
return False
device_info = identifiers[1].split('_')
if len(device_info) != 2:
_LOGGER.error(
'remove device failed, invalid device info, %s, %s',
device_entry.id, device_entry.identifiers)
return False
did = device_info[1]
if did not in miot_client.device_list:
_LOGGER.error(
'remove device failed, device not found, %s, %s',
device_entry.id, device_entry.identifiers)
return False
# Remove device
await miot_client.remove_device_async(did)
await miot_client.remove_device2_async(did_tag=identifiers[1])
device_registry.async_get(hass).async_remove_device(device_entry.id)
_LOGGER.info(
'remove device, %s, %s, %s', device_info[0], did, device_entry.id)
'remove device, %s, %s', identifiers[1], device_entry.id)
return True

View File

@ -68,9 +68,10 @@ async def async_setup_entry(
new_entities = []
for miot_device in device_list:
for prop in miot_device.prop_list.get('binary_sensor', []):
new_entities.append(BinarySensor(
miot_device=miot_device, spec=prop))
if miot_device.miot_client.display_binary_bool:
for prop in miot_device.prop_list.get('binary_sensor', []):
new_entities.append(BinarySensor(
miot_device=miot_device, spec=prop))
if new_entities:
async_add_entities(new_entities)

View File

@ -124,6 +124,7 @@ class XiaomiMihomeConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
_area_name_rule: str
_action_debug: bool
_hide_non_standard_entities: bool
_display_binary_mode: list[str]
_display_devices_changed_notify: list[str]
_cloud_server: str
@ -158,6 +159,7 @@ class XiaomiMihomeConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
self._area_name_rule = self.DEFAULT_AREA_NAME_RULE
self._action_debug = False
self._hide_non_standard_entities = False
self._display_binary_mode = ['bool']
self._display_devices_changed_notify = ['add', 'del', 'offline']
self._auth_info = {}
self._nick_name = DEFAULT_NICK_NAME
@ -728,6 +730,8 @@ class XiaomiMihomeConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
'action_debug', self._action_debug)
self._hide_non_standard_entities = user_input.get(
'hide_non_standard_entities', self._hide_non_standard_entities)
self._display_binary_mode = user_input.get(
'display_binary_mode', self._display_binary_mode)
self._display_devices_changed_notify = user_input.get(
'display_devices_changed_notify',
self._display_devices_changed_notify)
@ -750,6 +754,12 @@ class XiaomiMihomeConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
'hide_non_standard_entities',
default=self._hide_non_standard_entities # type: ignore
): bool,
vol.Required(
'display_binary_mode',
default=self._display_binary_mode # type: ignore
): cv.multi_select(
self._miot_i18n.translate(
key='config.binary_mode')), # type: ignore
vol.Required(
'display_devices_changed_notify',
default=self._display_devices_changed_notify # type: ignore
@ -932,6 +942,7 @@ class XiaomiMihomeConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
'action_debug': self._action_debug,
'hide_non_standard_entities':
self._hide_non_standard_entities,
'display_binary_mode': self._display_binary_mode,
'display_devices_changed_notify':
self._display_devices_changed_notify
})
@ -973,6 +984,7 @@ class OptionsFlowHandler(config_entries.OptionsFlow):
_devices_filter: dict
_action_debug: bool
_hide_non_standard_entities: bool
_display_binary_mode: list[str]
_display_devs_notify: list[str]
_oauth_redirect_url_full: str
@ -987,6 +999,7 @@ class OptionsFlowHandler(config_entries.OptionsFlow):
_nick_name_new: Optional[str]
_action_debug_new: bool
_hide_non_standard_entities_new: bool
_display_binary_mode_new: list[str]
_update_user_info: bool
_update_devices: bool
_update_trans_rules: bool
@ -1025,6 +1038,8 @@ class OptionsFlowHandler(config_entries.OptionsFlow):
self._action_debug = self._entry_data.get('action_debug', False)
self._hide_non_standard_entities = self._entry_data.get(
'hide_non_standard_entities', False)
self._display_binary_mode = self._entry_data.get(
'display_binary_mode', ['text'])
self._display_devs_notify = self._entry_data.get(
'display_devices_changed_notify', ['add', 'del', 'offline'])
self._home_selected_list = list(
@ -1043,6 +1058,7 @@ class OptionsFlowHandler(config_entries.OptionsFlow):
self._nick_name_new = None
self._action_debug_new = False
self._hide_non_standard_entities_new = False
self._display_binary_mode_new = []
self._update_user_info = False
self._update_devices = False
self._update_trans_rules = False
@ -1309,6 +1325,12 @@ class OptionsFlowHandler(config_entries.OptionsFlow):
'hide_non_standard_entities',
default=self._hide_non_standard_entities # type: ignore
): bool,
vol.Required(
'display_binary_mode',
default=self._display_binary_mode # type: ignore
): cv.multi_select(
self._miot_i18n.translate(
'config.binary_mode')), # type: ignore
vol.Required(
'update_trans_rules',
default=self._update_trans_rules # type: ignore
@ -1337,6 +1359,8 @@ class OptionsFlowHandler(config_entries.OptionsFlow):
'action_debug', self._action_debug)
self._hide_non_standard_entities_new = user_input.get(
'hide_non_standard_entities', self._hide_non_standard_entities)
self._display_binary_mode_new = user_input.get(
'display_binary_mode', self._display_binary_mode)
self._display_devs_notify = user_input.get(
'display_devices_changed_notify', self._display_devs_notify)
self._update_trans_rules = user_input.get(
@ -1940,6 +1964,10 @@ class OptionsFlowHandler(config_entries.OptionsFlow):
self._entry_data['hide_non_standard_entities'] = (
self._hide_non_standard_entities_new)
self._need_reload = True
if set(self._display_binary_mode) != set(self._display_binary_mode_new):
self._entry_data['display_binary_mode'] = (
self._display_binary_mode_new)
self._need_reload = True
# Update display_devices_changed_notify
self._entry_data['display_devices_changed_notify'] = (
self._display_devs_notify)

View File

@ -85,6 +85,8 @@ class Event(MIoTEventEntity, EventEntity):
# Set device_class
self._attr_device_class = spec.device_class
def on_event_occurred(self, name: str, arguments: list[dict[int, Any]]):
def on_event_occurred(
self, name: str, arguments: dict[str, Any] | None = None
) -> None:
"""An event is occurred."""
self._trigger_event(event_type=name, event_attributes=arguments)

View File

@ -55,6 +55,7 @@ from urllib.parse import urlencode
from urllib.request import Request, urlopen
from paho.mqtt.matcher import MQTTMatcher
import yaml
from slugify import slugify
MIOT_ROOT_PATH: str = path.dirname(path.abspath(__file__))
@ -92,6 +93,16 @@ def randomize_float(value: float, ratio: float) -> float:
return value * (1 - ratio + random.random()*2*ratio)
def slugify_name(name: str, separator: str = '_') -> str:
"""Slugify a name."""
return slugify(name, separator=separator)
def slugify_did(cloud_server: str, did: str) -> str:
"""Slugify a device id."""
return slugify(f'{cloud_server}_{did}', separator='_')
class MIoTMatcher(MQTTMatcher):
"""MIoT Pub/Sub topic matcher."""

View File

@ -103,6 +103,7 @@ INTEGRATION_LANGUAGES = {
'en': 'English',
'es': 'Español',
'fr': 'Français',
'it': 'Italiano',
'ja': '日本語',
'nl': 'Nederlands',
'pt': 'Português',

View File

@ -54,6 +54,10 @@
"enable": "aktivieren",
"disable": "deaktivieren"
},
"binary_mode": {
"text": "Textsensor-Entität",
"bool": "Binärsensor-Entität"
},
"device_state": {
"add": "hinzufügen",
"del": "nicht verfügbar",

View File

@ -54,6 +54,10 @@
"enable": "Enable",
"disable": "Disable"
},
"binary_mode": {
"text": "Text Sensor Entity",
"bool": "Binary Sensor Entity"
},
"device_state": {
"add": "Add",
"del": "Unavailable",

View File

@ -54,6 +54,10 @@
"enable": "habilitar",
"disable": "deshabilitar"
},
"binary_mode": {
"text": "Entidad del sensor de texto",
"bool": "Entidad del sensor binario"
},
"device_state": {
"add": "agregar",
"del": "no disponible",

View File

@ -54,6 +54,10 @@
"enable": "activer",
"disable": "désactiver"
},
"binary_mode": {
"text": "Entité du capteur de texte",
"bool": "Entité du capteur binaire"
},
"device_state": {
"add": "Ajouter",
"del": "Supprimer",

View File

@ -0,0 +1,156 @@
{
"config": {
"other": {
"devices": "Dispositivi",
"found_central_gateway": ", Trovato Gateway Hub Centrale Locale",
"without_room": "Nessuna stanza assegnata",
"no_display": "Non visualizzare"
},
"control_mode": {
"auto": "Auto",
"cloud": "Cloud"
},
"statistics_logic": {
"or": "Logica OR",
"and": "Logica AND"
},
"filter_mode": {
"exclude": "Escludere",
"include": "Includere"
},
"connect_type": {
"0": "WiFi",
"1": "Dispositivo yunyi",
"2": "Dispositivo Cloud",
"3": "ZigBee",
"4": "webSocket",
"5": "Dispositivo Virtuale",
"6": "BLE",
"7": "AP Locale",
"8": "WiFi+BLE",
"9": "Altro",
"10": "Plug-in Funzionale",
"11": "Rete Cellulare",
"12": "Cavo",
"13": "NB-IoT",
"14": "Accesso cloud di terze parti",
"15": "Dispositivo di controllo remoto a infrarossi",
"16": "BLE-Mesh",
"17": "Gruppo di Dispositivi Virtuali",
"18": "Sottodispositivo Gateway",
"19": "Sottodispositivo Gateway di livello di sicurezza",
"22": "PLC",
"23": "Solo Cavo",
"24": "Matter",
"25": "WiFi+Rete Cellulare"
},
"room_name_rule": {
"none": "Non sincronizzare",
"home_room": "Nome Casa e Nome Stanza (Camera da Letto Xiaomi Home)",
"room": "Nome Stanza (Camera da Letto)",
"home": "Nome Casa (Xiaomi Home)"
},
"option_status": {
"enable": "Abilita",
"disable": "Disabilita"
},
"binary_mode": {
"text": "Entità Sensore Testo",
"bool": "Entità Sensore Binario"
},
"device_state": {
"add": "Aggiungere",
"del": "Non disponibile",
"offline": "Offline"
},
"lan_ctrl_config": {
"notice_net_dup": "\r\n**[Avviso]** Rilevate più schede di rete che potrebbero essere connesse alla stessa rete. Si prega di prestare attenzione alla selezione.",
"net_unavailable": "Interfaccia non disponibile"
}
},
"oauth2": {
"success": {
"title": "Autenticazione Avvenuta",
"content": "Chiudere questa pagina e tornare alla pagina di autenticazione dell'account per fare clic su 'Avanti'.",
"button": "Chiudi"
},
"fail": {
"title": "Autenticazione Fallita",
"content": "{error_msg}, chiudere questa pagina e tornare alla pagina di autenticazione dell'account per fare clic nuovamente sul link di autenticazione.",
"button": "Chiudi"
},
"error_msg": {
"-10100": "Parametri di risposta non validi (i campi 'code' o 'state' sono vuoti)",
"-10101": "Campo 'state' passato non corrispondente"
}
},
"miot": {
"client": {
"invalid_oauth_info": "Le informazioni di autenticazione non sono valide, il collegamento al cloud non sarà disponibile, si prega di accedere alla pagina di integrazione Xiaomi Home e cliccare 'Opzioni' per ri-autenticarsi",
"invalid_device_cache": "Le informazioni memorizzate nella cache del dispositivo sono anomale, si prega di accedere alla pagina di integrazione Xiaomi Home e cliccare 'Opzioni->Aggiorna elenco dispositivi' per aggiornare la cache locale",
"invalid_cert_info": "Certificato utente non valido, il collegamento centrale locale non sarà disponibile, si prega di accedere alla pagina di integrazione Xiaomi Home e cliccare 'Opzioni' per ri-autenticarsi",
"device_cloud_error": "Si è verificata un'eccezione durante l'ottenimento delle informazioni del dispositivo dal cloud, si prega di controllare la connessione alla rete locale",
"xiaomi_home_error_title": "Errore di Integrazione Xiaomi Home",
"xiaomi_home_error": "Rilevato errore per **{nick_name}({uid}, {cloud_server})**, si prega di accedere alla pagina delle opzioni per riconfigurare.\n\n**Messaggio di errore**: \n{message}",
"device_list_changed_title": "Modifiche all'elenco dispositivi Xiaomi Home",
"device_list_changed": "Rilevato cambiamento nelle informazioni del dispositivo per **{nick_name}({uid}, {cloud_server})**, si prega di accedere alla pagina delle opzioni di integrazione, cliccare `Opzioni->Aggiorna elenco dispositivi` per aggiornare le informazioni locali dei dispositivi.\n\nStato corrente della rete: {network_status}\n{message}\n",
"device_list_add": "\n**{count} nuovi dispositivi:** \n{message}",
"device_list_del": "\n**{count} dispositivi non disponibili:** \n{message}",
"device_list_offline": "\n**{count} dispositivi offline:** \n{message}",
"network_status_online": "Online",
"network_status_offline": "Offline",
"device_exec_error": "Errore di esecuzione"
}
},
"error": {
"common": {
"-10000": "Errore sconosciuto",
"-10001": "Servizio non disponibile",
"-10002": "Parametro non valido",
"-10003": "Risorse insufficienti",
"-10004": "Errore interno",
"-10005": "Permessi insufficienti",
"-10006": "Timeout di esecuzione",
"-10007": "Dispositivo offline o inesistente",
"-10020": "Non autorizzato (OAuth2)",
"-10030": "Token non valido (HTTP)",
"-10040": "Formato messaggio non valido",
"-10050": "Certificato non valido",
"-704000000": "Errore sconosciuto",
"-704010000": "Non autorizzato (il dispositivo potrebbe essere stato eliminato)",
"-704014006": "Descrizione del dispositivo non trovata",
"-704030013": "Proprietà non leggibile",
"-704030023": "Proprietà non scrivibile",
"-704030033": "Proprietà non sottoscrivibile",
"-704040002": "Servizio inesistente",
"-704040003": "Proprietà inesistente",
"-704040004": "Evento inesistente",
"-704040005": "Azione inesistente",
"-704040999": "Funzione non online",
"-704042001": "Dispositivo inesistente",
"-704042011": "Dispositivo offline",
"-704053036": "Timeout operazione del dispositivo",
"-704053100": "Il dispositivo non può eseguire questa operazione nello stato attuale",
"-704083036": "Timeout operazione del dispositivo",
"-704090001": "Dispositivo inesistente",
"-704220008": "ID non valido",
"-704220025": "Conteggio parametri azione non corrispondente",
"-704220035": "Errore del parametro azione",
"-704220043": "Errore valore proprietà",
"-704222034": "Errore valore di ritorno dell'azione",
"-705004000": "Errore sconosciuto",
"-705004501": "Errore sconosciuto",
"-705201013": "Proprietà non leggibile",
"-705201015": "Errore di esecuzione azione",
"-705201023": "Proprietà non scrivibile",
"-705201033": "Proprietà non sottoscrivibile",
"-706012000": "Errore sconosciuto",
"-706012013": "Proprietà non leggibile",
"-706012015": "Errore di esecuzione azione",
"-706012023": "Proprietà non scrivibile",
"-706012033": "Proprietà non sottoscrivibile",
"-706012043": "Errore valore proprietà",
"-706014006": "Descrizione del dispositivo non trovata"
}
}
}

View File

@ -54,6 +54,10 @@
"enable": "有効",
"disable": "無効"
},
"binary_mode": {
"text": "テキストセンサーエンティティ",
"bool": "バイナリセンサーエンティティ"
},
"device_state": {
"add": "追加",
"del": "利用不可",

View File

@ -54,6 +54,10 @@
"enable": "Inschakelen",
"disable": "Uitschakelen"
},
"binary_mode": {
"text": "Tekstsensor-entiteit",
"bool": "Binairesensor-entiteit"
},
"device_state": {
"add": "Toevoegen",
"del": "Niet beschikbaar",

View File

@ -54,6 +54,10 @@
"enable": "habilitado",
"disable": "desabilitado"
},
"binary_mode": {
"text": "Entidade do sensor de texto",
"bool": "Entidade do sensor binário"
},
"device_state": {
"add": "adicionar",
"del": "indisponível",

View File

@ -54,6 +54,10 @@
"enable": "Habilitar",
"disable": "Desabilitar"
},
"binary_mode": {
"text": "Entidade do sensor de texto",
"bool": "Entidade do sensor binário"
},
"device_state": {
"add": "Adicionar",
"del": "Indisponível",

View File

@ -54,6 +54,10 @@
"enable": "Включить",
"disable": "Отключить"
},
"binary_mode": {
"text": "Сущность текстового датчика",
"bool": "Сущность бинарного датчика"
},
"device_state": {
"add": "Добавить",
"del": "Недоступно",

View File

@ -54,6 +54,10 @@
"enable": "启用",
"disable": "禁用"
},
"binary_mode": {
"text": "文本传感器实体",
"bool": "二进制传感器实体"
},
"device_state": {
"add": "新增",
"del": "不可用",

View File

@ -54,6 +54,10 @@
"enable": "啟用",
"disable": "禁用"
},
"binary_mode": {
"text": "文本傳感器實體",
"bool": "二進制傳感器實體"
},
"device_state": {
"add": "新增",
"del": "不可用",

View File

@ -59,7 +59,7 @@ from homeassistant.core import HomeAssistant
from homeassistant.components import zeroconf
# pylint: disable=relative-beyond-top-level
from .common import MIoTMatcher
from .common import MIoTMatcher, slugify_did
from .const import (
DEFAULT_CTRL_MODE, DEFAULT_INTEGRATION_LANGUAGE, DEFAULT_NICK_NAME, DOMAIN,
MIHOME_CERT_EXPIRE_MARGIN, NETWORK_REFRESH_INTERVAL,
@ -150,7 +150,7 @@ class MIoTClient:
# Device list update timestamp
_device_list_update_ts: int
_sub_source_list: dict[str]
_sub_source_list: dict[str, str]
_sub_tree: MIoTMatcher
_sub_device_state: dict[str, MipsDeviceState]
@ -169,6 +169,10 @@ class MIoTClient:
_show_devices_changed_notify_timer: Optional[asyncio.TimerHandle]
# Display devices changed notify
_display_devs_notify: list[str]
_display_notify_content_hash: Optional[int]
# Display binary mode
_display_binary_text: bool
_display_binary_bool: bool
def __init__(
self,
@ -235,6 +239,11 @@ class MIoTClient:
self._display_devs_notify = entry_data.get(
'display_devices_changed_notify', ['add', 'del', 'offline'])
self._display_notify_content_hash = None
self._display_binary_text = 'text' in entry_data.get(
'display_binary_mode', ['text'])
self._display_binary_bool = 'bool' in entry_data.get(
'display_binary_mode', ['text'])
async def init_async(self) -> None:
# Load user config and check
@ -469,6 +478,14 @@ class MIoTClient:
def display_devices_changed_notify(self) -> list[str]:
return self._display_devs_notify
@property
def display_binary_text(self) -> bool:
return self._display_binary_text
@property
def display_binary_bool(self) -> bool:
return self._display_binary_bool
@display_devices_changed_notify.setter
def display_devices_changed_notify(self, value: list[str]) -> None:
if set(value) == set(self._display_devs_notify):
@ -543,7 +560,8 @@ class MIoTClient:
return True
except Exception as err:
self.__show_client_error_notify(
message=self._i18n.translate('miot.client.invalid_oauth_info'),
message=self._i18n.translate(
'miot.client.invalid_oauth_info'), # type: ignore
notify_key='oauth_info')
_LOGGER.error(
'refresh oauth info error (%s, %s), %s, %s',
@ -586,7 +604,8 @@ class MIoTClient:
return True
except MIoTClientError as error:
self.__show_client_error_notify(
message=self._i18n.translate('miot.client.invalid_cert_info'),
message=self._i18n.translate(
'miot.client.invalid_cert_info'), # type: ignore
notify_key='user_cert')
_LOGGER.error(
'refresh user cert error, %s, %s',
@ -872,8 +891,16 @@ class MIoTClient:
# Update notify
self.__request_show_devices_changed_notify()
async def remove_device2_async(self, did_tag: str) -> None:
for did in self._device_list_cache:
d_tag = slugify_did(cloud_server=self._cloud_server, did=did)
if did_tag == d_tag:
await self.remove_device_async(did)
break
def __get_exec_error_with_rc(self, rc: int) -> str:
err_msg: str = self._i18n.translate(key=f'error.common.{rc}')
err_msg: str = self._i18n.translate(
key=f'error.common.{rc}') # type: ignore
if not err_msg:
err_msg = f'{self._i18n.translate(key="error.common.-10000")}, '
err_msg += f'code={rc}'
@ -1280,7 +1307,7 @@ class MIoTClient:
if not cache_list:
self.__show_client_error_notify(
message=self._i18n.translate(
'miot.client.invalid_device_cache'),
'miot.client.invalid_device_cache'), # type: ignore
notify_key='device_cache')
raise MIoTClientError('load device list from cache error')
else:
@ -1368,7 +1395,8 @@ class MIoTClient:
home_ids=list(self._entry_data.get('home_selected', {}).keys()))
if not result and 'devices' not in result:
self.__show_client_error_notify(
message=self._i18n.translate('miot.client.device_cloud_error'),
message=self._i18n.translate(
'miot.client.device_cloud_error'), # type: ignore
notify_key='device_cloud')
return
else:
@ -1725,13 +1753,14 @@ class MIoTClient:
@final
def __show_client_error_notify(
self, message: str, notify_key: str = ''
self, message: Optional[str], notify_key: str = ''
) -> None:
if message:
self._persistence_notify(
f'{DOMAIN}{self._uid}{self._cloud_server}{notify_key}error',
self._i18n.translate(
key='miot.client.xiaomi_home_error_title'),
key='miot.client.xiaomi_home_error_title'), # type: ignore
self._i18n.translate(
key='miot.client.xiaomi_home_error',
replace={
@ -1739,8 +1768,7 @@ class MIoTClient:
'nick_name', DEFAULT_NICK_NAME),
'uid': self._uid,
'cloud_server': self._cloud_server,
'message': message
}))
'message': message})) # type: ignore
else:
self._persistence_notify(
f'{DOMAIN}{self._uid}{self._cloud_server}{notify_key}error',
@ -1806,27 +1834,34 @@ class MIoTClient:
key='miot.client.device_list_add',
replace={
'count': count_add,
'message': message_add})
'message': message_add}) # type: ignore
if 'del' in self._display_devs_notify and count_del:
message += self._i18n.translate(
key='miot.client.device_list_del',
replace={
'count': count_del,
'message': message_del})
'message': message_del}) # type: ignore
if 'offline' in self._display_devs_notify and count_offline:
message += self._i18n.translate(
key='miot.client.device_list_offline',
replace={
'count': count_offline,
'message': message_offline})
'message': message_offline}) # type: ignore
if message != '':
msg_hash = hash(message)
if msg_hash == self._display_notify_content_hash:
# Notify content no change, return
_LOGGER.debug(
'device list changed notify content no change, return')
return
network_status = self._i18n.translate(
key='miot.client.network_status_online'
if self._network.network_status
else 'miot.client.network_status_offline')
self._persistence_notify(
self.__gen_notify_key('dev_list_changed'),
self._i18n.translate('miot.client.device_list_changed_title'),
self._i18n.translate(
'miot.client.device_list_changed_title'), # type: ignore
self._i18n.translate(
key='miot.client.device_list_changed',
replace={
@ -1835,8 +1870,8 @@ class MIoTClient:
'uid': self._uid,
'cloud_server': self._cloud_server,
'network_status': network_status,
'message': message
}))
'message': message})) # type: ignore
self._display_notify_content_hash = msg_hash
_LOGGER.debug(
'show device list changed notify, add %s, del %s, offline %s',
count_add, count_del, count_offline)

View File

@ -75,7 +75,7 @@ from homeassistant.const import (
)
from homeassistant.helpers.entity import DeviceInfo
from homeassistant.components.switch import SwitchDeviceClass
from homeassistant.util import slugify
# pylint: disable=relative-beyond-top-level
from .specs.specv2entity import (
@ -85,6 +85,7 @@ from .specs.specv2entity import (
SPEC_PROP_TRANS_MAP,
SPEC_SERVICE_TRANS_MAP
)
from .common import slugify_name, slugify_did
from .const import DOMAIN
from .miot_client import MIoTClient
from .miot_error import MIoTClientError, MIoTDeviceError
@ -146,7 +147,10 @@ class MIoTDevice:
_suggested_area: Optional[str]
_device_state_sub_list: dict[str, Callable[[str, MIoTDeviceState], None]]
_sub_id: int
_device_state_sub_list: dict[str, dict[
str, Callable[[str, MIoTDeviceState], None]]]
_value_sub_list: dict[str, dict[str, Callable[[dict, Any], None]]]
_entity_list: dict[str, list[MIoTEntityData]]
_prop_list: dict[str, list[MIoTSpecProperty]]
@ -185,7 +189,9 @@ class MIoTDevice:
case _:
self._suggested_area = None
self._sub_id = 0
self._device_state_sub_list = {}
self._value_sub_list = {}
self._entity_list = {}
self._prop_list = {}
self._event_list = {}
@ -236,40 +242,76 @@ class MIoTDevice:
def sub_device_state(
self, key: str, handler: Callable[[str, MIoTDeviceState], None]
) -> bool:
self._device_state_sub_list[key] = handler
return True
) -> int:
self._sub_id += 1
if key in self._device_state_sub_list:
self._device_state_sub_list[key][str(self._sub_id)] = handler
else:
self._device_state_sub_list[key] = {str(self._sub_id): handler}
return self._sub_id
def unsub_device_state(self, key: str) -> bool:
self._device_state_sub_list.pop(key, None)
return True
def unsub_device_state(self, key: str, sub_id: int) -> None:
sub_list = self._device_state_sub_list.get(key, None)
if sub_list:
sub_list.pop(str(sub_id), None)
if not sub_list:
self._device_state_sub_list.pop(key, None)
def sub_property(
self, handler: Callable[[dict, Any], None], siid: Optional[int] = None,
piid: Optional[int] = None, handler_ctx: Any = None
) -> bool:
return self.miot_client.sub_prop(
did=self._did, handler=handler, siid=siid, piid=piid,
handler_ctx=handler_ctx)
self, handler: Callable[[dict, Any], None], siid: int, piid: int
) -> int:
key: str = f'p.{siid}.{piid}'
def unsub_property(
self, siid: Optional[int] = None, piid: Optional[int] = None
) -> bool:
return self.miot_client.unsub_prop(did=self._did, siid=siid, piid=piid)
def _on_prop_changed(params: dict, ctx: Any) -> None:
for handler in self._value_sub_list[key].values():
handler(params, ctx)
self._sub_id += 1
if key in self._value_sub_list:
self._value_sub_list[key][str(self._sub_id)] = handler
else:
self._value_sub_list[key] = {str(self._sub_id): handler}
self.miot_client.sub_prop(
did=self._did, handler=_on_prop_changed, siid=siid, piid=piid)
return self._sub_id
def unsub_property(self, siid: int, piid: int, sub_id: int) -> None:
key: str = f'p.{siid}.{piid}'
sub_list = self._value_sub_list.get(key, None)
if sub_list:
sub_list.pop(str(sub_id), None)
if not sub_list:
self.miot_client.unsub_prop(did=self._did, siid=siid, piid=piid)
self._value_sub_list.pop(key, None)
def sub_event(
self, handler: Callable[[dict, Any], None], siid: Optional[int] = None,
eiid: Optional[int] = None, handler_ctx: Any = None
) -> bool:
return self.miot_client.sub_event(
did=self._did, handler=handler, siid=siid, eiid=eiid,
handler_ctx=handler_ctx)
self, handler: Callable[[dict, Any], None], siid: int, eiid: int
) -> int:
key: str = f'e.{siid}.{eiid}'
def unsub_event(
self, siid: Optional[int] = None, eiid: Optional[int] = None
) -> bool:
return self.miot_client.unsub_event(
did=self._did, siid=siid, eiid=eiid)
def _on_event_occurred(params: dict, ctx: Any) -> None:
for handler in self._value_sub_list[key].values():
handler(params, ctx)
self._sub_id += 1
if key in self._value_sub_list:
self._value_sub_list[key][str(self._sub_id)] = handler
else:
self._value_sub_list[key] = {str(self._sub_id): handler}
self.miot_client.sub_event(
did=self._did, handler=_on_event_occurred, siid=siid, eiid=eiid)
return self._sub_id
def unsub_event(self, siid: int, eiid: int, sub_id: int) -> None:
key: str = f'e.{siid}.{eiid}'
sub_list = self._value_sub_list.get(key, None)
if sub_list:
sub_list.pop(str(sub_id), None)
if not sub_list:
self.miot_client.unsub_event(did=self._did, siid=siid, eiid=eiid)
self._value_sub_list.pop(key, None)
@property
def device_info(self) -> DeviceInfo:
@ -293,11 +335,8 @@ class MIoTDevice:
@property
def did_tag(self) -> str:
return slugify(f'{self.miot_client.cloud_server}_{self._did}')
@staticmethod
def gen_did_tag(cloud_server: str, did: str) -> str:
return slugify(f'{cloud_server}_{did}')
return slugify_did(
cloud_server=self.miot_client.cloud_server, did=self._did)
def gen_device_entity_id(self, ha_domain: str) -> str:
return (
@ -314,21 +353,24 @@ class MIoTDevice:
) -> str:
return (
f'{ha_domain}.{self._model_strs[0][:9]}_{self.did_tag}_'
f'{self._model_strs[-1][:20]}_{slugify(spec_name)}_p_{siid}_{piid}')
f'{self._model_strs[-1][:20]}_{slugify_name(spec_name)}'
f'_p_{siid}_{piid}')
def gen_event_entity_id(
self, ha_domain: str, spec_name: str, siid: int, eiid: int
) -> str:
return (
f'{ha_domain}.{self._model_strs[0][:9]}_{self.did_tag}_'
f'{self._model_strs[-1][:20]}_{slugify(spec_name)}_e_{siid}_{eiid}')
f'{self._model_strs[-1][:20]}_{slugify_name(spec_name)}'
f'_e_{siid}_{eiid}')
def gen_action_entity_id(
self, ha_domain: str, spec_name: str, siid: int, aiid: int
) -> str:
return (
f'{ha_domain}.{self._model_strs[0][:9]}_{self.did_tag}_'
f'{self._model_strs[-1][:20]}_{slugify(spec_name)}_a_{siid}_{aiid}')
f'{self._model_strs[-1][:20]}_{slugify_name(spec_name)}'
f'_a_{siid}_{aiid}')
@property
def name(self) -> str:
@ -347,14 +389,20 @@ class MIoTDevice:
self._entity_list[entity_data.platform].append(entity_data)
def append_prop(self, prop: MIoTSpecProperty) -> None:
if not prop.platform:
return
self._prop_list.setdefault(prop.platform, [])
self._prop_list[prop.platform].append(prop)
def append_event(self, event: MIoTSpecEvent) -> None:
if not event.platform:
return
self._event_list.setdefault(event.platform, [])
self._event_list[event.platform].append(event)
def append_action(self, action: MIoTSpecAction) -> None:
if not action.platform:
return
self._action_list.setdefault(action.platform, [])
self._action_list[action.platform].append(action)
@ -579,9 +627,11 @@ class MIoTDevice:
# Irregular property will not be transformed.
pass
elif prop.readable or prop.notifiable:
prop.platform = 'sensor'
if prop.platform:
self.append_prop(prop=prop)
if prop.format_ == bool:
prop.platform = 'binary_sensor'
else:
prop.platform = 'sensor'
self.append_prop(prop=prop)
# STEP 3.2: event conversion
for event in service.events:
if event.platform:
@ -710,9 +760,10 @@ class MIoTDevice:
self, did: str, state: MIoTDeviceState, ctx: Any
) -> None:
self._online = state == MIoTDeviceState.ONLINE
for key, handler in self._device_state_sub_list.items():
self.miot_client.main_loop.call_soon_threadsafe(
handler, key, state)
for key, sub_list in self._device_state_sub_list.items():
for handler in sub_list.values():
self.miot_client.main_loop.call_soon_threadsafe(
handler, key, state)
class MIoTServiceEntity(Entity):
@ -724,6 +775,8 @@ class MIoTServiceEntity(Entity):
_main_loop: asyncio.AbstractEventLoop
_prop_value_map: dict[MIoTSpecProperty, Any]
_state_sub_id: int
_value_sub_ids: dict[str, int]
_event_occurred_handler: Optional[
Callable[[MIoTSpecEvent, dict], None]]
@ -745,13 +798,15 @@ class MIoTServiceEntity(Entity):
self.entity_data = entity_data
self._main_loop = miot_device.miot_client.main_loop
self._prop_value_map = {}
self._state_sub_id = 0
self._value_sub_ids = {}
# Gen entity id
if isinstance(entity_data.spec, MIoTSpecInstance):
if isinstance(self.entity_data.spec, MIoTSpecInstance):
self.entity_id = miot_device.gen_device_entity_id(DOMAIN)
self._attr_name = f' {self.entity_data.spec.description_trans}'
elif isinstance(entity_data.spec, MIoTSpecService):
elif isinstance(self.entity_data.spec, MIoTSpecService):
self.entity_id = miot_device.gen_service_entity_id(
DOMAIN, siid=entity_data.spec.iid)
DOMAIN, siid=self.entity_data.spec.iid)
self._attr_name = (
f'{"* "if self.entity_data.spec.proprietary else " "}'
f'{self.entity_data.spec.description_trans}')
@ -800,18 +855,20 @@ class MIoTServiceEntity(Entity):
state_id = 's.0'
if isinstance(self.entity_data.spec, MIoTSpecService):
state_id = f's.{self.entity_data.spec.iid}'
self.miot_device.sub_device_state(
self._state_sub_id = self.miot_device.sub_device_state(
key=state_id, handler=self.__on_device_state_changed)
# Sub prop
for prop in self.entity_data.props:
if not prop.notifiable and not prop.readable:
continue
self.miot_device.sub_property(
key = f'p.{prop.service.iid}.{prop.iid}'
self._value_sub_ids[key] = self.miot_device.sub_property(
handler=self.__on_properties_changed,
siid=prop.service.iid, piid=prop.iid)
# Sub event
for event in self.entity_data.events:
self.miot_device.sub_event(
key = f'e.{event.service.iid}.{event.iid}'
self._value_sub_ids[key] = self.miot_device.sub_event(
handler=self.__on_event_occurred,
siid=event.service.iid, eiid=event.iid)
@ -826,17 +883,24 @@ class MIoTServiceEntity(Entity):
state_id = 's.0'
if isinstance(self.entity_data.spec, MIoTSpecService):
state_id = f's.{self.entity_data.spec.iid}'
self.miot_device.unsub_device_state(key=state_id)
self.miot_device.unsub_device_state(
key=state_id, sub_id=self._state_sub_id)
# Unsub prop
for prop in self.entity_data.props:
if not prop.notifiable and not prop.readable:
continue
self.miot_device.unsub_property(
siid=prop.service.iid, piid=prop.iid)
sub_id = self._value_sub_ids.pop(
f'p.{prop.service.iid}.{prop.iid}', None)
if sub_id:
self.miot_device.unsub_property(
siid=prop.service.iid, piid=prop.iid, sub_id=sub_id)
# Unsub event
for event in self.entity_data.events:
self.miot_device.unsub_event(
siid=event.service.iid, eiid=event.iid)
sub_id = self._value_sub_ids.pop(
f'e.{event.service.iid}.{event.iid}', None)
if sub_id:
self.miot_device.unsub_event(
siid=event.service.iid, eiid=event.iid, sub_id=sub_id)
def get_map_value(
self, map_: dict[int, Any], key: int
@ -1014,6 +1078,8 @@ class MIoTPropertyEntity(Entity):
# {Any: Any}
_value_list: Optional[MIoTSpecValueList]
_value: Any
_state_sub_id: int
_value_sub_id: int
_pending_write_ha_state_timer: Optional[asyncio.TimerHandle]
@ -1027,6 +1093,8 @@ class MIoTPropertyEntity(Entity):
self._value_range = spec.value_range
self._value_list = spec.value_list
self._value = None
self._state_sub_id = 0
self._value_sub_id = 0
self._pending_write_ha_state_timer = None
# Gen entity_id
self.entity_id = self.miot_device.gen_prop_entity_id(
@ -1053,11 +1121,11 @@ class MIoTPropertyEntity(Entity):
async def async_added_to_hass(self) -> None:
# Sub device state changed
self.miot_device.sub_device_state(
self._state_sub_id = self.miot_device.sub_device_state(
key=f'{ self.service.iid}.{self.spec.iid}',
handler=self.__on_device_state_changed)
# Sub value changed
self.miot_device.sub_property(
self._value_sub_id = self.miot_device.sub_property(
handler=self.__on_value_changed,
siid=self.service.iid, piid=self.spec.iid)
# Refresh value
@ -1069,9 +1137,11 @@ class MIoTPropertyEntity(Entity):
self._pending_write_ha_state_timer.cancel()
self._pending_write_ha_state_timer = None
self.miot_device.unsub_device_state(
key=f'{ self.service.iid}.{self.spec.iid}')
key=f'{ self.service.iid}.{self.spec.iid}',
sub_id=self._state_sub_id)
self.miot_device.unsub_property(
siid=self.service.iid, piid=self.spec.iid)
siid=self.service.iid, piid=self.spec.iid,
sub_id=self._value_sub_id)
def get_vlist_description(self, value: Any) -> Optional[str]:
if not self._value_list:
@ -1151,9 +1221,10 @@ class MIoTEventEntity(Entity):
service: MIoTSpecService
_main_loop: asyncio.AbstractEventLoop
_value: Any
_attr_event_types: list[str]
_arguments_map: dict[int, str]
_state_sub_id: int
_value_sub_id: int
def __init__(self, miot_device: MIoTDevice, spec: MIoTSpecEvent) -> None:
if miot_device is None or spec is None or spec.service is None:
@ -1162,7 +1233,6 @@ class MIoTEventEntity(Entity):
self.spec = spec
self.service = spec.service
self._main_loop = miot_device.miot_client.main_loop
self._value = None
# Gen entity_id
self.entity_id = self.miot_device.gen_event_entity_id(
ha_domain=DOMAIN, spec_name=spec.name,
@ -1180,6 +1250,8 @@ class MIoTEventEntity(Entity):
self._arguments_map = {}
for prop in spec.argument:
self._arguments_map[prop.iid] = prop.description_trans
self._state_sub_id = 0
self._value_sub_id = 0
_LOGGER.info(
'new miot event entity, %s, %s, %s, %s, %s',
@ -1192,24 +1264,26 @@ class MIoTEventEntity(Entity):
async def async_added_to_hass(self) -> None:
# Sub device state changed
self.miot_device.sub_device_state(
self._state_sub_id = self.miot_device.sub_device_state(
key=f'event.{ self.service.iid}.{self.spec.iid}',
handler=self.__on_device_state_changed)
# Sub value changed
self.miot_device.sub_event(
self._value_sub_id = self.miot_device.sub_event(
handler=self.__on_event_occurred,
siid=self.service.iid, eiid=self.spec.iid)
async def async_will_remove_from_hass(self) -> None:
self.miot_device.unsub_device_state(
key=f'event.{ self.service.iid}.{self.spec.iid}')
key=f'event.{ self.service.iid}.{self.spec.iid}',
sub_id=self._state_sub_id)
self.miot_device.unsub_event(
siid=self.service.iid, eiid=self.spec.iid)
siid=self.service.iid, eiid=self.spec.iid,
sub_id=self._value_sub_id)
@abstractmethod
def on_event_occurred(
self, name: str, arguments: list[dict[int, Any]]
): ...
self, name: str, arguments: dict[str, Any] | None = None
) -> None: ...
def __on_event_occurred(self, params: dict, ctx: Any) -> None:
_LOGGER.debug('event occurred, %s', params)
@ -1256,11 +1330,11 @@ class MIoTActionEntity(Entity):
miot_device: MIoTDevice
spec: MIoTSpecAction
service: MIoTSpecService
action_platform: str
_main_loop: asyncio.AbstractEventLoop
_in_map: dict[int, MIoTSpecProperty]
_out_map: dict[int, MIoTSpecProperty]
_state_sub_id: int
def __init__(self, miot_device: MIoTDevice, spec: MIoTSpecAction) -> None:
if miot_device is None or spec is None or spec.service is None:
@ -1268,8 +1342,8 @@ class MIoTActionEntity(Entity):
self.miot_device = miot_device
self.spec = spec
self.service = spec.service
self.action_platform = 'action'
self._main_loop = miot_device.miot_client.main_loop
self._state_sub_id = 0
# Gen entity_id
self.entity_id = self.miot_device.gen_action_entity_id(
ha_domain=DOMAIN, spec_name=spec.name,
@ -1293,13 +1367,14 @@ class MIoTActionEntity(Entity):
return self.miot_device.device_info
async def async_added_to_hass(self) -> None:
self.miot_device.sub_device_state(
key=f'{self.action_platform}.{ self.service.iid}.{self.spec.iid}',
self._state_sub_id = self.miot_device.sub_device_state(
key=f'a.{ self.service.iid}.{self.spec.iid}',
handler=self.__on_device_state_changed)
async def async_will_remove_from_hass(self) -> None:
self.miot_device.unsub_device_state(
key=f'{self.action_platform}.{ self.service.iid}.{self.spec.iid}')
key=f'a.{ self.service.iid}.{self.spec.iid}',
sub_id=self._state_sub_id)
async def action_async(
self, in_list: Optional[list] = None

View File

@ -663,7 +663,8 @@ class _MipsClient(ABC):
def __on_disconnect(self, client, user_data, rc, props) -> None:
if self._mqtt_state:
self.log_error(f'mips disconnect, {rc}, {props}')
(self.log_info if rc == 0 else self.log_error)(
f'mips disconnect, {rc}, {props}')
self._mqtt_state = False
if self._mqtt_timer:
self._mqtt_timer.cancel()

View File

@ -155,6 +155,7 @@ class MIoTSpecValueListItem:
class MIoTSpecValueList:
"""MIoT SPEC value list class."""
# pylint: disable=inconsistent-quotes
items: list[MIoTSpecValueListItem]
def __init__(self, value_list: list[dict]) -> None:
@ -218,6 +219,7 @@ class MIoTSpecValueList:
class _SpecStdLib:
"""MIoT-Spec-V2 standard library."""
# pylint: disable=inconsistent-quotes
_lang: str
_devices: dict[str, dict[str, str]]
_services: dict[str, dict[str, str]]
@ -463,10 +465,10 @@ class _MIoTSpecBase:
iid: int
type_: str
description: str
description_trans: Optional[str]
description_trans: str
proprietary: bool
need_filter: bool
name: Optional[str]
name: str
# External params
platform: Optional[str]
@ -486,7 +488,7 @@ class _MIoTSpecBase:
self.description_trans = spec.get('description_trans', None)
self.proprietary = spec.get('proprietary', False)
self.need_filter = spec.get('need_filter', False)
self.name = spec.get('name', None)
self.name = spec.get('name', 'xiaomi')
self.platform = None
self.device_class = None
@ -975,8 +977,8 @@ class _SpecBoolTranslation:
DEFAULT_INTEGRATION_LANGUAGE, None))
if data_default:
self._data_default = [
{'value': True, 'description': data_default[True]},
{'value': False, 'description': data_default[False]}
{'value': True, 'description': data_default['true']},
{'value': False, 'description': data_default['false']}
]
for urn, key in data['data'].items():
@ -989,8 +991,8 @@ class _SpecBoolTranslation:
DEFAULT_INTEGRATION_LANGUAGE, None))
if trans_data:
self._data[urn] = [
{'value': True, 'description': trans_data[True]},
{'value': False, 'description': trans_data[False]}
{'value': True, 'description': trans_data['true']},
{'value': False, 'description': trans_data['false']}
]
async def deinit_async(self) -> None:
@ -1270,7 +1272,7 @@ class MIoTSpecParser:
urn_strs: list[str] = urn.split(':')
urn_key: str = ':'.join(urn_strs[:6])
# Set translation cache
await self._multi_lang.set_spec_async(urn=urn_key)
await self._multi_lang.set_spec_async(urn=urn)
# Set spec filter
await self._spec_filter.set_spec_spec(urn_key=urn_key)
# Parse device type
@ -1344,6 +1346,8 @@ class MIoTSpecParser:
elif 'value-list' in property_:
v_list: list[dict] = property_['value-list']
for index, v in enumerate(v_list):
if v['description'].strip() == '':
v['description'] = f'v_{v["value"]}'
v['name'] = v['description']
v['description'] = (
self._multi_lang.translate(

View File

@ -58,7 +58,6 @@ from enum import Enum, auto
from pathlib import Path
from typing import Any, Optional, Union
import logging
from urllib.request import Request, urlopen
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.backends import default_backend
from cryptography.x509.oid import NameOID
@ -66,13 +65,13 @@ from cryptography import x509
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import ed25519
# pylint: disable=relative-beyond-top-level
from .common import load_json_file
from .const import (
DEFAULT_INTEGRATION_LANGUAGE,
MANUFACTURER_EFFECTIVE_TIME,
MIHOME_CA_CERT_STR,
MIHOME_CA_CERT_SHA256)
from .common import MIoTHttp
from .miot_error import MIoTCertError, MIoTError, MIoTStorageError
_LOGGER = logging.getLogger(__name__)
@ -93,10 +92,10 @@ class MIoTStorage:
User data will be stored in the `.storage` directory of Home Assistant.
"""
_main_loop: asyncio.AbstractEventLoop = None
_main_loop: asyncio.AbstractEventLoop
_file_future: dict[str, tuple[MIoTStorageType, asyncio.Future]]
_root_path: str = None
_root_path: str
def __init__(
self, root_path: str,
@ -140,7 +139,7 @@ class MIoTStorage:
if r_data is None:
_LOGGER.error('load error, empty file, %s', full_path)
return None
data_bytes: bytes = None
data_bytes: bytes
# Hash check
if with_hash_check:
if len(r_data) <= 32:
@ -209,17 +208,17 @@ class MIoTStorage:
else:
os.makedirs(os.path.dirname(full_path), exist_ok=True)
try:
type_: type = type(data)
w_bytes: bytes = None
if type_ == bytes:
w_bytes: bytes
if isinstance(data, bytes):
w_bytes = data
elif type_ == str:
elif isinstance(data, str):
w_bytes = data.encode('utf-8')
elif type_ in [dict, list]:
elif isinstance(data, (dict, list)):
w_bytes = json.dumps(data).encode('utf-8')
else:
_LOGGER.error(
'save error, unsupported data type, %s', type_.__name__)
'save error, unsupported data type, %s',
type(data).__name__)
return False
with open(full_path, 'wb') as w_file:
w_file.write(w_bytes)
@ -353,7 +352,8 @@ class MIoTStorage:
def load_file(self, domain: str, name_with_suffix: str) -> Optional[bytes]:
full_path = os.path.join(self._root_path, domain, name_with_suffix)
return self.__load(
full_path=full_path, type_=bytes, with_hash_check=False)
full_path=full_path, type_=bytes,
with_hash_check=False) # type: ignore
async def load_file_async(
self, domain: str, name_with_suffix: str
@ -371,7 +371,7 @@ class MIoTStorage:
None, self.__load, full_path, bytes, False)
if not fut.done():
self.__add_file_future(full_path, MIoTStorageType.LOAD_FILE, fut)
return await fut
return await fut # type: ignore
def remove_file(self, domain: str, name_with_suffix: str) -> bool:
full_path = os.path.join(self._root_path, domain, name_with_suffix)
@ -438,7 +438,7 @@ class MIoTStorage:
domain=config_domain, name=config_name, data=config)
local_config = (self.load(domain=config_domain,
name=config_name, type_=dict)) or {}
local_config.update(config)
local_config.update(config) # type: ignore
return self.save(
domain=config_domain, name=config_name, data=local_config)
@ -474,27 +474,31 @@ class MIoTStorage:
domain=config_domain, name=config_name, data=config)
local_config = (await self.load_async(
domain=config_domain, name=config_name, type_=dict)) or {}
local_config.update(config)
local_config.update(config) # type: ignore
return await self.save_async(
domain=config_domain, name=config_name, data=local_config)
def load_user_config(
self, uid: str, cloud_server: str, keys: Optional[list[str]] = None
) -> dict[str, Any]:
if keys is not None and len(keys) == 0:
if isinstance(keys, list) and len(keys) == 0:
# Do nothing
return {}
config_domain = 'miot_config'
config_name = f'{uid}_{cloud_server}'
local_config = (self.load(domain=config_domain,
name=config_name, type_=dict)) or {}
name=config_name, type_=dict))
if not isinstance(local_config, dict):
return {}
if keys is None:
return local_config
return {key: local_config.get(key, None) for key in keys}
return {
key: local_config[key] for key in keys
if key in local_config}
async def load_user_config_async(
self, uid: str, cloud_server: str, keys: Optional[list[str]] = None
) -> dict[str, Any]:
) -> dict:
"""Load user configuration.
Args:
@ -505,13 +509,15 @@ class MIoTStorage:
Returns:
dict[str, Any]: query result
"""
if keys is not None and len(keys) == 0:
if isinstance(keys, list) and len(keys) == 0:
# Do nothing
return {}
config_domain = 'miot_config'
config_name = f'{uid}_{cloud_server}'
local_config = (await self.load_async(
domain=config_domain, name=config_name, type_=dict)) or {}
domain=config_domain, name=config_name, type_=dict))
if not isinstance(local_config, dict):
return {}
if keys is None:
return local_config
return {
@ -519,7 +525,8 @@ class MIoTStorage:
if key in local_config}
def gen_storage_path(
self, domain: str = None, name_with_suffix: str = None
self, domain: Optional[str] = None,
name_with_suffix: Optional[str] = None
) -> str:
"""Generate file path."""
result = self._root_path
@ -609,9 +616,8 @@ class MIoTCert:
if cert_data is None:
return 0
# Check user cert
user_cert: x509.Certificate = None
try:
user_cert = x509.load_pem_x509_certificate(
user_cert: x509.Certificate = x509.load_pem_x509_certificate(
cert_data, default_backend())
cert_info = {}
for attribute in user_cert.subject:
@ -669,7 +675,8 @@ class MIoTCert:
NameOID.COMMON_NAME, f'mips.{self._uid}.{did_hash}.2'),
]))
csr = builder.sign(
private_key, algorithm=None, backend=default_backend())
private_key, algorithm=None, # type: ignore
backend=default_backend())
return csr.public_bytes(serialization.Encoding.PEM).decode('utf-8')
async def load_user_key_async(self) -> Optional[str]:
@ -732,12 +739,11 @@ class DeviceManufacturer:
) -> None:
self._main_loop = loop or asyncio.get_event_loop()
self._storage = storage
self._data = None
self._data = {}
async def init_async(self) -> None:
if self._data:
return
data_cache: dict = None
data_cache = await self._storage.load_async(
domain=self.DOMAIN, name='manufacturer', type_=dict)
if (
@ -751,8 +757,15 @@ class DeviceManufacturer:
_LOGGER.debug('load manufacturer data success')
return
data_cloud = await self._main_loop.run_in_executor(
None, self.__get_manufacturer_data)
data_cloud = None
try:
data_cloud = await MIoTHttp.get_json_async(
url='https://cdn.cnbj1.fds.api.mi-img.com/res-conf/xiaomi-home/'
'manufacturer.json',
loop=self._main_loop)
except Exception as err: # pylint: disable=broad-exception-caught
_LOGGER.error('get manufacturer info failed, %s', err)
if data_cloud:
await self._storage.save_async(
domain=self.DOMAIN, name='manufacturer',
@ -760,32 +773,16 @@ class DeviceManufacturer:
self._data = data_cloud
_LOGGER.debug('update manufacturer data success')
else:
if data_cache:
self._data = data_cache.get('data', None)
if isinstance(data_cache, dict):
self._data = data_cache.get('data', {})
_LOGGER.error('load manufacturer data failed, use local data')
else:
_LOGGER.error('load manufacturer data failed')
async def deinit_async(self) -> None:
self._data = None
self._data.clear()
def get_name(self, short_name: str) -> str:
if not self._data or not short_name or short_name not in self._data:
return short_name
return self._data[short_name].get('name', None) or short_name
def __get_manufacturer_data(self) -> dict:
try:
request = Request(
'https://cdn.cnbj1.fds.api.mi-img.com/res-conf/xiaomi-home/'
'manufacturer.json',
method='GET')
content: bytes = None
with urlopen(request) as response:
content = response.read()
return (
json.loads(str(content, 'utf-8'))
if content else None)
except Exception as err: # pylint: disable=broad-exception-caught
_LOGGER.error('get manufacturer info failed, %s', err)
return None

View File

@ -59,173 +59,188 @@ data:
urn:miot-spec-v2:property:wifi-ssid-hidden:000000E3: yes_no
urn:miot-spec-v2:property:wind-reverse:00000117: yes_no
translate:
default:
de:
true: Wahr
false: Falsch
en:
true: True
false: False
es:
true: Verdadero
false: Falso
fr:
true: Vrai
false: Faux
ja:
true:
false:
nl:
true: True
false: False
pt:
true: True
false: False
pt-BR:
true: True
false: False
ru:
true: Истина
false: Ложь
zh-Hans:
true:
false:
zh-Hant:
true:
false:
open_close:
de:
true: Öffnen
false: Schließen
en:
true: Open
false: Close
es:
true: Abierto
false: Cerrado
fr:
true: Ouvert
false: Fermer
ja:
true: 開く
false: 閉じる
nl:
true: Open
false: Dicht
pt:
true: Aberto
false: Fechado
pt-BR:
true: Aberto
false: Fechado
ru:
true: Открыть
false: Закрыть
zh-Hans:
true: 开启
false: 关闭
zh-Hant:
true: 開啟
false: 關閉
yes_no:
de:
true: Ja
false: Nein
en:
true: Yes
false: No
es:
true:
false: No
fr:
true: Oui
false: Non
ja:
true: はい
false: いいえ
nl:
true: Ja
false: Nee
pt:
true: Sim
false: Não
pt-BR:
true: Sim
false: Não
ru:
true: Да
false: Нет
zh-Hans:
true:
false:
zh-Hant:
true:
false:
motion_state:
de:
true: Bewegung erkannt
false: Keine Bewegung erkannt
en:
true: Motion Detected
false: No Motion Detected
es:
true: Movimiento detectado
false: No se detecta movimiento
fr:
true: Mouvement détecté
false: Aucun mouvement détecté
ja:
true: 動きを検知
false: 動きが検出されません
nl:
true: Contact
false: Geen contact
pt:
true: Contato
false: Sem contato
pt-BR:
true: Contato
false: Sem contato
ru:
true: Обнаружено движение
false: Движение не обнаружено
zh-Hans:
true: 有人
false: 无人
zh-Hant:
true: 有人
false: 無人
contact_state:
de:
true: Kontakt
false: Kein Kontakt
'false': Kein Kontakt
'true': Kontakt
en:
true: Contact
false: No Contact
'false': No Contact
'true': Contact
es:
true: Contacto
false: Sin contacto
'false': Sin contacto
'true': Contacto
fr:
true: Contact
false: Pas de contact
'false': Pas de contact
'true': Contact
it:
'false': Nessun contatto
'true': Contatto
ja:
true: 接触
false: 非接触
'false': 非接触
'true': 接触
nl:
true: Contact
false: Geen contact
'false': Geen contact
'true': Contact
pt:
true: Contato
false: Sem contato
'false': Sem contato
'true': Contato
pt-BR:
true: Contato
false: Sem contato
'false': Sem contato
'true': Contato
ru:
true: Контакт
false: Нет контакта
'false': Нет контакта
'true': Контакт
zh-Hans:
true: 接触
false: 分离
'false': 分离
'true': 接触
zh-Hant:
true: 接觸
false: 分離
'false': 分離
'true': 接觸
default:
de:
'false': Falsch
'true': Wahr
en:
'false': 'False'
'true': 'True'
es:
'false': Falso
'true': Verdadero
fr:
'false': Faux
'true': Vrai
it:
'false': Falso
'true': Vero
ja:
'false':
'true':
nl:
'false': 'False'
'true': 'True'
pt:
'false': 'False'
'true': 'True'
pt-BR:
'false': 'False'
'true': 'True'
ru:
'false': Ложь
'true': Истина
zh-Hans:
'false':
'true':
zh-Hant:
'false':
'true':
motion_state:
de:
'false': Keine Bewegung erkannt
'true': Bewegung erkannt
en:
'false': No Motion Detected
'true': Motion Detected
es:
'false': No se detecta movimiento
'true': Movimiento detectado
fr:
'false': Aucun mouvement détecté
'true': Mouvement détecté
it:
'false': Nessun Movimento Rilevato
'true': Movimento Rilevato
ja:
'false': 動きが検出されません
'true': 動きを検知
nl:
'false': Geen contact
'true': Contact
pt:
'false': Sem contato
'true': Contato
pt-BR:
'false': Sem contato
'true': Contato
ru:
'false': Движение не обнаружено
'true': Обнаружено движение
zh-Hans:
'false': 无人
'true': 有人
zh-Hant:
'false': 無人
'true': 有人
open_close:
de:
'false': Schließen
'true': Öffnen
en:
'false': Close
'true': Open
es:
'false': Cerrado
'true': Abierto
fr:
'false': Fermer
'true': Ouvert
it:
'false': Chiuso
'true': Aperto
ja:
'false': 閉じる
'true': 開く
nl:
'false': Dicht
'true': Open
pt:
'false': Fechado
'true': Aberto
pt-BR:
'false': Fechado
'true': Aberto
ru:
'false': Закрыть
'true': Открыть
zh-Hans:
'false': 关闭
'true': 开启
zh-Hant:
'false': 關閉
'true': 開啟
yes_no:
de:
'false': Nein
'true': Ja
en:
'false': 'No'
'true': 'Yes'
es:
'false': 'No'
'true':
fr:
'false': Non
'true': Oui
it:
'false': 'No'
'true': Si
ja:
'false': いいえ
'true': はい
nl:
'false': Nee
'true': Ja
pt:
'false': Não
'true': Sim
pt-BR:
'false': Não
'true': Sim
ru:
'false': Нет
'true': Да
zh-Hans:
'false':
'true':
zh-Hant:
'false':
'true':

View File

@ -1,43 +1,43 @@
urn:miot-spec-v2:device:air-purifier:0000A007:zhimi-ma4:
properties:
- "9.*"
- "13.*"
- "15.*"
- 9.*
- 13.*
- 15.*
services:
- "10"
- '10'
urn:miot-spec-v2:device:curtain:0000A00C:lumi-hmcn01:
properties:
- "5.1"
- '5.1'
services:
- "4"
- "7"
- "8"
- '4'
- '7'
- '8'
urn:miot-spec-v2:device:gateway:0000A019:xiaomi-hub1:
events:
- "2.1"
- '2.1'
urn:miot-spec-v2:device:health-pot:0000A051:chunmi-a1:
services:
- "5"
- '5'
urn:miot-spec-v2:device:light:0000A001:philips-strip3:
properties:
- "2.2"
- '2.2'
services:
- "1"
- "3"
- '1'
- '3'
urn:miot-spec-v2:device:light:0000A001:yeelink-color2:
properties:
- "3.*"
- "2.5"
- 3.*
- '2.5'
urn:miot-spec-v2:device:light:0000A001:yeelink-dnlight2:
services:
- "3"
- '3'
urn:miot-spec-v2:device:light:0000A001:yeelink-mbulb3:
services:
- "3"
- '3'
urn:miot-spec-v2:device:motion-sensor:0000A014:xiaomi-pir1:
services:
- "1"
- "5"
- '1'
- '5'
urn:miot-spec-v2:device:router:0000A036:xiaomi-rd03:
services:
- "*"
- '*'

View File

@ -76,6 +76,12 @@ async def async_setup_entry(
for prop in miot_device.prop_list.get('sensor', []):
new_entities.append(Sensor(miot_device=miot_device, spec=prop))
if miot_device.miot_client.display_binary_text:
for prop in miot_device.prop_list.get('binary_sensor', []):
if not prop.value_list:
continue
new_entities.append(Sensor(miot_device=miot_device, spec=prop))
if new_entities:
async_add_entities(new_entities)
@ -100,15 +106,15 @@ class Sensor(MIoTPropertyEntity, SensorEntity):
# device_class is not empty but unit is empty.
# Set the default unit according to device_class.
unit_sets = DEVICE_CLASS_UNITS.get(
self._attr_device_class, None)
self._attr_device_class, None) # type: ignore
self._attr_native_unit_of_measurement = list(
unit_sets)[0] if unit_sets else None
# Set state_class
if spec.state_class:
self._attr_state_class = spec.state_class
# Set icon
if spec.icon:
self._attr_icon = spec.icon
# Set state_class
if spec.state_class:
self._attr_state_class = spec.state_class
@property
def native_value(self) -> Any:

View File

@ -76,9 +76,10 @@ async def async_setup_entry(
for prop in miot_device.prop_list.get('text', []):
new_entities.append(Text(miot_device=miot_device, spec=prop))
for action in miot_device.action_list.get('action_text', []):
new_entities.append(ActionText(
miot_device=miot_device, spec=action))
if miot_device.miot_client.action_debug:
for action in miot_device.action_list.get('notify', []):
new_entities.append(ActionText(
miot_device=miot_device, spec=action))
if new_entities:
async_add_entities(new_entities)
@ -114,8 +115,6 @@ class ActionText(MIoTActionEntity, TextEntity):
f'{prop.description_trans}({prop.format_.__name__})'
for prop in self.spec.in_])
self._attr_extra_state_attributes['action params'] = f'[{action_in}]'
# For action debug
self.action_platform = 'action_text'
async def async_set_value(self, value: str) -> None:
if not value:

View File

@ -42,12 +42,13 @@
},
"advanced_options": {
"title": "Erweiterte Einstellungen",
"description": "## Gebrauchsanweisung\r\n### Wenn Sie die Bedeutung der folgenden Optionen nicht genau kennen, belassen Sie sie bitte auf den Standardeinstellungen.\r\n### Geräte filtern\r\nUnterstützt das Filtern von Geräten nach Raumnamen und Gerätetypen sowie das Filtern nach Gerätedimensionen.\r\n\r\n### Steuerungsmodus\r\n- Automatisch: Wenn ein verfügbarer Xiaomi-Hub im lokalen Netzwerk vorhanden ist, priorisiert Home Assistant das Senden von Steuerbefehlen über den Hub, um eine lokale Steuerung zu ermöglichen. Wenn kein Hub vorhanden ist, wird versucht, Steuerbefehle über das Xiaomi-OT-Protokoll zu senden. Nur wenn diese Bedingungen für die lokale Steuerung nicht erfüllt sind, werden die Befehle über die Cloud gesendet.\r\n- Cloud: Steuerbefehle werden ausschließlich über die Cloud gesendet.\r\n### Action-Debug-Modus\r\nFür Methoden, die von MIoT-Spec-V2-Geräten definiert werden, wird neben der Benachrichtigungsentität auch eine Texteingabe-Entität erstellt, mit der Sie während des Debuggens Steuerbefehle an das Gerät senden können.\r\n### Nicht standardmäßige Entitäten ausblenden\r\nBlendet Entitäten aus, die von nicht-standardmäßigen MIoT-Spec-V2-Instanzen generiert werden und deren Name mit „*“ beginnt.\r\n### Gerätestatusänderungen anzeigen\r\nDetaillierte Anzeige von Gerätestatusänderungen, es werden nur die ausgewählten Benachrichtigungen angezeigt.",
"description": "## Gebrauchsanweisung\r\n### Wenn Sie die Bedeutung der folgenden Optionen nicht genau kennen, belassen Sie sie bitte auf den Standardeinstellungen.\r\n### Geräte filtern\r\nUnterstützt das Filtern von Geräten nach Raumnamen und Gerätetypen sowie das Filtern nach Gerätedimensionen.\r\n\r\n### Steuerungsmodus\r\n- Automatisch: Wenn ein verfügbarer Xiaomi-Hub im lokalen Netzwerk vorhanden ist, priorisiert Home Assistant das Senden von Steuerbefehlen über den Hub, um eine lokale Steuerung zu ermöglichen. Wenn kein Hub vorhanden ist, wird versucht, Steuerbefehle über das Xiaomi-OT-Protokoll zu senden. Nur wenn diese Bedingungen für die lokale Steuerung nicht erfüllt sind, werden die Befehle über die Cloud gesendet.\r\n- Cloud: Steuerbefehle werden ausschließlich über die Cloud gesendet.\r\n### Action-Debug-Modus\r\nFür Methoden, die von MIoT-Spec-V2-Geräten definiert werden, wird neben der Benachrichtigungsentität auch eine Texteingabe-Entität erstellt, mit der Sie während des Debuggens Steuerbefehle an das Gerät senden können.\r\n### Nicht standardmäßige Entitäten ausblenden\r\nBlendet Entitäten aus, die von nicht-standardmäßigen MIoT-Spec-V2-Instanzen generiert werden und deren Name mit „*“ beginnt.\r\n### Binärsensor-Anzeigemodus\r\nZeigt Binärsensoren in Xiaomi Home als Textsensor-Entität oder Binärsensor-Entität an。\r\n### Gerätestatusänderungen anzeigen\r\nDetaillierte Anzeige von Gerätestatusänderungen, es werden nur die ausgewählten Benachrichtigungen angezeigt.",
"data": {
"devices_filter": "Geräte filtern",
"ctrl_mode": "Steuerungsmodus",
"action_debug": "Action-Debug-Modus",
"hide_non_standard_entities": "Nicht standardmäßige Entitäten ausblenden",
"display_binary_mode": "Binärsensor-Anzeigemodus",
"display_devices_changed_notify": "Gerätestatusänderungen anzeigen"
}
},
@ -119,6 +120,7 @@
"update_devices": "Geräteliste aktualisieren",
"action_debug": "Action-Debug-Modus",
"hide_non_standard_entities": "Verstecke Nicht-Standard-Entitäten",
"display_binary_mode": "Binärsensor-Anzeigemodus",
"display_devices_changed_notify": "Gerätestatusänderungen anzeigen",
"update_trans_rules": "Entitätskonvertierungsregeln aktualisieren",
"update_lan_ctrl_config": "LAN-Steuerungskonfiguration aktualisieren",

View File

@ -42,12 +42,13 @@
},
"advanced_options": {
"title": "Advanced Settings",
"description": "## Introduction\r\n### Unless you are very clear about the meaning of the following options, please keep the default settings.\r\n### Filter Devices\r\nSupports filtering devices by room name and device type, and also supports device dimension filtering.\r\n### Control Mode\r\n- Auto: When there is an available Xiaomi central hub gateway in the local area network, Home Assistant will prioritize sending device control commands through the central hub gateway to achieve local control. If there is no central hub gateway in the local area network, it will attempt to send control commands through Xiaomi OT protocol to achieve local control. Only when the above local control conditions are not met, the device control commands will be sent through the cloud.\r\n- Cloud: All control commands are sent through the cloud.\r\n### Action Debug Mode\r\nFor the methods defined by the device MIoT-Spec-V2, in addition to generating notification entities, a text input box entity will also be generated. You can use it to send control commands to the device during debugging.\r\n### Hide Non-Standard Generated Entities\r\nHide entities generated by non-standard MIoT-Spec-V2 instances with names starting with \"*\".\r\n### Display Device Status Change Notifications\r\nDisplay detailed device status change notifications, only showing the selected notifications.",
"description": "## Introduction\r\n### Unless you are very clear about the meaning of the following options, please keep the default settings.\r\n### Filter Devices\r\nSupports filtering devices by room name and device type, and also supports device dimension filtering.\r\n### Control Mode\r\n- Auto: When there is an available Xiaomi central hub gateway in the local area network, Home Assistant will prioritize sending device control commands through the central hub gateway to achieve local control. If there is no central hub gateway in the local area network, it will attempt to send control commands through Xiaomi OT protocol to achieve local control. Only when the above local control conditions are not met, the device control commands will be sent through the cloud.\r\n- Cloud: All control commands are sent through the cloud.\r\n### Action Debug Mode\r\nFor the methods defined by the device MIoT-Spec-V2, in addition to generating notification entities, a text input box entity will also be generated. You can use it to send control commands to the device during debugging.\r\n### Hide Non-Standard Generated Entities\r\nHide entities generated by non-standard MIoT-Spec-V2 instances with names starting with \"*\".\r\n### Binary Sensor Display Mode\r\nDisplay binary sensors in Xiaomi Home as text sensor entity or binary sensor entity。\r\n### Display Device Status Change Notifications\r\nDisplay detailed device status change notifications, only showing the selected notifications.",
"data": {
"devices_filter": "Filter Devices",
"ctrl_mode": "Control Mode",
"action_debug": "Action Debug Mode",
"hide_non_standard_entities": "Hide Non-Standard Generated Entities",
"display_binary_mode": "Binary Sensor Display Mode",
"display_devices_changed_notify": "Display Device Status Change Notifications"
}
},
@ -119,6 +120,7 @@
"update_devices": "Update device list",
"action_debug": "Debug mode for action",
"hide_non_standard_entities": "Hide non-standard created entities",
"display_binary_mode": "Binary Sensor Display Mode",
"display_devices_changed_notify": "Display device status change notifications",
"update_trans_rules": "Update entity conversion rules",
"update_lan_ctrl_config": "Update LAN control configuration",

View File

@ -42,12 +42,13 @@
},
"advanced_options": {
"title": "Opciones Avanzadas",
"description": "## Introducción\r\n### A menos que entienda claramente el significado de las siguientes opciones, manténgalas en su configuración predeterminada.\r\n### Filtrar dispositivos\r\nAdmite la filtración de dispositivos por nombre de habitación y tipo de dispositivo, y también admite la filtración por familia.\r\n### Modo de Control\r\n- Automático: Cuando hay una puerta de enlace central de Xiaomi disponible en la red local, Home Assistant enviará comandos de control de dispositivos a través de la puerta de enlace central para lograr la función de control local. Cuando no hay una puerta de enlace central en la red local, intentará enviar comandos de control a través del protocolo OT de Xiaomi para lograr la función de control local. Solo cuando no se cumplan las condiciones de control local anteriores, los comandos de control de dispositivos se enviarán a través de la nube.\r\n- Nube: Los comandos de control solo se envían a través de la nube.\r\n### Modo de Depuración de Acciones\r\nPara los métodos definidos por el dispositivo MIoT-Spec-V2, además de generar una entidad de notificación, también se generará una entidad de cuadro de texto que se puede utilizar para enviar comandos de control al dispositivo durante la depuración.\r\n### Ocultar Entidades Generadas No Estándar\r\nOcultar entidades generadas por instancias MIoT-Spec-V2 no estándar que comienzan con \"*\".\r\n### Mostrar notificaciones de cambio de estado del dispositivo\r\nMostrar notificaciones detalladas de cambio de estado del dispositivo, mostrando solo las notificaciones seleccionadas.",
"description": "## Introducción\r\n### A menos que entienda claramente el significado de las siguientes opciones, manténgalas en su configuración predeterminada.\r\n### Filtrar dispositivos\r\nAdmite la filtración de dispositivos por nombre de habitación y tipo de dispositivo, y también admite la filtración por familia.\r\n### Modo de Control\r\n- Automático: Cuando hay una puerta de enlace central de Xiaomi disponible en la red local, Home Assistant enviará comandos de control de dispositivos a través de la puerta de enlace central para lograr la función de control local. Cuando no hay una puerta de enlace central en la red local, intentará enviar comandos de control a través del protocolo OT de Xiaomi para lograr la función de control local. Solo cuando no se cumplan las condiciones de control local anteriores, los comandos de control de dispositivos se enviarán a través de la nube.\r\n- Nube: Los comandos de control solo se envían a través de la nube.\r\n### Modo de Depuración de Acciones\r\nPara los métodos definidos por el dispositivo MIoT-Spec-V2, además de generar una entidad de notificación, también se generará una entidad de cuadro de texto que se puede utilizar para enviar comandos de control al dispositivo durante la depuración.\r\n### Ocultar Entidades Generadas No Estándar\r\nOcultar entidades generadas por instancias MIoT-Spec-V2 no estándar que comienzan con \"*\".\r\n### Modo de visualización del sensor binario\r\nMuestra los sensores binarios en Xiaomi Home como entidad de sensor de texto o entidad de sensor binario。\r\n### Mostrar notificaciones de cambio de estado del dispositivo\r\nMostrar notificaciones detalladas de cambio de estado del dispositivo, mostrando solo las notificaciones seleccionadas.",
"data": {
"devices_filter": "Filtrar Dispositivos",
"ctrl_mode": "Modo de Control",
"action_debug": "Modo de Depuración de Acciones",
"hide_non_standard_entities": "Ocultar Entidades Generadas No Estándar",
"display_binary_mode": "Modo de visualización del sensor binario",
"display_devices_changed_notify": "Mostrar notificaciones de cambio de estado del dispositivo"
}
},
@ -119,6 +120,7 @@
"update_devices": "Actualizar lista de dispositivos",
"action_debug": "Modo de depuración de Action",
"hide_non_standard_entities": "Ocultar entidades generadas no estándar",
"display_binary_mode": "Modo de visualización del sensor binario",
"display_devices_changed_notify": "Mostrar notificaciones de cambio de estado del dispositivo",
"update_trans_rules": "Actualizar reglas de conversión de entidad",
"update_lan_ctrl_config": "Actualizar configuración de control LAN",

View File

@ -42,12 +42,13 @@
},
"advanced_options": {
"title": "Paramètres Avancés",
"description": "## Introduction\r\n### Sauf si vous comprenez très bien la signification des options suivantes, veuillez les laisser par défaut.\r\n### Filtrer les appareils\r\nPrend en charge le filtrage des appareils en fonction du nom de la pièce et du type d'appareil, ainsi que le filtrage basé sur les appareils.\r\n### Mode de Contrôle\r\n- Automatique : Lorsqu'une passerelle Xiaomi est disponible dans le réseau local, Home Assistant enverra les commandes de contrôle des appareils via la passerelle pour permettre le contrôle local. Si aucune passerelle n'est disponible dans le réseau local, Home Assistant essaiera d'envoyer les commandes de contrôle des appareils via le protocole OT Xiaomi pour permettre le contrôle local. Seules si les conditions de contrôle local ci-dessus ne sont pas remplies, les commandes de contrôle des appareils seront envoyées via le cloud.\r\n- Cloud : Les commandes de contrôle des appareils sont envoyées uniquement via le cloud.\r\n### Mode de Débogage dActions\r\nPour les méthodes définies par les appareils MIoT-Spec-V2, en plus de générer une entité de notification, une entité de champ de texte sera également générée pour vous permettre d'envoyer des commandes de contrôle aux appareils lors du débogage.\r\n### Masquer les Entités Non Standard\r\nMasquer les entités générées par des instances MIoT-Spec-V2 non standard et commençant par \"*\".\r\n### Afficher les notifications de changement d'état de l'appareil\r\nAfficher les notifications détaillées de changement d'état de l'appareil, en affichant uniquement les notifications sélectionnées.",
"description": "## Introduction\r\n### Sauf si vous comprenez très bien la signification des options suivantes, veuillez les laisser par défaut.\r\n### Filtrer les appareils\r\nPrend en charge le filtrage des appareils en fonction du nom de la pièce et du type d'appareil, ainsi que le filtrage basé sur les appareils.\r\n### Mode de Contrôle\r\n- Automatique : Lorsqu'une passerelle Xiaomi est disponible dans le réseau local, Home Assistant enverra les commandes de contrôle des appareils via la passerelle pour permettre le contrôle local. Si aucune passerelle n'est disponible dans le réseau local, Home Assistant essaiera d'envoyer les commandes de contrôle des appareils via le protocole OT Xiaomi pour permettre le contrôle local. Seules si les conditions de contrôle local ci-dessus ne sont pas remplies, les commandes de contrôle des appareils seront envoyées via le cloud.\r\n- Cloud : Les commandes de contrôle des appareils sont envoyées uniquement via le cloud.\r\n### Mode de Débogage dActions\r\nPour les méthodes définies par les appareils MIoT-Spec-V2, en plus de générer une entité de notification, une entité de champ de texte sera également générée pour vous permettre d'envoyer des commandes de contrôle aux appareils lors du débogage.\r\n### Masquer les Entités Non Standard\r\nMasquer les entités générées par des instances MIoT-Spec-V2 non standard et commençant par \"*\".\r\n### Mode d'affichage du capteur binaire\r\nAffiche les capteurs binaires dans Xiaomi Home comme entité de capteur de texte ou entité de capteur binaire。\r\n### Afficher les notifications de changement d'état de l'appareil\r\nAfficher les notifications détaillées de changement d'état de l'appareil, en affichant uniquement les notifications sélectionnées.",
"data": {
"devices_filter": "Filtrer les Appareils",
"ctrl_mode": "Mode de Contrôle",
"action_debug": "Mode de Débogage dActions",
"hide_non_standard_entities": "Masquer les Entités Non Standard",
"display_binary_mode": "Mode d'affichage du capteur binaire",
"display_devices_changed_notify": "Afficher les notifications de changement d'état de l'appareil"
}
},
@ -119,6 +120,7 @@
"update_devices": "Mettre à jour la liste des appareils",
"action_debug": "Mode de débogage d'action",
"hide_non_standard_entities": "Masquer les entités générées non standard",
"display_binary_mode": "Mode d'affichage du capteur binaire",
"display_devices_changed_notify": "Afficher les notifications de changement d'état de l'appareil",
"update_trans_rules": "Mettre à jour les règles de conversion d'entités",
"update_lan_ctrl_config": "Mettre à jour la configuration de contrôle LAN",

View File

@ -0,0 +1,224 @@
{
"config": {
"flow_title": "Integrazione Xiaomi Home",
"step": {
"eula": {
"title": "Avviso sui Rischi",
"description": "1. Le informazioni del tuo utente Xiaomi e le informazioni del dispositivo saranno memorizzate nel sistema Home Assistant. **Xiaomi non può garantire la sicurezza del meccanismo di archiviazione di Home Assistant**. Sei responsabile per prevenire il furto delle tue informazioni.\r\n2. Questa integrazione è mantenuta dalla comunità open-source. Potrebbero esserci problemi di stabilità o altri problemi. In caso di problemi o bug con questa integrazione, **dovresti cercare aiuto dalla comunità open-source piuttosto che contattare il servizio clienti Xiaomi**.\r\n3. È necessaria una certa abilità tecnica per mantenere il tuo ambiente operativo locale. L'integrazione non è user-friendly per i principianti.\r\n4. Si prega di leggere il file README prima di iniziare.\n\n5. Per garantire un uso stabile dell'integrazione e prevenire l'abuso dell'interfaccia, **questa integrazione può essere utilizzata solo in Home Assistant. Per i dettagli, consulta il LICENSE**.",
"data": {
"eula": "Sono consapevole dei rischi sopra indicati e sono disposto ad assumermi volontariamente qualsiasi rischio associato all'uso dell'integrazione."
}
},
"auth_config": {
"title": "Configurazione di base",
"description": "### Regione di Login\r\nSeleziona la regione del tuo account Xiaomi. Puoi trovarla nell'APP Xiaomi Home > Profilo (nel menu in basso) > Impostazioni aggiuntive > Informazioni su Xiaomi Home.\r\n### Lingua\r\nSeleziona la lingua dei nomi dei dispositivi e delle entità. Alcune frasi senza traduzione verranno visualizzate in inglese.\r\n### URL di reindirizzamento OAuth2\r\nL'indirizzo di reindirizzamento dell'autenticazione OAuth2 è **[http://homeassistant.local:8123](http://homeassistant.local:8123)**. Home Assistant deve trovarsi nella stessa rete locale del terminale operativo corrente (ad esempio, il computer personale) e il terminale operativo deve poter accedere alla home page di Home Assistant tramite questo indirizzo. Altrimenti, l'autenticazione del login potrebbe fallire.\r\n### Nota\r\n- Per gli utenti con centinaia o più dispositivi Mi Home, l'aggiunta iniziale dell'integrazione richiederà del tempo. Si prega di essere pazienti.\r\n- Se Home Assistant è in esecuzione in un ambiente Docker, assicurarsi che la modalità di rete Docker sia impostata su host, altrimenti la funzionalità di controllo locale potrebbe non funzionare correttamente.\r\n- La funzionalità di controllo locale dell'integrazione ha alcune dipendenze. Si prega di leggere attentamente il README.",
"data": {
"cloud_server": "Regione di Login",
"integration_language": "Lingua",
"oauth_redirect_url": "URL di reindirizzamento OAuth2",
"network_detect_config": "Configurazione di rete integrata"
}
},
"network_detect_config": {
"title": "Configurazione di Rete Integrata",
"description": "## Introduzione all'uso\r\n### Indirizzo di Rilevamento della Rete\r\nUtilizzato per verificare se la rete funziona correttamente. Se non impostato, verrà utilizzato l'indirizzo di default del sistema. Se il controllo dell'indirizzo predefinito fallisce, puoi provare a inserire un indirizzo personalizzato.\r\n- Puoi inserire più indirizzi di rilevamento, separati da virgole, come `8.8.8.8,https://www.bing.com`\r\n- Se è un indirizzo IP, il rilevamento verrà eseguito tramite ping. Se è un indirizzo HTTP(s), il rilevamento verrà eseguito tramite richiesta HTTP GET.\r\n- Se desideri ripristinare l'indirizzo di rilevamento predefinito del sistema, inserisci una virgola `,` e fai clic su 'Avanti'.\r\n- **Questa configurazione è globale e le modifiche influenzeranno altre istanze di integrazione. Si prega di modificare con cautela.**\r\n### Controlla le Dipendenze di Rete\r\nControlla una per una le seguenti dipendenze di rete per vedere se sono accessibili. Se gli indirizzi correlati non sono accessibili, causerà problemi di integrazione.\r\n- Indirizzo di Autenticazione OAuth2: `https://account.xiaomi.com/oauth2/authorize`.\r\n- Indirizzo API HTTP di Xiaomi: `https://{http_host}/app/v2/ha/oauth/get_token`.\r\n- Indirizzo API SPEC di Xiaomi: `https://miot-spec.org/miot-spec-v2/template/list/device`.\r\n- Indirizzo del Broker MQTT di Xiaomi: `mqtts://{cloud_server}-ha.mqtt.io.mi.com:8883`.",
"data": {
"network_detect_addr": "Indirizzo di Rilevamento della Rete",
"check_network_deps": "Controlla le Dipendenze di Rete"
}
},
"oauth_error": {
"title": "Errore di Login",
"description": "Clicca AVANTI per riprovare."
},
"homes_select": {
"title": "Seleziona Famiglia e Dispositivo",
"description": "## Introduzione\r\n### Importa la Famiglia del Dispositivo\r\nL'integrazione aggiungerà i dispositivi dalla famiglia selezionata.\r\n### Modalità di Sincronizzazione del Nome della Stanza\r\nQuando si sincronizzano i dispositivi dall'app Mi Home a Home Assistant, la denominazione dell'area in Home Assistant seguirà le regole indicate di seguito. Si noti che il processo di sincronizzazione non modificherà le impostazioni di famiglia e stanza nell'app Mi Home.\r\n- Non sincronizzare: Il dispositivo non verrà aggiunto a nessuna area.\r\n- Altre opzioni: L'area a cui viene aggiunto il dispositivo verrà denominata come la famiglia o il nome della stanza nell'app Mi Home.\r\n### Impostazioni Avanzate\r\nMostra le impostazioni avanzate per modificare le opzioni di configurazione professionale dell'integrazione.\r\n\r\n&emsp;\r\n### {nick_name} Ciao! Seleziona la famiglia a cui desideri aggiungere il dispositivo.",
"data": {
"home_infos": "Importa la Famiglia del Dispositivo",
"area_name_rule": "Modalità di Sincronizzazione del Nome della Stanza",
"advanced_options": "Impostazioni Avanzate"
}
},
"advanced_options": {
"title": "Impostazioni Avanzate",
"description": "## Introduzione\r\n### A meno che tu non abbia chiaro il significato delle seguenti opzioni, si prega di mantenere le impostazioni predefinite.\r\n### Filtra Dispositivi\r\nSupporta il filtraggio dei dispositivi per nome della stanza e tipo di dispositivo, e supporta anche il filtraggio delle dimensioni del dispositivo.\r\n### Modalità di Controllo\r\n- Automatico: Quando è disponibile un gateway hub centrale Xiaomi nella rete locale, Home Assistant darà priorità all'invio dei comandi di controllo dei dispositivi tramite il gateway hub centrale per ottenere il controllo locale. Se non è presente un gateway hub centrale nella rete locale, tenterà di inviare comandi di controllo tramite il protocollo OT di Xiaomi per ottenere il controllo locale. Solo quando le condizioni di controllo locale sopra indicate non sono soddisfatte, i comandi di controllo del dispositivo verranno inviati tramite il cloud.\r\n- Cloud: Tutti i comandi di controllo vengono inviati tramite il cloud.\r\n### Modalità di Debug delle Azioni\r\nPer i metodi definiti dal dispositivo MIoT-Spec-V2, oltre a generare entità di notifica, verrà generata anche un'entità di casella di input di testo. È possibile utilizzarla per inviare comandi di controllo al dispositivo durante il debug.\r\n### Nascondi Entità Generate Non Standard\r\nNasconde le entità generate da istanze non standard MIoT-Spec-V2 con nomi che iniziano con \"*\".\r\n### Modalità di visualizzazione del sensore binario\r\nVisualizza i sensori binari in Mi Home come entità del sensore di testo o entità del sensore binario。\r\n### Mostra Notifiche di Cambio di Stato del Dispositivo\r\nMostra notifiche dettagliate sui cambiamenti di stato del dispositivo, mostrando solo le notifiche selezionate.",
"data": {
"devices_filter": "Filtra Dispositivi",
"ctrl_mode": "Modalità di Controllo",
"action_debug": "Modalità di Debug delle Azioni",
"hide_non_standard_entities": "Nascondi Entità Generate Non Standard",
"display_binary_mode": "Modalità di visualizzazione del sensore binario",
"display_devices_changed_notify": "Mostra Notifiche di Cambio di Stato del Dispositivo"
}
},
"devices_filter": {
"title": "Filtra Dispositivi",
"description": "## Istruzioni per l'uso\r\nSupporta il filtraggio dei dispositivi per nome della stanza, tipo di accesso al dispositivo e modello del dispositivo, e supporta anche il filtraggio delle dimensioni del dispositivo. La logica di filtraggio è la seguente:\r\n- Prima, secondo la logica statistica, ottieni l'unione o l'intersezione di tutti gli elementi inclusi, poi ottieni l'intersezione o l'unione degli elementi esclusi e infine sottrai il [risultato riassuntivo incluso] dal [risultato riassuntivo escluso] per ottenere il [risultato del filtro].\r\n- Se non vengono selezionati elementi inclusi, significa che tutti sono inclusi.\r\n### Modalità di Filtro\r\n- Escludi: Rimuovi gli elementi indesiderati.\r\n- Includi: Includi gli elementi desiderati.\r\n### Logica Statistica\r\n- Logica AND: Prendi l'intersezione di tutti gli elementi nella stessa modalità.\r\n- Logica OR: Prendi l'unione di tutti gli elementi nella stessa modalità.\r\n\r\nPuoi anche andare alla pagina [Configurazione > Aggiorna Elenco Dispositivi] dell'elemento di integrazione e controllare [Filtra Dispositivi] per rifiltrare.",
"data": {
"room_filter_mode": "Filtra Stanze della Famiglia",
"room_list": "Stanze della Famiglia",
"type_filter_mode": "Filtra Tipo di Connessione del Dispositivo",
"type_list": "Tipo di Connessione del Dispositivo",
"model_filter_mode": "Filtra Modello del Dispositivo",
"model_list": "Modello del Dispositivo",
"devices_filter_mode": "Filtra Dispositivi",
"device_list": "Elenco Dispositivi",
"statistics_logic": "Logica Statistica"
}
}
},
"progress": {
"oauth": "### {link_left}Clicca qui per accedere{link_right}\r\n(Verrai reindirizzato automaticamente alla pagina successiva dopo un accesso riuscito)"
},
"error": {
"eula_not_agree": "Si prega di leggere l'avviso sui rischi.",
"get_token_error": "Impossibile recuperare le informazioni di autorizzazione per il login (token OAuth).",
"get_homeinfo_error": "Impossibile recuperare le informazioni della casa.",
"mdns_discovery_error": "Eccezione del servizio di scoperta dei dispositivi locali.",
"get_cert_error": "Impossibile recuperare il certificato del gateway centrale.",
"no_family_selected": "Nessuna casa selezionata.",
"no_devices": "La casa selezionata non ha dispositivi. Si prega di scegliere una casa che contiene dispositivi e continuare.",
"no_filter_devices": "I dispositivi filtrati sono vuoti. Si prega di selezionare criteri di filtro validi e continuare.",
"no_central_device": "[Modalità Gateway Hub Centrale] richiede un gateway hub centrale Xiaomi disponibile nella rete locale in cui esiste Home Assistant. Si prega di verificare se la casa selezionata soddisfa il requisito.",
"invalid_network_addr": "Rilevato indirizzo IP o indirizzo HTTP non valido, si prega di inserire un indirizzo valido.",
"invalid_ip_addr": "Rilevato indirizzo IP non raggiungibile, si prega di inserire un indirizzo IP valido.",
"invalid_http_addr": "Rilevato indirizzo HTTP non raggiungibile, si prega di inserire un indirizzo HTTP valido.",
"invalid_default_addr": "Indirizzo di rilevamento della rete predefinito non raggiungibile, si prega di verificare la configurazione della rete o utilizzare un indirizzo di rilevamento della rete personalizzato.",
"unreachable_oauth2_host": "Impossibile raggiungere l'indirizzo di autenticazione OAuth2, si prega di verificare la configurazione della rete.",
"unreachable_http_host": "Impossibile raggiungere l'indirizzo API HTTP di Xiaomi, si prega di verificare la configurazione della rete.",
"unreachable_spec_host": "Impossibile raggiungere l'indirizzo API SPEC di Xiaomi, si prega di verificare la configurazione della rete.",
"unreachable_mqtt_broker": "Impossibile raggiungere l'indirizzo del broker MQTT di Xiaomi, si prega di verificare la configurazione della rete."
},
"abort": {
"ha_uuid_get_failed": "Impossibile ottenere l'UUID di Home Assistant.",
"network_connect_error": "Configurazione fallita. La connessione di rete è anomala. Si prega di controllare la configurazione della rete del dispositivo.",
"already_configured": "La configurazione per questo utente è già completata. Si prega di andare alla pagina dell'integrazione e cliccare sul pulsante CONFIGURA per le modifiche.",
"invalid_auth_info": "Le informazioni di autenticazione sono scadute. Si prega di andare alla pagina dell'integrazione e cliccare sul pulsante CONFIGURA per ri-autenticarsi.",
"config_flow_error": "Errore di configurazione dell'integrazione: {error}."
}
},
"options": {
"step": {
"auth_config": {
"title": "Configurazione dell'Autenticazione",
"description": "Le informazioni di autenticazione locale sono scadute. Si prega di riavviare il processo di autenticazione.\r\n### Regione di Login Corrente: {cloud_server}\r\n### URL di reindirizzamento OAuth2\r\nL'indirizzo di reindirizzamento dell'autenticazione OAuth2 è **[http://homeassistant.local:8123](http://homeassistant.local:8123)**. Home Assistant deve trovarsi nella stessa rete locale del terminale operativo corrente (ad esempio, il computer personale) e il terminale operativo deve poter accedere alla home page di Home Assistant tramite questo indirizzo. Altrimenti, l'autenticazione del login potrebbe fallire.",
"data": {
"oauth_redirect_url": "URL di reindirizzamento OAuth2"
}
},
"oauth_error": {
"title": "Si è verificato un errore durante il login.",
"description": "Clicca AVANTI per riprovare."
},
"config_options": {
"title": "Opzioni di Configurazione",
"description": "### Ciao, {nick_name}\r\n\r\nID Xiaomi: {uid}\r\nRegione di Login Corrente: {cloud_server}\r\n\r\nSeleziona le opzioni che desideri configurare, poi clicca AVANTI.",
"data": {
"integration_language": "Lingua dell'Integrazione",
"update_user_info": "Aggiorna le informazioni dell'utente",
"update_devices": "Aggiorna l'elenco dei dispositivi",
"action_debug": "Modalità debug per azione",
"hide_non_standard_entities": "Nascondi entità create non standard",
"display_binary_mode": "Modalità di visualizzazione del sensore binario",
"display_devices_changed_notify": "Mostra notifiche di cambio stato del dispositivo",
"update_trans_rules": "Aggiorna le regole di conversione delle entità",
"update_lan_ctrl_config": "Aggiorna configurazione del controllo LAN",
"network_detect_config": "Configurazione di Rete Integrata"
}
},
"update_user_info": {
"title": "Aggiorna il Nickname dell'Utente",
"description": "Ciao {nick_name}, puoi modificare il tuo nickname personalizzato qui sotto.",
"data": {
"nick_name": "Nickname"
}
},
"homes_select": {
"title": "Seleziona Nuovamente Casa e Dispositivi",
"description": "## Istruzioni per l'uso\r\n### Importa dispositivi da casa\r\nL'integrazione aggiungerà dispositivi dalle case selezionate.\r\n### Filtra Dispositivi\r\nSupporta il filtraggio dei dispositivi per nome della stanza, tipo di accesso al dispositivo e modello del dispositivo, e supporta anche il filtraggio delle dimensioni del dispositivo. **{local_count}** dispositivi sono stati filtrati.\r\n### Modalità di Controllo\r\n- Automatico: Quando è disponibile un gateway hub centrale Xiaomi nella rete locale, Home Assistant darà priorità all'invio dei comandi di controllo dei dispositivi tramite il gateway hub centrale per ottenere il controllo locale. Se non è presente un gateway hub centrale nella rete locale, tenterà di inviare comandi di controllo tramite la funzione di controllo LAN di Xiaomi. Solo quando le condizioni di controllo locale sopra indicate non sono soddisfatte, i comandi di controllo del dispositivo verranno inviati tramite il cloud.\r\n- Cloud: Tutti i comandi di controllo vengono inviati tramite il cloud.",
"data": {
"home_infos": "Importa dispositivi da casa",
"devices_filter": "Filtra dispositivi",
"ctrl_mode": "Modalità di controllo"
}
},
"devices_filter": {
"title": "Filtra Dispositivi",
"description": "## Istruzioni per l'uso\r\nSupporta il filtraggio dei dispositivi per nome della stanza, tipo di accesso al dispositivo e modello del dispositivo, e supporta anche il filtraggio delle dimensioni del dispositivo. La logica di filtraggio è la seguente:\r\n- Prima, secondo la logica statistica, ottieni l'unione o l'intersezione di tutti gli elementi inclusi, poi ottieni l'intersezione o l'unione degli elementi esclusi e infine sottrai il [risultato riassuntivo incluso] dal [risultato riassuntivo escluso] per ottenere il [risultato del filtro].\r\n- Se non vengono selezionati elementi inclusi, significa che tutti sono inclusi.\r\n### Modalità di Filtro\r\n- Escludi: Rimuovi gli elementi indesiderati.\r\n- Includi: Includi gli elementi desiderati.\r\n### Logica Statistica\r\n- Logica AND: Prendi l'intersezione di tutti gli elementi nella stessa modalità.\r\n- Logica OR: Prendi l'unione di tutti gli elementi nella stessa modalità.\r\n\r\nPuoi anche andare alla pagina [Configurazione > Aggiorna Elenco Dispositivi] dell'elemento di integrazione e controllare [Filtra Dispositivi] per rifiltrare.",
"data": {
"room_filter_mode": "Filtra Stanze della Famiglia",
"room_list": "Stanze della Famiglia",
"type_filter_mode": "Filtra Tipo di Connessione del Dispositivo",
"type_list": "Tipo di Connessione del Dispositivo",
"model_filter_mode": "Filtra Modello del Dispositivo",
"model_list": "Modello del Dispositivo",
"devices_filter_mode": "Filtra Dispositivi",
"device_list": "Elenco Dispositivi",
"statistics_logic": "Logica Statistica"
}
},
"update_trans_rules": {
"title": "Aggiorna le Regole di Trasformazione delle Entità",
"description": "## Istruzioni per l'uso\r\n- Aggiorna le informazioni delle entità dei dispositivi nell'istanza dell'integrazione corrente, incluse la configurazione multilingue MIoT-Spec-V2, la traduzione booleana e il filtro dei modelli.\r\n- **Avviso**: Questa è una configurazione globale e aggiornerà la cache locale. Influenzando tutte le istanze di integrazione.\r\n- Questa operazione richiederà del tempo, si prega di essere pazienti. Seleziona \"Conferma Aggiornamento\" e clicca \"Avanti\" per iniziare l'aggiornamento di **{urn_count}** regole, altrimenti salta l'aggiornamento.",
"data": {
"confirm": "Conferma l'aggiornamento"
}
},
"update_lan_ctrl_config": {
"title": "Aggiorna configurazione del controllo LAN",
"description": "## Istruzioni per l'uso\r\nAggiorna le configurazioni per la funzione di controllo LAN di Xiaomi. Quando il cloud e il gateway centrale non possono controllare i dispositivi, l'integrazione tenterà di controllare i dispositivi tramite la LAN. Se nessuna scheda di rete è selezionata, la funzione di controllo LAN non avrà effetto.\r\n- Solo i dispositivi compatibili con MIoT-Spec-V2 nella LAN sono supportati. Alcuni dispositivi prodotti prima del 2020 potrebbero non supportare il controllo LAN o l'abbonamento LAN.\r\n- Seleziona la/le scheda/e di rete nella stessa rete dei dispositivi da controllare. È possibile selezionare più schede di rete. Se Home Assistant ha due o più connessioni alla rete locale a causa della selezione multipla delle schede di rete, si consiglia di selezionare quella con la migliore connessione di rete, altrimenti potrebbe avere un effetto negativo sui dispositivi.\r\n- Se ci sono dispositivi terminali (altoparlanti Xiaomi con schermo, telefono cellulare, ecc.) nella LAN che supportano il controllo locale, abilitare l'abbonamento LAN potrebbe causare anomalie nell'automazione locale e nei dispositivi.\r\n- **Avviso**: Questa è una configurazione globale. Influenzando tutte le istanze di integrazione. Usala con cautela.\r\n{notice_net_dup}",
"data": {
"net_interfaces": "Si prega di selezionare la scheda di rete da utilizzare",
"enable_subscribe": "Abilita Sottoscrizione LAN"
}
},
"network_detect_config": {
"title": "Configurazione di Rete Integrata",
"description": "## Introduzione all'uso\r\n### Indirizzo di Rilevamento della Rete\r\nUtilizzato per verificare se la rete funziona correttamente. Se non impostato, verrà utilizzato l'indirizzo di default del sistema. Se il controllo dell'indirizzo predefinito fallisce, puoi provare a inserire un indirizzo personalizzato.\r\n- Puoi inserire più indirizzi di rilevamento, separati da virgole, come `8.8.8.8,https://www.bing.com`\r\n- Se è un indirizzo IP, il rilevamento verrà eseguito tramite ping. Se è un indirizzo HTTP(s), il rilevamento verrà eseguito tramite richiesta HTTP GET.\r\n- Se desideri ripristinare l'indirizzo di rilevamento predefinito del sistema, inserisci una virgola `,` e fai clic su 'Avanti'.\r\n- **Questa configurazione è globale e le modifiche influenzeranno altre istanze di integrazione. Si prega di modificare con cautela.**\r\n### Controlla le Dipendenze di Rete\r\nControlla una per una le seguenti dipendenze di rete per vedere se sono accessibili. Se gli indirizzi correlati non sono accessibili, causerà problemi di integrazione.\r\n- Indirizzo di Autenticazione OAuth2: `https://account.xiaomi.com/oauth2/authorize`.\r\n- Indirizzo API HTTP di Xiaomi: `https://{http_host}/app/v2/ha/oauth/get_token`.\r\n- Indirizzo API SPEC di Xiaomi: `https://miot-spec.org/miot-spec-v2/template/list/device`.\r\n- Indirizzo del Broker MQTT di Xiaomi: `mqtts://{cloud_server}-ha.mqtt.io.mi.com:8883`.",
"data": {
"network_detect_addr": "Indirizzo di Rilevamento della Rete",
"check_network_deps": "Controlla le Dipendenze di Rete"
}
},
"config_confirm": {
"title": "Conferma Configurazione",
"description": "Ciao **{nick_name}**, si prega di confermare le informazioni di configurazione più recenti e poi fare clic su INVIA.\r\nL'integrazione verrà ricaricata utilizzando la configurazione aggiornata.\r\n\r\nLingua dell'Integrazione: \t{lang_new}\r\nSoprannome: \t{nick_name_new}\r\nModalità di debug per azione: \t{action_debug}\r\nNascondi entità create non standard: \t{hide_non_standard_entities}\r\nMostra notifiche di cambio stato del dispositivo:\t{display_devices_changed_notify}\r\nCambiamenti del Dispositivo: \tAggiungi **{devices_add}** dispositivi, Rimuovi **{devices_remove}** dispositivi\r\nCambiamenti delle regole di trasformazione: \tCi sono un totale di **{trans_rules_count}** regole, e aggiornate **{trans_rules_count_success}** regole",
"data": {
"confirm": "Conferma la modifica"
}
}
},
"progress": {
"oauth": "### {link_left}Clicca qui per riaccedere{link_right}"
},
"error": {
"not_auth": "Non autenticato. Si prega di fare clic sul link di autenticazione per autenticare l'identità dell'utente.",
"get_token_error": "Impossibile recuperare le informazioni di autorizzazione all'accesso (token OAuth).",
"get_homeinfo_error": "Impossibile recuperare le informazioni sulla casa.",
"get_cert_error": "Impossibile recuperare il certificato del gateway hub centrale.",
"no_devices": "Non ci sono dispositivi nella casa selezionata. Si prega di selezionare una casa con dispositivi e continuare.",
"no_filter_devices": "I dispositivi filtrati sono vuoti. Si prega di selezionare criteri di filtro validi e continuare.",
"no_family_selected": "Nessuna casa selezionata.",
"no_central_device": "[Modalità Gateway Hub Centrale] richiede un gateway hub centrale Xiaomi disponibile nella rete locale in cui esiste Home Assistant. Si prega di verificare se la casa selezionata soddisfa il requisito.",
"mdns_discovery_error": "Eccezione nel servizio di rilevamento dei dispositivi locali.",
"update_config_error": "Impossibile aggiornare le informazioni di configurazione.",
"not_confirm": "Le modifiche non sono confermate. Si prega di confermare la modifica prima di inviare.",
"invalid_network_addr": "Rilevato indirizzo IP o indirizzo HTTP non valido, si prega di inserire un indirizzo valido.",
"invalid_ip_addr": "Rilevato indirizzo IP non raggiungibile, si prega di inserire un indirizzo IP valido.",
"invalid_http_addr": "Rilevato indirizzo HTTP non raggiungibile, si prega di inserire un indirizzo HTTP valido.",
"invalid_default_addr": "Indirizzo di rilevamento della rete predefinito non raggiungibile, si prega di verificare la configurazione della rete o utilizzare un indirizzo di rilevamento della rete personalizzato.",
"unreachable_oauth2_host": "Impossibile raggiungere l'indirizzo di autenticazione OAuth2, si prega di verificare la configurazione della rete.",
"unreachable_http_host": "Impossibile raggiungere l'indirizzo API HTTP di Xiaomi, si prega di verificare la configurazione della rete.",
"unreachable_spec_host": "Impossibile raggiungere l'indirizzo API SPEC di Xiaomi, si prega di verificare la configurazione della rete.",
"unreachable_mqtt_broker": "Impossibile raggiungere l'indirizzo del broker MQTT di Xiaomi, si prega di verificare la configurazione della rete."
},
"abort": {
"network_connect_error": "Configurazione fallita. La connessione di rete è anomala. Si prega di controllare la configurazione della rete del dispositivo.",
"options_flow_error": "Errore di riconfigurazione dell'integrazione: {error}",
"re_add": "Si prega di riaggiungere l'integrazione. Messaggio di errore: {error}",
"storage_error": "Eccezione del modulo di archiviazione dell'integrazione. Si prega di riprovare o riaggiungere l'integrazione: {error}",
"inconsistent_account": "Le informazioni dell'account sono incoerenti."
}
}
}

View File

@ -42,12 +42,13 @@
},
"advanced_options": {
"title": "高度な設定オプション",
"description": "## 紹介\r\n### 以下のオプションの意味がよくわからない場合は、デフォルトのままにしてください。\r\n### デバイスのフィルタリング\r\n部屋名とデバイスタイプでデバイスをフィルタリングすることができます。デバイスの次元でフィルタリングすることもできます。\r\n### コントロールモード\r\n- 自動ローカルネットワーク内に利用可能なXiaomi中央ゲートウェイがある場合、Home Assistantはデバイス制御命令を送信するために優先的に中央ゲートウェイを使用します。ローカルネットワークに中央ゲートウェイがない場合、Xiaomi OTプロトコルを使用してデバイス制御命令を送信し、ローカル制御機能を実現します。上記のローカル制御条件が満たされない場合のみ、デバイス制御命令はクラウドを介して送信されます。\r\n- クラウド:制御命令はクラウドを介してのみ送信されます。\r\n### Actionデバッグモード\r\nデバイスが定義するMIoT-Spec-V2のメソッドに対して、通知エンティティを生成するだけでなく、デバイスに制御命令を送信するためのテキスト入力ボックスエンティティも生成されます。デバッグ時にデバイスに制御命令を送信するために使用できます。\r\n### 非標準生成エンティティを隠す\r\n「*」で始まる名前の非標準MIoT-Spec-V2インスタンスによって生成されたエンティティを非表示にします。\r\n### デバイスの状態変化通知を表示\r\nデバイスの状態変化通知を詳細に表示し、選択された通知のみを表示します。",
"description": "## 紹介\r\n### 以下のオプションの意味がよくわからない場合は、デフォルトのままにしてください。\r\n### デバイスのフィルタリング\r\n部屋名とデバイスタイプでデバイスをフィルタリングすることができます。デバイスの次元でフィルタリングすることもできます。\r\n### コントロールモード\r\n- 自動ローカルネットワーク内に利用可能なXiaomi中央ゲートウェイがある場合、Home Assistantはデバイス制御命令を送信するために優先的に中央ゲートウェイを使用します。ローカルネットワークに中央ゲートウェイがない場合、Xiaomi OTプロトコルを使用してデバイス制御命令を送信し、ローカル制御機能を実現します。上記のローカル制御条件が満たされない場合のみ、デバイス制御命令はクラウドを介して送信されます。\r\n- クラウド:制御命令はクラウドを介してのみ送信されます。\r\n### Actionデバッグモード\r\nデバイスが定義するMIoT-Spec-V2のメソッドに対して、通知エンティティを生成するだけでなく、デバイスに制御命令を送信するためのテキスト入力ボックスエンティティも生成されます。デバッグ時にデバイスに制御命令を送信するために使用できます。\r\n### 非標準生成エンティティを隠す\r\n「*」で始まる名前の非標準MIoT-Spec-V2インスタンスによって生成されたエンティティを非表示にします。\r\n### バイナリセンサー表示モード\r\nXiaomi Homeのバイナリセンサーをテキストセンサーエンティティまたはバイナリセンサーエンティティとして表示します。\r\n### デバイスの状態変化通知を表示\r\nデバイスの状態変化通知を詳細に表示し、選択された通知のみを表示します。",
"data": {
"devices_filter": "デバイスをフィルタリング",
"ctrl_mode": "コントロールモード",
"action_debug": "Actionデバッグモード",
"hide_non_standard_entities": "非標準生成エンティティを隠す",
"display_binary_mode": "バイナリセンサー表示モード",
"display_devices_changed_notify": "デバイスの状態変化通知を表示"
}
},
@ -119,6 +120,7 @@
"update_devices": "デバイスリストを更新する",
"action_debug": "Action デバッグモード",
"hide_non_standard_entities": "非標準生成エンティティを非表示にする",
"display_binary_mode": "バイナリセンサー表示モード",
"display_devices_changed_notify": "デバイスの状態変化通知を表示",
"update_trans_rules": "エンティティ変換ルールを更新する",
"update_lan_ctrl_config": "LAN制御構成を更新する",

View File

@ -42,12 +42,13 @@
},
"advanced_options": {
"title": "Geavanceerde Instellingen",
"description": "## Inleiding\r\n### Tenzij u zeer goed op de hoogte bent van de betekenis van de volgende opties, houdt u de standaardinstellingen.\r\n### Apparaten filteren\r\nOndersteunt het filteren van apparaten op basis van kamer- en apparaattypen, en ondersteunt ook apparaatdimensiefiltering.\r\n### Besturingsmodus\r\n- Automatisch: Wanneer er een beschikbare Xiaomi centrale hubgateway in het lokale netwerk is, zal Home Assistant eerst apparaatbesturingsinstructies via de centrale hubgateway verzenden om lokale controlefunctionaliteit te bereiken. Als er geen centrale hub in het lokale netwerk is, zal het proberen om besturingsinstructies via het Xiaomi OT-protocol te verzenden om lokale controlefunctionaliteit te bereiken. Alleen als de bovenstaande lokale controlevoorwaarden niet worden vervuld, worden apparaatbesturingsinstructies via de cloud verzonden.\r\n- Cloud: Besturingsinstructies worden alleen via de cloud verzonden.\r\n### Actie-debugmodus\r\nVoor methoden die zijn gedefinieerd in de MIoT-Spec-V2 van het apparaat, wordt naast het genereren van een meldingsentiteit ook een tekstinvoerveldentiteit gegenereerd. U kunt dit gebruiken om besturingsinstructies naar het apparaat te sturen tijdens het debuggen.\r\n### Niet-standaard entiteiten verbergen\r\nVerberg entiteiten die zijn gegenereerd door niet-standaard MIoT-Spec-V2-instanties die beginnen met \"*\".\r\n### Apparaatstatuswijzigingen weergeven\r\nGedetailleerde apparaatstatuswijzigingen weergeven, alleen de geselecteerde meldingen weergeven.",
"description": "## Inleiding\r\n### Tenzij u zeer goed op de hoogte bent van de betekenis van de volgende opties, houdt u de standaardinstellingen.\r\n### Apparaten filteren\r\nOndersteunt het filteren van apparaten op basis van kamer- en apparaattypen, en ondersteunt ook apparaatdimensiefiltering.\r\n### Besturingsmodus\r\n- Automatisch: Wanneer er een beschikbare Xiaomi centrale hubgateway in het lokale netwerk is, zal Home Assistant eerst apparaatbesturingsinstructies via de centrale hubgateway verzenden om lokale controlefunctionaliteit te bereiken. Als er geen centrale hub in het lokale netwerk is, zal het proberen om besturingsinstructies via het Xiaomi OT-protocol te verzenden om lokale controlefunctionaliteit te bereiken. Alleen als de bovenstaande lokale controlevoorwaarden niet worden vervuld, worden apparaatbesturingsinstructies via de cloud verzonden.\r\n- Cloud: Besturingsinstructies worden alleen via de cloud verzonden.\r\n### Actie-debugmodus\r\nVoor methoden die zijn gedefinieerd in de MIoT-Spec-V2 van het apparaat, wordt naast het genereren van een meldingsentiteit ook een tekstinvoerveldentiteit gegenereerd. U kunt dit gebruiken om besturingsinstructies naar het apparaat te sturen tijdens het debuggen.\r\n### Niet-standaard entiteiten verbergen\r\nVerberg entiteiten die zijn gegenereerd door niet-standaard MIoT-Spec-V2-instanties die beginnen met \"*\".\r\n### Binaire sensorweergavemodus\r\nToont binaire sensoren in Xiaomi Home als tekstsensor-entiteit of binairesensor-entiteit。\r\n### Apparaatstatuswijzigingen weergeven\r\nGedetailleerde apparaatstatuswijzigingen weergeven, alleen de geselecteerde meldingen weergeven.",
"data": {
"devices_filter": "Apparaten filteren",
"ctrl_mode": "Besturingsmodus",
"action_debug": "Actie-debugmodus",
"hide_non_standard_entities": "Niet-standaard entiteiten verbergen",
"display_binary_mode": "Binaire sensorweergavemodus",
"display_devices_changed_notify": "Apparaatstatuswijzigingen weergeven"
}
},
@ -119,6 +120,7 @@
"update_devices": "Werk apparatenlijst bij",
"action_debug": "Debugmodus voor actie",
"hide_non_standard_entities": "Verberg niet-standaard gemaakte entiteiten",
"display_binary_mode": "Binaire sensorweergavemodus",
"display_devices_changed_notify": "Apparaatstatuswijzigingen weergeven",
"update_trans_rules": "Werk entiteitsconversieregels bij",
"update_lan_ctrl_config": "Werk LAN controleconfiguratie bij",

View File

@ -42,12 +42,13 @@
},
"advanced_options": {
"title": "Configurações Avançadas",
"description": "## Introdução\r\n### A menos que você entenda claramente o significado das opções a seguir, mantenha as configurações padrão.\r\n### Filtrar Dispositivos\r\nSuporte para filtrar dispositivos por nome da sala e tipo de dispositivo, bem como filtragem por família.\r\n### Modo de Controle\r\n- Automático: Quando um gateway central Xiaomi disponível na rede local está disponível, o Home Assistant enviará comandos de controle de dispositivo através do gateway central para realizar a função de controle local. Quando não há gateway central na rede local, ele tentará enviar comandos de controle através do protocolo OT da Xiaomi para realizar a função de controle local. Somente quando as condições de controle local acima não forem atendidas, os comandos de controle do dispositivo serão enviados através da nuvem.\r\n- Nuvem: Os comandos de controle são enviados apenas através da nuvem.\r\n### Modo de Depuração de Ações\r\nPara métodos definidos pelo MIoT-Spec-V2 do dispositivo, além de gerar uma entidade de notificação, também será gerada uma entidade de caixa de texto para você enviar comandos de controle ao dispositivo durante a depuração.\r\n### Ocultar Entidades Geradas Não Padrão\r\nOcultar entidades geradas por instâncias MIoT-Spec-V2 não padrão que começam com \"*\".\r\n### Exibir notificações de mudança de status do dispositivo\r\nExibir notificações detalhadas de mudança de status do dispositivo, mostrando apenas as notificações selecionadas.",
"description": "## Introdução\r\n### A menos que você entenda claramente o significado das opções a seguir, mantenha as configurações padrão.\r\n### Filtrar Dispositivos\r\nSuporte para filtrar dispositivos por nome da sala e tipo de dispositivo, bem como filtragem por família.\r\n### Modo de Controle\r\n- Automático: Quando um gateway central Xiaomi disponível na rede local está disponível, o Home Assistant enviará comandos de controle de dispositivo através do gateway central para realizar a função de controle local. Quando não há gateway central na rede local, ele tentará enviar comandos de controle através do protocolo OT da Xiaomi para realizar a função de controle local. Somente quando as condições de controle local acima não forem atendidas, os comandos de controle do dispositivo serão enviados através da nuvem.\r\n- Nuvem: Os comandos de controle são enviados apenas através da nuvem.\r\n### Modo de Depuração de Ações\r\nPara métodos definidos pelo MIoT-Spec-V2 do dispositivo, além de gerar uma entidade de notificação, também será gerada uma entidade de caixa de texto para você enviar comandos de controle ao dispositivo durante a depuração.\r\n### Ocultar Entidades Geradas Não Padrão\r\nOcultar entidades geradas por instâncias MIoT-Spec-V2 não padrão que começam com \"*\".\r\n### Modo de exibição do sensor binário\r\nExibe sensores binários no Xiaomi Home como entidade de sensor de texto ou entidade de sensor binário。\r\n### Exibir notificações de mudança de status do dispositivo\r\nExibir notificações detalhadas de mudança de status do dispositivo, mostrando apenas as notificações selecionadas.",
"data": {
"devices_filter": "Filtrar Dispositivos",
"ctrl_mode": "Modo de Controle",
"action_debug": "Modo de Depuração de Ações",
"hide_non_standard_entities": "Ocultar Entidades Geradas Não Padrão",
"display_binary_mode": "Modo de exibição do sensor binário",
"display_devices_changed_notify": "Exibir notificações de mudança de status do dispositivo"
}
},
@ -119,6 +120,7 @@
"update_devices": "Atualizar lista de dispositivos",
"action_debug": "Modo de depuração para ação",
"hide_non_standard_entities": "Ocultar entidades não padrão criadas",
"display_binary_mode": "Modo de exibição do sensor binário",
"display_devices_changed_notify": "Exibir notificações de mudança de status do dispositivo",
"update_trans_rules": "Atualizar regras de conversão de entidades",
"update_lan_ctrl_config": "Atualizar configuração de controle LAN",

View File

@ -42,12 +42,13 @@
},
"advanced_options": {
"title": "Opções Avançadas",
"description": "## Introdução\r\n### A menos que você entenda claramente o significado das opções abaixo, mantenha as configurações padrão.\r\n### Filtrar Dispositivos\r\nSuporte para filtrar dispositivos por nome da sala e tipo de dispositivo, bem como filtragem por família.\r\n### Modo de Controle\r\n- Automático: Quando um gateway central Xiaomi está disponível na rede local, o Home Assistant enviará comandos de controlo de dispositivos através do gateway central para realizar o controlo local. Quando não há gateway central na rede local, tentará enviar comandos de controlo através do protocolo Xiaomi OT para realizar o controlo local. Apenas quando as condições de controlo local acima não são atendidas, os comandos de controlo de dispositivos serão enviados através da nuvem.\r\n- Nuvem: Os comandos de controlo são enviados apenas através da nuvem.\r\n### Modo de Depuração de Ações\r\nPara métodos definidos pelo MIoT-Spec-V2, além de gerar uma entidade de notificação, também será gerada uma entidade de caixa de texto para depuração de controlo de dispositivos.\r\n### Ocultar Entidades Geradas Não Padrão\r\nOcultar entidades geradas por instâncias MIoT-Spec-V2 não padrão, cujos nomes começam com \"*\".\r\n### Exibir notificações de mudança de status do dispositivo\r\nExibir notificações detalhadas de mudança de status do dispositivo, mostrando apenas as notificações selecionadas.",
"description": "## Introdução\r\n### A menos que você entenda claramente o significado das opções abaixo, mantenha as configurações padrão.\r\n### Filtrar Dispositivos\r\nSuporte para filtrar dispositivos por nome da sala e tipo de dispositivo, bem como filtragem por família.\r\n### Modo de Controle\r\n- Automático: Quando um gateway central Xiaomi está disponível na rede local, o Home Assistant enviará comandos de controlo de dispositivos através do gateway central para realizar o controlo local. Quando não há gateway central na rede local, tentará enviar comandos de controlo através do protocolo Xiaomi OT para realizar o controlo local. Apenas quando as condições de controlo local acima não são atendidas, os comandos de controlo de dispositivos serão enviados através da nuvem.\r\n- Nuvem: Os comandos de controlo são enviados apenas através da nuvem.\r\n### Modo de Depuração de Ações\r\nPara métodos definidos pelo MIoT-Spec-V2, além de gerar uma entidade de notificação, também será gerada uma entidade de caixa de texto para depuração de controlo de dispositivos.\r\n### Ocultar Entidades Geradas Não Padrão\r\nOcultar entidades geradas por instâncias MIoT-Spec-V2 não padrão, cujos nomes começam com \"*\".\r\n### Modo de exibição do sensor binário\r\nExibe sensores binários no Xiaomi Home como entidade de sensor de texto ou entidade de sensor binário。\r\n### Exibir notificações de mudança de status do dispositivo\r\nExibir notificações detalhadas de mudança de status do dispositivo, mostrando apenas as notificações selecionadas.",
"data": {
"devices_filter": "Filtrar Dispositivos",
"ctrl_mode": "Modo de Controlo",
"action_debug": "Modo de Depuração de Ações",
"hide_non_standard_entities": "Ocultar Entidades Geradas Não Padrão",
"display_binary_mode": "Modo de exibição do sensor binário",
"display_devices_changed_notify": "Exibir notificações de mudança de status do dispositivo"
}
},
@ -119,6 +120,7 @@
"update_devices": "Atualizar lista de dispositivos",
"action_debug": "Modo de depuração de ação",
"hide_non_standard_entities": "Ocultar entidades não padrão",
"display_binary_mode": "Modo de exibição do sensor binário",
"display_devices_changed_notify": "Exibir notificações de mudança de status do dispositivo",
"update_trans_rules": "Atualizar regras de conversão de entidades",
"update_lan_ctrl_config": "Atualizar configuração de controlo LAN",

View File

@ -42,12 +42,13 @@
},
"advanced_options": {
"title": "Расширенные настройки",
"description": "## Введение\r\n### Если вы не очень хорошо понимаете значение следующих параметров, оставьте их по умолчанию.\r\n### Фильтрация устройств\r\nПоддерживает фильтрацию устройств по названию комнаты и типу устройства, а также фильтрацию по уровню устройства.\r\n### Режим управления\r\n- Автоматически: при наличии доступного центрального шлюза Xiaomi в локальной сети Home Assistant Home Assistant будет отправлять команды управления устройствами через центральный шлюз для локального управления. Если центрального шлюза нет в локальной сети, Home Assistant попытается отправить команды управления устройствами через протокол OT Xiaomi для локального управления. Только если вышеуказанные условия локального управления не выполняются, команды управления устройствами будут отправляться через облако.\r\n- Облако: команды управления отправляются только через облако.\r\n### Режим отладки действий\r\nДля методов, определенных устройством MIoT-Spec-V2, помимо создания уведомления, будет создана сущность текстового поля, которую вы можете использовать для отправки команд управления устройством во время отладки.\r\n### Скрыть нестандартные сущности\r\nСкрыть сущности, созданные нестандартными экземплярами MIoT-Spec-V2, имена которых начинаются с «*».\r\n### Отображать уведомления о изменении состояния устройства\r\nОтображать подробные уведомления о изменении состояния устройства, показывая только выбранные уведомления.",
"description": "## Введение\r\n### Если вы не очень хорошо понимаете значение следующих параметров, оставьте их по умолчанию.\r\n### Фильтрация устройств\r\nПоддерживает фильтрацию устройств по названию комнаты и типу устройства, а также фильтрацию по уровню устройства.\r\n### Режим управления\r\n- Автоматически: при наличии доступного центрального шлюза Xiaomi в локальной сети Home Assistant Home Assistant будет отправлять команды управления устройствами через центральный шлюз для локального управления. Если центрального шлюза нет в локальной сети, Home Assistant попытается отправить команды управления устройствами через протокол OT Xiaomi для локального управления. Только если вышеуказанные условия локального управления не выполняются, команды управления устройствами будут отправляться через облако.\r\n- Облако: команды управления отправляются только через облако.\r\n### Режим отладки действий\r\nДля методов, определенных устройством MIoT-Spec-V2, помимо создания уведомления, будет создана сущность текстового поля, которую вы можете использовать для отправки команд управления устройством во время отладки.\r\n### Скрыть нестандартные сущности\r\nСкрыть сущности, созданные нестандартными экземплярами MIoT-Spec-V2, имена которых начинаются с «*».\r\n### Режим отображения бинарного датчика\r\nОтображает бинарные датчики в Xiaomi Home как сущность текстового датчика или сущность бинарного датчика。\r\n### Отображать уведомления о изменении состояния устройства\r\nОтображать подробные уведомления о изменении состояния устройства, показывая только выбранные уведомления.",
"data": {
"devices_filter": "Фильтрация устройств",
"ctrl_mode": "Режим управления",
"action_debug": "Режим отладки действий",
"hide_non_standard_entities": "Скрыть нестандартные сущности",
"display_binary_mode": "Режим отображения бинарного датчика",
"display_devices_changed_notify": "Отображать уведомления о изменении состояния устройства"
}
},
@ -119,6 +120,7 @@
"update_devices": "Обновить список устройств",
"action_debug": "Режим отладки Action",
"hide_non_standard_entities": "Скрыть нестандартные сущности",
"display_binary_mode": "Режим отображения бинарного датчика",
"display_devices_changed_notify": "Отображать уведомления о изменении состояния устройства",
"update_trans_rules": "Обновить правила преобразования сущностей",
"update_lan_ctrl_config": "Обновить конфигурацию управления LAN",

View File

@ -42,12 +42,13 @@
},
"advanced_options": {
"title": "高级设置选项",
"description": "## 使用介绍\r\n### 除非您非常清楚下列选项的含义,否则请保持默认。\r\n### 筛选设备\r\n支持按照家庭房间名称、设备接入类型、设备型号筛选设备同时也支持设备维度筛选。\r\n### 控制模式\r\n- 自动:本地局域网内存在可用的小米中枢网关时, Home Assistant 会优先通过中枢网关发送设备控制指令以实现本地化控制功能。本地局域网不存在中枢时会尝试通过小米OT协议发送控制指令以实现本地化控制功能。只有当上述本地化控制条件不满足时设备控制指令才会通过云端发送。\r\n- 云端:控制指令仅通过云端发送。\r\n### Action 调试模式\r\n对于设备 MIoT-Spec-V2 定义的方法,在生成通知实体之外,还会生成一个文本输入框实体,您可以在调试时用它向设备发送控制指令。\r\n### 隐藏非标准生成实体\r\n隐藏名称以“*”开头的非标准 MIoT-Spec-V2 实例生成的实体。\r\n### 显示设备状态变化通知\r\n细化显示设备状态变化通知只显示勾选的通知消息。",
"description": "## 使用介绍\r\n### 除非您非常清楚下列选项的含义,否则请保持默认。\r\n### 筛选设备\r\n支持按照家庭房间名称、设备接入类型、设备型号筛选设备同时也支持设备维度筛选。\r\n### 控制模式\r\n- 自动:本地局域网内存在可用的小米中枢网关时, Home Assistant 会优先通过中枢网关发送设备控制指令以实现本地化控制功能。本地局域网不存在中枢时会尝试通过小米OT协议发送控制指令以实现本地化控制功能。只有当上述本地化控制条件不满足时设备控制指令才会通过云端发送。\r\n- 云端:控制指令仅通过云端发送。\r\n### Action 调试模式\r\n对于设备 MIoT-Spec-V2 定义的方法,在生成通知实体之外,还会生成一个文本输入框实体,您可以在调试时用它向设备发送控制指令。\r\n### 隐藏非标准生成实体\r\n隐藏名称以“*”开头的非标准 MIoT-Spec-V2 实例生成的实体。\r\n### 二进制传感器显示模式\r\n将米家中的二进制传感器显示为文本传感器实体或者二进制传感器实体。\r\n### 显示设备状态变化通知\r\n细化显示设备状态变化通知只显示勾选的通知消息。",
"data": {
"devices_filter": "筛选设备",
"ctrl_mode": "控制模式",
"action_debug": "Action 调试模式",
"hide_non_standard_entities": "隐藏非标准生成实体",
"display_binary_mode": "二进制传感器显示模式",
"display_devices_changed_notify": "显示设备状态变化通知"
}
},
@ -119,6 +120,7 @@
"update_devices": "更新设备列表",
"action_debug": "Action 调试模式",
"hide_non_standard_entities": "隐藏非标准生成实体",
"display_binary_mode": "二进制传感器显示模式",
"display_devices_changed_notify": "显示设备状态变化通知",
"update_trans_rules": "更新实体转换规则",
"update_lan_ctrl_config": "更新局域网控制配置",

View File

@ -42,12 +42,13 @@
},
"advanced_options": {
"title": "高級設置選項",
"description": "## 使用介紹\r\n### 除非您非常清楚下列選項的含義,否則請保持默認。\r\n### 篩選設備\r\n支持按照房間名稱和設備類型篩選設備同時也支持設備維度篩選。\r\n### 控制模式\r\n- 自動:本地局域網內存在可用的小米中樞網關時, Home Assistant 會優先通過中樞網關發送設備控制指令以實現本地化控制功能。本地局域網不存在中樞時會嘗試通過小米OT協議發送控制指令以實現本地化控制功能。只有當上述本地化控制條件不滿足時設備控制指令才會通過雲端發送。\r\n- 雲端:控制指令僅通過雲端發送。\r\n### Action 調試模式\r\n對於設備 MIoT-Spec-V2 定義的方法,在生成通知實體之外,還會生成一個文本輸入框實體,您可以在調試時用它向設備發送控制指令。\r\n### 隱藏非標準生成實體\r\n隱藏名稱以“*”開頭的非標準 MIoT-Spec-V2 實例生成的實體。\r\n### 顯示設備狀態變化通知\r\n細化顯示設備狀態變化通知只顯示勾選的通知消息。",
"description": "## 使用介紹\r\n### 除非您非常清楚下列選項的含義,否則請保持默認。\r\n### 篩選設備\r\n支持按照房間名稱和設備類型篩選設備同時也支持設備維度篩選。\r\n### 控制模式\r\n- 自動:本地局域網內存在可用的小米中樞網關時, Home Assistant 會優先通過中樞網關發送設備控制指令以實現本地化控制功能。本地局域網不存在中樞時會嘗試通過小米OT協議發送控制指令以實現本地化控制功能。只有當上述本地化控制條件不滿足時設備控制指令才會通過雲端發送。\r\n- 雲端:控制指令僅通過雲端發送。\r\n### Action 調試模式\r\n對於設備 MIoT-Spec-V2 定義的方法,在生成通知實體之外,還會生成一個文本輸入框實體,您可以在調試時用它向設備發送控制指令。\r\n### 隱藏非標準生成實體\r\n隱藏名稱以“*”開頭的非標準 MIoT-Spec-V2 實例生成的實體。\r\n### 二進制傳感器顯示模式\r\n將米家中的二進制傳感器顯示為文本傳感器實體或者二進制傳感器實體。\r\n### 顯示設備狀態變化通知\r\n細化顯示設備狀態變化通知只顯示勾選的通知消息。",
"data": {
"devices_filter": "篩選設備",
"ctrl_mode": "控制模式",
"action_debug": "Action 調試模式",
"hide_non_standard_entities": "隱藏非標準生成實體",
"display_binary_mode": "二進制傳感器顯示模式",
"display_devices_changed_notify": "顯示設備狀態變化通知"
}
},
@ -119,6 +120,7 @@
"update_devices": "更新設備列表",
"action_debug": "Action 調試模式",
"hide_non_standard_entities": "隱藏非標準生成實體",
"display_binary_mode": "二進制傳感器顯示模式",
"display_devices_changed_notify": "顯示設備狀態變化通知",
"update_trans_rules": "更新實體轉換規則",
"update_lan_ctrl_config": "更新局域網控制配置",

View File

@ -16,13 +16,10 @@ MIOT_I18N_RELATIVE_PATH: str = path.join(
ROOT_PATH, '../custom_components/xiaomi_home/miot/i18n')
SPEC_BOOL_TRANS_FILE = path.join(
ROOT_PATH,
'../custom_components/xiaomi_home/miot/specs/bool_trans.json')
SPEC_MULTI_LANG_FILE = path.join(
ROOT_PATH,
'../custom_components/xiaomi_home/miot/specs/multi_lang.json')
'../custom_components/xiaomi_home/miot/specs/bool_trans.yaml')
SPEC_FILTER_FILE = path.join(
ROOT_PATH,
'../custom_components/xiaomi_home/miot/specs/spec_filter.json')
'../custom_components/xiaomi_home/miot/specs/spec_filter.yaml')
def load_json_file(file_path: str) -> Optional[dict]:
@ -54,6 +51,12 @@ def load_yaml_file(file_path: str) -> Optional[dict]:
return None
def save_yaml_file(file_path: str, data: dict) -> None:
with open(file_path, 'w', encoding='utf-8') as file:
yaml.safe_dump(
data, file, default_flow_style=False, allow_unicode=True, indent=2)
def dict_str_str(d: dict) -> bool:
"""restricted format: dict[str, str]"""
if not isinstance(d, dict):
@ -161,25 +164,17 @@ def compare_dict_structure(dict1: dict, dict2: dict) -> bool:
def sort_bool_trans(file_path: str):
trans_data: dict = load_json_file(file_path=file_path)
trans_data = load_yaml_file(file_path=file_path)
assert isinstance(trans_data, dict), f'{file_path} format error'
trans_data['data'] = dict(sorted(trans_data['data'].items()))
for key, trans in trans_data['translate'].items():
trans_data['translate'][key] = dict(sorted(trans.items()))
return trans_data
def sort_multi_lang(file_path: str):
multi_lang: dict = load_json_file(file_path=file_path)
multi_lang = dict(sorted(multi_lang.items()))
for urn, trans in multi_lang.items():
multi_lang[urn] = dict(sorted(trans.items()))
for lang, spec in multi_lang[urn].items():
multi_lang[urn][lang] = dict(sorted(spec.items()))
return multi_lang
def sort_spec_filter(file_path: str):
filter_data: dict = load_json_file(file_path=file_path)
filter_data = load_yaml_file(file_path=file_path)
assert isinstance(filter_data, dict), f'{file_path} format error'
filter_data = dict(sorted(filter_data.items()))
for urn, spec in filter_data.items():
filter_data[urn] = dict(sorted(spec.items()))
@ -188,30 +183,26 @@ def sort_spec_filter(file_path: str):
@pytest.mark.github
def test_bool_trans():
data: dict = load_json_file(SPEC_BOOL_TRANS_FILE)
data = load_yaml_file(SPEC_BOOL_TRANS_FILE)
assert isinstance(data, dict)
assert data, f'load {SPEC_BOOL_TRANS_FILE} failed'
assert bool_trans(data), f'{SPEC_BOOL_TRANS_FILE} format error'
@pytest.mark.github
def test_spec_filter():
data: dict = load_json_file(SPEC_FILTER_FILE)
data = load_yaml_file(SPEC_FILTER_FILE)
assert isinstance(data, dict)
assert data, f'load {SPEC_FILTER_FILE} failed'
assert spec_filter(data), f'{SPEC_FILTER_FILE} format error'
@pytest.mark.github
def test_multi_lang():
data: dict = load_json_file(SPEC_MULTI_LANG_FILE)
assert data, f'load {SPEC_MULTI_LANG_FILE} failed'
assert nested_3_dict_str_str(data), f'{SPEC_MULTI_LANG_FILE} format error'
@pytest.mark.github
def test_miot_i18n():
for file_name in listdir(MIOT_I18N_RELATIVE_PATH):
file_path: str = path.join(MIOT_I18N_RELATIVE_PATH, file_name)
data: dict = load_json_file(file_path)
data = load_json_file(file_path)
assert isinstance(data, dict)
assert data, f'load {file_path} failed'
assert nested_3_dict_str_str(data), f'{file_path} format error'
@ -220,7 +211,8 @@ def test_miot_i18n():
def test_translations():
for file_name in listdir(TRANS_RELATIVE_PATH):
file_path: str = path.join(TRANS_RELATIVE_PATH, file_name)
data: dict = load_json_file(file_path)
data = load_json_file(file_path)
assert isinstance(data, dict)
assert data, f'load {file_path} failed'
assert dict_str_dict(data), f'{file_path} format error'
@ -237,15 +229,16 @@ def test_miot_lang_integrity():
i18n_names: set[str] = set(listdir(MIOT_I18N_RELATIVE_PATH))
assert len(i18n_names) == len(translations_names)
assert i18n_names == translations_names
bool_trans_data: set[str] = load_json_file(SPEC_BOOL_TRANS_FILE)
bool_trans_data = load_yaml_file(SPEC_BOOL_TRANS_FILE)
assert isinstance(bool_trans_data, dict)
bool_trans_names: set[str] = set(
bool_trans_data['translate']['default'].keys())
assert len(bool_trans_names) == len(translations_names)
# Check translation files structure
default_dict: dict = load_json_file(
default_dict = load_json_file(
path.join(TRANS_RELATIVE_PATH, integration_lang_list[0]))
for name in list(integration_lang_list)[1:]:
compare_dict: dict = load_json_file(
compare_dict = load_json_file(
path.join(TRANS_RELATIVE_PATH, name))
if not compare_dict_structure(default_dict, compare_dict):
_LOGGER.info(
@ -255,7 +248,7 @@ def test_miot_lang_integrity():
default_dict = load_json_file(
path.join(MIOT_I18N_RELATIVE_PATH, integration_lang_list[0]))
for name in list(integration_lang_list)[1:]:
compare_dict: dict = load_json_file(
compare_dict = load_json_file(
path.join(MIOT_I18N_RELATIVE_PATH, name))
if not compare_dict_structure(default_dict, compare_dict):
_LOGGER.info(
@ -272,19 +265,13 @@ def test_miot_data_sort():
'INTEGRATION_LANGUAGES not sorted, correct order\r\n'
f'{list(sort_langs.keys())}')
assert json.dumps(
load_json_file(file_path=SPEC_BOOL_TRANS_FILE)) == json.dumps(
load_yaml_file(file_path=SPEC_BOOL_TRANS_FILE)) == json.dumps(
sort_bool_trans(file_path=SPEC_BOOL_TRANS_FILE)), (
f'{SPEC_BOOL_TRANS_FILE} not sorted, goto project root path'
' and run the following command sorting, ',
'pytest -s -v -m update ./test/check_rule_format.py')
assert json.dumps(
load_json_file(file_path=SPEC_MULTI_LANG_FILE)) == json.dumps(
sort_multi_lang(file_path=SPEC_MULTI_LANG_FILE)), (
f'{SPEC_MULTI_LANG_FILE} not sorted, goto project root path'
' and run the following command sorting, ',
'pytest -s -v -m update ./test/check_rule_format.py')
assert json.dumps(
load_json_file(file_path=SPEC_FILTER_FILE)) == json.dumps(
load_yaml_file(file_path=SPEC_FILTER_FILE)) == json.dumps(
sort_spec_filter(file_path=SPEC_FILTER_FILE)), (
f'{SPEC_FILTER_FILE} not sorted, goto project root path'
' and run the following command sorting, ',
@ -294,11 +281,8 @@ def test_miot_data_sort():
@pytest.mark.update
def test_sort_spec_data():
sort_data: dict = sort_bool_trans(file_path=SPEC_BOOL_TRANS_FILE)
save_json_file(file_path=SPEC_BOOL_TRANS_FILE, data=sort_data)
save_yaml_file(file_path=SPEC_BOOL_TRANS_FILE, data=sort_data)
_LOGGER.info('%s formatted.', SPEC_BOOL_TRANS_FILE)
sort_data = sort_multi_lang(file_path=SPEC_MULTI_LANG_FILE)
save_json_file(file_path=SPEC_MULTI_LANG_FILE, data=sort_data)
_LOGGER.info('%s formatted.', SPEC_MULTI_LANG_FILE)
sort_data = sort_spec_filter(file_path=SPEC_FILTER_FILE)
save_json_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)