初始化config文件
This commit is contained in:
@@ -0,0 +1,351 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Copyright (C) 2024 Xiaomi Corporation.
|
||||
|
||||
The ownership and intellectual property rights of Xiaomi Home Assistant
|
||||
Integration and related Xiaomi cloud service API interface provided under this
|
||||
license, including source code and object code (collectively, "Licensed Work"),
|
||||
are owned by Xiaomi. Subject to the terms and conditions of this License, Xiaomi
|
||||
hereby grants you a personal, limited, non-exclusive, non-transferable,
|
||||
non-sublicensable, and royalty-free license to reproduce, use, modify, and
|
||||
distribute the Licensed Work only for your use of Home Assistant for
|
||||
non-commercial purposes. For the avoidance of doubt, Xiaomi does not authorize
|
||||
you to use the Licensed Work for any other purpose, including but not limited
|
||||
to use Licensed Work to develop applications (APP), Web services, and other
|
||||
forms of software.
|
||||
|
||||
You may reproduce and distribute copies of the Licensed Work, with or without
|
||||
modifications, whether in source or object form, provided that you must give
|
||||
any other recipients of the Licensed Work a copy of this License and retain all
|
||||
copyright and disclaimers.
|
||||
|
||||
Xiaomi provides the Licensed Work on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied, including, without
|
||||
limitation, any warranties, undertakes, or conditions of TITLE, NO ERROR OR
|
||||
OMISSION, CONTINUITY, RELIABILITY, NON-INFRINGEMENT, MERCHANTABILITY, or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. In any event, you are solely responsible
|
||||
for any direct, indirect, special, incidental, or consequential damages or
|
||||
losses arising from the use or inability to use the Licensed Work.
|
||||
|
||||
Xiaomi reserves all rights not expressly granted to you in this License.
|
||||
Except for the rights expressly granted by Xiaomi under this License, Xiaomi
|
||||
does not authorize you in any form to use the trademarks, copyrights, or other
|
||||
forms of intellectual property rights of Xiaomi and its affiliates, including,
|
||||
without limitation, without obtaining other written permission from Xiaomi, you
|
||||
shall not use "Xiaomi", "Mijia" and other words related to Xiaomi or words that
|
||||
may make the public associate with Xiaomi in any form to publicize or promote
|
||||
the software or hardware devices that use the Licensed Work.
|
||||
|
||||
Xiaomi has the right to immediately terminate all your authorization under this
|
||||
License in the event:
|
||||
1. You assert patent invalidation, litigation, or other claims against patents
|
||||
or other intellectual property rights of Xiaomi or its affiliates; or,
|
||||
2. You make, have made, manufacture, sell, or offer to sell products that knock
|
||||
off Xiaomi or its affiliates' products.
|
||||
|
||||
The Xiaomi Home integration Init File.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
import logging
|
||||
from typing import Optional
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
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 (
|
||||
MIoTSpecInstance, MIoTSpecParser, MIoTSpecService)
|
||||
from .miot.const import (
|
||||
DEFAULT_INTEGRATION_LANGUAGE, DOMAIN, SUPPORTED_PLATFORMS)
|
||||
from .miot.miot_error import MIoTOauthError
|
||||
from .miot.miot_device import MIoTDevice
|
||||
from .miot.miot_client import MIoTClient, get_miot_instance_async
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def async_setup(hass: HomeAssistant, hass_config: dict) -> bool:
|
||||
# pylint: disable=unused-argument
|
||||
hass.data.setdefault(DOMAIN, {})
|
||||
# {[entry_id:str]: MIoTClient}, miot client instance
|
||||
hass.data[DOMAIN].setdefault('miot_clients', {})
|
||||
# {[entry_id:str]: list[MIoTDevice]}
|
||||
hass.data[DOMAIN].setdefault('devices', {})
|
||||
# {[entry_id:str]: entities}
|
||||
hass.data[DOMAIN].setdefault('entities', {})
|
||||
for platform in SUPPORTED_PLATFORMS:
|
||||
hass.data[DOMAIN]['entities'][platform] = []
|
||||
return True
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant, config_entry: ConfigEntry
|
||||
) -> bool:
|
||||
"""Set up an entry."""
|
||||
def ha_persistent_notify(
|
||||
notify_id: str, title: Optional[str] = None,
|
||||
message: Optional[str] = None
|
||||
) -> None:
|
||||
"""Send messages in Notifications dialog box."""
|
||||
if title:
|
||||
persistent_notification.async_create(
|
||||
hass=hass, message=message or '',
|
||||
title=title, notification_id=notify_id)
|
||||
else:
|
||||
persistent_notification.async_dismiss(
|
||||
hass=hass, notification_id=notify_id)
|
||||
|
||||
entry_id = config_entry.entry_id
|
||||
entry_data = dict(config_entry.data)
|
||||
|
||||
ha_persistent_notify(
|
||||
notify_id=f'{entry_id}.oauth_error', title=None, message=None)
|
||||
|
||||
try:
|
||||
miot_client: MIoTClient = await get_miot_instance_async(
|
||||
hass=hass, entry_id=entry_id,
|
||||
entry_data=entry_data,
|
||||
persistent_notify=ha_persistent_notify)
|
||||
# Spec parser
|
||||
spec_parser = MIoTSpecParser(
|
||||
lang=entry_data.get(
|
||||
'integration_language', DEFAULT_INTEGRATION_LANGUAGE),
|
||||
storage=miot_client.miot_storage,
|
||||
loop=miot_client.main_loop
|
||||
)
|
||||
await spec_parser.init_async()
|
||||
# Manufacturer
|
||||
manufacturer: DeviceManufacturer = DeviceManufacturer(
|
||||
storage=miot_client.miot_storage,
|
||||
loop=miot_client.main_loop)
|
||||
await manufacturer.init_async()
|
||||
miot_devices: list[MIoTDevice] = []
|
||||
er = entity_registry.async_get(hass=hass)
|
||||
for did, info in miot_client.device_list.items():
|
||||
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(
|
||||
miot_client=miot_client,
|
||||
device_info={
|
||||
**info, 'manufacturer': manufacturer.get_name(
|
||||
info.get('manufacturer', ''))},
|
||||
spec_instance=spec_instance)
|
||||
miot_devices.append(device)
|
||||
device.spec_transform()
|
||||
# Remove filter entities and non-standard entities
|
||||
for platform in SUPPORTED_PLATFORMS:
|
||||
# ONLY support filter spec service translate entity
|
||||
if platform in device.entity_list:
|
||||
filter_entities = list(filter(
|
||||
lambda entity: (
|
||||
isinstance(entity.spec, MIoTSpecService)
|
||||
and (
|
||||
entity.spec.need_filter
|
||||
or (
|
||||
miot_client.hide_non_standard_entities
|
||||
and entity.spec.proprietary))
|
||||
),
|
||||
device.entity_list[platform]))
|
||||
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,
|
||||
description=entity.spec.description)
|
||||
if er.async_get(entity_id_or_uuid=entity_id):
|
||||
er.async_remove(entity_id=entity_id)
|
||||
if platform in device.prop_list:
|
||||
filter_props = list(filter(
|
||||
lambda prop: (
|
||||
prop.need_filter or (
|
||||
miot_client.hide_non_standard_entities
|
||||
and prop.proprietary)),
|
||||
device.prop_list[platform]))
|
||||
for prop in filter_props:
|
||||
device.prop_list[platform].remove(prop)
|
||||
entity_id = device.gen_prop_entity_id(
|
||||
ha_domain=platform, 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 platform in device.event_list:
|
||||
filter_events = list(filter(
|
||||
lambda event: (
|
||||
event.need_filter or (
|
||||
miot_client.hide_non_standard_entities
|
||||
and event.proprietary)),
|
||||
device.event_list[platform]))
|
||||
for event in filter_events:
|
||||
device.event_list[platform].remove(event)
|
||||
entity_id = device.gen_event_entity_id(
|
||||
ha_domain=platform, spec_name=event.name,
|
||||
siid=event.service.iid, eiid=event.iid)
|
||||
if er.async_get(entity_id_or_uuid=entity_id):
|
||||
er.async_remove(entity_id=entity_id)
|
||||
if platform in device.action_list:
|
||||
filter_actions = list(filter(
|
||||
lambda action: (
|
||||
action.need_filter or (
|
||||
miot_client.hide_non_standard_entities
|
||||
and action.proprietary)),
|
||||
device.action_list[platform]))
|
||||
for action in filter_actions:
|
||||
device.action_list[platform].remove(action)
|
||||
entity_id = device.gen_action_entity_id(
|
||||
ha_domain=platform, spec_name=action.name,
|
||||
siid=action.service.iid, aiid=action.iid)
|
||||
if er.async_get(entity_id_or_uuid=entity_id):
|
||||
er.async_remove(entity_id=entity_id)
|
||||
# Remove non-standard action debug entity
|
||||
if platform == 'notify':
|
||||
entity_id = device.gen_action_entity_id(
|
||||
ha_domain='text', spec_name=action.name,
|
||||
siid=action.service.iid, aiid=action.iid)
|
||||
if er.async_get(entity_id_or_uuid=entity_id):
|
||||
er.async_remove(entity_id=entity_id)
|
||||
# Action debug
|
||||
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(
|
||||
ha_domain='text', spec_name=action.name,
|
||||
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(
|
||||
config_entry, SUPPORTED_PLATFORMS)
|
||||
|
||||
# Remove the deleted devices
|
||||
devices_remove = (await miot_client.miot_storage.load_user_config_async(
|
||||
uid=config_entry.data['uid'],
|
||||
cloud_server=config_entry.data['cloud_server'],
|
||||
keys=['devices_remove'])).get('devices_remove', [])
|
||||
if isinstance(devices_remove, list) and devices_remove:
|
||||
dr = device_registry.async_get(hass)
|
||||
for did in devices_remove:
|
||||
device_entry = dr.async_get_device(
|
||||
identifiers={(
|
||||
DOMAIN,
|
||||
slugify_did(
|
||||
cloud_server=config_entry.data['cloud_server'],
|
||||
did=did))},
|
||||
connections=None)
|
||||
if not device_entry:
|
||||
_LOGGER.error('remove device not found, %s', did)
|
||||
continue
|
||||
dr.async_remove_device(device_id=device_entry.id)
|
||||
_LOGGER.info(
|
||||
'delete device entry, %s, %s', did, device_entry.id)
|
||||
await miot_client.miot_storage.update_user_config_async(
|
||||
uid=config_entry.data['uid'],
|
||||
cloud_server=config_entry.data['cloud_server'],
|
||||
config={'devices_remove': []})
|
||||
|
||||
await spec_parser.deinit_async()
|
||||
await manufacturer.deinit_async()
|
||||
|
||||
except MIoTOauthError as oauth_error:
|
||||
ha_persistent_notify(
|
||||
notify_id=f'{entry_id}.oauth_error',
|
||||
title='Xiaomi Home Oauth Error',
|
||||
message=f'Please re-add.\r\nerror: {oauth_error}'
|
||||
)
|
||||
except Exception as err:
|
||||
raise err
|
||||
|
||||
return True
|
||||
|
||||
|
||||
async def async_unload_entry(
|
||||
hass: HomeAssistant, config_entry: ConfigEntry
|
||||
) -> bool:
|
||||
"""Unload the entry."""
|
||||
entry_id = config_entry.entry_id
|
||||
# Unload the platform
|
||||
unload_ok = await hass.config_entries.async_unload_platforms(
|
||||
config_entry, SUPPORTED_PLATFORMS)
|
||||
if unload_ok:
|
||||
hass.data[DOMAIN]['entities'].pop(entry_id, None)
|
||||
hass.data[DOMAIN]['devices'].pop(entry_id, None)
|
||||
# Remove integration data
|
||||
miot_client: MIoTClient = hass.data[DOMAIN]['miot_clients'].pop(
|
||||
entry_id, None)
|
||||
if miot_client:
|
||||
await miot_client.deinit_async()
|
||||
del miot_client
|
||||
return True
|
||||
|
||||
|
||||
async def async_remove_entry(
|
||||
hass: HomeAssistant, config_entry: ConfigEntry
|
||||
) -> bool:
|
||||
"""Remove the entry."""
|
||||
entry_data = dict(config_entry.data)
|
||||
uid: str = entry_data['uid']
|
||||
cloud_server: str = entry_data['cloud_server']
|
||||
miot_storage: MIoTStorage = hass.data[DOMAIN]['miot_storage']
|
||||
miot_cert: MIoTCert = MIoTCert(
|
||||
storage=miot_storage, uid=uid, cloud_server=cloud_server)
|
||||
|
||||
# Clean device list
|
||||
await miot_storage.remove_async(
|
||||
domain='miot_devices', name=f'{uid}_{cloud_server}', type_=dict)
|
||||
# Clean user configuration
|
||||
await miot_storage.update_user_config_async(
|
||||
uid=uid, cloud_server=cloud_server, config=None)
|
||||
# Clean cert file
|
||||
await miot_cert.remove_user_cert_async()
|
||||
await miot_cert.remove_user_key_async()
|
||||
return True
|
||||
|
||||
|
||||
async def async_remove_config_entry_device(
|
||||
hass: HomeAssistant,
|
||||
config_entry: ConfigEntry,
|
||||
device_entry: device_registry.DeviceEntry
|
||||
) -> bool:
|
||||
"""Remove the device."""
|
||||
miot_client: MIoTClient = await get_miot_instance_async(
|
||||
hass=hass, entry_id=config_entry.entry_id)
|
||||
|
||||
if len(device_entry.identifiers) != 1:
|
||||
_LOGGER.error(
|
||||
'remove device failed, invalid identifiers, %s, %s',
|
||||
device_entry.id, device_entry.identifiers)
|
||||
return False
|
||||
identifiers = list(device_entry.identifiers)[0]
|
||||
if identifiers[0] != DOMAIN:
|
||||
_LOGGER.error(
|
||||
'remove device failed, invalid domain, %s, %s',
|
||||
device_entry.id, device_entry.identifiers)
|
||||
return False
|
||||
|
||||
# Remove device
|
||||
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', identifiers[1], device_entry.id)
|
||||
return True
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,96 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Copyright (C) 2024 Xiaomi Corporation.
|
||||
|
||||
The ownership and intellectual property rights of Xiaomi Home Assistant
|
||||
Integration and related Xiaomi cloud service API interface provided under this
|
||||
license, including source code and object code (collectively, "Licensed Work"),
|
||||
are owned by Xiaomi. Subject to the terms and conditions of this License, Xiaomi
|
||||
hereby grants you a personal, limited, non-exclusive, non-transferable,
|
||||
non-sublicensable, and royalty-free license to reproduce, use, modify, and
|
||||
distribute the Licensed Work only for your use of Home Assistant for
|
||||
non-commercial purposes. For the avoidance of doubt, Xiaomi does not authorize
|
||||
you to use the Licensed Work for any other purpose, including but not limited
|
||||
to use Licensed Work to develop applications (APP), Web services, and other
|
||||
forms of software.
|
||||
|
||||
You may reproduce and distribute copies of the Licensed Work, with or without
|
||||
modifications, whether in source or object form, provided that you must give
|
||||
any other recipients of the Licensed Work a copy of this License and retain all
|
||||
copyright and disclaimers.
|
||||
|
||||
Xiaomi provides the Licensed Work on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied, including, without
|
||||
limitation, any warranties, undertakes, or conditions of TITLE, NO ERROR OR
|
||||
OMISSION, CONTINUITY, RELIABILITY, NON-INFRINGEMENT, MERCHANTABILITY, or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. In any event, you are solely responsible
|
||||
for any direct, indirect, special, incidental, or consequential damages or
|
||||
losses arising from the use or inability to use the Licensed Work.
|
||||
|
||||
Xiaomi reserves all rights not expressly granted to you in this License.
|
||||
Except for the rights expressly granted by Xiaomi under this License, Xiaomi
|
||||
does not authorize you in any form to use the trademarks, copyrights, or other
|
||||
forms of intellectual property rights of Xiaomi and its affiliates, including,
|
||||
without limitation, without obtaining other written permission from Xiaomi, you
|
||||
shall not use "Xiaomi", "Mijia" and other words related to Xiaomi or words that
|
||||
may make the public associate with Xiaomi in any form to publicize or promote
|
||||
the software or hardware devices that use the Licensed Work.
|
||||
|
||||
Xiaomi has the right to immediately terminate all your authorization under this
|
||||
License in the event:
|
||||
1. You assert patent invalidation, litigation, or other claims against patents
|
||||
or other intellectual property rights of Xiaomi or its affiliates; or,
|
||||
2. You make, have made, manufacture, sell, or offer to sell products that knock
|
||||
off Xiaomi or its affiliates' products.
|
||||
|
||||
Binary sensor entities for Xiaomi Home.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.components.binary_sensor import BinarySensorEntity
|
||||
|
||||
from .miot.miot_spec import MIoTSpecProperty
|
||||
from .miot.miot_device import MIoTDevice, MIoTPropertyEntity
|
||||
from .miot.const import DOMAIN
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: ConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up a config entry."""
|
||||
device_list: list[MIoTDevice] = hass.data[DOMAIN]['devices'][
|
||||
config_entry.entry_id]
|
||||
|
||||
new_entities = []
|
||||
for miot_device in device_list:
|
||||
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)
|
||||
|
||||
|
||||
class BinarySensor(MIoTPropertyEntity, BinarySensorEntity):
|
||||
"""Binary sensor entities for Xiaomi Home."""
|
||||
|
||||
def __init__(self, miot_device: MIoTDevice, spec: MIoTSpecProperty) -> None:
|
||||
"""Initialize the BinarySensor."""
|
||||
super().__init__(miot_device=miot_device, spec=spec)
|
||||
# Set device_class
|
||||
self._attr_device_class = spec.device_class
|
||||
|
||||
@property
|
||||
def is_on(self) -> bool:
|
||||
"""On/Off state. True if the binary sensor is on, False otherwise."""
|
||||
if self.spec.name == 'contact-state':
|
||||
return bool(self._value) is False
|
||||
elif self.spec.name == 'occupancy-status':
|
||||
return bool(self._value)
|
||||
return self._value is True
|
||||
@@ -0,0 +1,88 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Copyright (C) 2024 Xiaomi Corporation.
|
||||
|
||||
The ownership and intellectual property rights of Xiaomi Home Assistant
|
||||
Integration and related Xiaomi cloud service API interface provided under this
|
||||
license, including source code and object code (collectively, "Licensed Work"),
|
||||
are owned by Xiaomi. Subject to the terms and conditions of this License, Xiaomi
|
||||
hereby grants you a personal, limited, non-exclusive, non-transferable,
|
||||
non-sublicensable, and royalty-free license to reproduce, use, modify, and
|
||||
distribute the Licensed Work only for your use of Home Assistant for
|
||||
non-commercial purposes. For the avoidance of doubt, Xiaomi does not authorize
|
||||
you to use the Licensed Work for any other purpose, including but not limited
|
||||
to use Licensed Work to develop applications (APP), Web services, and other
|
||||
forms of software.
|
||||
|
||||
You may reproduce and distribute copies of the Licensed Work, with or without
|
||||
modifications, whether in source or object form, provided that you must give
|
||||
any other recipients of the Licensed Work a copy of this License and retain all
|
||||
copyright and disclaimers.
|
||||
|
||||
Xiaomi provides the Licensed Work on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied, including, without
|
||||
limitation, any warranties, undertakes, or conditions of TITLE, NO ERROR OR
|
||||
OMISSION, CONTINUITY, RELIABILITY, NON-INFRINGEMENT, MERCHANTABILITY, or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. In any event, you are solely responsible
|
||||
for any direct, indirect, special, incidental, or consequential damages or
|
||||
losses arising from the use or inability to use the Licensed Work.
|
||||
|
||||
Xiaomi reserves all rights not expressly granted to you in this License.
|
||||
Except for the rights expressly granted by Xiaomi under this License, Xiaomi
|
||||
does not authorize you in any form to use the trademarks, copyrights, or other
|
||||
forms of intellectual property rights of Xiaomi and its affiliates, including,
|
||||
without limitation, without obtaining other written permission from Xiaomi, you
|
||||
shall not use "Xiaomi", "Mijia" and other words related to Xiaomi or words that
|
||||
may make the public associate with Xiaomi in any form to publicize or promote
|
||||
the software or hardware devices that use the Licensed Work.
|
||||
|
||||
Xiaomi has the right to immediately terminate all your authorization under this
|
||||
License in the event:
|
||||
1. You assert patent invalidation, litigation, or other claims against patents
|
||||
or other intellectual property rights of Xiaomi or its affiliates; or,
|
||||
2. You make, have made, manufacture, sell, or offer to sell products that knock
|
||||
off Xiaomi or its affiliates' products.
|
||||
|
||||
Button entities for Xiaomi Home.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.components.button import ButtonEntity
|
||||
|
||||
from .miot.miot_device import MIoTActionEntity, MIoTDevice
|
||||
from .miot.miot_spec import MIoTSpecAction
|
||||
from .miot.const import DOMAIN
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: ConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up a config entry."""
|
||||
device_list: list[MIoTDevice] = hass.data[DOMAIN]['devices'][
|
||||
config_entry.entry_id]
|
||||
|
||||
new_entities = []
|
||||
for miot_device in device_list:
|
||||
for action in miot_device.action_list.get('button', []):
|
||||
new_entities.append(Button(miot_device=miot_device, spec=action))
|
||||
|
||||
if new_entities:
|
||||
async_add_entities(new_entities)
|
||||
|
||||
|
||||
class Button(MIoTActionEntity, ButtonEntity):
|
||||
"""Button entities for Xiaomi Home."""
|
||||
|
||||
def __init__(self, miot_device: MIoTDevice, spec: MIoTSpecAction) -> None:
|
||||
"""Initialize the Button."""
|
||||
super().__init__(miot_device=miot_device, spec=spec)
|
||||
# Use default device class
|
||||
|
||||
async def async_press(self) -> None:
|
||||
"""Press the button."""
|
||||
return await self.action_async()
|
||||
@@ -0,0 +1,771 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Copyright (C) 2024 Xiaomi Corporation.
|
||||
|
||||
The ownership and intellectual property rights of Xiaomi Home Assistant
|
||||
Integration and related Xiaomi cloud service API interface provided under this
|
||||
license, including source code and object code (collectively, "Licensed Work"),
|
||||
are owned by Xiaomi. Subject to the terms and conditions of this License, Xiaomi
|
||||
hereby grants you a personal, limited, non-exclusive, non-transferable,
|
||||
non-sublicensable, and royalty-free license to reproduce, use, modify, and
|
||||
distribute the Licensed Work only for your use of Home Assistant for
|
||||
non-commercial purposes. For the avoidance of doubt, Xiaomi does not authorize
|
||||
you to use the Licensed Work for any other purpose, including but not limited
|
||||
to use Licensed Work to develop applications (APP), Web services, and other
|
||||
forms of software.
|
||||
|
||||
You may reproduce and distribute copies of the Licensed Work, with or without
|
||||
modifications, whether in source or object form, provided that you must give
|
||||
any other recipients of the Licensed Work a copy of this License and retain all
|
||||
copyright and disclaimers.
|
||||
|
||||
Xiaomi provides the Licensed Work on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied, including, without
|
||||
limitation, any warranties, undertakes, or conditions of TITLE, NO ERROR OR
|
||||
OMISSION, CONTINUITY, RELIABILITY, NON-INFRINGEMENT, MERCHANTABILITY, or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. In any event, you are solely responsible
|
||||
for any direct, indirect, special, incidental, or consequential damages or
|
||||
losses arising from the use or inability to use the Licensed Work.
|
||||
|
||||
Xiaomi reserves all rights not expressly granted to you in this License.
|
||||
Except for the rights expressly granted by Xiaomi under this License, Xiaomi
|
||||
does not authorize you in any form to use the trademarks, copyrights, or other
|
||||
forms of intellectual property rights of Xiaomi and its affiliates, including,
|
||||
without limitation, without obtaining other written permission from Xiaomi, you
|
||||
shall not use "Xiaomi", "Mijia" and other words related to Xiaomi or words that
|
||||
may make the public associate with Xiaomi in any form to publicize or promote
|
||||
the software or hardware devices that use the Licensed Work.
|
||||
|
||||
Xiaomi has the right to immediately terminate all your authorization under this
|
||||
License in the event:
|
||||
1. You assert patent invalidation, litigation, or other claims against patents
|
||||
or other intellectual property rights of Xiaomi or its affiliates; or,
|
||||
2. You make, have made, manufacture, sell, or offer to sell products that knock
|
||||
off Xiaomi or its affiliates' products.
|
||||
|
||||
Climate entities for Xiaomi Home.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
import logging
|
||||
from typing import Any, Optional
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.const import UnitOfTemperature
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.components.climate import (
|
||||
FAN_ON, FAN_OFF, SWING_OFF, SWING_BOTH, SWING_VERTICAL, SWING_HORIZONTAL,
|
||||
ATTR_TEMPERATURE, HVACMode, HVACAction, ClimateEntity, ClimateEntityFeature)
|
||||
|
||||
from .miot.const import DOMAIN
|
||||
from .miot.miot_device import MIoTDevice, MIoTServiceEntity, MIoTEntityData
|
||||
from .miot.miot_spec import MIoTSpecProperty
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback) -> None:
|
||||
"""Set up a config entry."""
|
||||
device_list: list[MIoTDevice] = hass.data[DOMAIN]['devices'][
|
||||
config_entry.entry_id]
|
||||
|
||||
new_entities = []
|
||||
for miot_device in device_list:
|
||||
for data in miot_device.entity_list.get('air-conditioner', []):
|
||||
new_entities.append(
|
||||
AirConditioner(miot_device=miot_device, entity_data=data))
|
||||
for data in miot_device.entity_list.get('heater', []):
|
||||
new_entities.append(
|
||||
Heater(miot_device=miot_device, entity_data=data))
|
||||
for data in miot_device.entity_list.get('bath-heater', []):
|
||||
new_entities.append(
|
||||
PtcBathHeater(miot_device=miot_device, entity_data=data))
|
||||
for data in miot_device.entity_list.get('thermostat', []):
|
||||
new_entities.append(
|
||||
Thermostat(miot_device=miot_device, entity_data=data))
|
||||
for data in miot_device.entity_list.get('electric-blanket', []):
|
||||
new_entities.append(
|
||||
ElectricBlanket(miot_device=miot_device, entity_data=data))
|
||||
|
||||
if new_entities:
|
||||
async_add_entities(new_entities)
|
||||
|
||||
|
||||
class FeatureOnOff(MIoTServiceEntity, ClimateEntity):
|
||||
"""TURN_ON and TURN_OFF feature of the climate entity."""
|
||||
_prop_on: Optional[MIoTSpecProperty]
|
||||
|
||||
def __init__(self, miot_device: MIoTDevice,
|
||||
entity_data: MIoTEntityData) -> None:
|
||||
"""Initialize the feature class."""
|
||||
self._prop_on = None
|
||||
|
||||
super().__init__(miot_device=miot_device, entity_data=entity_data)
|
||||
|
||||
def _init_on_off(self, service_name: str, prop_name: str) -> None:
|
||||
"""Initialize the on_off feature."""
|
||||
for prop in self.entity_data.props:
|
||||
if prop.name == prop_name and prop.service.name == service_name:
|
||||
if prop.format_ != bool:
|
||||
_LOGGER.error('wrong format %s %s, %s', service_name,
|
||||
prop_name, self.entity_id)
|
||||
continue
|
||||
self._attr_supported_features |= ClimateEntityFeature.TURN_ON
|
||||
self._attr_supported_features |= ClimateEntityFeature.TURN_OFF
|
||||
self._prop_on = prop
|
||||
break
|
||||
|
||||
async def async_turn_on(self) -> None:
|
||||
"""Turn on."""
|
||||
await self.set_property_async(prop=self._prop_on, value=True)
|
||||
|
||||
async def async_turn_off(self) -> None:
|
||||
"""Turn off."""
|
||||
await self.set_property_async(prop=self._prop_on, value=False)
|
||||
|
||||
|
||||
class FeatureTargetTemperature(MIoTServiceEntity, ClimateEntity):
|
||||
"""TARGET_TEMPERATURE feature of the climate entity."""
|
||||
_prop_target_temp: Optional[MIoTSpecProperty]
|
||||
|
||||
def __init__(self, miot_device: MIoTDevice,
|
||||
entity_data: MIoTEntityData) -> None:
|
||||
"""Initialize the feature class."""
|
||||
self._prop_target_temp = None
|
||||
self._attr_temperature_unit = None
|
||||
|
||||
super().__init__(miot_device=miot_device, entity_data=entity_data)
|
||||
# properties
|
||||
for prop in entity_data.props:
|
||||
if prop.name == 'target-temperature':
|
||||
if not prop.value_range:
|
||||
_LOGGER.error(
|
||||
'invalid target-temperature value_range format, %s',
|
||||
self.entity_id)
|
||||
continue
|
||||
self._attr_min_temp = prop.value_range.min_
|
||||
self._attr_max_temp = prop.value_range.max_
|
||||
self._attr_target_temperature_step = prop.value_range.step
|
||||
self._attr_temperature_unit = prop.external_unit
|
||||
self._attr_supported_features |= (
|
||||
ClimateEntityFeature.TARGET_TEMPERATURE)
|
||||
self._prop_target_temp = prop
|
||||
break
|
||||
# temperature_unit is required by the climate entity
|
||||
if not self._attr_temperature_unit:
|
||||
self._attr_temperature_unit = UnitOfTemperature.CELSIUS
|
||||
|
||||
async def async_set_temperature(self, **kwargs):
|
||||
"""Set the target temperature."""
|
||||
if ATTR_TEMPERATURE in kwargs:
|
||||
temp = kwargs[ATTR_TEMPERATURE]
|
||||
if temp > self._attr_max_temp:
|
||||
temp = self._attr_max_temp
|
||||
elif temp < self._attr_min_temp:
|
||||
temp = self._attr_min_temp
|
||||
|
||||
await self.set_property_async(prop=self._prop_target_temp,
|
||||
value=temp)
|
||||
|
||||
@property
|
||||
def target_temperature(self) -> Optional[float]:
|
||||
"""The current target temperature."""
|
||||
return (self.get_prop_value(
|
||||
prop=self._prop_target_temp) if self._prop_target_temp else None)
|
||||
|
||||
|
||||
class FeaturePresetMode(MIoTServiceEntity, ClimateEntity):
|
||||
"""PRESET_MODE feature of the climate entity."""
|
||||
_prop_mode: Optional[MIoTSpecProperty]
|
||||
_mode_map: Optional[dict[int, str]]
|
||||
|
||||
def __init__(self, miot_device: MIoTDevice,
|
||||
entity_data: MIoTEntityData) -> None:
|
||||
"""Initialize the feature class."""
|
||||
self._prop_mode = None
|
||||
self._mode_map = None
|
||||
|
||||
super().__init__(miot_device=miot_device, entity_data=entity_data)
|
||||
|
||||
def _init_preset_modes(self, service_name: str, prop_name: str) -> None:
|
||||
"""Initialize the preset modes."""
|
||||
for prop in self.entity_data.props:
|
||||
if prop.name == prop_name and prop.service.name == service_name:
|
||||
if not prop.value_list:
|
||||
_LOGGER.error('invalid %s %s value_list, %s', service_name,
|
||||
prop_name, self.entity_id)
|
||||
continue
|
||||
self._mode_map = prop.value_list.to_map()
|
||||
self._attr_preset_modes = prop.value_list.descriptions
|
||||
self._attr_supported_features |= (
|
||||
ClimateEntityFeature.PRESET_MODE)
|
||||
self._prop_mode = prop
|
||||
break
|
||||
|
||||
async def async_set_preset_mode(self, preset_mode: str) -> None:
|
||||
"""Set the preset mode."""
|
||||
await self.set_property_async(self._prop_mode,
|
||||
value=self.get_map_key(
|
||||
map_=self._mode_map,
|
||||
value=preset_mode))
|
||||
|
||||
@property
|
||||
def preset_mode(self) -> Optional[str]:
|
||||
"""The current preset mode."""
|
||||
return (self.get_map_value(
|
||||
map_=self._mode_map, key=self.get_prop_value(
|
||||
prop=self._prop_mode)) if self._prop_mode else None)
|
||||
|
||||
|
||||
class FeatureFanMode(MIoTServiceEntity, ClimateEntity):
|
||||
"""FAN_MODE feature of the climate entity."""
|
||||
_prop_fan_on: Optional[MIoTSpecProperty]
|
||||
_prop_fan_level: Optional[MIoTSpecProperty]
|
||||
_fan_mode_map: Optional[dict[int, str]]
|
||||
|
||||
def __init__(self, miot_device: MIoTDevice,
|
||||
entity_data: MIoTEntityData) -> None:
|
||||
"""Initialize the feature class."""
|
||||
self._prop_fan_on = None
|
||||
self._prop_fan_level = None
|
||||
self._fan_mode_map = None
|
||||
self._attr_fan_modes = None
|
||||
|
||||
super().__init__(miot_device=miot_device, entity_data=entity_data)
|
||||
# properties
|
||||
for prop in entity_data.props:
|
||||
if (prop.name == 'fan-level' and
|
||||
(prop.service.name == 'fan-control' or
|
||||
prop.service.name == 'thermostat')):
|
||||
if not prop.value_list:
|
||||
_LOGGER.error('invalid fan-level value_list, %s',
|
||||
self.entity_id)
|
||||
continue
|
||||
self._fan_mode_map = prop.value_list.to_map()
|
||||
self._attr_fan_modes = prop.value_list.descriptions
|
||||
self._attr_supported_features |= ClimateEntityFeature.FAN_MODE
|
||||
self._prop_fan_level = prop
|
||||
elif prop.name == 'on' and prop.service.name == 'fan-control':
|
||||
self._prop_fan_on = prop
|
||||
self._attr_supported_features |= ClimateEntityFeature.FAN_MODE
|
||||
|
||||
if self._prop_fan_on:
|
||||
if self._attr_fan_modes is None:
|
||||
self._attr_fan_modes = [FAN_ON, FAN_OFF]
|
||||
else:
|
||||
self._attr_fan_modes.append(FAN_OFF)
|
||||
|
||||
async def async_set_fan_mode(self, fan_mode):
|
||||
"""Set the target fan mode."""
|
||||
if fan_mode == FAN_OFF:
|
||||
await self.set_property_async(prop=self._prop_fan_on, value=False)
|
||||
return
|
||||
if fan_mode == FAN_ON:
|
||||
await self.set_property_async(prop=self._prop_fan_on, value=True)
|
||||
return
|
||||
mode_value = self.get_map_key(map_=self._fan_mode_map, value=fan_mode)
|
||||
if mode_value is None or not await self.set_property_async(
|
||||
prop=self._prop_fan_level, value=mode_value):
|
||||
raise RuntimeError(f'set climate prop.fan_mode failed, {fan_mode}, '
|
||||
f'{self.entity_id}')
|
||||
|
||||
@property
|
||||
def fan_mode(self) -> Optional[str]:
|
||||
"""The current fan mode."""
|
||||
if self._prop_fan_level is None and self._prop_fan_on is None:
|
||||
return None
|
||||
if self._prop_fan_level is None and self._prop_fan_on:
|
||||
return (FAN_ON if self.get_prop_value(
|
||||
prop=self._prop_fan_on) else FAN_OFF)
|
||||
return self.get_map_value(
|
||||
map_=self._fan_mode_map,
|
||||
key=self.get_prop_value(prop=self._prop_fan_level))
|
||||
|
||||
|
||||
class FeatureSwingMode(MIoTServiceEntity, ClimateEntity):
|
||||
"""SWING_MODE feature of the climate entity."""
|
||||
_prop_horizontal_swing: Optional[MIoTSpecProperty]
|
||||
_prop_vertical_swing: Optional[MIoTSpecProperty]
|
||||
|
||||
def __init__(self, miot_device: MIoTDevice,
|
||||
entity_data: MIoTEntityData) -> None:
|
||||
"""Initialize the feature class."""
|
||||
self._prop_horizontal_swing = None
|
||||
self._prop_vertical_swing = None
|
||||
|
||||
super().__init__(miot_device=miot_device, entity_data=entity_data)
|
||||
# properties
|
||||
swing_modes = []
|
||||
for prop in entity_data.props:
|
||||
if prop.name == 'horizontal-swing':
|
||||
swing_modes.append(SWING_HORIZONTAL)
|
||||
self._prop_horizontal_swing = prop
|
||||
elif prop.name == 'vertical-swing':
|
||||
swing_modes.append(SWING_VERTICAL)
|
||||
self._prop_vertical_swing = prop
|
||||
# swing modes
|
||||
if SWING_HORIZONTAL in swing_modes and SWING_VERTICAL in swing_modes:
|
||||
swing_modes.append(SWING_BOTH)
|
||||
if swing_modes:
|
||||
swing_modes.insert(0, SWING_OFF)
|
||||
self._attr_supported_features |= ClimateEntityFeature.SWING_MODE
|
||||
self._attr_swing_modes = swing_modes
|
||||
|
||||
async def async_set_swing_mode(self, swing_mode):
|
||||
"""Set the target swing operation."""
|
||||
if swing_mode == SWING_BOTH:
|
||||
await self.set_property_async(prop=self._prop_horizontal_swing,
|
||||
value=True)
|
||||
await self.set_property_async(prop=self._prop_vertical_swing,
|
||||
value=True)
|
||||
elif swing_mode == SWING_HORIZONTAL:
|
||||
if self._prop_vertical_swing:
|
||||
await self.set_property_async(prop=self._prop_vertical_swing,
|
||||
value=False)
|
||||
await self.set_property_async(prop=self._prop_horizontal_swing,
|
||||
value=True)
|
||||
elif swing_mode == SWING_VERTICAL:
|
||||
if self._prop_horizontal_swing:
|
||||
await self.set_property_async(prop=self._prop_horizontal_swing,
|
||||
value=False)
|
||||
await self.set_property_async(prop=self._prop_vertical_swing,
|
||||
value=True)
|
||||
elif swing_mode == SWING_OFF:
|
||||
if self._prop_horizontal_swing:
|
||||
await self.set_property_async(prop=self._prop_horizontal_swing,
|
||||
value=False)
|
||||
if self._prop_vertical_swing:
|
||||
await self.set_property_async(prop=self._prop_vertical_swing,
|
||||
value=False)
|
||||
else:
|
||||
raise RuntimeError(
|
||||
f'unknown swing_mode, {swing_mode}, {self.entity_id}')
|
||||
|
||||
@property
|
||||
def swing_mode(self) -> Optional[str]:
|
||||
"""The current swing mode of the fan."""
|
||||
if (self._prop_horizontal_swing is None and
|
||||
self._prop_vertical_swing is None):
|
||||
return None
|
||||
horizontal: bool = (self.get_prop_value(
|
||||
prop=self._prop_horizontal_swing)
|
||||
if self._prop_horizontal_swing else False)
|
||||
vertical: bool = (self.get_prop_value(prop=self._prop_vertical_swing)
|
||||
if self._prop_vertical_swing else False)
|
||||
if horizontal and vertical:
|
||||
return SWING_BOTH
|
||||
elif horizontal:
|
||||
return SWING_HORIZONTAL
|
||||
elif vertical:
|
||||
return SWING_VERTICAL
|
||||
else:
|
||||
return SWING_OFF
|
||||
|
||||
|
||||
class FeatureTemperature(MIoTServiceEntity, ClimateEntity):
|
||||
"""Temperature of the climate entity."""
|
||||
_prop_env_temperature: Optional[MIoTSpecProperty]
|
||||
|
||||
def __init__(self, miot_device: MIoTDevice,
|
||||
entity_data: MIoTEntityData) -> None:
|
||||
"""Initialize the feature class."""
|
||||
self._prop_env_temperature = None
|
||||
|
||||
super().__init__(miot_device=miot_device, entity_data=entity_data)
|
||||
# properties
|
||||
for prop in entity_data.props:
|
||||
if prop.name == 'temperature':
|
||||
self._prop_env_temperature = prop
|
||||
break
|
||||
|
||||
@property
|
||||
def current_temperature(self) -> Optional[float]:
|
||||
"""The current environment temperature."""
|
||||
return (self.get_prop_value(prop=self._prop_env_temperature)
|
||||
if self._prop_env_temperature else None)
|
||||
|
||||
|
||||
class FeatureHumidity(MIoTServiceEntity, ClimateEntity):
|
||||
"""Humidity of the climate entity."""
|
||||
_prop_env_humidity: Optional[MIoTSpecProperty]
|
||||
|
||||
def __init__(self, miot_device: MIoTDevice,
|
||||
entity_data: MIoTEntityData) -> None:
|
||||
"""Initialize the feature class."""
|
||||
self._prop_env_humidity = None
|
||||
|
||||
super().__init__(miot_device=miot_device, entity_data=entity_data)
|
||||
# properties
|
||||
for prop in entity_data.props:
|
||||
if prop.name == 'relative-humidity':
|
||||
self._prop_env_humidity = prop
|
||||
break
|
||||
|
||||
@property
|
||||
def current_humidity(self) -> Optional[float]:
|
||||
"""The current environment humidity."""
|
||||
return (self.get_prop_value(
|
||||
prop=self._prop_env_humidity) if self._prop_env_humidity else None)
|
||||
|
||||
|
||||
class FeatureTargetHumidity(MIoTServiceEntity, ClimateEntity):
|
||||
"""TARGET_HUMIDITY feature of the climate entity."""
|
||||
_prop_target_humidity: Optional[MIoTSpecProperty]
|
||||
|
||||
def __init__(self, miot_device: MIoTDevice,
|
||||
entity_data: MIoTEntityData) -> None:
|
||||
"""Initialize the feature class."""
|
||||
self._prop_target_humidity = None
|
||||
|
||||
super().__init__(miot_device=miot_device, entity_data=entity_data)
|
||||
# properties
|
||||
for prop in entity_data.props:
|
||||
if prop.name == 'target-humidity':
|
||||
if not prop.value_range:
|
||||
_LOGGER.error(
|
||||
'invalid target-humidity value_range format, %s',
|
||||
self.entity_id)
|
||||
continue
|
||||
self._attr_min_humidity = prop.value_range.min_
|
||||
self._attr_max_humidity = prop.value_range.max_
|
||||
self._attr_supported_features |= (
|
||||
ClimateEntityFeature.TARGET_HUMIDITY)
|
||||
self._prop_target_humidity = prop
|
||||
break
|
||||
|
||||
async def async_set_humidity(self, humidity):
|
||||
"""Set the target humidity."""
|
||||
if humidity > self._attr_max_humidity:
|
||||
humidity = self._attr_max_humidity
|
||||
elif humidity < self._attr_min_humidity:
|
||||
humidity = self._attr_min_humidity
|
||||
await self.set_property_async(prop=self._prop_target_humidity,
|
||||
value=humidity)
|
||||
|
||||
@property
|
||||
def target_humidity(self) -> Optional[int]:
|
||||
"""The current target humidity."""
|
||||
return (self.get_prop_value(prop=self._prop_target_humidity)
|
||||
if self._prop_target_humidity else None)
|
||||
|
||||
|
||||
class Heater(FeatureOnOff, FeatureTargetTemperature, FeatureTemperature,
|
||||
FeatureHumidity, FeaturePresetMode):
|
||||
"""Heater"""
|
||||
|
||||
def __init__(self, miot_device: MIoTDevice,
|
||||
entity_data: MIoTEntityData) -> None:
|
||||
"""Initialize the heater."""
|
||||
super().__init__(miot_device=miot_device, entity_data=entity_data)
|
||||
|
||||
self._attr_icon = 'mdi:radiator'
|
||||
# hvac modes
|
||||
self._attr_hvac_modes = [HVACMode.HEAT, HVACMode.OFF]
|
||||
# on/off
|
||||
self._init_on_off('heater', 'on')
|
||||
# preset modes
|
||||
self._init_preset_modes('heater', 'heat-level')
|
||||
|
||||
async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:
|
||||
"""Set the target hvac mode."""
|
||||
await self.set_property_async(
|
||||
prop=self._prop_on,
|
||||
value=False if hvac_mode == HVACMode.OFF else True)
|
||||
|
||||
@property
|
||||
def hvac_mode(self) -> Optional[HVACMode]:
|
||||
"""The current hvac mode."""
|
||||
return (HVACMode.HEAT if self.get_prop_value(
|
||||
prop=self._prop_on) else HVACMode.OFF)
|
||||
|
||||
@property
|
||||
def hvac_action(self) -> Optional[HVACAction]:
|
||||
"""The current hvac action."""
|
||||
if self.hvac_mode == HVACMode.HEAT:
|
||||
return HVACAction.HEATING
|
||||
return HVACAction.OFF
|
||||
|
||||
|
||||
class AirConditioner(FeatureOnOff, FeatureTargetTemperature,
|
||||
FeatureTargetHumidity, FeatureTemperature, FeatureHumidity,
|
||||
FeatureFanMode, FeatureSwingMode):
|
||||
"""Air conditioner"""
|
||||
_prop_mode: Optional[MIoTSpecProperty]
|
||||
_hvac_mode_map: Optional[dict[int, HVACMode]]
|
||||
_prop_ac_state: Optional[MIoTSpecProperty]
|
||||
_value_ac_state: Optional[dict[str, int]]
|
||||
|
||||
def __init__(self, miot_device: MIoTDevice,
|
||||
entity_data: MIoTEntityData) -> None:
|
||||
"""Initialize the air conditioner."""
|
||||
self._prop_mode = None
|
||||
self._hvac_mode_map = None
|
||||
self._prop_ac_state = None
|
||||
self._value_ac_state = None
|
||||
|
||||
super().__init__(miot_device=miot_device, entity_data=entity_data)
|
||||
self._attr_icon = 'mdi:air-conditioner'
|
||||
# on/off
|
||||
self._init_on_off('air-conditioner', 'on')
|
||||
# hvac modes
|
||||
self._attr_hvac_modes = None
|
||||
for prop in entity_data.props:
|
||||
if prop.name == 'mode' and prop.service.name == 'air-conditioner':
|
||||
if not prop.value_list:
|
||||
_LOGGER.error('invalid mode value_list, %s', self.entity_id)
|
||||
continue
|
||||
self._hvac_mode_map = {}
|
||||
for item in prop.value_list.items:
|
||||
if item.name in {'off', 'idle'}:
|
||||
self._hvac_mode_map[item.value] = HVACMode.OFF
|
||||
elif item.name in {'auto'}:
|
||||
self._hvac_mode_map[item.value] = HVACMode.AUTO
|
||||
elif item.name in {'cool'}:
|
||||
self._hvac_mode_map[item.value] = HVACMode.COOL
|
||||
elif item.name in {'heat'}:
|
||||
self._hvac_mode_map[item.value] = HVACMode.HEAT
|
||||
elif item.name in {'dry'}:
|
||||
self._hvac_mode_map[item.value] = HVACMode.DRY
|
||||
elif item.name in {'fan'}:
|
||||
self._hvac_mode_map[item.value] = HVACMode.FAN_ONLY
|
||||
elif item.name in {'heat_cool'}:
|
||||
self._hvac_mode_map[item.value] = HVACMode.HEAT_COOL
|
||||
self._attr_hvac_modes = list(self._hvac_mode_map.values())
|
||||
self._prop_mode = prop
|
||||
elif prop.name == 'ac-state':
|
||||
self._prop_ac_state = prop
|
||||
self._value_ac_state = {}
|
||||
self.sub_prop_changed(prop=prop,
|
||||
handler=self.__ac_state_changed)
|
||||
|
||||
if self._attr_hvac_modes is None:
|
||||
self._attr_hvac_modes = [HVACMode.OFF]
|
||||
elif HVACMode.OFF not in self._attr_hvac_modes:
|
||||
self._attr_hvac_modes.append(HVACMode.OFF)
|
||||
|
||||
async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:
|
||||
"""Set the target hvac mode."""
|
||||
# set the device off
|
||||
if hvac_mode == HVACMode.OFF:
|
||||
if not await self.set_property_async(prop=self._prop_on,
|
||||
value=False):
|
||||
raise RuntimeError(f'set climate prop.on failed, {hvac_mode}, '
|
||||
f'{self.entity_id}')
|
||||
return
|
||||
# set the device on
|
||||
if self.get_prop_value(prop=self._prop_on) is not True:
|
||||
await self.set_property_async(prop=self._prop_on,
|
||||
value=True,
|
||||
write_ha_state=False)
|
||||
# set mode
|
||||
if self._prop_mode is None:
|
||||
return
|
||||
mode_value = self.get_map_key(map_=self._hvac_mode_map, value=hvac_mode)
|
||||
if mode_value is None or not await self.set_property_async(
|
||||
prop=self._prop_mode, value=mode_value):
|
||||
raise RuntimeError(
|
||||
f'set climate prop.mode failed, {hvac_mode}, {self.entity_id}')
|
||||
|
||||
@property
|
||||
def hvac_mode(self) -> Optional[HVACMode]:
|
||||
"""The current hvac mode."""
|
||||
if self.get_prop_value(prop=self._prop_on) is False:
|
||||
return HVACMode.OFF
|
||||
return (self.get_map_value(map_=self._hvac_mode_map,
|
||||
key=self.get_prop_value(
|
||||
prop=self._prop_mode))
|
||||
if self._prop_mode else None)
|
||||
|
||||
@property
|
||||
def hvac_action(self) -> Optional[HVACAction]:
|
||||
"""The current hvac action."""
|
||||
if self.hvac_mode is None:
|
||||
return None
|
||||
if self.hvac_mode == HVACMode.OFF:
|
||||
return HVACAction.OFF
|
||||
if self.hvac_mode == HVACMode.FAN_ONLY:
|
||||
return HVACAction.FAN
|
||||
if self.hvac_mode == HVACMode.COOL:
|
||||
return HVACAction.COOLING
|
||||
if self.hvac_mode == HVACMode.HEAT:
|
||||
return HVACAction.HEATING
|
||||
if self.hvac_mode == HVACMode.DRY:
|
||||
return HVACAction.DRYING
|
||||
return HVACAction.IDLE
|
||||
|
||||
def __ac_state_changed(self, prop: MIoTSpecProperty, value: Any) -> None:
|
||||
del prop
|
||||
if not isinstance(value, str):
|
||||
_LOGGER.error('ac_status value format error, %s', value)
|
||||
return
|
||||
v_ac_state = {}
|
||||
v_split = value.split('_')
|
||||
for item in v_split:
|
||||
if len(item) < 2:
|
||||
_LOGGER.error('ac_status value error, %s', item)
|
||||
continue
|
||||
try:
|
||||
v_ac_state[item[0]] = int(item[1:])
|
||||
except ValueError:
|
||||
_LOGGER.error('ac_status value error, %s', item)
|
||||
# P: status. 0: on, 1: off
|
||||
if 'P' in v_ac_state and self._prop_on:
|
||||
self.set_prop_value(prop=self._prop_on, value=v_ac_state['P'] == 0)
|
||||
# M: model. 0: cool, 1: heat, 2: auto, 3: fan, 4: dry
|
||||
if 'M' in v_ac_state and self._prop_mode:
|
||||
mode: Optional[HVACMode] = {
|
||||
0: HVACMode.COOL,
|
||||
1: HVACMode.HEAT,
|
||||
2: HVACMode.AUTO,
|
||||
3: HVACMode.FAN_ONLY,
|
||||
4: HVACMode.DRY,
|
||||
}.get(v_ac_state['M'], None)
|
||||
if mode:
|
||||
self.set_prop_value(prop=self._prop_mode,
|
||||
value=self.get_map_key(
|
||||
map_=self._hvac_mode_map, value=mode))
|
||||
# T: target temperature
|
||||
if 'T' in v_ac_state and self._prop_target_temp:
|
||||
self.set_prop_value(prop=self._prop_target_temp,
|
||||
value=v_ac_state['T'])
|
||||
# S: fan level. 0: auto, 1: low, 2: media, 3: high
|
||||
if 'S' in v_ac_state and self._prop_fan_level:
|
||||
self.set_prop_value(prop=self._prop_fan_level,
|
||||
value=v_ac_state['S'])
|
||||
# D: swing mode. 0: on, 1: off
|
||||
if ('D' in v_ac_state and self._attr_swing_modes and
|
||||
len(self._attr_swing_modes) == 2):
|
||||
if (SWING_HORIZONTAL in self._attr_swing_modes and
|
||||
self._prop_horizontal_swing):
|
||||
self.set_prop_value(prop=self._prop_horizontal_swing,
|
||||
value=v_ac_state['D'] == 0)
|
||||
elif (SWING_VERTICAL in self._attr_swing_modes and
|
||||
self._prop_vertical_swing):
|
||||
self.set_prop_value(prop=self._prop_vertical_swing,
|
||||
value=v_ac_state['D'] == 0)
|
||||
|
||||
self._value_ac_state.update(v_ac_state)
|
||||
_LOGGER.debug('ac_state update, %s', self._value_ac_state)
|
||||
|
||||
|
||||
class PtcBathHeater(FeatureTargetTemperature, FeatureTemperature,
|
||||
FeatureFanMode, FeatureSwingMode, FeaturePresetMode):
|
||||
"""Ptc bath heater"""
|
||||
_prop_mode: Optional[MIoTSpecProperty]
|
||||
_hvac_mode_map: Optional[dict[int, HVACMode]]
|
||||
|
||||
def __init__(self, miot_device: MIoTDevice,
|
||||
entity_data: MIoTEntityData) -> None:
|
||||
"""Initialize the ptc bath heater."""
|
||||
self._prop_mode = None
|
||||
self._hvac_mode_map = None
|
||||
|
||||
super().__init__(miot_device=miot_device, entity_data=entity_data)
|
||||
self._attr_icon = 'mdi:hvac'
|
||||
# hvac modes
|
||||
for prop in entity_data.props:
|
||||
if prop.name == 'mode' and prop.service.name == 'ptc-bath-heater':
|
||||
if not prop.value_list:
|
||||
_LOGGER.error('invalid mode value_list, %s', self.entity_id)
|
||||
continue
|
||||
self._hvac_mode_map = {}
|
||||
for item in prop.value_list.items:
|
||||
if item.name in {'off', 'idle'}:
|
||||
self._hvac_mode_map[item.value] = HVACMode.OFF
|
||||
break
|
||||
if self._hvac_mode_map:
|
||||
self._attr_hvac_modes = [HVACMode.AUTO, HVACMode.OFF]
|
||||
else:
|
||||
_LOGGER.error('no idle mode, %s', self.entity_id)
|
||||
# preset modes
|
||||
self._init_preset_modes('ptc-bath-heater', 'mode')
|
||||
|
||||
async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:
|
||||
"""Set the target hvac mode."""
|
||||
if self._prop_mode is None or hvac_mode != HVACMode.OFF:
|
||||
return
|
||||
mode_value = self.get_map_key(map_=self._hvac_mode_map, value=hvac_mode)
|
||||
if mode_value is None or not await self.set_property_async(
|
||||
prop=self._prop_mode, value=mode_value):
|
||||
raise RuntimeError(
|
||||
f'set ptc-bath-heater {hvac_mode} failed, {self.entity_id}')
|
||||
|
||||
@property
|
||||
def hvac_mode(self) -> Optional[HVACMode]:
|
||||
"""The current hvac mode."""
|
||||
if self._prop_mode is None:
|
||||
return None
|
||||
current_mode = self.get_prop_value(prop=self._prop_mode)
|
||||
if current_mode is None:
|
||||
return None
|
||||
mode_value = self.get_map_value(map_=self._hvac_mode_map,
|
||||
key=current_mode)
|
||||
return HVACMode.OFF if mode_value == HVACMode.OFF else HVACMode.AUTO
|
||||
|
||||
|
||||
class Thermostat(FeatureOnOff, FeatureTargetTemperature, FeatureTemperature,
|
||||
FeatureHumidity, FeatureFanMode, FeaturePresetMode):
|
||||
"""Thermostat"""
|
||||
|
||||
def __init__(self, miot_device: MIoTDevice,
|
||||
entity_data: MIoTEntityData) -> None:
|
||||
"""Initialize the thermostat."""
|
||||
super().__init__(miot_device=miot_device, entity_data=entity_data)
|
||||
|
||||
self._attr_icon = 'mdi:thermostat'
|
||||
# hvac modes
|
||||
self._attr_hvac_modes = [HVACMode.AUTO, HVACMode.OFF]
|
||||
# on/off
|
||||
self._init_on_off('thermostat', 'on')
|
||||
# preset modes
|
||||
self._init_preset_modes('thermostat', 'mode')
|
||||
|
||||
async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:
|
||||
"""Set the target hvac mode."""
|
||||
await self.set_property_async(
|
||||
prop=self._prop_on,
|
||||
value=False if hvac_mode == HVACMode.OFF else True)
|
||||
|
||||
@property
|
||||
def hvac_mode(self) -> Optional[HVACMode]:
|
||||
"""The current hvac mode."""
|
||||
return (HVACMode.AUTO if self.get_prop_value(
|
||||
prop=self._prop_on) else HVACMode.OFF)
|
||||
|
||||
|
||||
class ElectricBlanket(FeatureOnOff, FeatureTargetTemperature,
|
||||
FeatureTemperature, FeaturePresetMode):
|
||||
"""Electric blanket"""
|
||||
|
||||
def __init__(self, miot_device: MIoTDevice,
|
||||
entity_data: MIoTEntityData) -> None:
|
||||
"""Initialize the electric blanket."""
|
||||
super().__init__(miot_device=miot_device, entity_data=entity_data)
|
||||
|
||||
self._attr_icon = 'mdi:rug'
|
||||
# hvac modes
|
||||
self._attr_hvac_modes = [HVACMode.HEAT, HVACMode.OFF]
|
||||
# on/off
|
||||
self._init_on_off('electric-blanket', 'on')
|
||||
# preset modes
|
||||
self._init_preset_modes('electric-blanket', 'mode')
|
||||
|
||||
async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:
|
||||
"""Set the target hvac mode."""
|
||||
await self.set_property_async(
|
||||
prop=self._prop_on,
|
||||
value=False if hvac_mode == HVACMode.OFF else True)
|
||||
|
||||
@property
|
||||
def hvac_mode(self) -> Optional[HVACMode]:
|
||||
"""The current hvac mode."""
|
||||
return (HVACMode.HEAT if self.get_prop_value(
|
||||
prop=self._prop_on) else HVACMode.OFF)
|
||||
|
||||
@property
|
||||
def hvac_action(self) -> Optional[HVACAction]:
|
||||
"""The current hvac action."""
|
||||
if self.hvac_mode == HVACMode.OFF:
|
||||
return HVACAction.OFF
|
||||
return HVACAction.HEATING
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,317 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Copyright (C) 2024 Xiaomi Corporation.
|
||||
|
||||
The ownership and intellectual property rights of Xiaomi Home Assistant
|
||||
Integration and related Xiaomi cloud service API interface provided under this
|
||||
license, including source code and object code (collectively, "Licensed Work"),
|
||||
are owned by Xiaomi. Subject to the terms and conditions of this License, Xiaomi
|
||||
hereby grants you a personal, limited, non-exclusive, non-transferable,
|
||||
non-sublicensable, and royalty-free license to reproduce, use, modify, and
|
||||
distribute the Licensed Work only for your use of Home Assistant for
|
||||
non-commercial purposes. For the avoidance of doubt, Xiaomi does not authorize
|
||||
you to use the Licensed Work for any other purpose, including but not limited
|
||||
to use Licensed Work to develop applications (APP), Web services, and other
|
||||
forms of software.
|
||||
|
||||
You may reproduce and distribute copies of the Licensed Work, with or without
|
||||
modifications, whether in source or object form, provided that you must give
|
||||
any other recipients of the Licensed Work a copy of this License and retain all
|
||||
copyright and disclaimers.
|
||||
|
||||
Xiaomi provides the Licensed Work on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied, including, without
|
||||
limitation, any warranties, undertakes, or conditions of TITLE, NO ERROR OR
|
||||
OMISSION, CONTINUITY, RELIABILITY, NON-INFRINGEMENT, MERCHANTABILITY, or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. In any event, you are solely responsible
|
||||
for any direct, indirect, special, incidental, or consequential damages or
|
||||
losses arising from the use or inability to use the Licensed Work.
|
||||
|
||||
Xiaomi reserves all rights not expressly granted to you in this License.
|
||||
Except for the rights expressly granted by Xiaomi under this License, Xiaomi
|
||||
does not authorize you in any form to use the trademarks, copyrights, or other
|
||||
forms of intellectual property rights of Xiaomi and its affiliates, including,
|
||||
without limitation, without obtaining other written permission from Xiaomi, you
|
||||
shall not use "Xiaomi", "Mijia" and other words related to Xiaomi or words that
|
||||
may make the public associate with Xiaomi in any form to publicize or promote
|
||||
the software or hardware devices that use the Licensed Work.
|
||||
|
||||
Xiaomi has the right to immediately terminate all your authorization under this
|
||||
License in the event:
|
||||
1. You assert patent invalidation, litigation, or other claims against patents
|
||||
or other intellectual property rights of Xiaomi or its affiliates; or,
|
||||
2. You make, have made, manufacture, sell, or offer to sell products that knock
|
||||
off Xiaomi or its affiliates' products.
|
||||
|
||||
Cover entities for Xiaomi Home.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
from typing import Any, Optional
|
||||
import re
|
||||
import logging
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.components.cover import (ATTR_POSITION, CoverEntity,
|
||||
CoverEntityFeature,
|
||||
CoverDeviceClass)
|
||||
|
||||
from .miot.miot_spec import MIoTSpecProperty
|
||||
from .miot.miot_device import MIoTDevice, MIoTEntityData, MIoTServiceEntity
|
||||
from .miot.const import DOMAIN
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback) -> None:
|
||||
"""Set up a config entry."""
|
||||
device_list: list[MIoTDevice] = hass.data[DOMAIN]['devices'][
|
||||
config_entry.entry_id]
|
||||
|
||||
new_entities = []
|
||||
for miot_device in device_list:
|
||||
for data in miot_device.entity_list.get('cover', []):
|
||||
if data.spec.name == 'curtain':
|
||||
data.spec.device_class = CoverDeviceClass.CURTAIN
|
||||
elif data.spec.name == 'window-opener':
|
||||
data.spec.device_class = CoverDeviceClass.WINDOW
|
||||
elif data.spec.name == 'motor-controller':
|
||||
data.spec.device_class = CoverDeviceClass.SHUTTER
|
||||
elif data.spec.name == 'airer':
|
||||
data.spec.device_class = CoverDeviceClass.BLIND
|
||||
new_entities.append(Cover(miot_device=miot_device,
|
||||
entity_data=data))
|
||||
|
||||
if new_entities:
|
||||
async_add_entities(new_entities)
|
||||
|
||||
|
||||
class Cover(MIoTServiceEntity, CoverEntity):
|
||||
"""Cover entities for Xiaomi Home."""
|
||||
# pylint: disable=unused-argument
|
||||
_cover_dead_zone_width: int
|
||||
_prop_motor_control: Optional[MIoTSpecProperty]
|
||||
_prop_motor_value_open: Optional[int]
|
||||
_prop_motor_value_close: Optional[int]
|
||||
_prop_motor_value_pause: Optional[int]
|
||||
_prop_status: Optional[MIoTSpecProperty]
|
||||
_prop_status_opening: Optional[list[int]]
|
||||
_prop_status_closing: Optional[list[int]]
|
||||
_prop_status_closed: Optional[list[int]]
|
||||
_prop_current_position: Optional[MIoTSpecProperty]
|
||||
_prop_target_position: Optional[MIoTSpecProperty]
|
||||
_prop_position_value_min: Optional[int]
|
||||
_prop_position_value_max: Optional[int]
|
||||
_prop_position_value_range: Optional[int]
|
||||
_prop_pos_closing: bool
|
||||
_prop_pos_opening: bool
|
||||
|
||||
def __init__(self, miot_device: MIoTDevice,
|
||||
entity_data: MIoTEntityData) -> None:
|
||||
"""Initialize the Cover."""
|
||||
super().__init__(miot_device=miot_device, entity_data=entity_data)
|
||||
self._attr_device_class = entity_data.spec.device_class
|
||||
self._attr_supported_color_modes = set()
|
||||
self._attr_supported_features = CoverEntityFeature(0)
|
||||
|
||||
self._cover_dead_zone_width = (
|
||||
miot_device.miot_client.cover_dead_zone_width)
|
||||
|
||||
self._prop_motor_control = None
|
||||
self._prop_motor_value_open = None
|
||||
self._prop_motor_value_close = None
|
||||
self._prop_motor_value_pause = None
|
||||
self._prop_status = None
|
||||
self._prop_status_opening = []
|
||||
self._prop_status_closing = []
|
||||
self._prop_status_closed = []
|
||||
self._prop_current_position = None
|
||||
self._prop_target_position = None
|
||||
self._prop_position_value_min = None
|
||||
self._prop_position_value_max = None
|
||||
self._prop_position_value_range = None
|
||||
self._prop_pos_closing = False
|
||||
self._prop_pos_opening = False
|
||||
|
||||
# properties
|
||||
for prop in entity_data.props:
|
||||
if prop.name == 'motor-control':
|
||||
if not prop.value_list:
|
||||
_LOGGER.error('motor-control value_list is None, %s',
|
||||
self.entity_id)
|
||||
continue
|
||||
for item in prop.value_list.items:
|
||||
if item.name in {'open', 'up'}:
|
||||
self._attr_supported_features |= (
|
||||
CoverEntityFeature.OPEN)
|
||||
self._prop_motor_value_open = item.value
|
||||
elif item.name in {'close', 'down'}:
|
||||
self._attr_supported_features |= (
|
||||
CoverEntityFeature.CLOSE)
|
||||
self._prop_motor_value_close = item.value
|
||||
elif item.name in {'pause', 'stop'}:
|
||||
self._attr_supported_features |= (
|
||||
CoverEntityFeature.STOP)
|
||||
self._prop_motor_value_pause = item.value
|
||||
self._prop_motor_control = prop
|
||||
elif prop.name == 'status':
|
||||
if not prop.value_list:
|
||||
_LOGGER.error('status value_list is None, %s',
|
||||
self.entity_id)
|
||||
continue
|
||||
for item in prop.value_list.items:
|
||||
item_str: str = item.name
|
||||
item_name: str = re.sub(r'[^a-z]', '', item_str)
|
||||
if item_name in {
|
||||
'opening', 'open', 'up', 'uping', 'rise', 'rising'
|
||||
}:
|
||||
self._prop_status_opening.append(item.value)
|
||||
elif item_name in {
|
||||
'closing', 'close', 'down', 'dowm', 'falling',
|
||||
'fallin', 'dropping', 'downing', 'lower'
|
||||
}:
|
||||
self._prop_status_closing.append(item.value)
|
||||
elif item_name in {
|
||||
'closed', 'closeover', 'stopatlowest',
|
||||
'stoplowerlimit', 'lowerlimitstop', 'floor',
|
||||
'lowerlimit'
|
||||
}:
|
||||
self._prop_status_closed.append(item.value)
|
||||
self._prop_status = prop
|
||||
elif prop.name == 'current-position':
|
||||
if not prop.value_range:
|
||||
_LOGGER.error(
|
||||
'invalid current-position value_range format, %s',
|
||||
self.entity_id)
|
||||
continue
|
||||
self._prop_position_value_min = prop.value_range.min_
|
||||
self._prop_position_value_max = prop.value_range.max_
|
||||
self._prop_position_value_range = (prop.value_range.max_ -
|
||||
prop.value_range.min_)
|
||||
self._prop_current_position = prop
|
||||
elif prop.name == 'target-position':
|
||||
if not prop.value_range:
|
||||
_LOGGER.error(
|
||||
'invalid target-position value_range format, %s',
|
||||
self.entity_id)
|
||||
continue
|
||||
self._prop_position_value_min = prop.value_range.min_
|
||||
self._prop_position_value_max = prop.value_range.max_
|
||||
self._prop_position_value_range = (prop.value_range.max_ -
|
||||
prop.value_range.min_)
|
||||
self._attr_supported_features |= CoverEntityFeature.SET_POSITION
|
||||
self._prop_target_position = prop
|
||||
# For the device that has the current position property but no status
|
||||
# property, the current position property will be used to determine the
|
||||
# opening and the closing status.
|
||||
if (self._prop_status is None) and (self._prop_current_position
|
||||
is not None):
|
||||
self.sub_prop_changed(self._prop_current_position,
|
||||
self._position_changed_handler)
|
||||
|
||||
def _position_changed_handler(self, prop: MIoTSpecProperty,
|
||||
ctx: Any) -> None:
|
||||
self._prop_pos_closing = False
|
||||
self._prop_pos_opening = False
|
||||
self.async_write_ha_state()
|
||||
|
||||
async def async_open_cover(self, **kwargs) -> None:
|
||||
"""Open the cover."""
|
||||
current = None if (self._prop_current_position
|
||||
is None) else self.get_prop_value(
|
||||
prop=self._prop_current_position)
|
||||
if (current is not None) and (current < self._prop_position_value_max):
|
||||
self._prop_pos_opening = True
|
||||
self._prop_pos_closing = False
|
||||
await self.set_property_async(self._prop_motor_control,
|
||||
self._prop_motor_value_open)
|
||||
|
||||
async def async_close_cover(self, **kwargs) -> None:
|
||||
"""Close the cover."""
|
||||
current = None if (self._prop_current_position
|
||||
is None) else self.get_prop_value(
|
||||
prop=self._prop_current_position)
|
||||
if (current is not None) and (current > self._prop_position_value_min):
|
||||
self._prop_pos_opening = False
|
||||
self._prop_pos_closing = True
|
||||
await self.set_property_async(self._prop_motor_control,
|
||||
self._prop_motor_value_close)
|
||||
|
||||
async def async_stop_cover(self, **kwargs) -> None:
|
||||
"""Stop the cover."""
|
||||
self._prop_pos_opening = False
|
||||
self._prop_pos_closing = False
|
||||
await self.set_property_async(self._prop_motor_control,
|
||||
self._prop_motor_value_pause)
|
||||
|
||||
async def async_set_cover_position(self, **kwargs) -> None:
|
||||
"""Set the position of the cover."""
|
||||
pos = kwargs.get(ATTR_POSITION, None)
|
||||
if pos is None:
|
||||
return None
|
||||
current = self.current_cover_position
|
||||
if current is not None:
|
||||
self._prop_pos_opening = pos > current
|
||||
self._prop_pos_closing = pos < current
|
||||
pos = round(pos * self._prop_position_value_range / 100)
|
||||
await self.set_property_async(prop=self._prop_target_position,
|
||||
value=pos)
|
||||
|
||||
@property
|
||||
def current_cover_position(self) -> Optional[int]:
|
||||
"""Return the current position.
|
||||
|
||||
0: the cover is closed, 100: the cover is fully opened, None: unknown.
|
||||
"""
|
||||
if self._prop_current_position is None:
|
||||
# Assume that the current position is the same as the target
|
||||
# position when the current position is not defined in the device's
|
||||
# MIoT-Spec-V2.
|
||||
if self._prop_target_position is None:
|
||||
return None
|
||||
self._prop_pos_opening = False
|
||||
self._prop_pos_closing = False
|
||||
return self.get_prop_value(prop=self._prop_target_position)
|
||||
pos = self.get_prop_value(prop=self._prop_current_position)
|
||||
if pos is None:
|
||||
return None
|
||||
pos = round(pos*100/self._prop_position_value_range)
|
||||
if pos <= self._cover_dead_zone_width:
|
||||
pos = 0
|
||||
elif pos >= (100 - self._cover_dead_zone_width):
|
||||
pos = 100
|
||||
return pos
|
||||
|
||||
@property
|
||||
def is_opening(self) -> Optional[bool]:
|
||||
"""Return if the cover is opening."""
|
||||
if self._prop_status and self._prop_status_opening:
|
||||
return (self.get_prop_value(prop=self._prop_status)
|
||||
in self._prop_status_opening)
|
||||
# The status has higher priority when determining whether the cover
|
||||
# is opening.
|
||||
return self._prop_pos_opening
|
||||
|
||||
@property
|
||||
def is_closing(self) -> Optional[bool]:
|
||||
"""Return if the cover is closing."""
|
||||
if self._prop_status and self._prop_status_closing:
|
||||
return (self.get_prop_value(prop=self._prop_status)
|
||||
in self._prop_status_closing)
|
||||
# The status has higher priority when determining whether the cover
|
||||
# is closing.
|
||||
return self._prop_pos_closing
|
||||
|
||||
@property
|
||||
def is_closed(self) -> Optional[bool]:
|
||||
"""Return if the cover is closed."""
|
||||
if self.current_cover_position is not None:
|
||||
return self.current_cover_position == 0
|
||||
# The current position is prior to the status when determining
|
||||
# whether the cover is closed.
|
||||
if self._prop_status and self._prop_status_closed:
|
||||
return (self.get_prop_value(prop=self._prop_status)
|
||||
in self._prop_status_closed)
|
||||
return None
|
||||
@@ -0,0 +1,126 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Copyright (C) 2024 Xiaomi Corporation.
|
||||
|
||||
The ownership and intellectual property rights of Xiaomi Home Assistant
|
||||
Integration and related Xiaomi cloud service API interface provided under this
|
||||
license, including source code and object code (collectively, "Licensed Work"),
|
||||
are owned by Xiaomi. Subject to the terms and conditions of this License, Xiaomi
|
||||
hereby grants you a personal, limited, non-exclusive, non-transferable,
|
||||
non-sublicensable, and royalty-free license to reproduce, use, modify, and
|
||||
distribute the Licensed Work only for your use of Home Assistant for
|
||||
non-commercial purposes. For the avoidance of doubt, Xiaomi does not authorize
|
||||
you to use the Licensed Work for any other purpose, including but not limited
|
||||
to use Licensed Work to develop applications (APP), Web services, and other
|
||||
forms of software.
|
||||
|
||||
You may reproduce and distribute copies of the Licensed Work, with or without
|
||||
modifications, whether in source or object form, provided that you must give
|
||||
any other recipients of the Licensed Work a copy of this License and retain all
|
||||
copyright and disclaimers.
|
||||
|
||||
Xiaomi provides the Licensed Work on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied, including, without
|
||||
limitation, any warranties, undertakes, or conditions of TITLE, NO ERROR OR
|
||||
OMISSION, CONTINUITY, RELIABILITY, NON-INFRINGEMENT, MERCHANTABILITY, or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. In any event, you are solely responsible
|
||||
for any direct, indirect, special, incidental, or consequential damages or
|
||||
losses arising from the use or inability to use the Licensed Work.
|
||||
|
||||
Xiaomi reserves all rights not expressly granted to you in this License.
|
||||
Except for the rights expressly granted by Xiaomi under this License, Xiaomi
|
||||
does not authorize you in any form to use the trademarks, copyrights, or other
|
||||
forms of intellectual property rights of Xiaomi and its affiliates, including,
|
||||
without limitation, without obtaining other written permission from Xiaomi, you
|
||||
shall not use "Xiaomi", "Mijia" and other words related to Xiaomi or words that
|
||||
may make the public associate with Xiaomi in any form to publicize or promote
|
||||
the software or hardware devices that use the Licensed Work.
|
||||
|
||||
Xiaomi has the right to immediately terminate all your authorization under this
|
||||
License in the event:
|
||||
1. You assert patent invalidation, litigation, or other claims against patents
|
||||
or other intellectual property rights of Xiaomi or its affiliates; or,
|
||||
2. You make, have made, manufacture, sell, or offer to sell products that knock
|
||||
off Xiaomi or its affiliates' products.
|
||||
|
||||
Device tracker entities for Xiaomi Home.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
from typing import Optional
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.components.device_tracker import TrackerEntity
|
||||
|
||||
from .miot.const import DOMAIN
|
||||
from .miot.miot_device import MIoTDevice, MIoTServiceEntity, MIoTEntityData
|
||||
from .miot.miot_spec import MIoTSpecProperty
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: ConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
) -> None:
|
||||
device_list: list[MIoTDevice] = hass.data[DOMAIN]['devices'][
|
||||
config_entry.entry_id]
|
||||
new_entities = []
|
||||
for miot_device in device_list:
|
||||
for data in miot_device.entity_list.get('device_tracker', []):
|
||||
new_entities.append(
|
||||
DeviceTracker(miot_device=miot_device, entity_data=data))
|
||||
if new_entities:
|
||||
async_add_entities(new_entities)
|
||||
|
||||
|
||||
class DeviceTracker(MIoTServiceEntity, TrackerEntity):
|
||||
"""Tracker entities for Xiaomi Home."""
|
||||
_prop_battery_level: Optional[MIoTSpecProperty]
|
||||
_prop_latitude: Optional[MIoTSpecProperty]
|
||||
_prop_longitude: Optional[MIoTSpecProperty]
|
||||
_prop_area_id: Optional[MIoTSpecProperty]
|
||||
|
||||
def __init__(self, miot_device: MIoTDevice,
|
||||
entity_data: MIoTEntityData) -> None:
|
||||
super().__init__(miot_device=miot_device, entity_data=entity_data)
|
||||
self._prop_battery_level = None
|
||||
self._prop_latitude = None
|
||||
self._prop_longitude = None
|
||||
self._prop_area_id = None
|
||||
|
||||
# properties
|
||||
for prop in entity_data.props:
|
||||
if prop.name == 'battery-level':
|
||||
self._prop_battery_level = prop
|
||||
elif prop.name == 'latitude':
|
||||
self._prop_latitude = prop
|
||||
elif prop.name == 'longitude':
|
||||
self._prop_longitude = prop
|
||||
elif prop.name == 'area-id':
|
||||
self._prop_area_id = prop
|
||||
|
||||
@property
|
||||
def battery_level(self) -> Optional[int]:
|
||||
"""The battery level of the device."""
|
||||
return None if (self._prop_battery_level
|
||||
is None) else self.get_prop_value(
|
||||
prop=self._prop_battery_level)
|
||||
|
||||
@property
|
||||
def latitude(self) -> Optional[float]:
|
||||
"""The latitude coordinate of the device."""
|
||||
return None if self._prop_latitude is None else self.get_prop_value(
|
||||
prop=self._prop_latitude)
|
||||
|
||||
@property
|
||||
def longitude(self) -> Optional[float]:
|
||||
"""The longitude coordinate of the device."""
|
||||
return None if self._prop_longitude is None else self.get_prop_value(
|
||||
prop=self._prop_longitude)
|
||||
|
||||
@property
|
||||
def location_name(self) -> Optional[str]:
|
||||
"""The location name of the device."""
|
||||
return None if self._prop_area_id is None else self.get_prop_value(
|
||||
prop=self._prop_area_id)
|
||||
@@ -0,0 +1,96 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Copyright (C) 2024 Xiaomi Corporation.
|
||||
|
||||
The ownership and intellectual property rights of Xiaomi Home Assistant
|
||||
Integration and related Xiaomi cloud service API interface provided under this
|
||||
license, including source code and object code (collectively, "Licensed Work"),
|
||||
are owned by Xiaomi. Subject to the terms and conditions of this License, Xiaomi
|
||||
hereby grants you a personal, limited, non-exclusive, non-transferable,
|
||||
non-sublicensable, and royalty-free license to reproduce, use, modify, and
|
||||
distribute the Licensed Work only for your use of Home Assistant for
|
||||
non-commercial purposes. For the avoidance of doubt, Xiaomi does not authorize
|
||||
you to use the Licensed Work for any other purpose, including but not limited
|
||||
to use Licensed Work to develop applications (APP), Web services, and other
|
||||
forms of software.
|
||||
|
||||
You may reproduce and distribute copies of the Licensed Work, with or without
|
||||
modifications, whether in source or object form, provided that you must give
|
||||
any other recipients of the Licensed Work a copy of this License and retain all
|
||||
copyright and disclaimers.
|
||||
|
||||
Xiaomi provides the Licensed Work on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied, including, without
|
||||
limitation, any warranties, undertakes, or conditions of TITLE, NO ERROR OR
|
||||
OMISSION, CONTINUITY, RELIABILITY, NON-INFRINGEMENT, MERCHANTABILITY, or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. In any event, you are solely responsible
|
||||
for any direct, indirect, special, incidental, or consequential damages or
|
||||
losses arising from the use or inability to use the Licensed Work.
|
||||
|
||||
Xiaomi reserves all rights not expressly granted to you in this License.
|
||||
Except for the rights expressly granted by Xiaomi under this License, Xiaomi
|
||||
does not authorize you in any form to use the trademarks, copyrights, or other
|
||||
forms of intellectual property rights of Xiaomi and its affiliates, including,
|
||||
without limitation, without obtaining other written permission from Xiaomi, you
|
||||
shall not use "Xiaomi", "Mijia" and other words related to Xiaomi or words that
|
||||
may make the public associate with Xiaomi in any form to publicize or promote
|
||||
the software or hardware devices that use the Licensed Work.
|
||||
|
||||
Xiaomi has the right to immediately terminate all your authorization under this
|
||||
License in the event:
|
||||
1. You assert patent invalidation, litigation, or other claims against patents
|
||||
or other intellectual property rights of Xiaomi or its affiliates; or,
|
||||
2. You make, have made, manufacture, sell, or offer to sell products that knock
|
||||
off Xiaomi or its affiliates' products.
|
||||
|
||||
Event entities for Xiaomi Home.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
import logging
|
||||
from typing import Any
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.components.event import EventEntity
|
||||
|
||||
from .miot.miot_spec import MIoTSpecEvent
|
||||
from .miot.miot_device import MIoTDevice, MIoTEventEntity
|
||||
from .miot.const import DOMAIN
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: ConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up a config entry."""
|
||||
device_list: list[MIoTDevice] = hass.data[DOMAIN]['devices'][
|
||||
config_entry.entry_id]
|
||||
|
||||
new_entities = []
|
||||
for miot_device in device_list:
|
||||
for event in miot_device.event_list.get('event', []):
|
||||
new_entities.append(Event(miot_device=miot_device, spec=event))
|
||||
|
||||
if new_entities:
|
||||
async_add_entities(new_entities)
|
||||
|
||||
|
||||
class Event(MIoTEventEntity, EventEntity):
|
||||
"""Event entities for Xiaomi Home."""
|
||||
|
||||
def __init__(self, miot_device: MIoTDevice, spec: MIoTSpecEvent) -> None:
|
||||
"""Initialize the Event."""
|
||||
super().__init__(miot_device=miot_device, spec=spec)
|
||||
# Set device_class
|
||||
self._attr_device_class = spec.device_class
|
||||
|
||||
def on_event_occurred(
|
||||
self, name: str, arguments: dict[str, Any] | None = None
|
||||
) -> None:
|
||||
"""An event is occurred."""
|
||||
_LOGGER.debug('%s, attributes: %s', name, str(arguments))
|
||||
self._trigger_event(event_type=name, event_attributes=arguments)
|
||||
@@ -0,0 +1,326 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Copyright (C) 2024 Xiaomi Corporation.
|
||||
|
||||
The ownership and intellectual property rights of Xiaomi Home Assistant
|
||||
Integration and related Xiaomi cloud service API interface provided under this
|
||||
license, including source code and object code (collectively, "Licensed Work"),
|
||||
are owned by Xiaomi. Subject to the terms and conditions of this License, Xiaomi
|
||||
hereby grants you a personal, limited, non-exclusive, non-transferable,
|
||||
non-sublicensable, and royalty-free license to reproduce, use, modify, and
|
||||
distribute the Licensed Work only for your use of Home Assistant for
|
||||
non-commercial purposes. For the avoidance of doubt, Xiaomi does not authorize
|
||||
you to use the Licensed Work for any other purpose, including but not limited
|
||||
to use Licensed Work to develop applications (APP), Web services, and other
|
||||
forms of software.
|
||||
|
||||
You may reproduce and distribute copies of the Licensed Work, with or without
|
||||
modifications, whether in source or object form, provided that you must give
|
||||
any other recipients of the Licensed Work a copy of this License and retain all
|
||||
copyright and disclaimers.
|
||||
|
||||
Xiaomi provides the Licensed Work on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied, including, without
|
||||
limitation, any warranties, undertakes, or conditions of TITLE, NO ERROR OR
|
||||
OMISSION, CONTINUITY, RELIABILITY, NON-INFRINGEMENT, MERCHANTABILITY, or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. In any event, you are solely responsible
|
||||
for any direct, indirect, special, incidental, or consequential damages or
|
||||
losses arising from the use or inability to use the Licensed Work.
|
||||
|
||||
Xiaomi reserves all rights not expressly granted to you in this License.
|
||||
Except for the rights expressly granted by Xiaomi under this License, Xiaomi
|
||||
does not authorize you in any form to use the trademarks, copyrights, or other
|
||||
forms of intellectual property rights of Xiaomi and its affiliates, including,
|
||||
without limitation, without obtaining other written permission from Xiaomi, you
|
||||
shall not use "Xiaomi", "Mijia" and other words related to Xiaomi or words that
|
||||
may make the public associate with Xiaomi in any form to publicize or promote
|
||||
the software or hardware devices that use the Licensed Work.
|
||||
|
||||
Xiaomi has the right to immediately terminate all your authorization under this
|
||||
License in the event:
|
||||
1. You assert patent invalidation, litigation, or other claims against patents
|
||||
or other intellectual property rights of Xiaomi or its affiliates; or,
|
||||
2. You make, have made, manufacture, sell, or offer to sell products that knock
|
||||
off Xiaomi or its affiliates' products.
|
||||
|
||||
Fan entities for Xiaomi Home.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
from typing import Any, Optional
|
||||
import logging
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.components.fan import (
|
||||
FanEntity,
|
||||
FanEntityFeature,
|
||||
DIRECTION_FORWARD,
|
||||
DIRECTION_REVERSE
|
||||
)
|
||||
from homeassistant.util.percentage import (
|
||||
percentage_to_ranged_value,
|
||||
ranged_value_to_percentage,
|
||||
ordered_list_item_to_percentage,
|
||||
percentage_to_ordered_list_item
|
||||
)
|
||||
|
||||
from .miot.miot_spec import MIoTSpecProperty
|
||||
from .miot.const import DOMAIN
|
||||
from .miot.miot_device import MIoTDevice, MIoTEntityData, MIoTServiceEntity
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: ConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up a config entry."""
|
||||
device_list: list[MIoTDevice] = hass.data[DOMAIN]['devices'][
|
||||
config_entry.entry_id]
|
||||
new_entities = []
|
||||
for miot_device in device_list:
|
||||
for data in miot_device.entity_list.get('fan', []):
|
||||
new_entities.append(Fan(miot_device=miot_device, entity_data=data))
|
||||
|
||||
if new_entities:
|
||||
async_add_entities(new_entities)
|
||||
|
||||
|
||||
class Fan(MIoTServiceEntity, FanEntity):
|
||||
"""Fan entities for Xiaomi Home."""
|
||||
# pylint: disable=unused-argument
|
||||
_prop_on: MIoTSpecProperty
|
||||
_prop_fan_level: Optional[MIoTSpecProperty]
|
||||
_prop_mode: Optional[MIoTSpecProperty]
|
||||
_prop_horizontal_swing: Optional[MIoTSpecProperty]
|
||||
_prop_wind_reverse: Optional[MIoTSpecProperty]
|
||||
_prop_wind_reverse_forward: Any
|
||||
_prop_wind_reverse_reverse: Any
|
||||
|
||||
_speed_min: int
|
||||
_speed_max: int
|
||||
_speed_step: int
|
||||
_speed_names: Optional[list]
|
||||
_speed_name_map: Optional[dict[int, str]]
|
||||
_mode_map: Optional[dict[Any, Any]]
|
||||
|
||||
def __init__(
|
||||
self, miot_device: MIoTDevice, entity_data: MIoTEntityData
|
||||
) -> None:
|
||||
"""Initialize the Fan."""
|
||||
super().__init__(miot_device=miot_device, entity_data=entity_data)
|
||||
self._attr_preset_modes = []
|
||||
self._attr_current_direction = None
|
||||
self._attr_supported_features = FanEntityFeature(0)
|
||||
|
||||
# _prop_on is required
|
||||
self._prop_fan_level = None
|
||||
self._prop_mode = None
|
||||
self._prop_horizontal_swing = None
|
||||
self._prop_wind_reverse = None
|
||||
self._prop_wind_reverse_forward = None
|
||||
self._prop_wind_reverse_reverse = None
|
||||
self._speed_min = 65535
|
||||
self._speed_max = 0
|
||||
self._speed_step = 1
|
||||
self._speed_names = []
|
||||
self._speed_name_map = {}
|
||||
|
||||
self._mode_map = None
|
||||
|
||||
# properties
|
||||
for prop in entity_data.props:
|
||||
if prop.name == 'on':
|
||||
self._attr_supported_features |= FanEntityFeature.TURN_ON
|
||||
self._attr_supported_features |= FanEntityFeature.TURN_OFF
|
||||
self._prop_on = prop
|
||||
elif prop.name == 'fan-level':
|
||||
if prop.value_range:
|
||||
# Fan level with value-range
|
||||
self._speed_min = prop.value_range.min_
|
||||
self._speed_max = prop.value_range.max_
|
||||
self._speed_step = prop.value_range.step
|
||||
self._attr_speed_count = int((
|
||||
self._speed_max - self._speed_min)/self._speed_step)+1
|
||||
self._attr_supported_features |= FanEntityFeature.SET_SPEED
|
||||
self._prop_fan_level = prop
|
||||
elif (
|
||||
self._prop_fan_level is None
|
||||
and prop.value_list
|
||||
):
|
||||
# Fan level with value-list
|
||||
# Fan level with value-range is prior to fan level with
|
||||
# value-list when a fan has both fan level properties.
|
||||
self._speed_name_map = prop.value_list.to_map()
|
||||
self._speed_names = list(self._speed_name_map.values())
|
||||
self._attr_speed_count = len(self._speed_names)
|
||||
self._attr_supported_features |= FanEntityFeature.SET_SPEED
|
||||
self._prop_fan_level = prop
|
||||
elif prop.name == 'mode':
|
||||
if not prop.value_list:
|
||||
_LOGGER.error(
|
||||
'mode value_list is None, %s', self.entity_id)
|
||||
continue
|
||||
self._mode_map = prop.value_list.to_map()
|
||||
self._attr_preset_modes = list(self._mode_map.values())
|
||||
self._attr_supported_features |= FanEntityFeature.PRESET_MODE
|
||||
self._prop_mode = prop
|
||||
elif prop.name == 'horizontal-swing':
|
||||
self._attr_supported_features |= FanEntityFeature.OSCILLATE
|
||||
self._prop_horizontal_swing = prop
|
||||
elif prop.name == 'wind-reverse':
|
||||
if prop.format_ == bool:
|
||||
self._prop_wind_reverse_forward = False
|
||||
self._prop_wind_reverse_reverse = True
|
||||
elif prop.value_list:
|
||||
for item in prop.value_list.items:
|
||||
if item.name in {'foreward', 'forward'}:
|
||||
self._prop_wind_reverse_forward = item.value
|
||||
elif item.name in {'reversal', 'reverse'}:
|
||||
self._prop_wind_reverse_reverse = item.value
|
||||
if (
|
||||
self._prop_wind_reverse_forward is None
|
||||
or self._prop_wind_reverse_reverse is None
|
||||
):
|
||||
# NOTICE: Value may be 0 or False
|
||||
_LOGGER.error(
|
||||
'invalid wind-reverse, %s', self.entity_id)
|
||||
continue
|
||||
self._attr_supported_features |= FanEntityFeature.DIRECTION
|
||||
self._prop_wind_reverse = prop
|
||||
|
||||
async def async_turn_on(
|
||||
self, percentage: Optional[int] = None,
|
||||
preset_mode: Optional[str] = None, **kwargs: Any
|
||||
) -> None:
|
||||
"""Turn the fan on.
|
||||
|
||||
Shall set the percentage or the preset_mode attr to complying
|
||||
if applicable.
|
||||
"""
|
||||
# on
|
||||
await self.set_property_async(prop=self._prop_on, value=True)
|
||||
# percentage
|
||||
if percentage:
|
||||
if self._speed_names:
|
||||
await self.set_property_async(
|
||||
prop=self._prop_fan_level,
|
||||
value=self.get_map_key(
|
||||
map_=self._speed_name_map,
|
||||
value=percentage_to_ordered_list_item(
|
||||
self._speed_names, percentage)))
|
||||
else:
|
||||
await self.set_property_async(
|
||||
prop=self._prop_fan_level,
|
||||
value=int(percentage_to_ranged_value(
|
||||
low_high_range=(self._speed_min, self._speed_max),
|
||||
percentage=percentage)))
|
||||
# preset_mode
|
||||
if preset_mode:
|
||||
await self.set_property_async(
|
||||
prop=self._prop_mode,
|
||||
value=self.get_map_key(
|
||||
map_=self._mode_map, value=preset_mode))
|
||||
|
||||
async def async_turn_off(self, **kwargs: Any) -> None:
|
||||
"""Turn the fan off."""
|
||||
await self.set_property_async(prop=self._prop_on, value=False)
|
||||
|
||||
async def async_toggle(self, **kwargs: Any) -> None:
|
||||
"""Toggle the fan."""
|
||||
await self.set_property_async(prop=self._prop_on, value=not self.is_on)
|
||||
|
||||
async def async_set_percentage(self, percentage: int) -> None:
|
||||
"""Set the percentage of the fan speed."""
|
||||
if percentage > 0:
|
||||
if not self.is_on:
|
||||
# If the fan is off, turn it on.
|
||||
await self.set_property_async(prop=self._prop_on, value=True)
|
||||
if self._speed_names:
|
||||
await self.set_property_async(
|
||||
prop=self._prop_fan_level,
|
||||
value=self.get_map_key(
|
||||
map_=self._speed_name_map,
|
||||
value=percentage_to_ordered_list_item(
|
||||
self._speed_names, percentage)))
|
||||
else:
|
||||
await self.set_property_async(
|
||||
prop=self._prop_fan_level,
|
||||
value=int(percentage_to_ranged_value(
|
||||
low_high_range=(self._speed_min, self._speed_max),
|
||||
percentage=percentage)))
|
||||
else:
|
||||
await self.set_property_async(prop=self._prop_on, value=False)
|
||||
|
||||
async def async_set_preset_mode(self, preset_mode: str) -> None:
|
||||
"""Set the preset mode."""
|
||||
await self.set_property_async(
|
||||
prop=self._prop_mode,
|
||||
value=self.get_map_key(
|
||||
map_=self._mode_map, value=preset_mode))
|
||||
|
||||
async def async_set_direction(self, direction: str) -> None:
|
||||
"""Set the direction of the fan."""
|
||||
if not self._prop_wind_reverse:
|
||||
return
|
||||
await self.set_property_async(
|
||||
prop=self._prop_wind_reverse,
|
||||
value=(
|
||||
self._prop_wind_reverse_reverse
|
||||
if direction == DIRECTION_REVERSE
|
||||
else self._prop_wind_reverse_forward))
|
||||
|
||||
async def async_oscillate(self, oscillating: bool) -> None:
|
||||
"""Oscillate the fan."""
|
||||
await self.set_property_async(
|
||||
prop=self._prop_horizontal_swing, value=oscillating)
|
||||
|
||||
@property
|
||||
def is_on(self) -> Optional[bool]:
|
||||
"""Return if the fan is on. """
|
||||
return self.get_prop_value(
|
||||
prop=self._prop_on) if self._prop_on else None
|
||||
|
||||
@property
|
||||
def preset_mode(self) -> Optional[str]:
|
||||
"""Return the current preset mode,
|
||||
e.g., auto, smart, eco, favorite."""
|
||||
return (
|
||||
self.get_map_value(
|
||||
map_=self._mode_map,
|
||||
key=self.get_prop_value(prop=self._prop_mode))
|
||||
if self._prop_mode else None)
|
||||
|
||||
@property
|
||||
def current_direction(self) -> Optional[str]:
|
||||
"""Return the current direction of the fan."""
|
||||
if not self._prop_wind_reverse:
|
||||
return None
|
||||
return DIRECTION_REVERSE if self.get_prop_value(
|
||||
prop=self._prop_wind_reverse
|
||||
) == self._prop_wind_reverse_reverse else DIRECTION_FORWARD
|
||||
|
||||
@property
|
||||
def percentage(self) -> Optional[int]:
|
||||
"""Return the current percentage of the fan speed."""
|
||||
fan_level = self.get_prop_value(prop=self._prop_fan_level)
|
||||
if fan_level is None:
|
||||
return None
|
||||
if self._speed_names and self._speed_name_map:
|
||||
return ordered_list_item_to_percentage(
|
||||
self._speed_names, self._speed_name_map[fan_level])
|
||||
else:
|
||||
return ranged_value_to_percentage(
|
||||
low_high_range=(self._speed_min, self._speed_max),
|
||||
value=fan_level)
|
||||
|
||||
@property
|
||||
def oscillating(self) -> Optional[bool]:
|
||||
"""Return if the fan is oscillating."""
|
||||
return (
|
||||
self.get_prop_value(
|
||||
prop=self._prop_horizontal_swing)
|
||||
if self._prop_horizontal_swing else None)
|
||||
@@ -0,0 +1,192 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Copyright (C) 2024 Xiaomi Corporation.
|
||||
|
||||
The ownership and intellectual property rights of Xiaomi Home Assistant
|
||||
Integration and related Xiaomi cloud service API interface provided under this
|
||||
license, including source code and object code (collectively, "Licensed Work"),
|
||||
are owned by Xiaomi. Subject to the terms and conditions of this License, Xiaomi
|
||||
hereby grants you a personal, limited, non-exclusive, non-transferable,
|
||||
non-sublicensable, and royalty-free license to reproduce, use, modify, and
|
||||
distribute the Licensed Work only for your use of Home Assistant for
|
||||
non-commercial purposes. For the avoidance of doubt, Xiaomi does not authorize
|
||||
you to use the Licensed Work for any other purpose, including but not limited
|
||||
to use Licensed Work to develop applications (APP), Web services, and other
|
||||
forms of software.
|
||||
|
||||
You may reproduce and distribute copies of the Licensed Work, with or without
|
||||
modifications, whether in source or object form, provided that you must give
|
||||
any other recipients of the Licensed Work a copy of this License and retain all
|
||||
copyright and disclaimers.
|
||||
|
||||
Xiaomi provides the Licensed Work on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied, including, without
|
||||
limitation, any warranties, undertakes, or conditions of TITLE, NO ERROR OR
|
||||
OMISSION, CONTINUITY, RELIABILITY, NON-INFRINGEMENT, MERCHANTABILITY, or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. In any event, you are solely responsible
|
||||
for any direct, indirect, special, incidental, or consequential damages or
|
||||
losses arising from the use or inability to use the Licensed Work.
|
||||
|
||||
Xiaomi reserves all rights not expressly granted to you in this License.
|
||||
Except for the rights expressly granted by Xiaomi under this License, Xiaomi
|
||||
does not authorize you in any form to use the trademarks, copyrights, or other
|
||||
forms of intellectual property rights of Xiaomi and its affiliates, including,
|
||||
without limitation, without obtaining other written permission from Xiaomi, you
|
||||
shall not use "Xiaomi", "Mijia" and other words related to Xiaomi or words that
|
||||
may make the public associate with Xiaomi in any form to publicize or promote
|
||||
the software or hardware devices that use the Licensed Work.
|
||||
|
||||
Xiaomi has the right to immediately terminate all your authorization under this
|
||||
License in the event:
|
||||
1. You assert patent invalidation, litigation, or other claims against patents
|
||||
or other intellectual property rights of Xiaomi or its affiliates; or,
|
||||
2. You make, have made, manufacture, sell, or offer to sell products that knock
|
||||
off Xiaomi or its affiliates' products.
|
||||
|
||||
Humidifier entities for Xiaomi Home.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
import logging
|
||||
from typing import Any, Optional
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.components.humidifier import (HumidifierEntity,
|
||||
HumidifierDeviceClass,
|
||||
HumidifierEntityFeature,
|
||||
HumidifierAction)
|
||||
|
||||
from .miot.miot_spec import MIoTSpecProperty
|
||||
from .miot.miot_device import MIoTDevice, MIoTEntityData, MIoTServiceEntity
|
||||
from .miot.const import DOMAIN
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: ConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up a config entry."""
|
||||
device_list: list[MIoTDevice] = hass.data[DOMAIN]['devices'][
|
||||
config_entry.entry_id]
|
||||
|
||||
new_entities = []
|
||||
for miot_device in device_list:
|
||||
for data in miot_device.entity_list.get('humidifier', []):
|
||||
data.device_class = HumidifierDeviceClass.HUMIDIFIER
|
||||
new_entities.append(
|
||||
Humidifier(miot_device=miot_device, entity_data=data))
|
||||
for data in miot_device.entity_list.get('dehumidifier', []):
|
||||
data.device_class = HumidifierDeviceClass.DEHUMIDIFIER
|
||||
new_entities.append(
|
||||
Humidifier(miot_device=miot_device, entity_data=data))
|
||||
|
||||
if new_entities:
|
||||
async_add_entities(new_entities)
|
||||
|
||||
|
||||
class Humidifier(MIoTServiceEntity, HumidifierEntity):
|
||||
"""Humidifier entities for Xiaomi Home."""
|
||||
# pylint: disable=unused-argument
|
||||
_prop_on: Optional[MIoTSpecProperty]
|
||||
_prop_mode: Optional[MIoTSpecProperty]
|
||||
_prop_target_humidity: Optional[MIoTSpecProperty]
|
||||
_prop_humidity: Optional[MIoTSpecProperty]
|
||||
|
||||
_mode_map: dict[Any, Any]
|
||||
|
||||
def __init__(self, miot_device: MIoTDevice,
|
||||
entity_data: MIoTEntityData) -> None:
|
||||
"""Initialize the Humidifier."""
|
||||
super().__init__(miot_device=miot_device, entity_data=entity_data)
|
||||
self._attr_device_class = entity_data.device_class
|
||||
self._attr_supported_features = HumidifierEntityFeature(0)
|
||||
self._prop_on = None
|
||||
self._prop_mode = None
|
||||
self._prop_target_humidity = None
|
||||
self._prop_humidity = None
|
||||
self._mode_map = None
|
||||
|
||||
# properties
|
||||
for prop in entity_data.props:
|
||||
# on
|
||||
if prop.name == 'on':
|
||||
self._prop_on = prop
|
||||
# target-humidity
|
||||
elif prop.name == 'target-humidity':
|
||||
if not prop.value_range:
|
||||
_LOGGER.error(
|
||||
'invalid target-humidity value_range format, %s',
|
||||
self.entity_id)
|
||||
continue
|
||||
self._attr_min_humidity = prop.value_range.min_
|
||||
self._attr_max_humidity = prop.value_range.max_
|
||||
self._prop_target_humidity = prop
|
||||
# mode
|
||||
elif prop.name == 'mode':
|
||||
if not prop.value_list:
|
||||
_LOGGER.error('mode value_list is None, %s', self.entity_id)
|
||||
continue
|
||||
self._mode_map = prop.value_list.to_map()
|
||||
self._attr_available_modes = list(self._mode_map.values())
|
||||
self._attr_supported_features |= HumidifierEntityFeature.MODES
|
||||
self._prop_mode = prop
|
||||
# relative-humidity
|
||||
elif prop.name == 'relative-humidity':
|
||||
self._prop_humidity = prop
|
||||
|
||||
async def async_turn_on(self, **kwargs):
|
||||
"""Turn the humidifier on."""
|
||||
await self.set_property_async(prop=self._prop_on, value=True)
|
||||
|
||||
async def async_turn_off(self, **kwargs):
|
||||
"""Turn the humidifier off."""
|
||||
await self.set_property_async(prop=self._prop_on, value=False)
|
||||
|
||||
async def async_set_humidity(self, humidity: int) -> None:
|
||||
"""Set new target humidity."""
|
||||
if self._prop_target_humidity is None:
|
||||
return
|
||||
await self.set_property_async(prop=self._prop_target_humidity,
|
||||
value=humidity)
|
||||
|
||||
async def async_set_mode(self, mode: str) -> None:
|
||||
"""Set new target preset mode."""
|
||||
await self.set_property_async(prop=self._prop_mode,
|
||||
value=self.get_map_key(
|
||||
map_=self._mode_map, value=mode))
|
||||
|
||||
@property
|
||||
def is_on(self) -> Optional[bool]:
|
||||
"""Return if the humidifier is on."""
|
||||
return self.get_prop_value(prop=self._prop_on)
|
||||
|
||||
@property
|
||||
def action(self) -> Optional[HumidifierAction]:
|
||||
"""Return the current status of the device."""
|
||||
if not self.is_on:
|
||||
return HumidifierAction.OFF
|
||||
if self._attr_device_class == HumidifierDeviceClass.HUMIDIFIER:
|
||||
return HumidifierAction.HUMIDIFYING
|
||||
return HumidifierAction.DRYING
|
||||
|
||||
@property
|
||||
def current_humidity(self) -> Optional[int]:
|
||||
"""Return the current humidity."""
|
||||
return (self.get_prop_value(
|
||||
prop=self._prop_humidity) if self._prop_humidity else None)
|
||||
|
||||
@property
|
||||
def target_humidity(self) -> Optional[int]:
|
||||
"""Return the target humidity."""
|
||||
return (self.get_prop_value(prop=self._prop_target_humidity)
|
||||
if self._prop_target_humidity else None)
|
||||
|
||||
@property
|
||||
def mode(self) -> Optional[str]:
|
||||
"""Return the current preset mode."""
|
||||
return self.get_map_value(map_=self._mode_map,
|
||||
key=self.get_prop_value(prop=self._prop_mode))
|
||||
@@ -0,0 +1,298 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Copyright (C) 2024 Xiaomi Corporation.
|
||||
|
||||
The ownership and intellectual property rights of Xiaomi Home Assistant
|
||||
Integration and related Xiaomi cloud service API interface provided under this
|
||||
license, including source code and object code (collectively, "Licensed Work"),
|
||||
are owned by Xiaomi. Subject to the terms and conditions of this License, Xiaomi
|
||||
hereby grants you a personal, limited, non-exclusive, non-transferable,
|
||||
non-sublicensable, and royalty-free license to reproduce, use, modify, and
|
||||
distribute the Licensed Work only for your use of Home Assistant for
|
||||
non-commercial purposes. For the avoidance of doubt, Xiaomi does not authorize
|
||||
you to use the Licensed Work for any other purpose, including but not limited
|
||||
to use Licensed Work to develop applications (APP), Web services, and other
|
||||
forms of software.
|
||||
|
||||
You may reproduce and distribute copies of the Licensed Work, with or without
|
||||
modifications, whether in source or object form, provided that you must give
|
||||
any other recipients of the Licensed Work a copy of this License and retain all
|
||||
copyright and disclaimers.
|
||||
|
||||
Xiaomi provides the Licensed Work on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied, including, without
|
||||
limitation, any warranties, undertakes, or conditions of TITLE, NO ERROR OR
|
||||
OMISSION, CONTINUITY, RELIABILITY, NON-INFRINGEMENT, MERCHANTABILITY, or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. In any event, you are solely responsible
|
||||
for any direct, indirect, special, incidental, or consequential damages or
|
||||
losses arising from the use or inability to use the Licensed Work.
|
||||
|
||||
Xiaomi reserves all rights not expressly granted to you in this License.
|
||||
Except for the rights expressly granted by Xiaomi under this License, Xiaomi
|
||||
does not authorize you in any form to use the trademarks, copyrights, or other
|
||||
forms of intellectual property rights of Xiaomi and its affiliates, including,
|
||||
without limitation, without obtaining other written permission from Xiaomi, you
|
||||
shall not use "Xiaomi", "Mijia" and other words related to Xiaomi or words that
|
||||
may make the public associate with Xiaomi in any form to publicize or promote
|
||||
the software or hardware devices that use the Licensed Work.
|
||||
|
||||
Xiaomi has the right to immediately terminate all your authorization under this
|
||||
License in the event:
|
||||
1. You assert patent invalidation, litigation, or other claims against patents
|
||||
or other intellectual property rights of Xiaomi or its affiliates; or,
|
||||
2. You make, have made, manufacture, sell, or offer to sell products that knock
|
||||
off Xiaomi or its affiliates' products.
|
||||
|
||||
Light entities for Xiaomi Home.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
import logging
|
||||
from typing import Any, Optional
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.components.light import (
|
||||
ATTR_BRIGHTNESS,
|
||||
ATTR_COLOR_TEMP_KELVIN,
|
||||
ATTR_RGB_COLOR,
|
||||
ATTR_EFFECT,
|
||||
LightEntity,
|
||||
LightEntityFeature,
|
||||
ColorMode
|
||||
)
|
||||
from homeassistant.util.color import (
|
||||
value_to_brightness,
|
||||
brightness_to_value
|
||||
)
|
||||
|
||||
from .miot.miot_spec import MIoTSpecProperty
|
||||
from .miot.miot_device import MIoTDevice, MIoTEntityData, MIoTServiceEntity
|
||||
from .miot.const import DOMAIN
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: ConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up a config entry."""
|
||||
device_list: list[MIoTDevice] = hass.data[DOMAIN]['devices'][
|
||||
config_entry.entry_id]
|
||||
|
||||
new_entities = []
|
||||
for miot_device in device_list:
|
||||
for data in miot_device.entity_list.get('light', []):
|
||||
new_entities.append(
|
||||
Light(miot_device=miot_device, entity_data=data))
|
||||
|
||||
if new_entities:
|
||||
async_add_entities(new_entities)
|
||||
|
||||
|
||||
class Light(MIoTServiceEntity, LightEntity):
|
||||
"""Light entities for Xiaomi Home."""
|
||||
# pylint: disable=unused-argument
|
||||
_VALUE_RANGE_MODE_COUNT_MAX = 30
|
||||
_prop_on: Optional[MIoTSpecProperty]
|
||||
_prop_brightness: Optional[MIoTSpecProperty]
|
||||
_prop_color_temp: Optional[MIoTSpecProperty]
|
||||
_prop_color: Optional[MIoTSpecProperty]
|
||||
_prop_mode: Optional[MIoTSpecProperty]
|
||||
|
||||
_brightness_scale: Optional[tuple[int, int]]
|
||||
_mode_map: Optional[dict[Any, Any]]
|
||||
|
||||
def __init__(
|
||||
self, miot_device: MIoTDevice, entity_data: MIoTEntityData
|
||||
) -> None:
|
||||
"""Initialize the Light."""
|
||||
super().__init__(miot_device=miot_device, entity_data=entity_data)
|
||||
self._attr_color_mode = None
|
||||
self._attr_supported_color_modes = set()
|
||||
self._attr_supported_features = LightEntityFeature(0)
|
||||
if miot_device.did.startswith('group.'):
|
||||
self._attr_icon = 'mdi:lightbulb-group'
|
||||
|
||||
self._prop_on = None
|
||||
self._prop_brightness = None
|
||||
self._prop_color_temp = None
|
||||
self._prop_color = None
|
||||
self._prop_mode = None
|
||||
self._brightness_scale = None
|
||||
self._mode_map = None
|
||||
|
||||
# properties
|
||||
for prop in entity_data.props:
|
||||
# on
|
||||
if prop.name == 'on':
|
||||
self._prop_on = prop
|
||||
# brightness
|
||||
if prop.name == 'brightness':
|
||||
if prop.value_range:
|
||||
self._brightness_scale = (
|
||||
prop.value_range.min_, prop.value_range.max_)
|
||||
self._prop_brightness = prop
|
||||
elif (
|
||||
self._mode_map is None
|
||||
and prop.value_list
|
||||
):
|
||||
# For value-list brightness
|
||||
self._mode_map = prop.value_list.to_map()
|
||||
self._attr_effect_list = list(self._mode_map.values())
|
||||
self._attr_supported_features |= LightEntityFeature.EFFECT
|
||||
self._prop_mode = prop
|
||||
else:
|
||||
_LOGGER.info(
|
||||
'invalid brightness format, %s', self.entity_id)
|
||||
continue
|
||||
# color-temperature
|
||||
if prop.name == 'color-temperature':
|
||||
if not prop.value_range:
|
||||
_LOGGER.info(
|
||||
'invalid color-temperature value_range format, %s',
|
||||
self.entity_id)
|
||||
continue
|
||||
self._attr_min_color_temp_kelvin = prop.value_range.min_
|
||||
self._attr_max_color_temp_kelvin = prop.value_range.max_
|
||||
self._attr_supported_color_modes.add(ColorMode.COLOR_TEMP)
|
||||
self._attr_color_mode = ColorMode.COLOR_TEMP
|
||||
self._prop_color_temp = prop
|
||||
# color
|
||||
if prop.name == 'color':
|
||||
self._attr_supported_color_modes.add(ColorMode.RGB)
|
||||
self._attr_color_mode = ColorMode.RGB
|
||||
self._prop_color = prop
|
||||
# mode
|
||||
if prop.name == 'mode':
|
||||
mode_list = None
|
||||
if prop.value_list:
|
||||
mode_list = prop.value_list.to_map()
|
||||
elif prop.value_range:
|
||||
mode_list = {}
|
||||
if (
|
||||
int((
|
||||
prop.value_range.max_
|
||||
- prop.value_range.min_
|
||||
) / prop.value_range.step)
|
||||
> self._VALUE_RANGE_MODE_COUNT_MAX
|
||||
):
|
||||
_LOGGER.error(
|
||||
'too many mode values, %s, %s, %s',
|
||||
self.entity_id, prop.name, prop.value_range)
|
||||
else:
|
||||
for value in range(
|
||||
prop.value_range.min_,
|
||||
prop.value_range.max_,
|
||||
prop.value_range.step):
|
||||
mode_list[value] = f'mode {value}'
|
||||
if mode_list:
|
||||
self._mode_map = mode_list
|
||||
self._attr_effect_list = list(self._mode_map.values())
|
||||
self._attr_supported_features |= LightEntityFeature.EFFECT
|
||||
self._prop_mode = prop
|
||||
else:
|
||||
_LOGGER.info('invalid mode format, %s', self.entity_id)
|
||||
continue
|
||||
|
||||
if not self._attr_supported_color_modes:
|
||||
if self._prop_brightness:
|
||||
self._attr_supported_color_modes.add(ColorMode.BRIGHTNESS)
|
||||
self._attr_color_mode = ColorMode.BRIGHTNESS
|
||||
elif self._prop_on:
|
||||
self._attr_supported_color_modes.add(ColorMode.ONOFF)
|
||||
self._attr_color_mode = ColorMode.ONOFF
|
||||
|
||||
@property
|
||||
def is_on(self) -> Optional[bool]:
|
||||
"""Return if the light is on."""
|
||||
value_on = self.get_prop_value(prop=self._prop_on)
|
||||
# Dirty logic for lumi.gateway.mgl03 indicator light
|
||||
if isinstance(value_on, int):
|
||||
value_on = value_on == 1
|
||||
return value_on
|
||||
|
||||
@property
|
||||
def brightness(self) -> Optional[int]:
|
||||
"""Return the brightness."""
|
||||
brightness_value = self.get_prop_value(prop=self._prop_brightness)
|
||||
if brightness_value is None:
|
||||
return None
|
||||
return value_to_brightness(self._brightness_scale, brightness_value)
|
||||
|
||||
@property
|
||||
def color_temp_kelvin(self) -> Optional[int]:
|
||||
"""Return the color temperature."""
|
||||
return self.get_prop_value(prop=self._prop_color_temp)
|
||||
|
||||
@property
|
||||
def rgb_color(self) -> Optional[tuple[int, int, int]]:
|
||||
"""Return the rgb color value."""
|
||||
rgb = self.get_prop_value(prop=self._prop_color)
|
||||
if rgb is None:
|
||||
return None
|
||||
r = (rgb >> 16) & 0xFF
|
||||
g = (rgb >> 8) & 0xFF
|
||||
b = rgb & 0xFF
|
||||
return r, g, b
|
||||
|
||||
@property
|
||||
def effect(self) -> Optional[str]:
|
||||
"""Return the current mode."""
|
||||
return self.get_map_value(
|
||||
map_=self._mode_map,
|
||||
key=self.get_prop_value(prop=self._prop_mode))
|
||||
|
||||
async def async_turn_on(self, **kwargs) -> None:
|
||||
"""Turn the light on.
|
||||
|
||||
Shall set attributes in kwargs if applicable.
|
||||
"""
|
||||
# on
|
||||
# Dirty logic for lumi.gateway.mgl03 indicator light
|
||||
if self._prop_on:
|
||||
value_on = True if self._prop_on.format_ == bool else 1
|
||||
await self.set_property_async(
|
||||
prop=self._prop_on, value=value_on)
|
||||
# brightness
|
||||
if ATTR_BRIGHTNESS in kwargs:
|
||||
brightness = brightness_to_value(
|
||||
self._brightness_scale, kwargs[ATTR_BRIGHTNESS])
|
||||
await self.set_property_async(
|
||||
prop=self._prop_brightness, value=brightness,
|
||||
write_ha_state=False)
|
||||
# color-temperature
|
||||
if ATTR_COLOR_TEMP_KELVIN in kwargs:
|
||||
await self.set_property_async(
|
||||
prop=self._prop_color_temp,
|
||||
value=kwargs[ATTR_COLOR_TEMP_KELVIN],
|
||||
write_ha_state=False)
|
||||
self._attr_color_mode = ColorMode.COLOR_TEMP
|
||||
# rgb color
|
||||
if ATTR_RGB_COLOR in kwargs:
|
||||
r = kwargs[ATTR_RGB_COLOR][0]
|
||||
g = kwargs[ATTR_RGB_COLOR][1]
|
||||
b = kwargs[ATTR_RGB_COLOR][2]
|
||||
rgb = (r << 16) | (g << 8) | b
|
||||
await self.set_property_async(
|
||||
prop=self._prop_color, value=rgb,
|
||||
write_ha_state=False)
|
||||
self._attr_color_mode = ColorMode.RGB
|
||||
# mode
|
||||
if ATTR_EFFECT in kwargs:
|
||||
await self.set_property_async(
|
||||
prop=self._prop_mode,
|
||||
value=self.get_map_key(
|
||||
map_=self._mode_map, value=kwargs[ATTR_EFFECT]),
|
||||
write_ha_state=False)
|
||||
self.async_write_ha_state()
|
||||
|
||||
async def async_turn_off(self, **kwargs) -> None:
|
||||
"""Turn the light off."""
|
||||
if not self._prop_on:
|
||||
return
|
||||
# Dirty logic for lumi.gateway.mgl03 indicator light
|
||||
value_on = False if self._prop_on.format_ == bool else 0
|
||||
await self.set_property_async(prop=self._prop_on, value=value_on)
|
||||
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"domain": "xiaomi_home",
|
||||
"name": "Xiaomi Home",
|
||||
"codeowners": [
|
||||
"@XiaoMi"
|
||||
],
|
||||
"config_flow": true,
|
||||
"dependencies": [
|
||||
"http",
|
||||
"persistent_notification",
|
||||
"ffmpeg",
|
||||
"zeroconf"
|
||||
],
|
||||
"documentation": "https://github.com/XiaoMi/ha_xiaomi_home/blob/main/README.md",
|
||||
"integration_type": "hub",
|
||||
"iot_class": "cloud_polling",
|
||||
"issue_tracker": "https://github.com/XiaoMi/ha_xiaomi_home/issues",
|
||||
"loggers": [
|
||||
"Xiaomi Home"
|
||||
],
|
||||
"requirements": [
|
||||
"construct>=2.10.56",
|
||||
"paho-mqtt",
|
||||
"numpy",
|
||||
"cryptography",
|
||||
"psutil"
|
||||
],
|
||||
"version": "v0.4.7",
|
||||
"zeroconf": [
|
||||
"_miot-central._tcp.local."
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,471 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Copyright (C) 2024 Xiaomi Corporation.
|
||||
|
||||
The ownership and intellectual property rights of Xiaomi Home Assistant
|
||||
Integration and related Xiaomi cloud service API interface provided under this
|
||||
license, including source code and object code (collectively, "Licensed Work"),
|
||||
are owned by Xiaomi. Subject to the terms and conditions of this License, Xiaomi
|
||||
hereby grants you a personal, limited, non-exclusive, non-transferable,
|
||||
non-sublicensable, and royalty-free license to reproduce, use, modify, and
|
||||
distribute the Licensed Work only for your use of Home Assistant for
|
||||
non-commercial purposes. For the avoidance of doubt, Xiaomi does not authorize
|
||||
you to use the Licensed Work for any other purpose, including but not limited
|
||||
to use Licensed Work to develop applications (APP), Web services, and other
|
||||
forms of software.
|
||||
|
||||
You may reproduce and distribute copies of the Licensed Work, with or without
|
||||
modifications, whether in source or object form, provided that you must give
|
||||
any other recipients of the Licensed Work a copy of this License and retain all
|
||||
copyright and disclaimers.
|
||||
|
||||
Xiaomi provides the Licensed Work on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied, including, without
|
||||
limitation, any warranties, undertakes, or conditions of TITLE, NO ERROR OR
|
||||
OMISSION, CONTINUITY, RELIABILITY, NON-INFRINGEMENT, MERCHANTABILITY, or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. In any event, you are solely responsible
|
||||
for any direct, indirect, special, incidental, or consequential damages or
|
||||
losses arising from the use or inability to use the Licensed Work.
|
||||
|
||||
Xiaomi reserves all rights not expressly granted to you in this License.
|
||||
Except for the rights expressly granted by Xiaomi under this License, Xiaomi
|
||||
does not authorize you in any form to use the trademarks, copyrights, or other
|
||||
forms of intellectual property rights of Xiaomi and its affiliates, including,
|
||||
without limitation, without obtaining other written permission from Xiaomi, you
|
||||
shall not use "Xiaomi", "Mijia" and other words related to Xiaomi or words that
|
||||
may make the public associate with Xiaomi in any form to publicize or promote
|
||||
the software or hardware devices that use the Licensed Work.
|
||||
|
||||
Xiaomi has the right to immediately terminate all your authorization under this
|
||||
License in the event:
|
||||
1. You assert patent invalidation, litigation, or other claims against patents
|
||||
or other intellectual property rights of Xiaomi or its affiliates; or,
|
||||
2. You make, have made, manufacture, sell, or offer to sell products that knock
|
||||
off Xiaomi or its affiliates' products.
|
||||
|
||||
Media player entities for Xiaomi Home.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
import logging
|
||||
from typing import Optional
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.components.media_player import (MediaPlayerEntity,
|
||||
MediaPlayerEntityFeature,
|
||||
MediaPlayerDeviceClass,
|
||||
MediaPlayerState, MediaType)
|
||||
|
||||
from .miot.const import DOMAIN
|
||||
from .miot.miot_device import MIoTDevice, MIoTServiceEntity, MIoTEntityData
|
||||
from .miot.miot_spec import MIoTSpecProperty, MIoTSpecAction
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback) -> None:
|
||||
"""Set up a config entry."""
|
||||
device_list: list[MIoTDevice] = hass.data[DOMAIN]['devices'][
|
||||
config_entry.entry_id]
|
||||
|
||||
new_entities = []
|
||||
for miot_device in device_list:
|
||||
for data in miot_device.entity_list.get('wifi-speaker', []):
|
||||
new_entities.append(
|
||||
WifiSpeaker(miot_device=miot_device, entity_data=data))
|
||||
for data in miot_device.entity_list.get('television', []):
|
||||
new_entities.append(
|
||||
Television(miot_device=miot_device, entity_data=data))
|
||||
|
||||
if new_entities:
|
||||
async_add_entities(new_entities)
|
||||
|
||||
|
||||
class FeatureVolumeMute(MIoTServiceEntity, MediaPlayerEntity):
|
||||
"""VOLUME_MUTE feature of the media player entity."""
|
||||
_prop_mute: Optional[MIoTSpecProperty]
|
||||
|
||||
def __init__(self, miot_device: MIoTDevice,
|
||||
entity_data: MIoTEntityData) -> None:
|
||||
"""Initialize the feature class."""
|
||||
self._prop_mute = None
|
||||
|
||||
super().__init__(miot_device=miot_device, entity_data=entity_data)
|
||||
# properties
|
||||
for prop in entity_data.props:
|
||||
if prop.name == 'mute':
|
||||
self._attr_supported_features |= (
|
||||
MediaPlayerEntityFeature.VOLUME_MUTE)
|
||||
self._prop_mute = prop
|
||||
|
||||
@property
|
||||
def is_volume_muted(self) -> Optional[bool]:
|
||||
"""True if volume is currently muted."""
|
||||
return self.get_prop_value(
|
||||
prop=self._prop_mute) if self._prop_mute else None
|
||||
|
||||
async def async_mute_volume(self, mute: bool) -> None:
|
||||
"""Mute the volume."""
|
||||
await self.set_property_async(prop=self._prop_mute, value=mute)
|
||||
|
||||
|
||||
class FeatureVolumeSet(MIoTServiceEntity, MediaPlayerEntity):
|
||||
"""VOLUME_SET feature of the media player entity."""
|
||||
_prop_volume: Optional[MIoTSpecProperty]
|
||||
_volume_value_min: Optional[float]
|
||||
_volume_value_max: Optional[float]
|
||||
_volume_value_range: Optional[float]
|
||||
|
||||
def __init__(self, miot_device: MIoTDevice,
|
||||
entity_data: MIoTEntityData) -> None:
|
||||
"""Initialize the feature class."""
|
||||
self._prop_volume = None
|
||||
self._volume_value_min = None
|
||||
self._volume_value_max = None
|
||||
self._volume_value_range = None
|
||||
|
||||
super().__init__(miot_device=miot_device, entity_data=entity_data)
|
||||
# properties
|
||||
for prop in entity_data.props:
|
||||
if prop.name == 'volume':
|
||||
if not prop.value_range:
|
||||
_LOGGER.error('invalid volume value_range format, %s',
|
||||
self.entity_id)
|
||||
continue
|
||||
self._volume_value_min = prop.value_range.min_
|
||||
self._volume_value_max = prop.value_range.max_
|
||||
self._volume_value_range = (prop.value_range.max_ -
|
||||
prop.value_range.min_)
|
||||
self._attr_volume_step = (prop.value_range.step /
|
||||
self._volume_value_range)
|
||||
self._attr_supported_features |= (
|
||||
MediaPlayerEntityFeature.VOLUME_SET |
|
||||
MediaPlayerEntityFeature.VOLUME_STEP)
|
||||
self._prop_volume = prop
|
||||
|
||||
async def async_set_volume_level(self, volume: float) -> None:
|
||||
"""Set volume level."""
|
||||
value = volume * self._volume_value_range + self._volume_value_min
|
||||
if value > self._volume_value_max:
|
||||
value = self._volume_value_max
|
||||
elif value < self._volume_value_min:
|
||||
value = self._volume_value_min
|
||||
await self.set_property_async(prop=self._prop_volume, value=value)
|
||||
|
||||
@property
|
||||
def volume_level(self) -> Optional[float]:
|
||||
"""The current volume level, range [0, 1]."""
|
||||
value = self.get_prop_value(
|
||||
prop=self._prop_volume) if self._prop_volume else None
|
||||
if value is None:
|
||||
return None
|
||||
return (value - self._volume_value_min) / self._volume_value_range
|
||||
|
||||
|
||||
class FeaturePlay(MIoTServiceEntity, MediaPlayerEntity):
|
||||
"""PLAY feature of the media player entity."""
|
||||
_action_play: Optional[MIoTSpecAction]
|
||||
|
||||
def __init__(self, miot_device: MIoTDevice,
|
||||
entity_data: MIoTEntityData) -> None:
|
||||
"""Initialize the feature class."""
|
||||
self._action_play = None
|
||||
|
||||
super().__init__(miot_device=miot_device, entity_data=entity_data)
|
||||
# actions
|
||||
for act in entity_data.actions:
|
||||
if act.name == 'play':
|
||||
self._attr_supported_features |= (MediaPlayerEntityFeature.PLAY)
|
||||
self._action_play = act
|
||||
|
||||
async def async_media_play(self) -> None:
|
||||
"""Send play command."""
|
||||
await self.action_async(action=self._action_play)
|
||||
|
||||
|
||||
class FeaturePause(MIoTServiceEntity, MediaPlayerEntity):
|
||||
"""PAUSE feature of the media player entity."""
|
||||
_action_pause: Optional[MIoTSpecAction]
|
||||
|
||||
def __init__(self, miot_device: MIoTDevice,
|
||||
entity_data: MIoTEntityData) -> None:
|
||||
"""Initialize the feature class."""
|
||||
self._action_pause = None
|
||||
|
||||
super().__init__(miot_device=miot_device, entity_data=entity_data)
|
||||
# actions
|
||||
for act in entity_data.actions:
|
||||
if act.name == 'pause':
|
||||
self._attr_supported_features |= (
|
||||
MediaPlayerEntityFeature.PAUSE)
|
||||
self._action_pause = act
|
||||
|
||||
async def async_media_pause(self) -> None:
|
||||
"""Send pause command."""
|
||||
await self.action_async(action=self._action_pause)
|
||||
|
||||
|
||||
class FeatureStop(MIoTServiceEntity, MediaPlayerEntity):
|
||||
"""STOP feature of the media player entity."""
|
||||
_action_stop: Optional[MIoTSpecAction]
|
||||
|
||||
def __init__(self, miot_device: MIoTDevice,
|
||||
entity_data: MIoTEntityData) -> None:
|
||||
"""Initialize the feature class."""
|
||||
self._action_stop = None
|
||||
|
||||
super().__init__(miot_device=miot_device, entity_data=entity_data)
|
||||
# actions
|
||||
for act in entity_data.actions:
|
||||
if act.name == 'stop':
|
||||
self._attr_supported_features |= (MediaPlayerEntityFeature.STOP)
|
||||
self._action_stop = act
|
||||
|
||||
async def async_media_stop(self) -> None:
|
||||
"""Send stop command."""
|
||||
await self.action_async(action=self._action_stop)
|
||||
|
||||
|
||||
class FeatureNextTrack(MIoTServiceEntity, MediaPlayerEntity):
|
||||
"""NEXT_TRACK feature of the media player entity."""
|
||||
_action_next: Optional[MIoTSpecAction]
|
||||
|
||||
def __init__(self, miot_device: MIoTDevice,
|
||||
entity_data: MIoTEntityData) -> None:
|
||||
"""Initialize the feature class."""
|
||||
self._action_next = None
|
||||
|
||||
super().__init__(miot_device=miot_device, entity_data=entity_data)
|
||||
# actions
|
||||
for act in entity_data.actions:
|
||||
if act.name == 'next':
|
||||
self._attr_supported_features |= (
|
||||
MediaPlayerEntityFeature.NEXT_TRACK)
|
||||
self._action_next = act
|
||||
|
||||
async def async_media_next_track(self) -> None:
|
||||
"""Send next track command."""
|
||||
await self.action_async(action=self._action_next)
|
||||
|
||||
|
||||
class FeaturePreviousTrack(MIoTServiceEntity, MediaPlayerEntity):
|
||||
"""PREVIOUS_TRACK feature of the media player entity."""
|
||||
_action_previous: Optional[MIoTSpecAction]
|
||||
|
||||
def __init__(self, miot_device: MIoTDevice,
|
||||
entity_data: MIoTEntityData) -> None:
|
||||
"""Initialize the feature class."""
|
||||
self._action_previous = None
|
||||
|
||||
super().__init__(miot_device=miot_device, entity_data=entity_data)
|
||||
# actions
|
||||
for act in entity_data.actions:
|
||||
if act.name == 'previous':
|
||||
self._attr_supported_features |= (
|
||||
MediaPlayerEntityFeature.PREVIOUS_TRACK)
|
||||
self._action_previous = act
|
||||
|
||||
async def async_media_previous_track(self) -> None:
|
||||
"""Send previous track command."""
|
||||
await self.action_async(action=self._action_previous)
|
||||
|
||||
|
||||
class FeatureSoundMode(MIoTServiceEntity, MediaPlayerEntity):
|
||||
"""SELECT_SOUND_MODE feature of the media player entity."""
|
||||
_prop_play_loop_mode: Optional[MIoTSpecProperty]
|
||||
_sound_mode_map: Optional[dict[int, str]]
|
||||
|
||||
def __init__(self, miot_device: MIoTDevice,
|
||||
entity_data: MIoTEntityData) -> None:
|
||||
"""Initialize the feature class."""
|
||||
self._prop_play_loop_mode = None
|
||||
self._sound_mode_map = None
|
||||
|
||||
super().__init__(miot_device=miot_device, entity_data=entity_data)
|
||||
# properties
|
||||
for prop in entity_data.props:
|
||||
if prop.name == 'play-loop-mode':
|
||||
if not prop.value_list:
|
||||
_LOGGER.error('invalid play-loop-mode value_list, %s',
|
||||
self.entity_id)
|
||||
continue
|
||||
self._sound_mode_map = prop.value_list.to_map()
|
||||
self._attr_sound_mode_list = list(self._sound_mode_map.values())
|
||||
self._attr_supported_features |= (
|
||||
MediaPlayerEntityFeature.SELECT_SOUND_MODE)
|
||||
self._prop_play_loop_mode = prop
|
||||
|
||||
async def async_select_sound_mode(self, sound_mode: str):
|
||||
"""Switch the sound mode of the entity."""
|
||||
await self.set_property_async(prop=self._prop_play_loop_mode,
|
||||
value=self.get_map_key(
|
||||
map_=self._sound_mode_map,
|
||||
value=sound_mode))
|
||||
|
||||
@property
|
||||
def sound_mode(self) -> Optional[str]:
|
||||
"""The current sound mode."""
|
||||
return (self.get_map_value(map_=self._sound_mode_map,
|
||||
key=self.get_prop_value(
|
||||
prop=self._prop_play_loop_mode))
|
||||
if self._prop_play_loop_mode else None)
|
||||
|
||||
|
||||
class FeatureTurnOn(MIoTServiceEntity, MediaPlayerEntity):
|
||||
"""TURN_ON feature of the media player entity."""
|
||||
_action_turn_on: Optional[MIoTSpecAction]
|
||||
|
||||
def __init__(self, miot_device: MIoTDevice,
|
||||
entity_data: MIoTEntityData) -> None:
|
||||
"""Initialize the feature class."""
|
||||
self._action_turn_on = None
|
||||
|
||||
super().__init__(miot_device=miot_device, entity_data=entity_data)
|
||||
# actions
|
||||
for act in entity_data.actions:
|
||||
if act.name == 'turn-on':
|
||||
self._attr_supported_features |= (
|
||||
MediaPlayerEntityFeature.TURN_ON)
|
||||
self._action_turn_on = act
|
||||
|
||||
async def async_turn_on(self) -> None:
|
||||
"""Turn the media player on."""
|
||||
await self.action_async(action=self._action_turn_on)
|
||||
|
||||
|
||||
class FeatureTurnOff(MIoTServiceEntity, MediaPlayerEntity):
|
||||
"""TURN_OFF feature of the media player entity."""
|
||||
_action_turn_off: Optional[MIoTSpecAction]
|
||||
|
||||
def __init__(self, miot_device: MIoTDevice,
|
||||
entity_data: MIoTEntityData) -> None:
|
||||
"""Initialize the feature class."""
|
||||
self._action_turn_off = None
|
||||
|
||||
super().__init__(miot_device=miot_device, entity_data=entity_data)
|
||||
# actions
|
||||
for act in entity_data.actions:
|
||||
if act.name == 'turn-off':
|
||||
self._attr_supported_features |= (
|
||||
MediaPlayerEntityFeature.TURN_OFF)
|
||||
self._action_turn_off = act
|
||||
|
||||
async def async_turn_off(self) -> None:
|
||||
"""Turn the media player off."""
|
||||
await self.action_async(action=self._action_turn_off)
|
||||
|
||||
|
||||
class FeatureSource(MIoTServiceEntity, MediaPlayerEntity):
|
||||
"""SELECT_SOURCE feature of the media player entity."""
|
||||
_prop_input_control: Optional[MIoTSpecProperty]
|
||||
_input_source_map: Optional[dict[int, str]]
|
||||
|
||||
def __init__(self, miot_device: MIoTDevice,
|
||||
entity_data: MIoTEntityData) -> None:
|
||||
"""Initialize the feature class."""
|
||||
self._prop_input_control = None
|
||||
self._input_source_map = None
|
||||
|
||||
super().__init__(miot_device=miot_device, entity_data=entity_data)
|
||||
# properties
|
||||
for prop in entity_data.props:
|
||||
if prop.name == 'input-control':
|
||||
if not prop.value_list:
|
||||
_LOGGER.error('invalid input-control value_list, %s',
|
||||
self.entity_id)
|
||||
continue
|
||||
self._input_source_map = prop.value_list.to_map()
|
||||
self._attr_source_list = list(self._input_source_map.values())
|
||||
self._attr_supported_features |= (
|
||||
MediaPlayerEntityFeature.SELECT_SOURCE)
|
||||
self._prop_input_control = prop
|
||||
|
||||
async def async_select_source(self, source: str) -> None:
|
||||
"""Select input source."""
|
||||
await self.set_property_async(prop=self._prop_input_control,
|
||||
value=self.get_map_key(
|
||||
map_=self._input_source_map,
|
||||
value=source))
|
||||
|
||||
@property
|
||||
def source(self) -> Optional[str]:
|
||||
"""The current input source."""
|
||||
return (self.get_map_value(map_=self._input_source_map,
|
||||
key=self.get_prop_value(
|
||||
prop=self._prop_input_control))
|
||||
if self._prop_input_control else None)
|
||||
|
||||
|
||||
class FeatureState(MIoTServiceEntity, MediaPlayerEntity):
|
||||
"""States feature of the media player entity."""
|
||||
_prop_playing_state: Optional[MIoTSpecProperty]
|
||||
_playing_state_map: Optional[dict[int, str]]
|
||||
|
||||
def __init__(self, miot_device: MIoTDevice,
|
||||
entity_data: MIoTEntityData) -> None:
|
||||
"""Initialize the feature class."""
|
||||
self._prop_playing_state = None
|
||||
self._playing_state_map = None
|
||||
|
||||
super().__init__(miot_device=miot_device, entity_data=entity_data)
|
||||
# properties
|
||||
for prop in entity_data.props:
|
||||
if prop.name == 'playing-state':
|
||||
if not prop.value_list:
|
||||
_LOGGER.error('invalid mode value_list, %s', self.entity_id)
|
||||
continue
|
||||
self._playing_state_map = {}
|
||||
for item in prop.value_list.items:
|
||||
if item.name in {'off'}:
|
||||
self._playing_state_map[
|
||||
item.value] = MediaPlayerState.OFF
|
||||
elif item.name in {'idle', 'stop', 'stopped'}:
|
||||
self._playing_state_map[
|
||||
item.value] = MediaPlayerState.IDLE
|
||||
elif item.name in {'playing'}:
|
||||
self._playing_state_map[
|
||||
item.value] = MediaPlayerState.PLAYING
|
||||
elif item.name in {'pause', 'paused'}:
|
||||
self._playing_state_map[
|
||||
item.value] = MediaPlayerState.PAUSED
|
||||
self._prop_playing_state = prop
|
||||
|
||||
@property
|
||||
def state(self) -> Optional[MediaPlayerState]:
|
||||
"""The current state."""
|
||||
current_state = self.get_prop_value(
|
||||
prop=self._prop_playing_state) if self._prop_playing_state else None
|
||||
return (MediaPlayerState.ON if
|
||||
(current_state is None) else self.get_map_value(
|
||||
map_=self._playing_state_map, key=current_state))
|
||||
|
||||
|
||||
class WifiSpeaker(FeatureVolumeSet, FeatureVolumeMute, FeaturePlay,
|
||||
FeaturePause, FeatureStop, FeatureNextTrack,
|
||||
FeaturePreviousTrack, FeatureSoundMode, FeatureState):
|
||||
"""WiFi speaker, aka XiaoAI sound speaker."""
|
||||
|
||||
def __init__(self, miot_device: MIoTDevice,
|
||||
entity_data: MIoTEntityData) -> None:
|
||||
"""Initialize the device."""
|
||||
super().__init__(miot_device=miot_device, entity_data=entity_data)
|
||||
|
||||
self._attr_device_class = MediaPlayerDeviceClass.SPEAKER
|
||||
self._attr_media_content_type = MediaType.MUSIC
|
||||
|
||||
|
||||
class Television(FeatureVolumeSet, FeatureVolumeMute, FeaturePlay, FeaturePause,
|
||||
FeatureStop, FeatureNextTrack, FeaturePreviousTrack,
|
||||
FeatureSoundMode, FeatureState, FeatureSource, FeatureTurnOn,
|
||||
FeatureTurnOff):
|
||||
"""Television"""
|
||||
|
||||
def __init__(self, miot_device: MIoTDevice,
|
||||
entity_data: MIoTEntityData) -> None:
|
||||
"""Initialize the device."""
|
||||
super().__init__(miot_device=miot_device, entity_data=entity_data)
|
||||
|
||||
self._attr_device_class = MediaPlayerDeviceClass.TV
|
||||
self._attr_media_content_type = MediaType.VIDEO
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,188 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Copyright (C) 2024 Xiaomi Corporation.
|
||||
|
||||
The ownership and intellectual property rights of Xiaomi Home Assistant
|
||||
Integration and related Xiaomi cloud service API interface provided under this
|
||||
license, including source code and object code (collectively, "Licensed Work"),
|
||||
are owned by Xiaomi. Subject to the terms and conditions of this License, Xiaomi
|
||||
hereby grants you a personal, limited, non-exclusive, non-transferable,
|
||||
non-sublicensable, and royalty-free license to reproduce, use, modify, and
|
||||
distribute the Licensed Work only for your use of Home Assistant for
|
||||
non-commercial purposes. For the avoidance of doubt, Xiaomi does not authorize
|
||||
you to use the Licensed Work for any other purpose, including but not limited
|
||||
to use Licensed Work to develop applications (APP), Web services, and other
|
||||
forms of software.
|
||||
|
||||
You may reproduce and distribute copies of the Licensed Work, with or without
|
||||
modifications, whether in source or object form, provided that you must give
|
||||
any other recipients of the Licensed Work a copy of this License and retain all
|
||||
copyright and disclaimers.
|
||||
|
||||
Xiaomi provides the Licensed Work on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied, including, without
|
||||
limitation, any warranties, undertakes, or conditions of TITLE, NO ERROR OR
|
||||
OMISSION, CONTINUITY, RELIABILITY, NON-INFRINGEMENT, MERCHANTABILITY, or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. In any event, you are solely responsible
|
||||
for any direct, indirect, special, incidental, or consequential damages or
|
||||
losses arising from the use or inability to use the Licensed Work.
|
||||
|
||||
Xiaomi reserves all rights not expressly granted to you in this License.
|
||||
Except for the rights expressly granted by Xiaomi under this License, Xiaomi
|
||||
does not authorize you in any form to use the trademarks, copyrights, or other
|
||||
forms of intellectual property rights of Xiaomi and its affiliates, including,
|
||||
without limitation, without obtaining other written permission from Xiaomi, you
|
||||
shall not use "Xiaomi", "Mijia" and other words related to Xiaomi or words that
|
||||
may make the public associate with Xiaomi in any form to publicize or promote
|
||||
the software or hardware devices that use the Licensed Work.
|
||||
|
||||
Xiaomi has the right to immediately terminate all your authorization under this
|
||||
License in the event:
|
||||
1. You assert patent invalidation, litigation, or other claims against patents
|
||||
or other intellectual property rights of Xiaomi or its affiliates; or,
|
||||
2. You make, have made, manufacture, sell, or offer to sell products that knock
|
||||
off Xiaomi or its affiliates' products.
|
||||
|
||||
Common utilities.
|
||||
"""
|
||||
import asyncio
|
||||
import json
|
||||
from os import path
|
||||
import random
|
||||
from typing import Any, Optional
|
||||
import hashlib
|
||||
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__))
|
||||
|
||||
|
||||
def gen_absolute_path(relative_path: str) -> str:
|
||||
"""Generate an absolute path."""
|
||||
return path.join(MIOT_ROOT_PATH, relative_path)
|
||||
|
||||
|
||||
def calc_group_id(uid: str, home_id: str) -> str:
|
||||
"""Calculate the group ID based on a user ID and a home ID."""
|
||||
return hashlib.sha1(
|
||||
f'{uid}central_service{home_id}'.encode('utf-8')).hexdigest()[:16]
|
||||
|
||||
|
||||
def load_json_file(json_file: str) -> dict:
|
||||
"""Load a JSON file."""
|
||||
with open(json_file, 'r', encoding='utf-8') as f:
|
||||
return json.load(f)
|
||||
|
||||
|
||||
def load_yaml_file(yaml_file: str) -> dict:
|
||||
"""Load a YAML file."""
|
||||
with open(yaml_file, 'r', encoding='utf-8') as f:
|
||||
return yaml.load(f, Loader=yaml.FullLoader)
|
||||
|
||||
|
||||
def randomize_int(value: int, ratio: float) -> int:
|
||||
"""Randomize an integer value."""
|
||||
return int(value * (1 - ratio + random.random()*2*ratio))
|
||||
|
||||
|
||||
def randomize_float(value: float, ratio: float) -> float:
|
||||
"""Randomize a float value."""
|
||||
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."""
|
||||
|
||||
def iter_all_nodes(self) -> Any:
|
||||
"""Return an iterator on all nodes with their paths and contents."""
|
||||
def rec(node, path_):
|
||||
# pylint: disable=protected-access
|
||||
if node._content:
|
||||
yield ('/'.join(path_), node._content)
|
||||
for part, child in node._children.items():
|
||||
yield from rec(child, path_ + [part])
|
||||
return rec(self._root, [])
|
||||
|
||||
def get(self, topic: str) -> Optional[Any]:
|
||||
try:
|
||||
return self[topic]
|
||||
except KeyError:
|
||||
return None
|
||||
|
||||
|
||||
class MIoTHttp:
|
||||
"""MIoT Common HTTP API."""
|
||||
@staticmethod
|
||||
def get(
|
||||
url: str, params: Optional[dict] = None, headers: Optional[dict] = None
|
||||
) -> Optional[str]:
|
||||
full_url = url
|
||||
if params:
|
||||
encoded_params = urlencode(params)
|
||||
full_url = f'{url}?{encoded_params}'
|
||||
request = Request(full_url, method='GET', headers=headers or {})
|
||||
content: Optional[bytes] = None
|
||||
with urlopen(request) as response:
|
||||
content = response.read()
|
||||
return str(content, 'utf-8') if content else None
|
||||
|
||||
@staticmethod
|
||||
def get_json(
|
||||
url: str, params: Optional[dict] = None, headers: Optional[dict] = None
|
||||
) -> Optional[dict]:
|
||||
response = MIoTHttp.get(url, params, headers)
|
||||
return json.loads(response) if response else None
|
||||
|
||||
@staticmethod
|
||||
def post(
|
||||
url: str, data: Optional[dict] = None, headers: Optional[dict] = None
|
||||
) -> Optional[str]:
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
def post_json(
|
||||
url: str, data: Optional[dict] = None, headers: Optional[dict] = None
|
||||
) -> Optional[dict]:
|
||||
response = MIoTHttp.post(url, data, headers)
|
||||
return json.loads(response) if response else None
|
||||
|
||||
@staticmethod
|
||||
async def get_async(
|
||||
url: str, params: Optional[dict] = None, headers: Optional[dict] = None,
|
||||
loop: Optional[asyncio.AbstractEventLoop] = None
|
||||
) -> Optional[str]:
|
||||
# TODO: Use aiohttp
|
||||
ev_loop = loop or asyncio.get_running_loop()
|
||||
return await ev_loop.run_in_executor(
|
||||
None, MIoTHttp.get, url, params, headers)
|
||||
|
||||
@staticmethod
|
||||
async def get_json_async(
|
||||
url: str, params: Optional[dict] = None, headers: Optional[dict] = None,
|
||||
loop: Optional[asyncio.AbstractEventLoop] = None
|
||||
) -> Optional[dict]:
|
||||
ev_loop = loop or asyncio.get_running_loop()
|
||||
return await ev_loop.run_in_executor(
|
||||
None, MIoTHttp.get_json, url, params, headers)
|
||||
|
||||
@ staticmethod
|
||||
async def post_async(
|
||||
url: str, data: Optional[dict] = None, headers: Optional[dict] = None,
|
||||
loop: Optional[asyncio.AbstractEventLoop] = None
|
||||
) -> Optional[str]:
|
||||
ev_loop = loop or asyncio.get_running_loop()
|
||||
return await ev_loop.run_in_executor(
|
||||
None, MIoTHttp.post, url, data, headers)
|
||||
@@ -0,0 +1,160 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Copyright (C) 2024 Xiaomi Corporation.
|
||||
|
||||
The ownership and intellectual property rights of Xiaomi Home Assistant
|
||||
Integration and related Xiaomi cloud service API interface provided under this
|
||||
license, including source code and object code (collectively, "Licensed Work"),
|
||||
are owned by Xiaomi. Subject to the terms and conditions of this License, Xiaomi
|
||||
hereby grants you a personal, limited, non-exclusive, non-transferable,
|
||||
non-sublicensable, and royalty-free license to reproduce, use, modify, and
|
||||
distribute the Licensed Work only for your use of Home Assistant for
|
||||
non-commercial purposes. For the avoidance of doubt, Xiaomi does not authorize
|
||||
you to use the Licensed Work for any other purpose, including but not limited
|
||||
to use Licensed Work to develop applications (APP), Web services, and other
|
||||
forms of software.
|
||||
|
||||
You may reproduce and distribute copies of the Licensed Work, with or without
|
||||
modifications, whether in source or object form, provided that you must give
|
||||
any other recipients of the Licensed Work a copy of this License and retain all
|
||||
copyright and disclaimers.
|
||||
|
||||
Xiaomi provides the Licensed Work on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied, including, without
|
||||
limitation, any warranties, undertakes, or conditions of TITLE, NO ERROR OR
|
||||
OMISSION, CONTINUITY, RELIABILITY, NON-INFRINGEMENT, MERCHANTABILITY, or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. In any event, you are solely responsible
|
||||
for any direct, indirect, special, incidental, or consequential damages or
|
||||
losses arising from the use or inability to use the Licensed Work.
|
||||
|
||||
Xiaomi reserves all rights not expressly granted to you in this License.
|
||||
Except for the rights expressly granted by Xiaomi under this License, Xiaomi
|
||||
does not authorize you in any form to use the trademarks, copyrights, or other
|
||||
forms of intellectual property rights of Xiaomi and its affiliates, including,
|
||||
without limitation, without obtaining other written permission from Xiaomi, you
|
||||
shall not use "Xiaomi", "Mijia" and other words related to Xiaomi or words that
|
||||
may make the public associate with Xiaomi in any form to publicize or promote
|
||||
the software or hardware devices that use the Licensed Work.
|
||||
|
||||
Xiaomi has the right to immediately terminate all your authorization under this
|
||||
License in the event:
|
||||
1. You assert patent invalidation, litigation, or other claims against patents
|
||||
or other intellectual property rights of Xiaomi or its affiliates; or,
|
||||
2. You make, have made, manufacture, sell, or offer to sell products that knock
|
||||
off Xiaomi or its affiliates' products.
|
||||
|
||||
Constants.
|
||||
"""
|
||||
DOMAIN: str = 'xiaomi_home'
|
||||
DEFAULT_NAME: str = 'Xiaomi Home'
|
||||
|
||||
DEFAULT_NICK_NAME: str = 'Xiaomi'
|
||||
|
||||
MIHOME_HTTP_API_TIMEOUT: int = 30
|
||||
MIHOME_MQTT_KEEPALIVE: int = 60
|
||||
# seconds, 3 days
|
||||
MIHOME_CERT_EXPIRE_MARGIN: int = 3600*24*3
|
||||
|
||||
NETWORK_REFRESH_INTERVAL: int = 30
|
||||
|
||||
OAUTH2_CLIENT_ID: str = '2882303761520251711'
|
||||
OAUTH2_AUTH_URL: str = 'https://account.xiaomi.com/oauth2/authorize'
|
||||
DEFAULT_OAUTH2_API_HOST: str = 'ha.api.io.mi.com'
|
||||
DEFAULT_CLOUD_BROKER_HOST: str = 'ha.mqtt.io.mi.com'
|
||||
|
||||
# seconds, 14 days
|
||||
SPEC_STD_LIB_EFFECTIVE_TIME = 3600*24*14
|
||||
# seconds, 14 days
|
||||
MANUFACTURER_EFFECTIVE_TIME = 3600*24*14
|
||||
|
||||
SUPPORTED_PLATFORMS: list = [
|
||||
'binary_sensor',
|
||||
'button',
|
||||
'climate',
|
||||
'cover',
|
||||
'device_tracker',
|
||||
'event',
|
||||
'fan',
|
||||
'humidifier',
|
||||
'light',
|
||||
'media_player',
|
||||
'notify',
|
||||
'number',
|
||||
'select',
|
||||
'sensor',
|
||||
'switch',
|
||||
'text',
|
||||
'vacuum',
|
||||
'water_heater',
|
||||
]
|
||||
|
||||
UNSUPPORTED_MODELS: list = [
|
||||
'chuangmi.ir.v2',
|
||||
'era.airp.cwb03',
|
||||
'hmpace.motion.v6nfc',
|
||||
'k0918.toothbrush.t700'
|
||||
]
|
||||
|
||||
DEFAULT_CLOUD_SERVER: str = 'cn'
|
||||
CLOUD_SERVERS: dict = {
|
||||
'cn': '中国大陆',
|
||||
'de': 'Europe',
|
||||
'i2': 'India',
|
||||
'ru': 'Russia',
|
||||
'sg': 'Singapore',
|
||||
'us': 'United States'
|
||||
}
|
||||
|
||||
SUPPORT_CENTRAL_GATEWAY_CTRL: list = ['cn']
|
||||
|
||||
DEFAULT_INTEGRATION_LANGUAGE: str = 'en'
|
||||
INTEGRATION_LANGUAGES = {
|
||||
'de': 'Deutsch',
|
||||
'en': 'English',
|
||||
'es': 'Español',
|
||||
'fr': 'Français',
|
||||
'it': 'Italiano',
|
||||
'ja': '日本語',
|
||||
'nl': 'Nederlands',
|
||||
'pt': 'Português',
|
||||
'pt-BR': 'Português (Brasil)',
|
||||
'ru': 'Русский',
|
||||
'tr': 'Türkçe',
|
||||
'zh-Hans': '简体中文',
|
||||
'zh-Hant': '繁體中文'
|
||||
}
|
||||
|
||||
DEFAULT_COVER_DEAD_ZONE_WIDTH: int = 0
|
||||
MIN_COVER_DEAD_ZONE_WIDTH: int = 0
|
||||
MAX_COVER_DEAD_ZONE_WIDTH: int = 5
|
||||
|
||||
DEFAULT_CTRL_MODE: str = 'auto'
|
||||
|
||||
# Registered in Xiaomi OAuth 2.0 Service
|
||||
# DO NOT CHANGE UNLESS YOU HAVE AN ADMINISTRATOR PERMISSION
|
||||
OAUTH_REDIRECT_URL: str = 'http://homeassistant.local:8123'
|
||||
|
||||
MIHOME_CA_CERT_STR: str = '-----BEGIN CERTIFICATE-----\n' \
|
||||
'MIIBazCCAQ+gAwIBAgIEA/UKYDAMBggqhkjOPQQDAgUAMCIxEzARBgNVBAoTCk1p\n' \
|
||||
'amlhIFJvb3QxCzAJBgNVBAYTAkNOMCAXDTE2MTEyMzAxMzk0NVoYDzIwNjYxMTEx\n' \
|
||||
'MDEzOTQ1WjAiMRMwEQYDVQQKEwpNaWppYSBSb290MQswCQYDVQQGEwJDTjBZMBMG\n' \
|
||||
'ByqGSM49AgEGCCqGSM49AwEHA0IABL71iwLa4//4VBqgRI+6xE23xpovqPCxtv96\n' \
|
||||
'2VHbZij61/Ag6jmi7oZ/3Xg/3C+whglcwoUEE6KALGJ9vccV9PmjLzAtMAwGA1Ud\n' \
|
||||
'EwQFMAMBAf8wHQYDVR0OBBYEFJa3onw5sblmM6n40QmyAGDI5sURMAwGCCqGSM49\n' \
|
||||
'BAMCBQADSAAwRQIgchciK9h6tZmfrP8Ka6KziQ4Lv3hKfrHtAZXMHPda4IYCIQCG\n' \
|
||||
'az93ggFcbrG9u2wixjx1HKW4DUA5NXZG0wWQTpJTbQ==\n' \
|
||||
'-----END CERTIFICATE-----\n' \
|
||||
'-----BEGIN CERTIFICATE-----\n' \
|
||||
'MIIBjzCCATWgAwIBAgIBATAKBggqhkjOPQQDAjAiMRMwEQYDVQQKEwpNaWppYSBS\n' \
|
||||
'b290MQswCQYDVQQGEwJDTjAgFw0yMjA2MDkxNDE0MThaGA8yMDcyMDUyNzE0MTQx\n' \
|
||||
'OFowLDELMAkGA1UEBhMCQ04xHTAbBgNVBAoMFE1JT1QgQ0VOVFJBTCBHQVRFV0FZ\n' \
|
||||
'MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEdYrzbnp/0x/cZLZnuEDXTFf8mhj4\n' \
|
||||
'CVpZPwgj9e9Ve5r3K7zvu8Jjj7JF1JjQYvEC6yhp1SzBgglnK4L8xQzdiqNQME4w\n' \
|
||||
'HQYDVR0OBBYEFCf9+YBU7pXDs6K6CAQPRhlGJ+cuMB8GA1UdIwQYMBaAFJa3onw5\n' \
|
||||
'sblmM6n40QmyAGDI5sURMAwGA1UdEwQFMAMBAf8wCgYIKoZIzj0EAwIDSAAwRQIh\n' \
|
||||
'AKUv+c8v98vypkGMTzMwckGjjVqTef8xodsy6PhcSCq+AiA/n9mDs62hAo5zXyJy\n' \
|
||||
'Bs1s7mqXPf1XgieoxIvs1MqyiA==\n' \
|
||||
'-----END CERTIFICATE-----\n'
|
||||
|
||||
MIHOME_CA_CERT_SHA256: str = \
|
||||
'8b7bf306be3632e08b0ead308249e5f2b2520dc921ad143872d5fcc7c68d6759'
|
||||
@@ -0,0 +1,160 @@
|
||||
{
|
||||
"config": {
|
||||
"other": {
|
||||
"devices": "Geräte",
|
||||
"found_central_gateway": ", lokales zentrales Gateway gefunden",
|
||||
"without_room": "Kein Raum zugewiesen",
|
||||
"no_display": "nicht anzeigen"
|
||||
},
|
||||
"control_mode": {
|
||||
"auto": "automatisch",
|
||||
"cloud": "Cloud"
|
||||
},
|
||||
"statistics_logic": {
|
||||
"or": "ODER-Logik",
|
||||
"and": "UND-Logik"
|
||||
},
|
||||
"filter_mode": {
|
||||
"exclude": "ausschließen",
|
||||
"include": "einschließen"
|
||||
},
|
||||
"connect_type": {
|
||||
"0": "WiFi",
|
||||
"1": "yunyi-Gerät",
|
||||
"2": "Cloud-Gerät",
|
||||
"3": "ZigBee",
|
||||
"4": "webSocket",
|
||||
"5": "virtuelles Gerät",
|
||||
"6": "BLE",
|
||||
"7": "lokaler AP",
|
||||
"8": "WiFi+BLE",
|
||||
"9": "andere",
|
||||
"10": "Funktions-Plug-in",
|
||||
"11": "Zellnetz",
|
||||
"12": "Kabel",
|
||||
"13": "NB-IoT",
|
||||
"14": "Drittanbieter-Cloud-Zugriff",
|
||||
"15": "Infrarot-Fernbedienungsgerät",
|
||||
"16": "BLE-Mesh",
|
||||
"17": "virtuelle Gerätegruppe",
|
||||
"18": "Gateway-Untergerät",
|
||||
"19": "Sicherheitsstufe Gateway-Untergerät",
|
||||
"22": "PLC",
|
||||
"23": "nur Kabel",
|
||||
"24": "Matter",
|
||||
"25": "WiFi+Zellnetz"
|
||||
},
|
||||
"room_name_rule": {
|
||||
"none": "nicht synchronisieren",
|
||||
"home_room": "Hausname und Raumname (Xiaomi Home Schlafzimmer)",
|
||||
"room": "Raumname (Schlafzimmer)",
|
||||
"home": "Hausname (Xiaomi Home)"
|
||||
},
|
||||
"option_status": {
|
||||
"enable": "aktivieren",
|
||||
"disable": "deaktivieren"
|
||||
},
|
||||
"binary_mode": {
|
||||
"text": "Textsensor-Entität",
|
||||
"bool": "Binärsensor-Entität"
|
||||
},
|
||||
"device_state": {
|
||||
"add": "hinzufügen",
|
||||
"del": "nicht verfügbar",
|
||||
"offline": "offline"
|
||||
},
|
||||
"lan_ctrl_config": {
|
||||
"notice_net_dup": "\r\n**[Hinweis]** Es wurden mehrere Netzwerkkarten erkannt, die möglicherweise mit demselben Netzwerk verbunden sind. Bitte achten Sie auf die Auswahl.",
|
||||
"net_unavailable": "Schnittstelle nicht verfügbar"
|
||||
}
|
||||
},
|
||||
"oauth2": {
|
||||
"success": {
|
||||
"title": "Authentifizierung erfolgreich",
|
||||
"content": "Bitte schließen Sie diese Seite und kehren Sie zur Kontoauthentifizierungsseite zurück, um auf „Weiter“ zu klicken.",
|
||||
"button": "Schließen"
|
||||
},
|
||||
"fail": {
|
||||
"title": "Authentifizierung fehlgeschlagen",
|
||||
"content": "{error_msg}, bitte schließen Sie diese Seite und kehren Sie zur Kontoauthentifizierungsseite zurück, um den Authentifizierungslink erneut zu klicken.",
|
||||
"button": "Schließen"
|
||||
},
|
||||
"error_msg": {
|
||||
"-10100": "Ungültige Antwortparameter ('code' oder 'state' Feld ist leer)",
|
||||
"-10101": "Übergebenes 'state' Feld stimmt nicht überein"
|
||||
}
|
||||
},
|
||||
"miot": {
|
||||
"client": {
|
||||
"invalid_oauth_info": "Ungültige Authentifizierungsinformationen, Cloud-Verbindung nicht verfügbar, bitte betreten Sie die Xiaomi Home-Integrationsseite und klicken Sie auf 'Optionen', um die Authentifizierung erneut durchzuführen",
|
||||
"invalid_device_cache": "Ungültige Gerätecache-Informationen, bitte betreten Sie die Xiaomi Home-Integrationsseite und klicken Sie auf 'Optionen->Geräteliste aktualisieren', um den lokalen Gerätecache zu aktualisieren",
|
||||
"invalid_cert_info": "Ungültiges Benutzerzertifikat, lokale zentrale Verbindung nicht verfügbar, bitte betreten Sie die Xiaomi Home-Integrationsseite und klicken Sie auf 'Optionen', um die Authentifizierung erneut durchzuführen",
|
||||
"device_cloud_error": "Fehler beim Abrufen von Geräteinformationen aus der Cloud, bitte überprüfen Sie die lokale Netzwerkverbindung",
|
||||
"xiaomi_home_error_title": "Xiaomi Home-Integrationsfehler",
|
||||
"xiaomi_home_error": "Fehler **{nick_name}({uid}, {cloud_server})** festgestellt, bitte betreten Sie die Optionen-Seite, um die Konfiguration erneut durchzuführen.\n\n**Fehlermeldung**: \n{message}",
|
||||
"device_list_changed_title": "Xiaomi Home-Geräteliste geändert",
|
||||
"device_list_changed": "Änderung der Geräteinformationen **{nick_name}({uid}, {cloud_server})** festgestellt, bitte betreten Sie die Integrations-Optionen-Seite, klicken Sie auf 'Optionen->Geräteliste aktualisieren', um den lokalen Gerätecache zu aktualisieren.\n\nAktueller Netzwerkstatus: {network_status}\n{message}\n",
|
||||
"device_list_add": "\n**{count} neue Geräte:** \n{message}",
|
||||
"device_list_del": "\n**{count} Geräte nicht verfügbar:** \n{message}",
|
||||
"device_list_offline": "\n**{count} Geräte offline:** \n{message}",
|
||||
"network_status_online": "Online",
|
||||
"network_status_offline": "Offline",
|
||||
"central_state_changed_title": "Verbindungsstatus des Zentral-Gateways",
|
||||
"central_state_changed": "**{nick_name}({uid}, {cloud_server})** Lokale Verbindungsstrecke des Zentral-Gateways: {conn_status}",
|
||||
"central_state_connected": "verbunden",
|
||||
"central_state_disconnected": "getrennt",
|
||||
"device_exec_error": "Fehler bei der Ausführung"
|
||||
}
|
||||
},
|
||||
"error": {
|
||||
"common": {
|
||||
"-10000": "Unbekannter Fehler",
|
||||
"-10001": "Dienst nicht verfügbar",
|
||||
"-10002": "Ungültiger Parameter",
|
||||
"-10003": "Unzureichende Ressourcen",
|
||||
"-10004": "Interner Fehler",
|
||||
"-10005": "Unzureichende Berechtigungen",
|
||||
"-10006": "Ausführungszeitüberschreitung",
|
||||
"-10007": "Gerät offline oder nicht vorhanden",
|
||||
"-10020": "Nicht autorisiert (OAuth2)",
|
||||
"-10030": "Ungültiges Token (HTTP)",
|
||||
"-10040": "Ungültiges Nachrichtenformat",
|
||||
"-10050": "Ungültiges Zertifikat",
|
||||
"-704000000": "Unbekannter Fehler",
|
||||
"-704010000": "Nicht autorisiert (Gerät wurde möglicherweise gelöscht)",
|
||||
"-704014006": "Gerätebeschreibung nicht gefunden",
|
||||
"-704030013": "Eigenschaft nicht lesbar",
|
||||
"-704030023": "Eigenschaft nicht beschreibbar",
|
||||
"-704030033": "Eigenschaft nicht abonnierbar",
|
||||
"-704040002": "Dienst existiert nicht",
|
||||
"-704040003": "Eigenschaft existiert nicht",
|
||||
"-704040004": "Ereignis existiert nicht",
|
||||
"-704040005": "Aktion existiert nicht",
|
||||
"-704040999": "Funktion nicht online",
|
||||
"-704042001": "Gerät existiert nicht",
|
||||
"-704042011": "Gerät offline",
|
||||
"-704053036": "Gerätebetrieb zeitüberschreitung",
|
||||
"-704053100": "Gerät kann diese Operation im aktuellen Zustand nicht ausführen",
|
||||
"-704083036": "Gerätebetrieb zeitüberschreitung",
|
||||
"-704090001": "Gerät existiert nicht",
|
||||
"-704220008": "Ungültige ID",
|
||||
"-704220025": "Aktionsparameteranzahl stimmt nicht überein",
|
||||
"-704220035": "Aktionsparameterfehler",
|
||||
"-704220043": "Eigenschaftswertfehler",
|
||||
"-704222034": "Aktionsrückgabewertfehler",
|
||||
"-705004000": "Unbekannter Fehler",
|
||||
"-705004501": "Unbekannter Fehler",
|
||||
"-705201013": "Eigenschaft nicht lesbar",
|
||||
"-705201015": "Aktionsausführungsfehler",
|
||||
"-705201023": "Eigenschaft nicht beschreibbar",
|
||||
"-705201033": "Eigenschaft nicht abonnierbar",
|
||||
"-706012000": "Unbekannter Fehler",
|
||||
"-706012013": "Eigenschaft nicht lesbar",
|
||||
"-706012015": "Aktionsausführungsfehler",
|
||||
"-706012023": "Eigenschaft nicht beschreibbar",
|
||||
"-706012033": "Eigenschaft nicht abonnierbar",
|
||||
"-706012043": "Eigenschaftswertfehler",
|
||||
"-706014006": "Gerätebeschreibung nicht gefunden"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
{
|
||||
"config": {
|
||||
"other": {
|
||||
"devices": "Devices",
|
||||
"found_central_gateway": ", Found Local Central Hub Gateway",
|
||||
"without_room": "No room assigned",
|
||||
"no_display": "Do not display"
|
||||
},
|
||||
"control_mode": {
|
||||
"auto": "Auto",
|
||||
"cloud": "Cloud"
|
||||
},
|
||||
"statistics_logic": {
|
||||
"or": "OR logic",
|
||||
"and": "AND logic"
|
||||
},
|
||||
"filter_mode": {
|
||||
"exclude": "Exclude",
|
||||
"include": "Include"
|
||||
},
|
||||
"connect_type": {
|
||||
"0": "WiFi",
|
||||
"1": "yunyi device",
|
||||
"2": "Cloud device",
|
||||
"3": "ZigBee",
|
||||
"4": "webSocket",
|
||||
"5": "Virtual device",
|
||||
"6": "BLE",
|
||||
"7": "Local AP",
|
||||
"8": "WiFi+BLE",
|
||||
"9": "Other",
|
||||
"10": "Function plug-in",
|
||||
"11": "Cellular network",
|
||||
"12": "Cable",
|
||||
"13": "NB-IoT",
|
||||
"14": "Third-party cloud access",
|
||||
"15": "Infrared remote control device",
|
||||
"16": "BLE-Mesh",
|
||||
"17": "Virtual device group",
|
||||
"18": "Gateway sub-device",
|
||||
"19": "Security level gateway sub-device",
|
||||
"22": "PLC",
|
||||
"23": "Cable only",
|
||||
"24": "Matter",
|
||||
"25": "WiFi+Cellular network"
|
||||
},
|
||||
"room_name_rule": {
|
||||
"none": "Do not synchronize",
|
||||
"home_room": "Home Name and Room Name (Xiaomi Home Bedroom)",
|
||||
"room": "Room Name (Bedroom)",
|
||||
"home": "Home Name (Xiaomi Home)"
|
||||
},
|
||||
"option_status": {
|
||||
"enable": "Enable",
|
||||
"disable": "Disable"
|
||||
},
|
||||
"binary_mode": {
|
||||
"text": "Text Sensor Entity",
|
||||
"bool": "Binary Sensor Entity"
|
||||
},
|
||||
"device_state": {
|
||||
"add": "Add",
|
||||
"del": "Unavailable",
|
||||
"offline": "Offline"
|
||||
},
|
||||
"lan_ctrl_config": {
|
||||
"notice_net_dup": "\r\n**[Notice]** Multiple network cards detected that may be connected to the same network. Please pay attention to the selection.",
|
||||
"net_unavailable": "Interface unavailable"
|
||||
}
|
||||
},
|
||||
"oauth2": {
|
||||
"success": {
|
||||
"title": "Authentication Successful",
|
||||
"content": "Please close this page and return to the account authentication page to click 'Next'.",
|
||||
"button": "Close"
|
||||
},
|
||||
"fail": {
|
||||
"title": "Authentication Failed",
|
||||
"content": "{error_msg}, please close this page and return to the account authentication page to click the authentication link again.",
|
||||
"button": "Close"
|
||||
},
|
||||
"error_msg": {
|
||||
"-10100": "Invalid response parameters ('code' or 'state' field is empty)",
|
||||
"-10101": "Passed-in 'state' field mismatch"
|
||||
}
|
||||
},
|
||||
"miot": {
|
||||
"client": {
|
||||
"invalid_oauth_info": "Authentication information is invalid, cloud link will be unavailable, please enter the Xiaomi Home integration page, click 'Options' to re-authenticate",
|
||||
"invalid_device_cache": "Cache device information is abnormal, please enter the Xiaomi Home integration page, click 'Options->Update device list', update the local cache",
|
||||
"invalid_cert_info": "Invalid user certificate, local central link will be unavailable, please enter the Xiaomi Home integration page, click 'Options' to re-authenticate",
|
||||
"device_cloud_error": "An exception occurred when obtaining device information from the cloud, please check the local network connection",
|
||||
"xiaomi_home_error_title": "Xiaomi Home Integration Error",
|
||||
"xiaomi_home_error": "Detected **{nick_name}({uid}, {cloud_server})** error, please enter the options page to reconfigure.\n\n**Error message**: \n{message}",
|
||||
"device_list_changed_title": "Xiaomi Home device list changes",
|
||||
"device_list_changed": "Detected **{nick_name}({uid}, {cloud_server})** device information has changed, please enter the integration options page, click `Options->Update device list`, update local device information.\n\nCurrent network status: {network_status}\n{message}\n",
|
||||
"device_list_add": "\n**{count} new devices:** \n{message}",
|
||||
"device_list_del": "\n**{count} devices unavailable:** \n{message}",
|
||||
"device_list_offline": "\n**{count} devices offline:** \n{message}",
|
||||
"network_status_online": "Online",
|
||||
"network_status_offline": "Offline",
|
||||
"central_state_changed_title": "Central Hub Gateway Connection Status",
|
||||
"central_state_changed":"**{nick_name}({uid}, {cloud_server})** local connection to Xiaomi central hub gateway: {conn_status}",
|
||||
"central_state_connected": "Connected",
|
||||
"central_state_disconnected": "Disconnected",
|
||||
"device_exec_error": "Execution error"
|
||||
}
|
||||
},
|
||||
"error": {
|
||||
"common": {
|
||||
"-10000": "Unknown error",
|
||||
"-10001": "Service unavailable",
|
||||
"-10002": "Invalid parameter",
|
||||
"-10003": "Insufficient resources",
|
||||
"-10004": "Internal error",
|
||||
"-10005": "Insufficient permissions",
|
||||
"-10006": "Execution timeout",
|
||||
"-10007": "Device offline or does not exist",
|
||||
"-10020": "Unauthorized (OAuth2)",
|
||||
"-10030": "Invalid token (HTTP)",
|
||||
"-10040": "Invalid message format",
|
||||
"-10050": "Invalid certificate",
|
||||
"-704000000": "Unknown error",
|
||||
"-704010000": "Unauthorized (device may have been deleted)",
|
||||
"-704014006": "Device description not found",
|
||||
"-704030013": "Property not readable",
|
||||
"-704030023": "Property not writable",
|
||||
"-704030033": "Property not subscribable",
|
||||
"-704040002": "Service does not exist",
|
||||
"-704040003": "Property does not exist",
|
||||
"-704040004": "Event does not exist",
|
||||
"-704040005": "Action does not exist",
|
||||
"-704040999": "Feature not online",
|
||||
"-704042001": "Device does not exist",
|
||||
"-704042011": "Device offline",
|
||||
"-704053036": "Device operation timeout",
|
||||
"-704053100": "Device cannot perform this operation in the current state",
|
||||
"-704083036": "Device operation timeout",
|
||||
"-704090001": "Device does not exist",
|
||||
"-704220008": "Invalid ID",
|
||||
"-704220025": "Action parameter count mismatch",
|
||||
"-704220035": "Action parameter error",
|
||||
"-704220043": "Property value error",
|
||||
"-704222034": "Action return value error",
|
||||
"-705004000": "Unknown error",
|
||||
"-705004501": "Unknown error",
|
||||
"-705201013": "Property not readable",
|
||||
"-705201015": "Action execution error",
|
||||
"-705201023": "Property not writable",
|
||||
"-705201033": "Property not subscribable",
|
||||
"-706012000": "Unknown error",
|
||||
"-706012013": "Property not readable",
|
||||
"-706012015": "Action execution error",
|
||||
"-706012023": "Property not writable",
|
||||
"-706012033": "Property not subscribable",
|
||||
"-706012043": "Property value error",
|
||||
"-706014006": "Device description not found"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
{
|
||||
"config": {
|
||||
"other": {
|
||||
"devices": "dispositivos",
|
||||
"found_central_gateway": ", se encontró la puerta de enlace central local",
|
||||
"without_room": "Sin habitación asignada",
|
||||
"no_display": "no mostrar"
|
||||
},
|
||||
"control_mode": {
|
||||
"auto": "automático",
|
||||
"cloud": "nube"
|
||||
},
|
||||
"statistics_logic": {
|
||||
"or": "lógica OR",
|
||||
"and": "lógica AND"
|
||||
},
|
||||
"filter_mode": {
|
||||
"exclude": "excluir",
|
||||
"include": "incluir"
|
||||
},
|
||||
"connect_type": {
|
||||
"0": "WiFi",
|
||||
"1": "dispositivo yunyi",
|
||||
"2": "dispositivo de nube",
|
||||
"3": "ZigBee",
|
||||
"4": "webSocket",
|
||||
"5": "dispositivo virtual",
|
||||
"6": "BLE",
|
||||
"7": "AP local",
|
||||
"8": "WiFi+BLE",
|
||||
"9": "otro",
|
||||
"10": "complemento de función",
|
||||
"11": "red celular",
|
||||
"12": "cable",
|
||||
"13": "NB-IoT",
|
||||
"14": "acceso a la nube de terceros",
|
||||
"15": "dispositivo de control remoto infrarrojo",
|
||||
"16": "BLE-Mesh",
|
||||
"17": "grupo de dispositivos virtuales",
|
||||
"18": "subdispositivo de puerta de enlace",
|
||||
"19": "subdispositivo de puerta de enlace de nivel de seguridad",
|
||||
"22": "PLC",
|
||||
"23": "solo cable",
|
||||
"24": "Matter",
|
||||
"25": "WiFi+red celular"
|
||||
},
|
||||
"room_name_rule": {
|
||||
"none": "no sincronizar",
|
||||
"home_room": "nombre de la casa y nombre de la habitación (Xiaomi Home Dormitorio)",
|
||||
"room": "nombre de la habitación (Dormitorio)",
|
||||
"home": "nombre de la casa (Xiaomi Home)"
|
||||
},
|
||||
"option_status": {
|
||||
"enable": "habilitar",
|
||||
"disable": "deshabilitar"
|
||||
},
|
||||
"binary_mode": {
|
||||
"text": "Entidad del sensor de texto",
|
||||
"bool": "Entidad del sensor binario"
|
||||
},
|
||||
"device_state": {
|
||||
"add": "agregar",
|
||||
"del": "no disponible",
|
||||
"offline": "fuera de línea"
|
||||
},
|
||||
"lan_ctrl_config": {
|
||||
"notice_net_dup": "\r\n**[Aviso]** Se detectaron varias tarjetas de red que pueden estar conectadas a la misma red. Por favor, preste atención a la selección.",
|
||||
"net_unavailable": "Interfaz no disponible"
|
||||
}
|
||||
},
|
||||
"oauth2": {
|
||||
"success": {
|
||||
"title": "Autenticación exitosa",
|
||||
"content": "Por favor, cierre esta página y regrese a la página de autenticación de la cuenta para hacer clic en 'Siguiente'.",
|
||||
"button": "Cerrar"
|
||||
},
|
||||
"fail": {
|
||||
"title": "Autenticación fallida",
|
||||
"content": "{error_msg}, por favor, cierre esta página y regrese a la página de autenticación de la cuenta para hacer clic en el enlace de autenticación nuevamente.",
|
||||
"button": "Cerrar"
|
||||
},
|
||||
"error_msg": {
|
||||
"-10100": "Parámetros de respuesta inválidos ('code' o 'state' está vacío)",
|
||||
"-10101": "El campo 'state' proporcionado no coincide"
|
||||
}
|
||||
},
|
||||
"miot": {
|
||||
"client": {
|
||||
"invalid_oauth_info": "La información de autenticación es inválida, la conexión en la nube no estará disponible, por favor, vaya a la página de integración de Xiaomi Home, haga clic en 'Opciones' para volver a autenticar",
|
||||
"invalid_device_cache": "La información de caché del dispositivo es anormal, por favor, vaya a la página de integración de Xiaomi Home, haga clic en 'Opciones -> Actualizar lista de dispositivos' para actualizar la información del dispositivo local",
|
||||
"invalid_cert_info": "Certificado de usuario inválido, la conexión del centro local no estará disponible, por favor, vaya a la página de integración de Xiaomi Home, haga clic en 'Opciones' para volver a autenticar",
|
||||
"device_cloud_error": "Error al obtener la información del dispositivo desde la nube, por favor, compruebe la conexión de red local",
|
||||
"xiaomi_home_error_title": "Error de integración de Xiaomi Home",
|
||||
"xiaomi_home_error": "Se detectó un error en **{nick_name}({uid}, {cloud_server})**, por favor, vaya a la página de opciones para reconfigurar.\n\n**Mensaje de error**: \n{message}",
|
||||
"device_list_changed_title": "Cambio en la lista de dispositivos de Xiaomi Home",
|
||||
"device_list_changed": "Se detectó un cambio en la información del dispositivo **{nick_name}({uid}, {cloud_server})**, por favor, vaya a la página de integración, haga clic en 'Opciones -> Actualizar lista de dispositivos' para actualizar la información del dispositivo local.\n\nEstado actual de la red: {network_status}\n{message}\n",
|
||||
"device_list_add": "\n**{count} nuevos dispositivos:** \n{message}",
|
||||
"device_list_del": "\n**{count} dispositivos no disponibles:** \n{message}",
|
||||
"device_list_offline": "\n**{count} dispositivos sin conexión:** \n{message}",
|
||||
"network_status_online": "En línea",
|
||||
"network_status_offline": "Desconectado",
|
||||
"central_state_changed_title": "Estado de conexión de la puerta de enlace central",
|
||||
"central_state_changed": "**{nick_name}({uid}, {cloud_server})** enlace de conexión local de la puerta de enlace central: {conn_status}",
|
||||
"central_state_connected": "conectado",
|
||||
"central_state_disconnected": "desconectado",
|
||||
"device_exec_error": "Error de ejecución"
|
||||
}
|
||||
},
|
||||
"error": {
|
||||
"common": {
|
||||
"-10000": "Error desconocido",
|
||||
"-10001": "Servicio no disponible",
|
||||
"-10002": "Parámetro inválido",
|
||||
"-10003": "Recursos insuficientes",
|
||||
"-10004": "Error interno",
|
||||
"-10005": "Permisos insuficientes",
|
||||
"-10006": "Tiempo de ejecución agotado",
|
||||
"-10007": "Dispositivo fuera de línea o no existe",
|
||||
"-10020": "No autorizado (OAuth2)",
|
||||
"-10030": "Token inválido (HTTP)",
|
||||
"-10040": "Formato de mensaje inválido",
|
||||
"-10050": "Certificado inválido",
|
||||
"-704000000": "Error desconocido",
|
||||
"-704010000": "No autorizado (el dispositivo puede haber sido eliminado)",
|
||||
"-704014006": "Descripción del dispositivo no encontrada",
|
||||
"-704030013": "Propiedad no legible",
|
||||
"-704030023": "Propiedad no escribible",
|
||||
"-704030033": "Propiedad no suscribible",
|
||||
"-704040002": "Servicio no existe",
|
||||
"-704040003": "Propiedad no existe",
|
||||
"-704040004": "Evento no existe",
|
||||
"-704040005": "Acción no existe",
|
||||
"-704040999": "Función no en línea",
|
||||
"-704042001": "Dispositivo no existe",
|
||||
"-704042011": "Dispositivo fuera de línea",
|
||||
"-704053036": "Tiempo de operación del dispositivo agotado",
|
||||
"-704053100": "El dispositivo no puede realizar esta operación en el estado actual",
|
||||
"-704083036": "Tiempo de operación del dispositivo agotado",
|
||||
"-704090001": "Dispositivo no existe",
|
||||
"-704220008": "ID inválido",
|
||||
"-704220025": "Número de parámetros de acción no coincide",
|
||||
"-704220035": "Error de parámetro de acción",
|
||||
"-704220043": "Error de valor de propiedad",
|
||||
"-704222034": "Error de valor de retorno de acción",
|
||||
"-705004000": "Error desconocido",
|
||||
"-705004501": "Error desconocido",
|
||||
"-705201013": "Propiedad no legible",
|
||||
"-705201015": "Error de ejecución de acción",
|
||||
"-705201023": "Propiedad no escribible",
|
||||
"-705201033": "Propiedad no suscribible",
|
||||
"-706012000": "Error desconocido",
|
||||
"-706012013": "Propiedad no legible",
|
||||
"-706012015": "Error de ejecución de acción",
|
||||
"-706012023": "Propiedad no escribible",
|
||||
"-706012033": "Propiedad no suscribible",
|
||||
"-706012043": "Error de valor de propiedad",
|
||||
"-706014006": "Descripción del dispositivo no encontrada"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
{
|
||||
"config": {
|
||||
"other": {
|
||||
"devices": "appareils",
|
||||
"found_central_gateway": ", passerelle centrale locale trouvée",
|
||||
"without_room": "Aucune pièce attribuée",
|
||||
"no_display": "ne pas afficher"
|
||||
},
|
||||
"control_mode": {
|
||||
"auto": "automatique",
|
||||
"cloud": "cloud"
|
||||
},
|
||||
"statistics_logic": {
|
||||
"or": "ou logique",
|
||||
"and": "et logique"
|
||||
},
|
||||
"filter_mode": {
|
||||
"exclude": "exclure",
|
||||
"include": "inclure"
|
||||
},
|
||||
"connect_type": {
|
||||
"0": "WiFi",
|
||||
"1": "appareil yunyi",
|
||||
"2": "appareil cloud",
|
||||
"3": "ZigBee",
|
||||
"4": "webSocket",
|
||||
"5": "appareil virtuel",
|
||||
"6": "BLE",
|
||||
"7": "AP local",
|
||||
"8": "WiFi+BLE",
|
||||
"9": "autre",
|
||||
"10": "plug-in de fonction",
|
||||
"11": "réseau cellulaire",
|
||||
"12": "câble",
|
||||
"13": "NB-IoT",
|
||||
"14": "accès cloud tiers",
|
||||
"15": "appareil de télécommande infrarouge",
|
||||
"16": "BLE-Mesh",
|
||||
"17": "groupe d'appareils virtuels",
|
||||
"18": "sous-appareil de passerelle",
|
||||
"19": "niveau de sécurité sous-appareil de passerelle",
|
||||
"22": "PLC",
|
||||
"23": "câble uniquement",
|
||||
"24": "Matter",
|
||||
"25": "WiFi+réseau cellulaire"
|
||||
},
|
||||
"room_name_rule": {
|
||||
"none": "ne pas synchroniser",
|
||||
"home_room": "nom de la maison et nom de la pièce (Xiaomi Home Chambre)",
|
||||
"room": "nom de la pièce (Chambre)",
|
||||
"home": "nom de la maison (Xiaomi Home)"
|
||||
},
|
||||
"option_status": {
|
||||
"enable": "activer",
|
||||
"disable": "désactiver"
|
||||
},
|
||||
"binary_mode": {
|
||||
"text": "Entité du capteur de texte",
|
||||
"bool": "Entité du capteur binaire"
|
||||
},
|
||||
"device_state": {
|
||||
"add": "Ajouter",
|
||||
"del": "Supprimer",
|
||||
"offline": "hors ligne"
|
||||
},
|
||||
"lan_ctrl_config": {
|
||||
"notice_net_dup": "\r\n**[Remarque]** Plusieurs cartes réseau détectées qui peuvent être connectées au même réseau. Veuillez faire attention à la sélection.",
|
||||
"net_unavailable": "Interface non disponible"
|
||||
}
|
||||
},
|
||||
"oauth2": {
|
||||
"success": {
|
||||
"title": "Authentification réussie",
|
||||
"content": "Veuillez fermer cette page et revenir à la page d'authentification du compte pour cliquer sur 'Suivant'.",
|
||||
"button": "Fermer"
|
||||
},
|
||||
"fail": {
|
||||
"title": "Échec de l'authentification",
|
||||
"content": "{error_msg}, veuillez fermer cette page et revenir à la page d'authentification du compte pour cliquer à nouveau sur le lien d'authentification.",
|
||||
"button": "Fermer"
|
||||
},
|
||||
"error_msg": {
|
||||
"-10100": "Paramètres de réponse invalides ('code' ou 'state' est vide)",
|
||||
"-10101": "Le champ 'state' transmis ne correspond pas"
|
||||
}
|
||||
},
|
||||
"miot": {
|
||||
"client": {
|
||||
"invalid_oauth_info": "Informations d'authentification non valides, le lien cloud ne sera pas disponible, veuillez accéder à la page d'intégration Xiaomi Home, cliquez sur \"Options\" pour vous réauthentifier",
|
||||
"invalid_device_cache": "Informations de cache de périphérique non valides, veuillez accéder à la page d'intégration Xiaomi Home, cliquez sur `Options-> Mettre à jour la liste des appareils`, pour mettre à jour les informations locales des appareils",
|
||||
"invalid_cert_info": "Certificat utilisateur non valide, le lien central local ne sera pas disponible, veuillez accéder à la page d'intégration Xiaomi Home, cliquez sur \"Options\" pour vous réauthentifier",
|
||||
"device_cloud_error": "Erreur lors de la récupération des informations de l'appareil à partir du cloud, veuillez vérifier la connexion réseau locale",
|
||||
"xiaomi_home_error_title": "Erreur d'intégration Xiaomi Home",
|
||||
"xiaomi_home_error": "Erreur détectée sur **{nick_name}({uid}, {cloud_server})**, veuillez accéder à la page d'options pour reconfigurer.\n\n**Message d'erreur**: \n{message}",
|
||||
"device_list_changed_title": "Changements dans la liste des appareils Xiaomi Home",
|
||||
"device_list_changed": "Changements détectés sur **{nick_name}({uid}, {cloud_server})**, veuillez accéder à la page d'intégration, cliquez sur `Options-> Mettre à jour la liste des appareils`, pour mettre à jour les informations locales des appareils.\n\nÉtat actuel du réseau : {network_status}\n{message}\n",
|
||||
"device_list_add": "\n**{count} nouveaux appareils :** \n{message}",
|
||||
"device_list_del": "\n**{count} appareils non disponibles :** \n{message}",
|
||||
"device_list_offline": "\n**{count} appareils hors ligne :** \n{message}",
|
||||
"network_status_online": "En ligne",
|
||||
"network_status_offline": "Hors ligne",
|
||||
"central_state_changed_title": "État de connexion de la passerelle centrale",
|
||||
"central_state_changed": "**{nick_name}({uid}, {cloud_server})** liaison de connexion locale de la passerelle centrale : {conn_status}",
|
||||
"central_state_connected": "connecté",
|
||||
"central_state_disconnected": "déconnecté",
|
||||
"device_exec_error": "Erreur d'exécution"
|
||||
}
|
||||
},
|
||||
"error": {
|
||||
"common": {
|
||||
"-10000": "Erreur inconnue",
|
||||
"-10001": "Service indisponible",
|
||||
"-10002": "Paramètre invalide",
|
||||
"-10003": "Ressources insuffisantes",
|
||||
"-10004": "Erreur interne",
|
||||
"-10005": "Permissions insuffisantes",
|
||||
"-10006": "Délai d'exécution dépassé",
|
||||
"-10007": "Appareil hors ligne ou n'existe pas",
|
||||
"-10020": "Non autorisé (OAuth2)",
|
||||
"-10030": "Jeton invalide (HTTP)",
|
||||
"-10040": "Format de message invalide",
|
||||
"-10050": "Certificat invalide",
|
||||
"-704000000": "Erreur inconnue",
|
||||
"-704010000": "Non autorisé (l'appareil peut avoir été supprimé)",
|
||||
"-704014006": "Description de l'appareil introuvable",
|
||||
"-704030013": "Propriété non lisible",
|
||||
"-704030023": "Propriété non inscriptible",
|
||||
"-704030033": "Propriété non abonnable",
|
||||
"-704040002": "Service n'existe pas",
|
||||
"-704040003": "Propriété n'existe pas",
|
||||
"-704040004": "Événement n'existe pas",
|
||||
"-704040005": "Action n'existe pas",
|
||||
"-704040999": "Fonction non en ligne",
|
||||
"-704042001": "Appareil n'existe pas",
|
||||
"-704042011": "Appareil hors ligne",
|
||||
"-704053036": "Délai d'opération de l'appareil dépassé",
|
||||
"-704053100": "L'appareil ne peut pas effectuer cette opération dans l'état actuel",
|
||||
"-704083036": "Délai d'opération de l'appareil dépassé",
|
||||
"-704090001": "Appareil n'existe pas",
|
||||
"-704220008": "ID invalide",
|
||||
"-704220025": "Nombre de paramètres d'action ne correspond pas",
|
||||
"-704220035": "Erreur de paramètre d'action",
|
||||
"-704220043": "Erreur de valeur de propriété",
|
||||
"-704222034": "Erreur de valeur de retour d'action",
|
||||
"-705004000": "Erreur inconnue",
|
||||
"-705004501": "Erreur inconnue",
|
||||
"-705201013": "Propriété non lisible",
|
||||
"-705201015": "Erreur d'exécution d'action",
|
||||
"-705201023": "Propriété non inscriptible",
|
||||
"-705201033": "Propriété non abonnable",
|
||||
"-706012000": "Erreur inconnue",
|
||||
"-706012013": "Propriété non lisible",
|
||||
"-706012015": "Erreur d'exécution d'action",
|
||||
"-706012023": "Propriété non inscriptible",
|
||||
"-706012033": "Propriété non abonnable",
|
||||
"-706012043": "Erreur de valeur de propriété",
|
||||
"-706014006": "Description de l'appareil introuvable"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
{
|
||||
"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",
|
||||
"central_state_changed_title": "Stato di connessione del gateway centrale",
|
||||
"central_state_changed": "**{nick_name}({uid}, {cloud_server})** collegamento locale del gateway centrale: {conn_status}",
|
||||
"central_state_connected": "connesso",
|
||||
"central_state_disconnected": "disconnesso",
|
||||
"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"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
{
|
||||
"config": {
|
||||
"other": {
|
||||
"devices": "デバイス",
|
||||
"found_central_gateway": "、ローカル中央ゲートウェイが見つかりました",
|
||||
"without_room": "部屋が割り当てられていません",
|
||||
"no_display": "表示しない"
|
||||
},
|
||||
"control_mode": {
|
||||
"auto": "自動",
|
||||
"cloud": "クラウド"
|
||||
},
|
||||
"statistics_logic": {
|
||||
"or": "ORロジック",
|
||||
"and": "ANDロジック"
|
||||
},
|
||||
"filter_mode": {
|
||||
"exclude": "除外",
|
||||
"include": "含む"
|
||||
},
|
||||
"connect_type": {
|
||||
"0": "WiFi",
|
||||
"1": "yunyiデバイス",
|
||||
"2": "クラウドデバイス",
|
||||
"3": "ZigBee",
|
||||
"4": "webSocket",
|
||||
"5": "仮想デバイス",
|
||||
"6": "BLE",
|
||||
"7": "ローカルAP",
|
||||
"8": "WiFi+BLE",
|
||||
"9": "その他",
|
||||
"10": "機能プラグイン",
|
||||
"11": "セルラーネットワーク",
|
||||
"12": "ケーブル",
|
||||
"13": "NB-IoT",
|
||||
"14": "サードパーティクラウドアクセス",
|
||||
"15": "赤外線リモコンデバイス",
|
||||
"16": "BLE-Mesh",
|
||||
"17": "仮想デバイスグループ",
|
||||
"18": "ゲートウェイサブデバイス",
|
||||
"19": "セキュリティレベルゲートウェイサブデバイス",
|
||||
"22": "PLC",
|
||||
"23": "ケーブルのみ",
|
||||
"24": "Matter",
|
||||
"25": "WiFi+セルラーネットワーク"
|
||||
},
|
||||
"room_name_rule": {
|
||||
"none": "同期しない",
|
||||
"home_room": "家の名前と部屋の名前 (Xiaomi Home 寝室)",
|
||||
"room": "部屋の名前(寝室)",
|
||||
"home": "家の名前 (Xiaomi Home)"
|
||||
},
|
||||
"option_status": {
|
||||
"enable": "有効",
|
||||
"disable": "無効"
|
||||
},
|
||||
"binary_mode": {
|
||||
"text": "テキストセンサーエンティティ",
|
||||
"bool": "バイナリセンサーエンティティ"
|
||||
},
|
||||
"device_state": {
|
||||
"add": "追加",
|
||||
"del": "利用不可",
|
||||
"offline": "オフライン"
|
||||
},
|
||||
"lan_ctrl_config": {
|
||||
"notice_net_dup": "\r\n**[注意]** 複数のネットワークカードが同じネットワークに接続されている可能性があります。選択に注意してください。",
|
||||
"net_unavailable": "インターフェースが利用できません"
|
||||
}
|
||||
},
|
||||
"oauth2": {
|
||||
"success": {
|
||||
"title": "認証成功",
|
||||
"content": "このページを閉じて、アカウント認証ページに戻り、「次へ」をクリックしてください。",
|
||||
"button": "閉じる"
|
||||
},
|
||||
"fail": {
|
||||
"title": "認証失敗",
|
||||
"content": "{error_msg}、このページを閉じて、アカウント認証ページに戻り、再度認証リンクをクリックしてください。",
|
||||
"button": "閉じる"
|
||||
},
|
||||
"error_msg": {
|
||||
"-10100": "無効な応答パラメータ('code'または'state'フィールドが空です)",
|
||||
"-10101": "渡された'state'フィールドが一致しません"
|
||||
}
|
||||
},
|
||||
"miot": {
|
||||
"client": {
|
||||
"invalid_oauth_info": "認証情報が無効です。クラウドリンクは利用できません。Xiaomi Home統合ページに入り、[オプション]をクリックして再認証してください",
|
||||
"invalid_device_cache": "キャッシュデバイス情報が異常です。Xiaomi Home統合ページに入り、[オプション->デバイスリストの更新]をクリックして、ローカルキャッシュを更新してください",
|
||||
"invalid_cert_info": "無効なユーザー証明書です。ローカルセントラルリンクは利用できません。Xiaomi Home統合ページに入り、[オプション]をクリックして再認証してください",
|
||||
"device_cloud_error": "クラウドからデバイス情報を取得する際に例外が発生しました。ローカルネットワーク接続を確認してください",
|
||||
"xiaomi_home_error_title": "Xiaomi Home統合エラー",
|
||||
"xiaomi_home_error": "エラーが検出されました **{nick_name}({uid}, {cloud_server})** 、オプションページに入り再構成してください。\n\n**エラーメッセージ**: \n{message}",
|
||||
"device_list_changed_title": "Xiaomi Homeデバイスリストの変更",
|
||||
"device_list_changed": "変更が検出されました **{nick_name}({uid}, {cloud_server})** デバイス情報が変更されました。統合オプションページに入り、`オプション->デバイスリストの更新`をクリックして、ローカルデバイス情報を更新してください。\n\n現在のネットワーク状態:{network_status}\n{message}\n",
|
||||
"device_list_add": "\n**{count} 新しいデバイス:** \n{message}",
|
||||
"device_list_del": "\n**{count} デバイスが利用できません:** \n{message}",
|
||||
"device_list_offline": "\n**{count} デバイスがオフライン:** \n{message}",
|
||||
"network_status_online": "オンライン",
|
||||
"network_status_offline": "オフライン",
|
||||
"central_state_changed_title": "中枢ゲートウェイ接続ステータス",
|
||||
"central_state_changed": "**{nick_name}({uid}, {cloud_server})** 中枢ゲートウェイのローカル接続リンク: {conn_status}",
|
||||
"central_state_connected": "接続済み",
|
||||
"central_state_disconnected": "切断されました",
|
||||
"device_exec_error": "実行エラー"
|
||||
}
|
||||
},
|
||||
"error": {
|
||||
"common": {
|
||||
"-10000": "不明なエラー",
|
||||
"-10001": "サービス利用不可",
|
||||
"-10002": "無効なパラメータ",
|
||||
"-10003": "リソース不足",
|
||||
"-10004": "内部エラー",
|
||||
"-10005": "権限不足",
|
||||
"-10006": "実行タイムアウト",
|
||||
"-10007": "デバイスがオフラインまたは存在しない",
|
||||
"-10020": "未認証(OAuth2)",
|
||||
"-10030": "無効なトークン(HTTP)",
|
||||
"-10040": "無効なメッセージ形式",
|
||||
"-10050": "無効な証明書",
|
||||
"-704000000": "不明なエラー",
|
||||
"-704010000": "未認証(デバイスが削除された可能性があります)",
|
||||
"-704014006": "デバイスの説明が見つかりません",
|
||||
"-704030013": "プロパティが読み取れません",
|
||||
"-704030023": "プロパティが書き込めません",
|
||||
"-704030033": "プロパティが購読できません",
|
||||
"-704040002": "サービスが存在しません",
|
||||
"-704040003": "プロパティが存在しません",
|
||||
"-704040004": "イベントが存在しません",
|
||||
"-704040005": "アクションが存在しません",
|
||||
"-704040999": "機能がオンラインではありません",
|
||||
"-704042001": "デバイスが存在しません",
|
||||
"-704042011": "デバイスがオフラインです",
|
||||
"-704053036": "デバイス操作タイムアウト",
|
||||
"-704053100": "デバイスが現在の状態でこの操作を実行できません",
|
||||
"-704083036": "デバイス操作タイムアウト",
|
||||
"-704090001": "デバイスが存在しません",
|
||||
"-704220008": "無効なID",
|
||||
"-704220025": "アクションパラメータの数が一致しません",
|
||||
"-704220035": "アクションパラメータエラー",
|
||||
"-704220043": "プロパティ値エラー",
|
||||
"-704222034": "アクションの戻り値エラー",
|
||||
"-705004000": "不明なエラー",
|
||||
"-705004501": "不明なエラー",
|
||||
"-705201013": "プロパティが読み取れません",
|
||||
"-705201015": "アクション実行エラー",
|
||||
"-705201023": "プロパティが書き込めません",
|
||||
"-705201033": "プロパティが購読できません",
|
||||
"-706012000": "不明なエラー",
|
||||
"-706012013": "プロパティが読み取れません",
|
||||
"-706012015": "アクション実行エラー",
|
||||
"-706012023": "プロパティが書き込めません",
|
||||
"-706012033": "プロパティが購読できません",
|
||||
"-706012043": "プロパティ値エラー",
|
||||
"-706014006": "デバイスの説明が見つかりません"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
{
|
||||
"config": {
|
||||
"other": {
|
||||
"devices": "Apparaten",
|
||||
"found_central_gateway": ", Lokale centrale hub-gateway gevonden",
|
||||
"without_room": "Niet toegewezen kamer",
|
||||
"no_display": "Niet weergeven"
|
||||
},
|
||||
"control_mode": {
|
||||
"auto": "Automatisch",
|
||||
"cloud": "Cloud"
|
||||
},
|
||||
"statistics_logic": {
|
||||
"or": "OF-logica",
|
||||
"and": "EN-logica"
|
||||
},
|
||||
"filter_mode": {
|
||||
"exclude": "Uitsluiten",
|
||||
"include": "Inclusief"
|
||||
},
|
||||
"connect_type": {
|
||||
"0": "WiFi",
|
||||
"1": "yunyi-apparaat",
|
||||
"2": "Cloudapparaat",
|
||||
"3": "ZigBee",
|
||||
"4": "webSocket",
|
||||
"5": "Virtueel apparaat",
|
||||
"6": "BLE",
|
||||
"7": "Lokaal AP",
|
||||
"8": "WiFi+BLE",
|
||||
"9": "Andere",
|
||||
"10": "Functieplug-in",
|
||||
"11": "Cellulair netwerk",
|
||||
"12": "Kabel",
|
||||
"13": "NB-IoT",
|
||||
"14": "Toegang van derden tot de cloud",
|
||||
"15": "Infrarood afstandsbedieningsapparaat",
|
||||
"16": "BLE-Mesh",
|
||||
"17": "Virtuele apparaatgroep",
|
||||
"18": "Gateway sub-apparaat",
|
||||
"19": "Beveiligingsniveau gateway sub-apparaat",
|
||||
"22": "PLC",
|
||||
"23": "Alleen kabel",
|
||||
"24": "Matter",
|
||||
"25": "WiFi+Cellulair netwerk"
|
||||
},
|
||||
"room_name_rule": {
|
||||
"none": "Niet synchroniseren",
|
||||
"home_room": "Huisnaam en Kamernaam (Xiaomi Home Slaapkamer)",
|
||||
"room": "Kamernaam (Slaapkamer)",
|
||||
"home": "Huisnaam (Xiaomi Home)"
|
||||
},
|
||||
"option_status": {
|
||||
"enable": "Inschakelen",
|
||||
"disable": "Uitschakelen"
|
||||
},
|
||||
"binary_mode": {
|
||||
"text": "Tekstsensor-entiteit",
|
||||
"bool": "Binairesensor-entiteit"
|
||||
},
|
||||
"device_state": {
|
||||
"add": "Toevoegen",
|
||||
"del": "Niet beschikbaar",
|
||||
"offline": "Offline"
|
||||
},
|
||||
"lan_ctrl_config": {
|
||||
"notice_net_dup": "\r\n**[Let op]** Meerdere netwerkkaarten gedetecteerd die mogelijk zijn verbonden met hetzelfde netwerk. Let op bij de selectie.",
|
||||
"net_unavailable": "Interface niet beschikbaar"
|
||||
}
|
||||
},
|
||||
"oauth2": {
|
||||
"success": {
|
||||
"title": "Authenticatie geslaagd",
|
||||
"content": "Sluit deze pagina en ga terug naar de accountauthenticatiepagina om op 'Volgende' te klikken.",
|
||||
"button": "Sluiten"
|
||||
},
|
||||
"fail": {
|
||||
"title": "Authenticatie mislukt",
|
||||
"content": "{error_msg}, sluit deze pagina en ga terug naar de accountauthenticatiepagina om opnieuw op de authenticatielink te klikken.",
|
||||
"button": "Sluiten"
|
||||
},
|
||||
"error_msg": {
|
||||
"-10100": "Ongeldige antwoordparameters ('code' of 'state' veld is leeg)",
|
||||
"-10101": "Doorgegeven 'state' veld komt niet overeen"
|
||||
}
|
||||
},
|
||||
"miot": {
|
||||
"client": {
|
||||
"invalid_oauth_info": "Authenticatie-informatie is ongeldig, cloudverbinding zal niet beschikbaar zijn. Ga naar de Xiaomi Home-integratiepagina en klik op 'Opties' om opnieuw te verifiëren.",
|
||||
"invalid_device_cache": "Cache van apparaatgegevens is abnormaal. Ga naar de Xiaomi Home-integratiepagina, klik op 'Opties->Apparaatlijst bijwerken' en werk de lokale cache bij.",
|
||||
"invalid_cert_info": "Ongeldig gebruikerscertificaat, lokale centrale verbinding zal niet beschikbaar zijn. Ga naar de Xiaomi Home-integratiepagina en klik op 'Opties' om opnieuw te verifiëren.",
|
||||
"device_cloud_error": "Er is een uitzondering opgetreden bij het ophalen van apparaatgegevens uit de cloud. Controleer de lokale netwerkverbinding.",
|
||||
"xiaomi_home_error_title": "Xiaomi Home-integratiefout",
|
||||
"xiaomi_home_error": "Gedetecteerd **{nick_name}({uid}, {cloud_server})** fout, ga naar de optiespagina om opnieuw te configureren.\n\n**Foutmelding**: \n{message}",
|
||||
"device_list_changed_title": "Wijzigingen in Xiaomi Home-apparaatlijst",
|
||||
"device_list_changed": "Gedetecteerd **{nick_name}({uid}, {cloud_server})** apparaatgegevens zijn gewijzigd. Ga naar de integratie-optiespagina, klik op `Opties->Apparaatlijst bijwerken` en werk lokale apparaatgegevens bij.\n\nHuidige netwerkstatus: {network_status}\n{message}\n",
|
||||
"device_list_add": "\n**{count} nieuwe apparaten:** \n{message}",
|
||||
"device_list_del": "\n**{count} apparaten niet beschikbaar:** \n{message}",
|
||||
"device_list_offline": "\n**{count} apparaten offline:** \n{message}",
|
||||
"network_status_online": "Online",
|
||||
"network_status_offline": "Offline",
|
||||
"central_state_changed_title": "Verbindingsstatus van centrale gateway",
|
||||
"central_state_changed": "**{nick_name}({uid}, {cloud_server})** Lokale verbinding van centrale gateway: {conn_status}",
|
||||
"central_state_connected": "verbonden",
|
||||
"central_state_disconnected": "verbinding verbroken",
|
||||
"device_exec_error": "Uitvoeringsfout"
|
||||
}
|
||||
},
|
||||
"error": {
|
||||
"common": {
|
||||
"-10000": "Onbekende fout",
|
||||
"-10001": "Service niet beschikbaar",
|
||||
"-10002": "Ongeldige parameter",
|
||||
"-10003": "Onvoldoende middelen",
|
||||
"-10004": "Interne fout",
|
||||
"-10005": "Onvoldoende machtigingen",
|
||||
"-10006": "Uitvoeringstijd verstreken",
|
||||
"-10007": "Apparaat offline of bestaat niet",
|
||||
"-10020": "Niet geautoriseerd (OAuth2)",
|
||||
"-10030": "Ongeldig token (HTTP)",
|
||||
"-10040": "Ongeldig berichtformaat",
|
||||
"-10050": "Ongeldig certificaat",
|
||||
"-704000000": "Onbekende fout",
|
||||
"-704010000": "Niet geautoriseerd (apparaat kan zijn verwijderd)",
|
||||
"-704014006": "Apparaatbeschrijving niet gevonden",
|
||||
"-704030013": "Eigenschap niet leesbaar",
|
||||
"-704030023": "Eigenschap niet schrijfbaar",
|
||||
"-704030033": "Eigenschap niet abonneerbaar",
|
||||
"-704040002": "Service bestaat niet",
|
||||
"-704040003": "Eigenschap bestaat niet",
|
||||
"-704040004": "Gebeurtenis bestaat niet",
|
||||
"-704040005": "Actie bestaat niet",
|
||||
"-704040999": "Functie niet online",
|
||||
"-704042001": "Apparaat bestaat niet",
|
||||
"-704042011": "Apparaat offline",
|
||||
"-704053036": "Apparaatbedieningstijd verstreken",
|
||||
"-704053100": "Apparaat kan deze handeling niet uitvoeren in de huidige staat",
|
||||
"-704083036": "Apparaatbedieningstijd verstreken",
|
||||
"-704090001": "Apparaat bestaat niet",
|
||||
"-704220008": "Ongeldige ID",
|
||||
"-704220025": "Aantal actieparameters komt niet overeen",
|
||||
"-704220035": "Fout in actieparameter",
|
||||
"-704220043": "Fout in eigenschapswaarde",
|
||||
"-704222034": "Fout in retourwaarde actie",
|
||||
"-705004000": "Onbekende fout",
|
||||
"-705004501": "Onbekende fout",
|
||||
"-705201013": "Eigenschap niet leesbaar",
|
||||
"-705201015": "Fout bij uitvoeren van actie",
|
||||
"-705201023": "Eigenschap niet schrijfbaar",
|
||||
"-705201033": "Eigenschap niet abonneerbaar",
|
||||
"-706012000": "Onbekende fout",
|
||||
"-706012013": "Eigenschap niet leesbaar",
|
||||
"-706012015": "Fout bij uitvoeren van actie",
|
||||
"-706012023": "Eigenschap niet schrijfbaar",
|
||||
"-706012033": "Eigenschap niet abonneerbaar",
|
||||
"-706012043": "Fout in eigenschapswaarde",
|
||||
"-706014006": "Apparaatbeschrijving niet gevonden"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
{
|
||||
"config": {
|
||||
"other": {
|
||||
"devices": "dispositivos",
|
||||
"found_central_gateway": "encontrado o gateway central local",
|
||||
"without_room": "sem quarto atribuído",
|
||||
"no_display": "não exibir"
|
||||
},
|
||||
"control_mode": {
|
||||
"auto": "automático",
|
||||
"cloud": "nuvem"
|
||||
},
|
||||
"statistics_logic": {
|
||||
"or": "lógica OU",
|
||||
"and": "lógica E"
|
||||
},
|
||||
"filter_mode": {
|
||||
"exclude": "excluir",
|
||||
"include": "incluir"
|
||||
},
|
||||
"connect_type": {
|
||||
"0": "WiFi",
|
||||
"1": "dispositivo yunyi",
|
||||
"2": "dispositivo de nuvem",
|
||||
"3": "ZigBee",
|
||||
"4": "webSocket",
|
||||
"5": "dispositivo virtual",
|
||||
"6": "BLE",
|
||||
"7": "AP local",
|
||||
"8": "WiFi+BLE",
|
||||
"9": "outro",
|
||||
"10": "plug-in de função",
|
||||
"11": "rede celular",
|
||||
"12": "cabo",
|
||||
"13": "NB-IoT",
|
||||
"14": "acesso à nuvem de terceiros",
|
||||
"15": "dispositivo de controle remoto infravermelho",
|
||||
"16": "BLE-Mesh",
|
||||
"17": "grupo de dispositivos virtuais",
|
||||
"18": "subdispositivo de gateway",
|
||||
"19": "subdispositivo de gateway de nível de segurança",
|
||||
"22": "PLC",
|
||||
"23": "somente cabo",
|
||||
"24": "Matter",
|
||||
"25": "WiFi+rede celular"
|
||||
},
|
||||
"room_name_rule": {
|
||||
"none": "não sincronizado",
|
||||
"home_room": "Nome da casa e nome do quarto (Xiaomi Home Quarto)",
|
||||
"room": "Nome do quarto (Quarto)",
|
||||
"home": "Nome da casa (Xiaomi Home)"
|
||||
},
|
||||
"option_status": {
|
||||
"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",
|
||||
"offline": "offline"
|
||||
},
|
||||
"lan_ctrl_config": {
|
||||
"notice_net_dup": "\r\n**[Aviso]** Detectado múltiplas interfaces de rede que podem estar conectando à mesma rede, por favor, selecione a correta.",
|
||||
"net_unavailable": "Interface indisponível"
|
||||
}
|
||||
},
|
||||
"oauth2": {
|
||||
"success": {
|
||||
"title": "Autenticação bem-sucedida",
|
||||
"content": "Por favor, feche esta página e volte para a página de autenticação da conta para clicar em 'Próximo'.",
|
||||
"button": "Fechar"
|
||||
},
|
||||
"fail": {
|
||||
"title": "Falha na autenticação",
|
||||
"content": "{error_msg}, por favor, feche esta página e volte para a página de autenticação da conta para clicar no link de autenticação novamente.",
|
||||
"button": "Fechar"
|
||||
},
|
||||
"error_msg": {
|
||||
"-10100": "Parâmetros de resposta inválidos ('code' ou 'state' está vazio)",
|
||||
"-10101": "O campo 'state' fornecido não corresponde"
|
||||
}
|
||||
},
|
||||
"miot": {
|
||||
"client": {
|
||||
"invalid_oauth_info": "Informações de autenticação inválidas, a conexão com a nuvem estará indisponível. Vá para a página de integração do Xiaomi Home e clique em 'Opções' para reautenticar.",
|
||||
"invalid_device_cache": "Informações de dispositivo no cache inválidas. Vá para a página de integração do Xiaomi Home e clique em 'Opções -> Atualizar lista de dispositivos' para atualizar as informações locais.",
|
||||
"invalid_cert_info": "Certificado de usuário inválido. A conexão local do gateway central estará indisponível. Vá para a página de integração do Xiaomi Home e clique em 'Opções' para reautenticar.",
|
||||
"device_cloud_error": "Erro ao obter informações do dispositivo da nuvem. Verifique a conexão da rede local.",
|
||||
"xiaomi_home_error_title": "Erro de Integração do Xiaomi Home",
|
||||
"xiaomi_home_error": "Erro detectado em **{nick_name}({uid}, {cloud_server})**. Vá para a página de opções para reconfigurar.\n\n**Erro**: \n{message}",
|
||||
"device_list_changed_title": "Mudança na lista de dispositivos do Xiaomi Home",
|
||||
"device_list_changed": "Detectado que as informações do dispositivo **{nick_name}({uid}, {cloud_server})** mudaram. Vá para a página de integração e clique em 'Opções -> Atualizar lista de dispositivos' para atualizar as informações locais.\n\nStatus atual da rede: {network_status}\n{message}\n",
|
||||
"device_list_add": "\n**{count} dispositivos novos**: \n{message}",
|
||||
"device_list_del": "\n**{count} dispositivos não disponíveis**: \n{message}",
|
||||
"device_list_offline": "\n**{count} dispositivos offline**: \n{message}",
|
||||
"network_status_online": "online",
|
||||
"network_status_offline": "offline",
|
||||
"central_state_changed_title": "Status de conexão do gateway central",
|
||||
"central_state_changed": "**{nick_name}({uid}, {cloud_server})** conexão local do gateway central: {conn_status}",
|
||||
"central_state_connected": "conectado",
|
||||
"central_state_disconnected": "desconectado",
|
||||
"device_exec_error": "Erro na execução"
|
||||
}
|
||||
},
|
||||
"error": {
|
||||
"common": {
|
||||
"-10000": "Erro desconhecido",
|
||||
"-10001": "Serviço indisponível",
|
||||
"-10002": "Parâmetro inválido",
|
||||
"-10003": "Recursos insuficientes",
|
||||
"-10004": "Erro interno",
|
||||
"-10005": "Permissões insuficientes",
|
||||
"-10006": "Execução expirada",
|
||||
"-10007": "Dispositivo offline ou inexistente",
|
||||
"-10020": "OAuth2 não autorizado",
|
||||
"-10030": "Token inválido (HTTP)",
|
||||
"-10040": "Formato de mensagem inválido",
|
||||
"-10050": "Certificado inválido",
|
||||
"-704000000": "Erro desconhecido",
|
||||
"-704010000": "Não autorizado (o dispositivo pode ter sido excluído)",
|
||||
"-704014006": "Descrição do dispositivo não encontrada",
|
||||
"-704030013": "Propriedade não pode ser lida",
|
||||
"-704030023": "Propriedade não pode ser escrita",
|
||||
"-704030033": "Propriedade não pode ser assinada",
|
||||
"-704040002": "Serviço inexistente",
|
||||
"-704040003": "Propriedade inexistente",
|
||||
"-704040004": "Evento inexistente",
|
||||
"-704040005": "Ação inexistente",
|
||||
"-704040999": "Funcionalidade não lançada",
|
||||
"-704042001": "Dispositivo inexistente",
|
||||
"-704042011": "Dispositivo offline",
|
||||
"-704053036": "Tempo de operação do dispositivo expirado",
|
||||
"-704053100": "Dispositivo não pode executar esta operação no estado atual",
|
||||
"-704083036": "Tempo de operação do dispositivo expirado",
|
||||
"-704090001": "Dispositivo inexistente",
|
||||
"-704220008": "ID inválido",
|
||||
"-704220025": "Número de parâmetros de ação incompatível",
|
||||
"-704220035": "Parâmetro de ação incorreto",
|
||||
"-704220043": "Valor da propriedade incorreto",
|
||||
"-704222034": "Valor de retorno de ação incorreto",
|
||||
"-705004000": "Erro desconhecido",
|
||||
"-705004501": "Erro desconhecido",
|
||||
"-705201013": "Propriedade não pode ser lida",
|
||||
"-705201015": "Erro na execução da ação",
|
||||
"-705201023": "Propriedade não pode ser escrita",
|
||||
"-705201033": "Propriedade não pode ser assinada",
|
||||
"-706012000": "Erro desconhecido",
|
||||
"-706012013": "Propriedade não pode ser lida",
|
||||
"-706012015": "Erro na execução da ação",
|
||||
"-706012023": "Propriedade não pode ser escrita",
|
||||
"-706012033": "Propriedade não pode ser assinada",
|
||||
"-706012043": "Valor da propriedade incorreto",
|
||||
"-706014006": "Descrição do dispositivo não encontrada"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
{
|
||||
"config": {
|
||||
"other": {
|
||||
"devices": "dispositivos",
|
||||
"found_central_gateway": ", encontrou a central de gateway local",
|
||||
"without_room": "Sem quarto atribuído",
|
||||
"no_display": "Não exibir"
|
||||
},
|
||||
"control_mode": {
|
||||
"auto": "Automático",
|
||||
"cloud": "Nuvem"
|
||||
},
|
||||
"statistics_logic": {
|
||||
"or": "Ou lógica",
|
||||
"and": "E lógica"
|
||||
},
|
||||
"filter_mode": {
|
||||
"exclude": "Excluir",
|
||||
"include": "Incluir"
|
||||
},
|
||||
"connect_type": {
|
||||
"0": "WiFi",
|
||||
"1": "dispositivo yunyi",
|
||||
"2": "dispositivo de nuvem",
|
||||
"3": "ZigBee",
|
||||
"4": "webSocket",
|
||||
"5": "dispositivo virtual",
|
||||
"6": "BLE",
|
||||
"7": "AP local",
|
||||
"8": "WiFi+BLE",
|
||||
"9": "outro",
|
||||
"10": "plug-in de função",
|
||||
"11": "rede celular",
|
||||
"12": "cabo",
|
||||
"13": "NB-IoT",
|
||||
"14": "acesso à nuvem de terceiros",
|
||||
"15": "dispositivo de controle remoto infravermelho",
|
||||
"16": "BLE-Mesh",
|
||||
"17": "grupo de dispositivos virtuais",
|
||||
"18": "subdispositivo de gateway",
|
||||
"19": "subdispositivo de gateway de nível de segurança",
|
||||
"22": "PLC",
|
||||
"23": "somente cabo",
|
||||
"24": "Matter",
|
||||
"25": "WiFi+rede celular"
|
||||
},
|
||||
"room_name_rule": {
|
||||
"none": "Não sincronizar",
|
||||
"home_room": "Nome da casa e Nome do quarto (Xiaomi Home Quarto)",
|
||||
"room": "Nome do quarto (Quarto)",
|
||||
"home": "Nome da casa (Xiaomi Home)"
|
||||
},
|
||||
"option_status": {
|
||||
"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",
|
||||
"offline": "Offline"
|
||||
},
|
||||
"lan_ctrl_config": {
|
||||
"notice_net_dup": "\r\n**[Aviso]** Detectado que várias interfaces podem estar conectadas à mesma rede, escolha com cuidado.",
|
||||
"net_unavailable": "Interface indisponível"
|
||||
}
|
||||
},
|
||||
"oauth2": {
|
||||
"success": {
|
||||
"title": "Autenticação bem-sucedida",
|
||||
"content": "Por favor, feche esta página e volte para a página de autenticação da conta para clicar em 'Seguinte'.",
|
||||
"button": "Fechar"
|
||||
},
|
||||
"fail": {
|
||||
"title": "Falha na autenticação",
|
||||
"content": "{error_msg}, por favor, feche esta página e volte para a página de autenticação da conta para clicar no link de autenticação novamente.",
|
||||
"button": "Fechar"
|
||||
},
|
||||
"error_msg": {
|
||||
"-10100": "Parâmetros de resposta inválidos ('code' ou 'state' está vazio)",
|
||||
"-10101": "O campo 'state' fornecido não corresponde"
|
||||
}
|
||||
},
|
||||
"miot": {
|
||||
"client": {
|
||||
"invalid_oauth_info": "Informações de autenticação inválidas, a conexão na nuvem ficará indisponível. Por favor, acesse a página de integração do Xiaomi Home e clique em 'Opções' para autenticar novamente.",
|
||||
"invalid_device_cache": "Erro no cache de informações do dispositivo. Por favor, acesse a página de integração do Xiaomi Home e clique em 'Opções -> Atualizar lista de dispositivos' para atualizar as informações locais.",
|
||||
"invalid_cert_info": "Certificado de usuário inválido, a conexão com a central local ficará indisponível. Por favor, acesse a página de integração do Xiaomi Home e clique em 'Opções' para autenticar novamente.",
|
||||
"device_cloud_error": "Erro ao obter informações do dispositivo na nuvem. Verifique a conexão de rede local.",
|
||||
"xiaomi_home_error_title": "Erro de integração do Xiaomi Home",
|
||||
"xiaomi_home_error": "Detectado erro em **{nick_name}({uid}, {cloud_server})**. Por favor, acesse a página de opções para reconfigurar.\n\n**Informação do erro**: \n{message}",
|
||||
"device_list_changed_title": "Mudança na lista de dispositivos do Xiaomi Home",
|
||||
"device_list_changed": "Detectada alteração nas informações do dispositivo de **{nick_name}({uid}, {cloud_server})**. Por favor, acesse a página de opções de integração e clique em 'Opções -> Atualizar lista de dispositivos' para atualizar as informações locais.\n\nStatus atual da rede: {network_status}\n{message}\n",
|
||||
"device_list_add": "\n**{count} novos dispositivos**: \n{message}",
|
||||
"device_list_del": "\n**{count} dispositivos indisponíveis**: \n{message}",
|
||||
"device_list_offline": "\n**{count} dispositivos offline**: \n{message}",
|
||||
"network_status_online": "Online",
|
||||
"network_status_offline": "Offline",
|
||||
"central_state_changed_title": "Estado da ligação do gateway central",
|
||||
"central_state_changed": "**{nick_name}({uid}, {cloud_server})** ligação local do gateway central: {conn_status}",
|
||||
"central_state_connected": "ligado",
|
||||
"central_state_disconnected": "desligado",
|
||||
"device_exec_error": "Erro de execução"
|
||||
}
|
||||
},
|
||||
"error": {
|
||||
"common": {
|
||||
"-10000": "Erro desconhecido",
|
||||
"-10001": "Serviço indisponível",
|
||||
"-10002": "Parâmetro inválido",
|
||||
"-10003": "Recursos insuficientes",
|
||||
"-10004": "Erro interno",
|
||||
"-10005": "Permissão negada",
|
||||
"-10006": "Tempo limite de execução",
|
||||
"-10007": "Dispositivo offline ou inexistente",
|
||||
"-10020": "Não autorizado (OAuth2)",
|
||||
"-10030": "Token inválido (HTTP)",
|
||||
"-10040": "Formato de mensagem inválido",
|
||||
"-10050": "Certificado inválido",
|
||||
"-704000000": "Erro desconhecido",
|
||||
"-704010000": "Não autorizado (o dispositivo pode ter sido removido)",
|
||||
"-704014006": "Descrição do dispositivo não encontrada",
|
||||
"-704030013": "Propriedade não legível",
|
||||
"-704030023": "Propriedade não gravável",
|
||||
"-704030033": "Propriedade não subscritível",
|
||||
"-704040002": "Serviço inexistente",
|
||||
"-704040003": "Propriedade inexistente",
|
||||
"-704040004": "Evento inexistente",
|
||||
"-704040005": "Ação inexistente",
|
||||
"-704040999": "Funcionalidade não disponível",
|
||||
"-704042001": "Dispositivo inexistente",
|
||||
"-704042011": "Dispositivo offline",
|
||||
"-704053036": "Tempo limite de operação do dispositivo",
|
||||
"-704053100": "O dispositivo não pode executar esta operação no estado atual",
|
||||
"-704083036": "Tempo limite de operação do dispositivo",
|
||||
"-704090001": "Dispositivo inexistente",
|
||||
"-704220008": "ID inválido",
|
||||
"-704220025": "Número de parâmetros da ação não corresponde",
|
||||
"-704220035": "Erro nos parâmetros da ação",
|
||||
"-704220043": "Valor de propriedade inválido",
|
||||
"-704222034": "Erro no valor de retorno da ação",
|
||||
"-705004000": "Erro desconhecido",
|
||||
"-705004501": "Erro desconhecido",
|
||||
"-705201013": "Propriedade não legível",
|
||||
"-705201015": "Erro na execução da ação",
|
||||
"-705201023": "Propriedade não gravável",
|
||||
"-705201033": "Propriedade não subscritível",
|
||||
"-706012000": "Erro desconhecido",
|
||||
"-706012013": "Propriedade não legível",
|
||||
"-706012015": "Erro na execução da ação",
|
||||
"-706012023": "Propriedade não gravável",
|
||||
"-706012033": "Propriedade não subscritível",
|
||||
"-706012043": "Valor de propriedade inválido",
|
||||
"-706014006": "Descrição do dispositivo não encontrada"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
{
|
||||
"config": {
|
||||
"other": {
|
||||
"devices": "устройства",
|
||||
"found_central_gateway": ", найден локальный центральный шлюз",
|
||||
"without_room": "без комнаты",
|
||||
"no_display": "не отображать"
|
||||
},
|
||||
"control_mode": {
|
||||
"auto": "автоматический",
|
||||
"cloud": "облако"
|
||||
},
|
||||
"statistics_logic": {
|
||||
"or": "логика ИЛИ",
|
||||
"and": "логика И"
|
||||
},
|
||||
"filter_mode": {
|
||||
"exclude": "исключить",
|
||||
"include": "включить"
|
||||
},
|
||||
"connect_type": {
|
||||
"0": "WiFi",
|
||||
"1": "yunyi устройство",
|
||||
"2": "Облачное устройство",
|
||||
"3": "ZigBee",
|
||||
"4": "webSocket",
|
||||
"5": "Виртуальное устройство",
|
||||
"6": "BLE",
|
||||
"7": "Локальный AP",
|
||||
"8": "WiFi+BLE",
|
||||
"9": "Другое",
|
||||
"10": "Плагин функции",
|
||||
"11": "Сотовая сеть",
|
||||
"12": "Кабель",
|
||||
"13": "NB-IoT",
|
||||
"14": "Доступ к стороннему облаку",
|
||||
"15": "Устройство с ИК-пультом дистанционного управления",
|
||||
"16": "BLE-Mesh",
|
||||
"17": "Группа виртуальных устройств",
|
||||
"18": "Подустройство шлюза",
|
||||
"19": "Подустройство шлюза уровня безопасности",
|
||||
"22": "PLC",
|
||||
"23": "Только кабель",
|
||||
"24": "Matter",
|
||||
"25": "WiFi+Сотовая сеть"
|
||||
},
|
||||
"room_name_rule": {
|
||||
"none": "не синхронизировать",
|
||||
"home_room": "название дома и название комнаты (Xiaomi Home Спальня)",
|
||||
"room": "название комнаты (Спальня)",
|
||||
"home": "название дома (Xiaomi Home)"
|
||||
},
|
||||
"option_status": {
|
||||
"enable": "Включить",
|
||||
"disable": "Отключить"
|
||||
},
|
||||
"binary_mode": {
|
||||
"text": "Сущность текстового датчика",
|
||||
"bool": "Сущность бинарного датчика"
|
||||
},
|
||||
"device_state": {
|
||||
"add": "Добавить",
|
||||
"del": "Недоступно",
|
||||
"offline": "Не в сети"
|
||||
},
|
||||
"lan_ctrl_config": {
|
||||
"notice_net_dup": "\r\n**[Уведомление]** Обнаружено несколько сетевых карт, которые могут быть подключены к одной и той же сети. Пожалуйста, обратите внимание на выбор.",
|
||||
"net_unavailable": "Интерфейс недоступен"
|
||||
}
|
||||
},
|
||||
"oauth2": {
|
||||
"success": {
|
||||
"title": "Аутентификация успешна",
|
||||
"content": "Пожалуйста, закройте эту страницу и вернитесь на страницу аутентификации учетной записи, чтобы нажать 'Далее'.",
|
||||
"button": "Закрыть"
|
||||
},
|
||||
"fail": {
|
||||
"title": "Аутентификация не удалась",
|
||||
"content": "{error_msg}, пожалуйста, закройте эту страницу и вернитесь на страницу аутентификации учетной записи, чтобы снова нажать на ссылку аутентификации.",
|
||||
"button": "Закрыть"
|
||||
},
|
||||
"error_msg": {
|
||||
"-10100": "Недействительные параметры ответа ('code' или 'state' поле пусто)",
|
||||
"-10101": "Переданное поле 'state' не совпадает"
|
||||
}
|
||||
},
|
||||
"miot": {
|
||||
"client": {
|
||||
"invalid_oauth_info": "Информация об аутентификации недействительна, облако будет недоступно, пожалуйста, войдите на страницу интеграции Xiaomi Home, нажмите 'Опции' для повторной аутентификации",
|
||||
"invalid_device_cache": "Кэш информации об устройстве ненормальный, пожалуйста, войдите на страницу интеграции Xiaomi Home, нажмите 'Опции->Обновить список устройств', обновите локальный кэш",
|
||||
"invalid_cert_info": "Недействительный пользовательский сертификат, локальное центральное соединение будет недоступно, пожалуйста, войдите на страницу интеграции Xiaomi Home, нажмите 'Опции' для повторной аутентификации",
|
||||
"device_cloud_error": "При получении информации об устройстве из облака произошло исключение, пожалуйста, проверьте локальное сетевое соединение",
|
||||
"xiaomi_home_error_title": "Ошибка интеграции Xiaomi Home",
|
||||
"xiaomi_home_error": "Обнаружена ошибка **{nick_name}({uid}, {cloud_server})**, пожалуйста, войдите на страницу опций для повторной настройки.\n\n**Сообщение об ошибке**: \n{message}",
|
||||
"device_list_changed_title": "Изменения в списке устройств Xiaomi Home",
|
||||
"device_list_changed": "Обнаружены изменения в информации об устройствах **{nick_name}({uid}, {cloud_server})**, пожалуйста, войдите на страницу интеграции, нажмите `Опции->Обновить список устройств`, обновите локальную информацию об устройствах.\n\nТекущий статус сети: {network_status}\n{message}\n",
|
||||
"device_list_add": "\n**{count} новых устройств:** \n{message}",
|
||||
"device_list_del": "\n**{count} устройств недоступно:** \n{message}",
|
||||
"device_list_offline": "\n**{count} устройств недоступно:** \n{message}",
|
||||
"network_status_online": "В сети",
|
||||
"network_status_offline": "Не в сети",
|
||||
"central_state_changed_title": "Статус подключения центрального шлюза",
|
||||
"central_state_changed": "**{nick_name}({uid}, {cloud_server})** локальное подключение центрального шлюза: {conn_status}",
|
||||
"central_state_connected": "подключено",
|
||||
"central_state_disconnected": "разъединено",
|
||||
"device_exec_error": "Ошибка выполнения"
|
||||
}
|
||||
},
|
||||
"error": {
|
||||
"common": {
|
||||
"-10000": "Неизвестная ошибка",
|
||||
"-10001": "Сервис недоступен",
|
||||
"-10002": "Недопустимый параметр",
|
||||
"-10003": "Недостаточно ресурсов",
|
||||
"-10004": "Внутренняя ошибка",
|
||||
"-10005": "Недостаточно прав",
|
||||
"-10006": "Тайм-аут выполнения",
|
||||
"-10007": "Устройство не в сети или не существует",
|
||||
"-10020": "Неавторизовано (OAuth2)",
|
||||
"-10030": "Недействительный токен (HTTP)",
|
||||
"-10040": "Недопустимый формат сообщения",
|
||||
"-10050": "Недействительный сертификат",
|
||||
"-704000000": "Неизвестная ошибка",
|
||||
"-704010000": "Неавторизовано (устройство могло быть удалено)",
|
||||
"-704014006": "Описание устройства не найдено",
|
||||
"-704030013": "Свойство не читается",
|
||||
"-704030023": "Свойство не записывается",
|
||||
"-704030033": "Свойство не подписывается",
|
||||
"-704040002": "Сервис не существует",
|
||||
"-704040003": "Свойство не существует",
|
||||
"-704040004": "Событие не существует",
|
||||
"-704040005": "Действие не существует",
|
||||
"-704040999": "Функция не в сети",
|
||||
"-704042001": "Устройство не существует",
|
||||
"-704042011": "Устройство не в сети",
|
||||
"-704053036": "Тайм-аут операции устройства",
|
||||
"-704053100": "Устройство не может выполнить эту операцию в текущем состоянии",
|
||||
"-704083036": "Тайм-аут операции устройства",
|
||||
"-704090001": "Устройство не существует",
|
||||
"-704220008": "Недействительный ID",
|
||||
"-704220025": "Несоответствие количества параметров действия",
|
||||
"-704220035": "Ошибка параметра действия",
|
||||
"-704220043": "Ошибка значения свойства",
|
||||
"-704222034": "Ошибка возвращаемого значения действия",
|
||||
"-705004000": "Неизвестная ошибка",
|
||||
"-705004501": "Неизвестная ошибка",
|
||||
"-705201013": "Свойство не читается",
|
||||
"-705201015": "Ошибка выполнения действия",
|
||||
"-705201023": "Свойство не записывается",
|
||||
"-705201033": "Свойство не подписывается",
|
||||
"-706012000": "Неизвестная ошибка",
|
||||
"-706012013": "Свойство не читается",
|
||||
"-706012015": "Ошибка выполнения действия",
|
||||
"-706012023": "Свойство не записывается",
|
||||
"-706012033": "Свойство не подписывается",
|
||||
"-706012043": "Ошибка значения свойства",
|
||||
"-706014006": "Описание устройства не найдено"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
{
|
||||
"config": {
|
||||
"other": {
|
||||
"devices": "Cihazlar",
|
||||
"found_central_gateway": ", Yerel Merkezi Hub Ağ Geçidi Bulundu",
|
||||
"without_room": "Oda atanmamış",
|
||||
"no_display": "Gösterme"
|
||||
},
|
||||
"control_mode": {
|
||||
"auto": "Otomatik",
|
||||
"cloud": "Bulut"
|
||||
},
|
||||
"statistics_logic": {
|
||||
"or": "VEYA mantığı",
|
||||
"and": "VE mantığı"
|
||||
},
|
||||
"filter_mode": {
|
||||
"exclude": "Hariç tut",
|
||||
"include": "Dahil et"
|
||||
},
|
||||
"connect_type": {
|
||||
"0": "WiFi",
|
||||
"1": "yunyi cihazı",
|
||||
"2": "Bulut cihazı",
|
||||
"3": "ZigBee",
|
||||
"4": "webSocket",
|
||||
"5": "Sanal cihaz",
|
||||
"6": "BLE",
|
||||
"7": "Yerel AP",
|
||||
"8": "WiFi+BLE",
|
||||
"9": "Diğer",
|
||||
"10": "İşlev eklentisi",
|
||||
"11": "Hücresel ağ",
|
||||
"12": "Kablo",
|
||||
"13": "NB-IoT",
|
||||
"14": "Üçüncü taraf bulut erişimi",
|
||||
"15": "Kızılötesi uzaktan kumanda cihazı",
|
||||
"16": "BLE-Mesh",
|
||||
"17": "Sanal cihaz grubu",
|
||||
"18": "Ağ geçidi alt cihazı",
|
||||
"19": "Güvenlik seviyesi ağ geçidi alt cihazı",
|
||||
"22": "PLC",
|
||||
"23": "Yalnızca kablo",
|
||||
"24": "Matter",
|
||||
"25": "WiFi+Hücresel ağ"
|
||||
},
|
||||
"room_name_rule": {
|
||||
"none": "Senkronize etme",
|
||||
"home_room": "Ev Adı ve Oda Adı (Xiaomi Home Yatak Odası)",
|
||||
"room": "Oda Adı (Yatak Odası)",
|
||||
"home": "Ev Adı (Xiaomi Home)"
|
||||
},
|
||||
"option_status": {
|
||||
"enable": "Etkinleştir",
|
||||
"disable": "Devre Dışı Bırak"
|
||||
},
|
||||
"binary_mode": {
|
||||
"text": "Metin Sensör Varlığı",
|
||||
"bool": "İkili Sensör Varlığı"
|
||||
},
|
||||
"device_state": {
|
||||
"add": "Ekle",
|
||||
"del": "Kullanılamıyor",
|
||||
"offline": "Çevrimdışı"
|
||||
},
|
||||
"lan_ctrl_config": {
|
||||
"notice_net_dup": "\r\n**[Bildirim]** Aynı ağa bağlı olabilecek birden fazla ağ kartı algılandı. Lütfen seçime dikkat edin.",
|
||||
"net_unavailable": "Arayüz kullanılamıyor"
|
||||
}
|
||||
},
|
||||
"oauth2": {
|
||||
"success": {
|
||||
"title": "Kimlik Doğrulama Başarılı",
|
||||
"content": "Lütfen bu sayfayı kapatın ve 'İleri'ye tıklamak için hesap kimlik doğrulama sayfasına geri dönün.",
|
||||
"button": "Kapat"
|
||||
},
|
||||
"fail": {
|
||||
"title": "Kimlik Doğrulama Başarısız",
|
||||
"content": "{error_msg}, lütfen bu sayfayı kapatın ve kimlik doğrulama bağlantısına tekrar tıklamak için hesap kimlik doğrulama sayfasına geri dönün.",
|
||||
"button": "Kapat"
|
||||
},
|
||||
"error_msg": {
|
||||
"-10100": "Geçersiz yanıt parametreleri ('code' veya 'state' alanı boş)",
|
||||
"-10101": "Geçirilen 'state' alanı uyumsuz"
|
||||
}
|
||||
},
|
||||
"miot": {
|
||||
"client": {
|
||||
"invalid_oauth_info": "Kimlik doğrulama bilgileri geçersiz, bulut bağlantısı kullanılamayacak, lütfen Xiaomi Home entegrasyon sayfasına girin, yeniden kimlik doğrulaması yapmak için 'Seçenekler'e tıklayın",
|
||||
"invalid_device_cache": "Önbellek cihaz bilgileri anormal, lütfen Xiaomi Home entegrasyon sayfasına girin, yerel önbelleği güncellemek için 'Seçenekler->Cihaz listesini güncelle'ye tıklayın",
|
||||
"invalid_cert_info": "Geçersiz kullanıcı sertifikası, yerel merkezi bağlantı kullanılamayacak, lütfen Xiaomi Home entegrasyon sayfasına girin, yeniden kimlik doğrulaması yapmak için 'Seçenekler'e tıklayın",
|
||||
"device_cloud_error": "Buluttan cihaz bilgileri alınırken bir istisna oluştu, lütfen yerel ağ bağlantısını kontrol edin",
|
||||
"xiaomi_home_error_title": "Xiaomi Home Entegrasyon Hatası",
|
||||
"xiaomi_home_error": "**{nick_name}({uid}, {cloud_server})** hatası algılandı, lütfen yeniden yapılandırmak için seçenekler sayfasına girin.\n\n**Hata mesajı**: \n{message}",
|
||||
"device_list_changed_title": "Xiaomi Home cihaz listesi değişiklikleri",
|
||||
"device_list_changed": "**{nick_name}({uid}, {cloud_server})** cihaz bilgilerinin değiştiği algılandı, lütfen entegrasyon seçenekleri sayfasına girin, yerel cihaz bilgilerini güncellemek için `Seçenekler->Cihaz listesini güncelle`ye tıklayın.\n\nGeçerli ağ durumu: {network_status}\n{message}\n",
|
||||
"device_list_add": "\n**{count} yeni cihaz:** \n{message}",
|
||||
"device_list_del": "\n**{count} cihaz kullanılamıyor:** \n{message}",
|
||||
"device_list_offline": "\n**{count} cihaz çevrimdışı:** \n{message}",
|
||||
"network_status_online": "Çevrimiçi",
|
||||
"network_status_offline": "Çevrimdışı",
|
||||
"central_state_changed_title": "Merkezi Hub Ağ Geçidi Bağlantı Durumu",
|
||||
"central_state_changed": "**{nick_name}({uid}, {cloud_server})** Xiaomi merkezi hub ağ geçidine yerel bağlantı: {conn_status}",
|
||||
"central_state_connected": "Bağlandı",
|
||||
"central_state_disconnected": "Bağlantı kesildi",
|
||||
"device_exec_error": "Yürütme hatası"
|
||||
}
|
||||
},
|
||||
"error": {
|
||||
"common": {
|
||||
"-10000": "Bilinmeyen hata",
|
||||
"-10001": "Hizmet kullanılamıyor",
|
||||
"-10002": "Geçersiz parametre",
|
||||
"-10003": "Yetersiz kaynaklar",
|
||||
"-10004": "İç hata",
|
||||
"-10005": "Yetersiz izinler",
|
||||
"-10006": "Yürütme zaman aşımı",
|
||||
"-10007": "Cihaz çevrimdışı veya mevcut değil",
|
||||
"-10020": "Yetkisiz (OAuth2)",
|
||||
"-10030": "Geçersiz token (HTTP)",
|
||||
"-10040": "Geçersiz mesaj formatı",
|
||||
"-10050": "Geçersiz sertifika",
|
||||
"-704000000": "Bilinmeyen hata",
|
||||
"-704010000": "Yetkisiz (cihaz silinmiş olabilir)",
|
||||
"-704014006": "Cihaz açıklaması bulunamadı",
|
||||
"-704030013": "Özellik okunabilir değil",
|
||||
"-704030023": "Özellik yazılabilir değil",
|
||||
"-704030033": "Özellik abone edilebilir değil",
|
||||
"-704040002": "Hizmet mevcut değil",
|
||||
"-704040003": "Özellik mevcut değil",
|
||||
"-704040004": "Olay mevcut değil",
|
||||
"-704040005": "Eylem mevcut değil",
|
||||
"-704040999": "Özellik çevrimiçi değil",
|
||||
"-704042001": "Cihaz mevcut değil",
|
||||
"-704042011": "Cihaz çevrimdışı",
|
||||
"-704053036": "Cihaz işlemi zaman aşımı",
|
||||
"-704053100": "Cihaz mevcut durumda bu işlemi gerçekleştiremiyor",
|
||||
"-704083036": "Cihaz işlemi zaman aşımı",
|
||||
"-704090001": "Cihaz mevcut değil",
|
||||
"-704220008": "Geçersiz ID",
|
||||
"-704220025": "Eylem parametre sayısı uyumsuz",
|
||||
"-704220035": "Eylem parametre hatası",
|
||||
"-704220043": "Özellik değer hatası",
|
||||
"-704222034": "Eylem dönüş değer hatası",
|
||||
"-705004000": "Bilinmeyen hata",
|
||||
"-705004501": "Bilinmeyen hata",
|
||||
"-705201013": "Özellik okunabilir değil",
|
||||
"-705201015": "Eylem yürütme hatası",
|
||||
"-705201023": "Özellik yazılabilir değil",
|
||||
"-705201033": "Özellik abone edilebilir değil",
|
||||
"-706012000": "Bilinmeyen hata",
|
||||
"-706012013": "Özellik okunabilir değil",
|
||||
"-706012015": "Eylem yürütme hatası",
|
||||
"-706012023": "Özellik yazılabilir değil",
|
||||
"-706012033": "Özellik abone edilebilir değil",
|
||||
"-706012043": "Özellik değer hatası",
|
||||
"-706014006": "Cihaz açıklaması bulunamadı"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
{
|
||||
"config": {
|
||||
"other": {
|
||||
"devices": "个设备",
|
||||
"found_central_gateway": ",发现本地中枢网关",
|
||||
"without_room": "未分配房间",
|
||||
"no_display": "不显示"
|
||||
},
|
||||
"control_mode": {
|
||||
"auto": "自动",
|
||||
"cloud": "云端"
|
||||
},
|
||||
"room_name_rule": {
|
||||
"none": "不同步",
|
||||
"home_room": "家庭名 和 房间名 (米家 卧室)",
|
||||
"room": "房间名 (卧室)",
|
||||
"home": "家庭名 (米家)"
|
||||
},
|
||||
"statistics_logic": {
|
||||
"or": "或逻辑",
|
||||
"and": "与逻辑"
|
||||
},
|
||||
"filter_mode": {
|
||||
"exclude": "排除",
|
||||
"include": "包含"
|
||||
},
|
||||
"connect_type": {
|
||||
"0": "WiFi",
|
||||
"1": "yunyi设备",
|
||||
"2": "云接入设备",
|
||||
"3": "ZigBee",
|
||||
"4": "webSocket",
|
||||
"5": "虚拟设备",
|
||||
"6": "BLE",
|
||||
"7": "本地AP",
|
||||
"8": "WiFi+BLE",
|
||||
"9": "其他",
|
||||
"10": "功能插件",
|
||||
"11": "蜂窝网",
|
||||
"12": "网线",
|
||||
"13": "NB-IoT",
|
||||
"14": "第三方云接入",
|
||||
"15": "红外遥控器子设备",
|
||||
"16": "BLE-Mesh",
|
||||
"17": "虚拟设备组",
|
||||
"18": "代理网关子设备",
|
||||
"19": "安全级代理网关子设备",
|
||||
"22": "PLC",
|
||||
"23": "仅网线",
|
||||
"24": "Matter",
|
||||
"25": "WiFi+蜂窝网"
|
||||
},
|
||||
"option_status": {
|
||||
"enable": "启用",
|
||||
"disable": "禁用"
|
||||
},
|
||||
"binary_mode": {
|
||||
"text": "文本传感器实体",
|
||||
"bool": "二进制传感器实体"
|
||||
},
|
||||
"device_state": {
|
||||
"add": "新增",
|
||||
"del": "不可用",
|
||||
"offline": "离线"
|
||||
},
|
||||
"lan_ctrl_config": {
|
||||
"notice_net_dup": "\r\n**[提示]** 检测到多个网卡可能连接同一个网络,请注意选择。",
|
||||
"net_unavailable": "接口不可用"
|
||||
}
|
||||
},
|
||||
"oauth2": {
|
||||
"success": {
|
||||
"title": "认证成功",
|
||||
"content": "请关闭此页面,返回账号认证页面点击“下一步”",
|
||||
"button": "关闭"
|
||||
},
|
||||
"fail": {
|
||||
"title": "认证失败",
|
||||
"content": "{error_msg},请关闭此页面,返回账号认证页面重新点击认链接进行认证。",
|
||||
"button": "关闭"
|
||||
},
|
||||
"error_msg": {
|
||||
"-10100": "无效的响应参数(“code”或者“state”字段为空)",
|
||||
"-10101": "传入“state”字段不一致"
|
||||
}
|
||||
},
|
||||
"miot": {
|
||||
"client": {
|
||||
"invalid_oauth_info": "认证信息失效,云端链路将不可用,请进入 Xiaomi Home 集成页面,点击“选项”重新认证",
|
||||
"invalid_device_cache": "缓存设备信息异常,请进入 Xiaomi Home 集成页面,点击`选项->更新设备列表`,更新本地设备信息",
|
||||
"invalid_cert_info": "无效的用户证书,本地中枢链路将不可用,请进入 Xiaomi Home 集成页面,点击“选项”重新认证",
|
||||
"device_cloud_error": "从云端获取设备信息异常,请检查本地网络连接",
|
||||
"xiaomi_home_error_title": "Xiaomi Home 集成错误",
|
||||
"xiaomi_home_error": "检测到 **{nick_name}({uid}, {cloud_server})** 出现错误,请进入选项页面重新配置。\n\n**错误信息**: \n{message}",
|
||||
"device_list_changed_title": "Xiaomi Home设备列表变化",
|
||||
"device_list_changed": "检测到 **{nick_name}({uid}, {cloud_server})** 设备信息发生变化,请进入集成选项页面,点击`选项->更新设备列表`,更新本地设备信息。\n\n当前网络状态:{network_status}\n{message}\n",
|
||||
"device_list_add": "\n**{count} 个新增设备**: \n{message}",
|
||||
"device_list_del": "\n**{count} 个设备不可用**: \n{message}",
|
||||
"device_list_offline": "\n**{count} 个设备离线**: \n{message}",
|
||||
"network_status_online": "在线",
|
||||
"network_status_offline": "离线",
|
||||
"central_state_changed_title": "中枢网关连接状态",
|
||||
"central_state_changed":"**{nick_name}({uid}, {cloud_server})** 中枢网关本地连接链路: {conn_status}",
|
||||
"central_state_connected": "已连接",
|
||||
"central_state_disconnected": "断连",
|
||||
"device_exec_error": "执行错误"
|
||||
}
|
||||
},
|
||||
"error": {
|
||||
"common": {
|
||||
"-10000": "未知错误",
|
||||
"-10001": "服务不可用",
|
||||
"-10002": "参数无效",
|
||||
"-10003": "资源不足",
|
||||
"-10004": "内部错误",
|
||||
"-10005": "权限不足",
|
||||
"-10006": "执行超时",
|
||||
"-10007": "设备离线或者不存在",
|
||||
"-10020": "未授权OAuth2)",
|
||||
"-10030": "无效的token(HTTP)",
|
||||
"-10040": "无效的消息格式",
|
||||
"-10050": "无效的证书",
|
||||
"-704000000": "未知错误",
|
||||
"-704010000": "未授权(设备可能被删除)",
|
||||
"-704014006": "没找到设备描述",
|
||||
"-704030013": "Property不可读",
|
||||
"-704030023": "Property不可写",
|
||||
"-704030033": "Property不可订阅",
|
||||
"-704040002": "Service不存在",
|
||||
"-704040003": "Property不存在",
|
||||
"-704040004": "Event不存在",
|
||||
"-704040005": "Action不存在",
|
||||
"-704040999": "功能未上线",
|
||||
"-704042001": "Device不存在",
|
||||
"-704042011": "设备离线",
|
||||
"-704053036": "设备操作超时",
|
||||
"-704053100": "设备在当前状态下无法执行此操作",
|
||||
"-704083036": "设备操作超时",
|
||||
"-704090001": "Device不存在",
|
||||
"-704220008": "无效的ID",
|
||||
"-704220025": "Action参数个数不匹配",
|
||||
"-704220035": "Action参数错误",
|
||||
"-704220043": "Property值错误",
|
||||
"-704222034": "Action返回值错误",
|
||||
"-705004000": "未知错误",
|
||||
"-705004501": "未知错误",
|
||||
"-705201013": "Property不可读",
|
||||
"-705201015": "Action执行错误",
|
||||
"-705201023": "Property不可写",
|
||||
"-705201033": "Property不可订阅",
|
||||
"-706012000": "未知错误",
|
||||
"-706012013": "Property不可读",
|
||||
"-706012015": "Action执行错误",
|
||||
"-706012023": "Property不可写",
|
||||
"-706012033": "Property不可订阅",
|
||||
"-706012043": "Property值错误",
|
||||
"-706014006": "没找到设备描述"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
{
|
||||
"config": {
|
||||
"other": {
|
||||
"devices": "個設備",
|
||||
"found_central_gateway": ",發現本地中樞網關",
|
||||
"without_room": "未分配房間",
|
||||
"no_display": "不顯示"
|
||||
},
|
||||
"control_mode": {
|
||||
"auto": "自動",
|
||||
"cloud": "雲端"
|
||||
},
|
||||
"statistics_logic": {
|
||||
"or": "或邏輯",
|
||||
"and": "與邏輯"
|
||||
},
|
||||
"filter_mode": {
|
||||
"exclude": "排除",
|
||||
"include": "包含"
|
||||
},
|
||||
"connect_type": {
|
||||
"0": "WiFi",
|
||||
"1": "yunyi設備",
|
||||
"2": "雲接入設備",
|
||||
"3": "ZigBee",
|
||||
"4": "webSocket",
|
||||
"5": "虛擬設備",
|
||||
"6": "BLE",
|
||||
"7": "本地AP",
|
||||
"8": "WiFi+BLE",
|
||||
"9": "其他",
|
||||
"10": "功能插件",
|
||||
"11": "蜂窩網",
|
||||
"12": "網線",
|
||||
"13": "NB-IoT",
|
||||
"14": "第三方雲接入",
|
||||
"15": "紅外遙控器子設備",
|
||||
"16": "BLE-Mesh",
|
||||
"17": "虛擬設備組",
|
||||
"18": "代理網關子設備",
|
||||
"19": "安全級代理網關子設備",
|
||||
"22": "PLC",
|
||||
"23": "僅網線",
|
||||
"24": "Matter",
|
||||
"25": "WiFi+蜂窩網"
|
||||
},
|
||||
"room_name_rule": {
|
||||
"none": "不同步",
|
||||
"home_room": "家庭名 和 房間名 (米家 臥室)",
|
||||
"room": "房間名 (臥室)",
|
||||
"home": "家庭名 (米家)"
|
||||
},
|
||||
"option_status": {
|
||||
"enable": "啟用",
|
||||
"disable": "禁用"
|
||||
},
|
||||
"binary_mode": {
|
||||
"text": "文本傳感器實體",
|
||||
"bool": "二進制傳感器實體"
|
||||
},
|
||||
"device_state": {
|
||||
"add": "新增",
|
||||
"del": "不可用",
|
||||
"offline": "離線"
|
||||
},
|
||||
"lan_ctrl_config": {
|
||||
"notice_net_dup": "\r\n**[提示]** 檢測到多個網卡可能連接同一個網絡,請注意選擇。",
|
||||
"net_unavailable": "接口不可用"
|
||||
}
|
||||
},
|
||||
"oauth2": {
|
||||
"success": {
|
||||
"title": "認證成功",
|
||||
"content": "請關閉此頁面,返回帳號認證頁面點擊“下一步”",
|
||||
"button": "關閉"
|
||||
},
|
||||
"fail": {
|
||||
"title": "認證失敗",
|
||||
"content": "{error_msg},請關閉此頁面,返回帳號認證頁面重新點擊認鏈接進行認證。",
|
||||
"button": "關閉"
|
||||
},
|
||||
"error_msg": {
|
||||
"-10100": "無效的響應參數(“code”或者“state”字段為空)",
|
||||
"-10101": "傳入的“state”字段不一致"
|
||||
}
|
||||
},
|
||||
"miot": {
|
||||
"client": {
|
||||
"invalid_oauth_info": "認證信息失效,雲端鏈路將不可用,請進入 Xiaomi Home 集成頁面,點擊“選項”重新認證",
|
||||
"invalid_device_cache": "緩存設備信息異常,請進入 Xiaomi Home 集成頁面,點擊`選項->更新設備列表`,更新本地設備信息",
|
||||
"invalid_cert_info": "無效的用戶證書,本地中樞鏈路將不可用,請進入 Xiaomi Home 集成頁面,點擊“選項”重新認證",
|
||||
"device_cloud_error": "從雲端獲取設備信息異常,請檢查本地網絡連接",
|
||||
"xiaomi_home_error_title": "Xiaomi Home 集成錯誤",
|
||||
"xiaomi_home_error": "檢測到 **{nick_name}({uid}, {cloud_server})** 出現錯誤,請進入選項頁面重新配置。\n\n**錯誤信息**: \n{message}",
|
||||
"device_list_changed_title": "Xiaomi Home設備列表變化",
|
||||
"device_list_changed": "檢測到 **{nick_name}({uid}, {cloud_server})** 設備信息發生變化,請進入集成選項頁面,點擊`選項->更新設備列表`,更新本地設備信息。\n\n當前網絡狀態:{network_status}\n{message}\n",
|
||||
"device_list_add": "\n**{count} 個新增設備:** \n{message}",
|
||||
"device_list_del": "\n**{count} 個設備不可用:** \n{message}",
|
||||
"device_list_offline": "\n**{count} 個設備離線:** \n{message}",
|
||||
"network_status_online": "在線",
|
||||
"network_status_offline": "離線",
|
||||
"central_state_changed_title": "中枢網關連接狀態",
|
||||
"central_state_changed":"**{nick_name}({uid}, {cloud_server})** 中枢網關本地連接鏈路: {conn_status}",
|
||||
"central_state_connected": "已連接",
|
||||
"central_state_disconnected": "断連",
|
||||
"device_exec_error": "執行錯誤"
|
||||
}
|
||||
},
|
||||
"error": {
|
||||
"common": {
|
||||
"-10000": "未知錯誤",
|
||||
"-10001": "服務不可用",
|
||||
"-10002": "參數無效",
|
||||
"-10003": "資源不足",
|
||||
"-10004": "內部錯誤",
|
||||
"-10005": "權限不足",
|
||||
"-10006": "執行超時",
|
||||
"-10007": "設備離線或者不存在",
|
||||
"-10020": "未授權(OAuth2)",
|
||||
"-10030": "無效的token(HTTP)",
|
||||
"-10040": "無效的消息格式",
|
||||
"-10050": "無效的證書",
|
||||
"-704000000": "未知錯誤",
|
||||
"-704010000": "未授權(設備可能被刪除)",
|
||||
"-704014006": "沒找到設備描述",
|
||||
"-704030013": "Property不可讀",
|
||||
"-704030023": "Property不可寫",
|
||||
"-704030033": "Property不可訂閱",
|
||||
"-704040002": "Service不存在",
|
||||
"-704040003": "Property不存在",
|
||||
"-704040004": "Event不存在",
|
||||
"-704040005": "Action不存在",
|
||||
"-704040999": "功能未上線",
|
||||
"-704042001": "Device不存在",
|
||||
"-704042011": "設備離線",
|
||||
"-704053036": "設備操作超時",
|
||||
"-704053100": "設備在當前狀態下無法執行此操作",
|
||||
"-704083036": "設備操作超時",
|
||||
"-704090001": "Device不存在",
|
||||
"-704220008": "無效的ID",
|
||||
"-704220025": "Action參數個數不匹配",
|
||||
"-704220035": "Action參數錯誤",
|
||||
"-704220043": "Property值錯誤",
|
||||
"-704222034": "Action返回值錯誤",
|
||||
"-705004000": "未知錯誤",
|
||||
"-705004501": "未知錯誤",
|
||||
"-705201013": "Property不可讀",
|
||||
"-705201015": "Action執行錯誤",
|
||||
"-705201023": "Property不可寫",
|
||||
"-705201033": "Property不可訂閱",
|
||||
"-706012000": "未知錯誤",
|
||||
"-706012013": "Property不可讀",
|
||||
"-706012015": "Action執行錯誤",
|
||||
"-706012023": "Property不可寫",
|
||||
"-706012033": "Property不可訂閱",
|
||||
"-706012043": "Property值錯誤",
|
||||
"-706014006": "沒找到設備描述"
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,849 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Copyright (C) 2024 Xiaomi Corporation.
|
||||
|
||||
The ownership and intellectual property rights of Xiaomi Home Assistant
|
||||
Integration and related Xiaomi cloud service API interface provided under this
|
||||
license, including source code and object code (collectively, "Licensed Work"),
|
||||
are owned by Xiaomi. Subject to the terms and conditions of this License, Xiaomi
|
||||
hereby grants you a personal, limited, non-exclusive, non-transferable,
|
||||
non-sublicensable, and royalty-free license to reproduce, use, modify, and
|
||||
distribute the Licensed Work only for your use of Home Assistant for
|
||||
non-commercial purposes. For the avoidance of doubt, Xiaomi does not authorize
|
||||
you to use the Licensed Work for any other purpose, including but not limited
|
||||
to use Licensed Work to develop applications (APP), Web services, and other
|
||||
forms of software.
|
||||
|
||||
You may reproduce and distribute copies of the Licensed Work, with or without
|
||||
modifications, whether in source or object form, provided that you must give
|
||||
any other recipients of the Licensed Work a copy of this License and retain all
|
||||
copyright and disclaimers.
|
||||
|
||||
Xiaomi provides the Licensed Work on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied, including, without
|
||||
limitation, any warranties, undertakes, or conditions of TITLE, NO ERROR OR
|
||||
OMISSION, CONTINUITY, RELIABILITY, NON-INFRINGEMENT, MERCHANTABILITY, or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. In any event, you are solely responsible
|
||||
for any direct, indirect, special, incidental, or consequential damages or
|
||||
losses arising from the use or inability to use the Licensed Work.
|
||||
|
||||
Xiaomi reserves all rights not expressly granted to you in this License.
|
||||
Except for the rights expressly granted by Xiaomi under this License, Xiaomi
|
||||
does not authorize you in any form to use the trademarks, copyrights, or other
|
||||
forms of intellectual property rights of Xiaomi and its affiliates, including,
|
||||
without limitation, without obtaining other written permission from Xiaomi, you
|
||||
shall not use "Xiaomi", "Mijia" and other words related to Xiaomi or words that
|
||||
may make the public associate with Xiaomi in any form to publicize or promote
|
||||
the software or hardware devices that use the Licensed Work.
|
||||
|
||||
Xiaomi has the right to immediately terminate all your authorization under this
|
||||
License in the event:
|
||||
1. You assert patent invalidation, litigation, or other claims against patents
|
||||
or other intellectual property rights of Xiaomi or its affiliates; or,
|
||||
2. You make, have made, manufacture, sell, or offer to sell products that knock
|
||||
off Xiaomi or its affiliates' products.
|
||||
|
||||
MIoT http client.
|
||||
"""
|
||||
import asyncio
|
||||
import base64
|
||||
import hashlib
|
||||
import json
|
||||
import logging
|
||||
import re
|
||||
import time
|
||||
from typing import Any, Optional
|
||||
from urllib.parse import urlencode
|
||||
import aiohttp
|
||||
|
||||
# pylint: disable=relative-beyond-top-level
|
||||
from .common import calc_group_id
|
||||
from .const import (
|
||||
UNSUPPORTED_MODELS,
|
||||
DEFAULT_OAUTH2_API_HOST,
|
||||
MIHOME_HTTP_API_TIMEOUT,
|
||||
OAUTH2_AUTH_URL)
|
||||
from .miot_error import MIoTErrorCode, MIoTHttpError, MIoTOauthError
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
TOKEN_EXPIRES_TS_RATIO = 0.7
|
||||
|
||||
|
||||
class MIoTOauthClient:
|
||||
"""oauth agent url, default: product env."""
|
||||
_main_loop: asyncio.AbstractEventLoop
|
||||
_session: aiohttp.ClientSession
|
||||
_oauth_host: str
|
||||
_client_id: int
|
||||
_redirect_url: str
|
||||
_device_id: str
|
||||
_state: str
|
||||
|
||||
def __init__(
|
||||
self, client_id: str, redirect_url: str, cloud_server: str,
|
||||
uuid: str, loop: Optional[asyncio.AbstractEventLoop] = None
|
||||
) -> None:
|
||||
self._main_loop = loop or asyncio.get_running_loop()
|
||||
if client_id is None or client_id.strip() == '':
|
||||
raise MIoTOauthError('invalid client_id')
|
||||
if not redirect_url:
|
||||
raise MIoTOauthError('invalid redirect_url')
|
||||
if not cloud_server:
|
||||
raise MIoTOauthError('invalid cloud_server')
|
||||
if not uuid:
|
||||
raise MIoTOauthError('invalid uuid')
|
||||
|
||||
self._client_id = int(client_id)
|
||||
self._redirect_url = redirect_url
|
||||
if cloud_server == 'cn':
|
||||
self._oauth_host = DEFAULT_OAUTH2_API_HOST
|
||||
else:
|
||||
self._oauth_host = f'{cloud_server}.{DEFAULT_OAUTH2_API_HOST}'
|
||||
self._device_id = f'ha.{uuid}'
|
||||
self._state = hashlib.sha1(
|
||||
f'd={self._device_id}'.encode('utf-8')).hexdigest()
|
||||
self._session = aiohttp.ClientSession(loop=self._main_loop)
|
||||
|
||||
@property
|
||||
def state(self) -> str:
|
||||
return self._state
|
||||
|
||||
async def deinit_async(self) -> None:
|
||||
if self._session and not self._session.closed:
|
||||
await self._session.close()
|
||||
|
||||
def set_redirect_url(self, redirect_url: str) -> None:
|
||||
if not isinstance(redirect_url, str) or redirect_url.strip() == '':
|
||||
raise MIoTOauthError('invalid redirect_url')
|
||||
self._redirect_url = redirect_url
|
||||
|
||||
def gen_auth_url(
|
||||
self,
|
||||
redirect_url: Optional[str] = None,
|
||||
state: Optional[str] = None,
|
||||
scope: Optional[list] = None,
|
||||
skip_confirm: Optional[bool] = False,
|
||||
) -> str:
|
||||
"""get auth url
|
||||
|
||||
Args:
|
||||
redirect_url
|
||||
state
|
||||
scope (list, optional):
|
||||
开放数据接口权限 ID,可以传递多个,用空格分隔,具体值可以参考开放
|
||||
[数据接口权限列表](https://dev.mi.com/distribute/doc/details?pId=1518).
|
||||
Defaults to None.\n
|
||||
skip_confirm (bool, optional):
|
||||
默认值为true,授权有效期内的用户在已登录情况下,不显示授权页面,直接通过。
|
||||
如果需要用户每次手动授权,设置为false. Defaults to True.\n
|
||||
|
||||
Returns:
|
||||
str: _description_
|
||||
"""
|
||||
params: dict = {
|
||||
'redirect_uri': redirect_url or self._redirect_url,
|
||||
'client_id': self._client_id,
|
||||
'response_type': 'code',
|
||||
'device_id': self._device_id,
|
||||
'state': self._state
|
||||
}
|
||||
if state:
|
||||
params['state'] = state
|
||||
if scope:
|
||||
params['scope'] = ' '.join(scope).strip()
|
||||
params['skip_confirm'] = skip_confirm
|
||||
encoded_params = urlencode(params)
|
||||
|
||||
return f'{OAUTH2_AUTH_URL}?{encoded_params}'
|
||||
|
||||
async def __get_token_async(self, data) -> dict:
|
||||
http_res = await self._session.get(
|
||||
url=f'https://{self._oauth_host}/app/v2/ha/oauth/get_token',
|
||||
params={'data': json.dumps(data)},
|
||||
headers={'content-type': 'application/x-www-form-urlencoded'},
|
||||
timeout=MIHOME_HTTP_API_TIMEOUT
|
||||
)
|
||||
if http_res.status == 401:
|
||||
raise MIoTOauthError(
|
||||
'unauthorized(401)', MIoTErrorCode.CODE_OAUTH_UNAUTHORIZED)
|
||||
if http_res.status != 200:
|
||||
raise MIoTOauthError(
|
||||
f'invalid http status code, {http_res.status}')
|
||||
|
||||
res_str = await http_res.text()
|
||||
res_obj = json.loads(res_str)
|
||||
if (
|
||||
not res_obj
|
||||
or res_obj.get('code', None) != 0
|
||||
or 'result' not in res_obj
|
||||
or not all(
|
||||
key in res_obj['result']
|
||||
for key in ['access_token', 'refresh_token', 'expires_in'])
|
||||
):
|
||||
raise MIoTOauthError(f'invalid http response, {res_str}')
|
||||
|
||||
return {
|
||||
**res_obj['result'],
|
||||
'expires_ts': int(
|
||||
time.time() +
|
||||
(res_obj['result'].get('expires_in', 0)*TOKEN_EXPIRES_TS_RATIO))
|
||||
}
|
||||
|
||||
async def get_access_token_async(self, code: str) -> dict:
|
||||
"""get access token by authorization code
|
||||
|
||||
Args:
|
||||
code (str): auth code
|
||||
|
||||
Returns:
|
||||
str: _description_
|
||||
"""
|
||||
if not isinstance(code, str):
|
||||
raise MIoTOauthError('invalid code')
|
||||
|
||||
return await self.__get_token_async(data={
|
||||
'client_id': self._client_id,
|
||||
'redirect_uri': self._redirect_url,
|
||||
'code': code,
|
||||
'device_id': self._device_id
|
||||
})
|
||||
|
||||
async def refresh_access_token_async(self, refresh_token: str) -> dict:
|
||||
"""get access token by refresh token.
|
||||
|
||||
Args:
|
||||
refresh_token (str): refresh_token
|
||||
|
||||
Returns:
|
||||
str: _description_
|
||||
"""
|
||||
if not isinstance(refresh_token, str):
|
||||
raise MIoTOauthError('invalid refresh_token')
|
||||
|
||||
return await self.__get_token_async(data={
|
||||
'client_id': self._client_id,
|
||||
'redirect_uri': self._redirect_url,
|
||||
'refresh_token': refresh_token,
|
||||
})
|
||||
|
||||
|
||||
class MIoTHttpClient:
|
||||
"""MIoT http client."""
|
||||
# pylint: disable=inconsistent-quotes
|
||||
GET_PROP_AGGREGATE_INTERVAL: float = 0.2
|
||||
GET_PROP_MAX_REQ_COUNT = 150
|
||||
_main_loop: asyncio.AbstractEventLoop
|
||||
_session: aiohttp.ClientSession
|
||||
_host: str
|
||||
_base_url: str
|
||||
_client_id: str
|
||||
_access_token: str
|
||||
|
||||
_get_prop_timer: Optional[asyncio.TimerHandle]
|
||||
_get_prop_list: dict[str, dict]
|
||||
|
||||
def __init__(
|
||||
self, cloud_server: str, client_id: str, access_token: str,
|
||||
loop: Optional[asyncio.AbstractEventLoop] = None
|
||||
) -> None:
|
||||
self._main_loop = loop or asyncio.get_running_loop()
|
||||
self._host = DEFAULT_OAUTH2_API_HOST
|
||||
self._base_url = ''
|
||||
self._client_id = ''
|
||||
self._access_token = ''
|
||||
|
||||
self._get_prop_timer = None
|
||||
self._get_prop_list = {}
|
||||
|
||||
if (
|
||||
not isinstance(cloud_server, str)
|
||||
or not isinstance(client_id, str)
|
||||
or not isinstance(access_token, str)
|
||||
):
|
||||
raise MIoTHttpError('invalid params')
|
||||
|
||||
self.update_http_header(
|
||||
cloud_server=cloud_server, client_id=client_id,
|
||||
access_token=access_token)
|
||||
|
||||
self._session = aiohttp.ClientSession(loop=self._main_loop)
|
||||
|
||||
async def deinit_async(self) -> None:
|
||||
if self._get_prop_timer:
|
||||
self._get_prop_timer.cancel()
|
||||
self._get_prop_timer = None
|
||||
for item in self._get_prop_list.values():
|
||||
fut: Optional[asyncio.Future] = item.get('fut', None)
|
||||
if fut:
|
||||
fut.cancel()
|
||||
self._get_prop_list.clear()
|
||||
if self._session and not self._session.closed:
|
||||
await self._session.close()
|
||||
|
||||
def update_http_header(
|
||||
self, cloud_server: Optional[str] = None,
|
||||
client_id: Optional[str] = None,
|
||||
access_token: Optional[str] = None
|
||||
) -> None:
|
||||
if isinstance(cloud_server, str):
|
||||
if cloud_server != 'cn':
|
||||
self._host = f'{cloud_server}.{DEFAULT_OAUTH2_API_HOST}'
|
||||
self._base_url = f'https://{self._host}'
|
||||
if isinstance(client_id, str):
|
||||
self._client_id = client_id
|
||||
if isinstance(access_token, str):
|
||||
self._access_token = access_token
|
||||
|
||||
@property
|
||||
def __api_request_headers(self) -> dict:
|
||||
return {
|
||||
'Host': self._host,
|
||||
'X-Client-BizId': 'haapi',
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': f'Bearer{self._access_token}',
|
||||
'X-Client-AppId': self._client_id,
|
||||
}
|
||||
|
||||
# pylint: disable=unused-private-member
|
||||
async def __mihome_api_get_async(
|
||||
self, url_path: str, params: dict,
|
||||
timeout: int = MIHOME_HTTP_API_TIMEOUT
|
||||
) -> dict:
|
||||
http_res = await self._session.get(
|
||||
url=f'{self._base_url}{url_path}',
|
||||
params=params,
|
||||
headers=self.__api_request_headers,
|
||||
timeout=timeout)
|
||||
if http_res.status == 401:
|
||||
raise MIoTHttpError(
|
||||
'mihome api get failed, unauthorized(401)',
|
||||
MIoTErrorCode.CODE_HTTP_INVALID_ACCESS_TOKEN)
|
||||
if http_res.status != 200:
|
||||
raise MIoTHttpError(
|
||||
f'mihome api get failed, {http_res.status}, '
|
||||
f'{url_path}, {params}')
|
||||
res_str = await http_res.text()
|
||||
res_obj: dict = json.loads(res_str)
|
||||
if res_obj.get('code', None) != 0:
|
||||
raise MIoTHttpError(
|
||||
f'invalid response code, {res_obj.get("code",None)}, '
|
||||
f'{res_obj.get("message","")}')
|
||||
_LOGGER.debug(
|
||||
'mihome api get, %s%s, %s -> %s',
|
||||
self._base_url, url_path, params, res_obj)
|
||||
return res_obj
|
||||
|
||||
async def __mihome_api_post_async(
|
||||
self, url_path: str, data: dict,
|
||||
timeout: int = MIHOME_HTTP_API_TIMEOUT
|
||||
) -> dict:
|
||||
http_res = await self._session.post(
|
||||
url=f'{self._base_url}{url_path}',
|
||||
json=data,
|
||||
headers=self.__api_request_headers,
|
||||
timeout=timeout)
|
||||
if http_res.status == 401:
|
||||
raise MIoTHttpError(
|
||||
'mihome api get failed, unauthorized(401)',
|
||||
MIoTErrorCode.CODE_HTTP_INVALID_ACCESS_TOKEN)
|
||||
if http_res.status != 200:
|
||||
raise MIoTHttpError(
|
||||
f'mihome api post failed, {http_res.status}, '
|
||||
f'{url_path}, {data}')
|
||||
res_str = await http_res.text()
|
||||
res_obj: dict = json.loads(res_str)
|
||||
if res_obj.get('code', None) != 0:
|
||||
raise MIoTHttpError(
|
||||
f'invalid response code, {res_obj.get("code",None)}, '
|
||||
f'{res_obj.get("message","")}')
|
||||
_LOGGER.debug(
|
||||
'mihome api post, %s%s, %s -> %s',
|
||||
self._base_url, url_path, data, res_obj)
|
||||
return res_obj
|
||||
|
||||
async def get_user_info_async(self) -> dict:
|
||||
http_res = await self._session.get(
|
||||
url='https://open.account.xiaomi.com/user/profile',
|
||||
params={
|
||||
'clientId': self._client_id, 'token': self._access_token},
|
||||
headers={'content-type': 'application/x-www-form-urlencoded'},
|
||||
timeout=MIHOME_HTTP_API_TIMEOUT
|
||||
)
|
||||
|
||||
res_str = await http_res.text()
|
||||
res_obj = json.loads(res_str)
|
||||
if (
|
||||
not res_obj
|
||||
or res_obj.get('code', None) != 0
|
||||
or 'data' not in res_obj
|
||||
or 'miliaoNick' not in res_obj['data']
|
||||
):
|
||||
raise MIoTOauthError(f'invalid http response, {http_res.text}')
|
||||
|
||||
return res_obj['data']
|
||||
|
||||
async def get_central_cert_async(self, csr: str) -> str:
|
||||
if not isinstance(csr, str):
|
||||
raise MIoTHttpError('invalid params')
|
||||
|
||||
res_obj: dict = await self.__mihome_api_post_async(
|
||||
url_path='/app/v2/ha/oauth/get_central_crt',
|
||||
data={
|
||||
'csr': str(base64.b64encode(csr.encode('utf-8')), 'utf-8')
|
||||
}
|
||||
)
|
||||
if 'result' not in res_obj:
|
||||
raise MIoTHttpError('invalid response result')
|
||||
cert: str = res_obj['result'].get('cert', None)
|
||||
if not isinstance(cert, str):
|
||||
raise MIoTHttpError('invalid cert')
|
||||
|
||||
return cert
|
||||
|
||||
async def __get_dev_room_page_async(
|
||||
self, max_id: Optional[str] = None
|
||||
) -> dict:
|
||||
res_obj = await self.__mihome_api_post_async(
|
||||
url_path='/app/v2/homeroom/get_dev_room_page',
|
||||
data={
|
||||
'start_id': max_id,
|
||||
'limit': 150,
|
||||
},
|
||||
)
|
||||
if 'result' not in res_obj and 'info' not in res_obj['result']:
|
||||
raise MIoTHttpError('invalid response result')
|
||||
home_list: dict = {}
|
||||
for home in res_obj['result']['info']:
|
||||
if 'id' not in home:
|
||||
_LOGGER.error(
|
||||
'get dev room page error, invalid home, %s', home)
|
||||
continue
|
||||
home_list[str(home['id'])] = {'dids': home.get(
|
||||
'dids', None) or [], 'room_info': {}}
|
||||
for room in home.get('roomlist', []):
|
||||
if 'id' not in room:
|
||||
_LOGGER.error(
|
||||
'get dev room page error, invalid room, %s', room)
|
||||
continue
|
||||
home_list[str(home['id'])]['room_info'][str(room['id'])] = {
|
||||
'dids': room.get('dids', None) or []}
|
||||
if (
|
||||
res_obj['result'].get('has_more', False)
|
||||
and isinstance(res_obj['result'].get('max_id', None), str)
|
||||
):
|
||||
next_list = await self.__get_dev_room_page_async(
|
||||
max_id=res_obj['result']['max_id'])
|
||||
for home_id, info in next_list.items():
|
||||
home_list.setdefault(home_id, {'dids': [], 'room_info': {}})
|
||||
home_list[home_id]['dids'].extend(info['dids'])
|
||||
for room_id, info in info['room_info'].items():
|
||||
home_list[home_id]['room_info'].setdefault(
|
||||
room_id, {'dids': []})
|
||||
home_list[home_id]['room_info'][room_id]['dids'].extend(
|
||||
info['dids'])
|
||||
|
||||
return home_list
|
||||
|
||||
async def get_separated_shared_devices_async(self) -> dict[str, dict]:
|
||||
separated_shared_devices: dict = {}
|
||||
device_list: dict[str, dict] = await self.__get_device_list_page_async(
|
||||
dids=[], start_did=None)
|
||||
for did, value in device_list.items():
|
||||
if value['owner'] is not None and ('userid' in value['owner']) and (
|
||||
'nickname' in value['owner']
|
||||
):
|
||||
separated_shared_devices.setdefault(did, value['owner'])
|
||||
return separated_shared_devices
|
||||
|
||||
async def get_homeinfos_async(self) -> dict:
|
||||
res_obj = await self.__mihome_api_post_async(
|
||||
url_path='/app/v2/homeroom/gethome',
|
||||
data={
|
||||
'limit': 150,
|
||||
'fetch_share': True,
|
||||
'fetch_share_dev': True,
|
||||
'plat_form': 0,
|
||||
'app_ver': 9,
|
||||
},
|
||||
)
|
||||
if 'result' not in res_obj:
|
||||
raise MIoTHttpError('invalid response result')
|
||||
|
||||
uid: Optional[str] = None
|
||||
home_infos: dict = {}
|
||||
for device_source in ['homelist', 'share_home_list']:
|
||||
home_infos.setdefault(device_source, {})
|
||||
for home in res_obj['result'].get(device_source, []):
|
||||
if (
|
||||
'id' not in home
|
||||
or 'name' not in home
|
||||
or 'roomlist' not in home
|
||||
):
|
||||
continue
|
||||
if uid is None and device_source == 'homelist':
|
||||
uid = str(home['uid'])
|
||||
home_infos[device_source][home['id']] = {
|
||||
'home_id': home['id'],
|
||||
'home_name': home['name'],
|
||||
'city_id': home.get('city_id', None),
|
||||
'longitude': home.get('longitude', None),
|
||||
'latitude': home.get('latitude', None),
|
||||
'address': home.get('address', None),
|
||||
'dids': home.get('dids', []),
|
||||
'room_info': {
|
||||
room['id']: {
|
||||
'room_id': room['id'],
|
||||
'room_name': room['name'],
|
||||
'dids': room.get('dids', [])
|
||||
}
|
||||
for room in home.get('roomlist', [])
|
||||
if 'id' in room
|
||||
},
|
||||
'group_id': calc_group_id(
|
||||
uid=home['uid'], home_id=home['id']),
|
||||
'uid': str(home['uid'])
|
||||
}
|
||||
home_infos['uid'] = uid
|
||||
if (
|
||||
res_obj['result'].get('has_more', False)
|
||||
and isinstance(res_obj['result'].get('max_id', None), str)
|
||||
):
|
||||
more_list = await self.__get_dev_room_page_async(
|
||||
max_id=res_obj['result']['max_id'])
|
||||
for device_source in ['homelist', 'share_home_list']:
|
||||
for home_id, info in more_list.items():
|
||||
if home_id not in home_infos[device_source]:
|
||||
_LOGGER.info('unknown home, %s, %s', home_id, info)
|
||||
continue
|
||||
home_infos[device_source][home_id]['dids'].extend(
|
||||
info['dids'])
|
||||
for room_id, info in info['room_info'].items():
|
||||
home_infos[device_source][home_id][
|
||||
'room_info'].setdefault(
|
||||
room_id, {
|
||||
'room_id': room_id,
|
||||
'room_name': '',
|
||||
'dids': []})
|
||||
home_infos[device_source][home_id]['room_info'][
|
||||
room_id]['dids'].extend(info['dids'])
|
||||
|
||||
return {
|
||||
'uid': uid,
|
||||
'home_list': home_infos.get('homelist', {}),
|
||||
'share_home_list': home_infos.get('share_home_list', [])
|
||||
}
|
||||
|
||||
async def get_uid_async(self) -> str:
|
||||
return (await self.get_homeinfos_async()).get('uid', None)
|
||||
|
||||
async def __get_device_list_page_async(
|
||||
self, dids: list[str], start_did: Optional[str] = None
|
||||
) -> dict[str, dict]:
|
||||
req_data: dict = {
|
||||
'limit': 200,
|
||||
'get_split_device': True,
|
||||
'get_third_device': True,
|
||||
'dids': dids
|
||||
}
|
||||
if start_did:
|
||||
req_data['start_did'] = start_did
|
||||
device_infos: dict = {}
|
||||
res_obj = await self.__mihome_api_post_async(
|
||||
url_path='/app/v2/home/device_list_page',
|
||||
data=req_data
|
||||
)
|
||||
if 'result' not in res_obj:
|
||||
raise MIoTHttpError('invalid response result')
|
||||
res_obj = res_obj['result']
|
||||
|
||||
for device in res_obj.get('list', []) or []:
|
||||
did = device.get('did', None)
|
||||
name = device.get('name', None)
|
||||
urn = device.get('spec_type', None)
|
||||
model = device.get('model', None)
|
||||
if did is None or name is None:
|
||||
_LOGGER.info(
|
||||
'invalid device, cloud, %s', device)
|
||||
continue
|
||||
if urn is None or model is None:
|
||||
_LOGGER.info(
|
||||
'missing the urn|model field, cloud, %s', device)
|
||||
continue
|
||||
if did.startswith('miwifi.'):
|
||||
# The miwifi.* routers defined SPEC functions, but none of them
|
||||
# were implemented.
|
||||
_LOGGER.info('ignore miwifi.* device, cloud, %s', did)
|
||||
continue
|
||||
if model in UNSUPPORTED_MODELS:
|
||||
_LOGGER.info('ignore unsupported model %s, cloud, %s',
|
||||
model, did)
|
||||
continue
|
||||
device_infos[did] = {
|
||||
'did': did,
|
||||
'uid': device.get('uid', None),
|
||||
'name': name,
|
||||
'urn': urn,
|
||||
'model': model,
|
||||
'connect_type': device.get('pid', -1),
|
||||
'token': device.get('token', None),
|
||||
'online': device.get('isOnline', False),
|
||||
'icon': device.get('icon', None),
|
||||
'parent_id': device.get('parent_id', None),
|
||||
'manufacturer': model.split('.')[0],
|
||||
# 2: xiao-ai, 1: general speaker
|
||||
'voice_ctrl': device.get('voice_ctrl', 0),
|
||||
'rssi': device.get('rssi', None),
|
||||
'owner': device.get('owner', None),
|
||||
'pid': device.get('pid', None),
|
||||
'local_ip': device.get('local_ip', None),
|
||||
'ssid': device.get('ssid', None),
|
||||
'bssid': device.get('bssid', None),
|
||||
'order_time': device.get('orderTime', 0),
|
||||
'fw_version': device.get('extra', {}).get(
|
||||
'fw_version', None)
|
||||
}
|
||||
|
||||
next_start_did = res_obj.get('next_start_did', None)
|
||||
if res_obj.get('has_more', False) and next_start_did:
|
||||
device_infos.update(await self.__get_device_list_page_async(
|
||||
dids=dids, start_did=next_start_did))
|
||||
|
||||
return device_infos
|
||||
|
||||
async def get_devices_with_dids_async(
|
||||
self, dids: list[str]
|
||||
) -> Optional[dict[str, dict]]:
|
||||
results: list[dict[str, dict]] = await asyncio.gather(
|
||||
*[self.__get_device_list_page_async(dids=dids[index:index+150])
|
||||
for index in range(0, len(dids), 150)])
|
||||
devices = {}
|
||||
for result in results:
|
||||
if result is None:
|
||||
return None
|
||||
devices.update(result)
|
||||
return devices
|
||||
|
||||
async def get_devices_async(
|
||||
self, home_ids: Optional[list[str]] = None
|
||||
) -> dict[str, dict]:
|
||||
homeinfos = await self.get_homeinfos_async()
|
||||
homes: dict[str, dict[str, Any]] = {}
|
||||
devices: dict[str, dict] = {}
|
||||
for device_type in ['home_list', 'share_home_list']:
|
||||
homes.setdefault(device_type, {})
|
||||
for home_id, home_info in (homeinfos.get(
|
||||
device_type, None) or {}).items():
|
||||
if isinstance(home_ids, list) and home_id not in home_ids:
|
||||
continue
|
||||
home_name: str = home_info['home_name']
|
||||
group_id: str = home_info['group_id']
|
||||
homes[device_type].setdefault(
|
||||
home_id, {
|
||||
'home_name': home_name,
|
||||
'uid': home_info['uid'],
|
||||
'group_id': group_id,
|
||||
'room_info': {}
|
||||
})
|
||||
devices.update({did: {
|
||||
'home_id': home_id,
|
||||
'home_name': home_name,
|
||||
'room_id': home_id,
|
||||
'room_name': home_name,
|
||||
'group_id': group_id
|
||||
} for did in home_info.get('dids', [])})
|
||||
for room_id, room_info in home_info.get('room_info').items():
|
||||
room_name: str = room_info.get('room_name', '')
|
||||
homes[device_type][home_id]['room_info'][
|
||||
room_id] = room_name
|
||||
devices.update({
|
||||
did: {
|
||||
'home_id': home_id,
|
||||
'home_name': home_name,
|
||||
'room_id': room_id,
|
||||
'room_name': room_name,
|
||||
'group_id': group_id
|
||||
} for did in room_info.get('dids', [])})
|
||||
separated_shared_devices: dict = (
|
||||
await self.get_separated_shared_devices_async())
|
||||
if separated_shared_devices:
|
||||
homes.setdefault('separated_shared_list', {})
|
||||
for did, owner in separated_shared_devices.items():
|
||||
owner_id = str(owner['userid'])
|
||||
homes['separated_shared_list'].setdefault(owner_id,{
|
||||
'home_name': owner['nickname'],
|
||||
'uid': owner_id,
|
||||
'group_id': 'NotSupport',
|
||||
'room_info': {'shared_device': 'shared_device'}
|
||||
})
|
||||
devices.update({did: {
|
||||
'home_id': owner_id,
|
||||
'home_name': owner['nickname'],
|
||||
'room_id': 'shared_device',
|
||||
'room_name': 'shared_device',
|
||||
'group_id': 'NotSupport'
|
||||
}})
|
||||
dids = sorted(list(devices.keys()))
|
||||
results = await self.get_devices_with_dids_async(dids=dids)
|
||||
if results is None:
|
||||
raise MIoTHttpError('get devices failed')
|
||||
for did in dids:
|
||||
if did not in results:
|
||||
devices.pop(did, None)
|
||||
_LOGGER.info('get device info failed, %s', did)
|
||||
continue
|
||||
devices[did].update(results[did])
|
||||
# Whether sub devices
|
||||
match_str = re.search(r'\.s\d+$', did)
|
||||
if not match_str:
|
||||
continue
|
||||
device = devices.pop(did, None)
|
||||
parent_did = did.replace(match_str.group(), '')
|
||||
if parent_did in devices:
|
||||
devices[parent_did].setdefault('sub_devices', {})
|
||||
devices[parent_did]['sub_devices'][match_str.group()[
|
||||
1:]] = device
|
||||
else:
|
||||
_LOGGER.error(
|
||||
'unknown sub devices, %s, %s', did, parent_did)
|
||||
return {
|
||||
'uid': homeinfos['uid'],
|
||||
'homes': homes,
|
||||
'devices': devices
|
||||
}
|
||||
|
||||
async def get_props_async(self, params: list) -> list:
|
||||
"""
|
||||
params = [{"did": "xxxx", "siid": 2, "piid": 1},
|
||||
{"did": "xxxxxx", "siid": 2, "piid": 2}]
|
||||
"""
|
||||
res_obj = await self.__mihome_api_post_async(
|
||||
url_path='/app/v2/miotspec/prop/get',
|
||||
data={
|
||||
'datasource': 1,
|
||||
'params': params
|
||||
},
|
||||
)
|
||||
if 'result' not in res_obj:
|
||||
raise MIoTHttpError('invalid response result')
|
||||
return res_obj['result']
|
||||
|
||||
async def __get_prop_async(self, did: str, siid: int, piid: int) -> Any:
|
||||
results = await self.get_props_async(
|
||||
params=[{'did': did, 'siid': siid, 'piid': piid}])
|
||||
if not results:
|
||||
return None
|
||||
result = results[0]
|
||||
if 'value' not in result:
|
||||
return None
|
||||
return result['value']
|
||||
|
||||
async def __get_prop_handler(self) -> bool:
|
||||
props_req: set[str] = set()
|
||||
props_buffer: list[dict] = []
|
||||
|
||||
for key, item in self._get_prop_list.items():
|
||||
if item.get('tag', False):
|
||||
continue
|
||||
# NOTICE: max req prop
|
||||
if len(props_req) >= self.GET_PROP_MAX_REQ_COUNT:
|
||||
break
|
||||
item['tag'] = True
|
||||
props_buffer.append(item['param'])
|
||||
props_req.add(key)
|
||||
|
||||
if not props_buffer:
|
||||
_LOGGER.error('get prop error, empty request list')
|
||||
return False
|
||||
results = await self.get_props_async(props_buffer)
|
||||
|
||||
for result in results:
|
||||
if not all(
|
||||
key in result for key in ['did', 'siid', 'piid', 'value']):
|
||||
continue
|
||||
key = f'{result["did"]}.{result["siid"]}.{result["piid"]}'
|
||||
prop_obj = self._get_prop_list.pop(key, None)
|
||||
if prop_obj is None:
|
||||
_LOGGER.info('get prop error, key not exists, %s', result)
|
||||
continue
|
||||
prop_obj['fut'].set_result(result['value'])
|
||||
props_req.remove(key)
|
||||
|
||||
for key in props_req:
|
||||
prop_obj = self._get_prop_list.pop(key, None)
|
||||
if prop_obj is None:
|
||||
continue
|
||||
prop_obj['fut'].set_result(None)
|
||||
if props_req:
|
||||
_LOGGER.info(
|
||||
'get prop from cloud failed, %s', props_req)
|
||||
|
||||
if self._get_prop_list:
|
||||
self._get_prop_timer = self._main_loop.call_later(
|
||||
self.GET_PROP_AGGREGATE_INTERVAL,
|
||||
lambda: self._main_loop.create_task(
|
||||
self.__get_prop_handler()))
|
||||
else:
|
||||
self._get_prop_timer = None
|
||||
return True
|
||||
|
||||
async def get_prop_async(
|
||||
self, did: str, siid: int, piid: int, immediately: bool = False
|
||||
) -> Any:
|
||||
if immediately:
|
||||
return await self.__get_prop_async(did, siid, piid)
|
||||
key: str = f'{did}.{siid}.{piid}'
|
||||
prop_obj = self._get_prop_list.get(key, None)
|
||||
if prop_obj:
|
||||
return await prop_obj['fut']
|
||||
fut = self._main_loop.create_future()
|
||||
self._get_prop_list[key] = {
|
||||
'param': {'did': did, 'siid': siid, 'piid': piid},
|
||||
'fut': fut
|
||||
}
|
||||
if self._get_prop_timer is None:
|
||||
self._get_prop_timer = self._main_loop.call_later(
|
||||
self.GET_PROP_AGGREGATE_INTERVAL,
|
||||
lambda: self._main_loop.create_task(
|
||||
self.__get_prop_handler()))
|
||||
|
||||
return await fut
|
||||
|
||||
async def set_prop_async(self, params: list) -> list:
|
||||
"""
|
||||
params = [{"did": "xxxx", "siid": 2, "piid": 1, "value": False}]
|
||||
"""
|
||||
res_obj = await self.__mihome_api_post_async(
|
||||
url_path='/app/v2/miotspec/prop/set',
|
||||
data={
|
||||
'params': params
|
||||
},
|
||||
timeout=15
|
||||
)
|
||||
if 'result' not in res_obj:
|
||||
raise MIoTHttpError('invalid response result')
|
||||
|
||||
return res_obj['result']
|
||||
|
||||
async def action_async(
|
||||
self, did: str, siid: int, aiid: int, in_list: list[dict]
|
||||
) -> dict:
|
||||
"""
|
||||
params = {"did": "xxxx", "siid": 2, "aiid": 1, "in": []}
|
||||
"""
|
||||
# NOTICE: Non-standard action param
|
||||
res_obj = await self.__mihome_api_post_async(
|
||||
url_path='/app/v2/miotspec/action',
|
||||
data={
|
||||
'params': {
|
||||
'did': did,
|
||||
'siid': siid,
|
||||
'aiid': aiid,
|
||||
'in': [item['value'] for item in in_list]}
|
||||
},
|
||||
timeout=15
|
||||
)
|
||||
if 'result' not in res_obj:
|
||||
raise MIoTHttpError('invalid response result')
|
||||
|
||||
return res_obj['result']
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,150 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Copyright (C) 2024 Xiaomi Corporation.
|
||||
|
||||
The ownership and intellectual property rights of Xiaomi Home Assistant
|
||||
Integration and related Xiaomi cloud service API interface provided under this
|
||||
license, including source code and object code (collectively, "Licensed Work"),
|
||||
are owned by Xiaomi. Subject to the terms and conditions of this License, Xiaomi
|
||||
hereby grants you a personal, limited, non-exclusive, non-transferable,
|
||||
non-sublicensable, and royalty-free license to reproduce, use, modify, and
|
||||
distribute the Licensed Work only for your use of Home Assistant for
|
||||
non-commercial purposes. For the avoidance of doubt, Xiaomi does not authorize
|
||||
you to use the Licensed Work for any other purpose, including but not limited
|
||||
to use Licensed Work to develop applications (APP), Web services, and other
|
||||
forms of software.
|
||||
|
||||
You may reproduce and distribute copies of the Licensed Work, with or without
|
||||
modifications, whether in source or object form, provided that you must give
|
||||
any other recipients of the Licensed Work a copy of this License and retain all
|
||||
copyright and disclaimers.
|
||||
|
||||
Xiaomi provides the Licensed Work on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied, including, without
|
||||
limitation, any warranties, undertakes, or conditions of TITLE, NO ERROR OR
|
||||
OMISSION, CONTINUITY, RELIABILITY, NON-INFRINGEMENT, MERCHANTABILITY, or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. In any event, you are solely responsible
|
||||
for any direct, indirect, special, incidental, or consequential damages or
|
||||
losses arising from the use or inability to use the Licensed Work.
|
||||
|
||||
Xiaomi reserves all rights not expressly granted to you in this License.
|
||||
Except for the rights expressly granted by Xiaomi under this License, Xiaomi
|
||||
does not authorize you in any form to use the trademarks, copyrights, or other
|
||||
forms of intellectual property rights of Xiaomi and its affiliates, including,
|
||||
without limitation, without obtaining other written permission from Xiaomi, you
|
||||
shall not use "Xiaomi", "Mijia" and other words related to Xiaomi or words that
|
||||
may make the public associate with Xiaomi in any form to publicize or promote
|
||||
the software or hardware devices that use the Licensed Work.
|
||||
|
||||
Xiaomi has the right to immediately terminate all your authorization under this
|
||||
License in the event:
|
||||
1. You assert patent invalidation, litigation, or other claims against patents
|
||||
or other intellectual property rights of Xiaomi or its affiliates; or,
|
||||
2. You make, have made, manufacture, sell, or offer to sell products that knock
|
||||
off Xiaomi or its affiliates' products.
|
||||
|
||||
MIoT error code and exception.
|
||||
"""
|
||||
from enum import Enum
|
||||
from typing import Any
|
||||
|
||||
|
||||
class MIoTErrorCode(Enum):
|
||||
"""MIoT error code."""
|
||||
# Base error code
|
||||
CODE_UNKNOWN = -10000
|
||||
CODE_UNAVAILABLE = -10001
|
||||
CODE_INVALID_PARAMS = -10002
|
||||
CODE_RESOURCE_ERROR = -10003
|
||||
CODE_INTERNAL_ERROR = -10004
|
||||
CODE_UNAUTHORIZED_ACCESS = -10005
|
||||
CODE_TIMEOUT = -10006
|
||||
# OAuth error code
|
||||
CODE_OAUTH_UNAUTHORIZED = -10020
|
||||
# Http error code
|
||||
CODE_HTTP_INVALID_ACCESS_TOKEN = -10030
|
||||
# MIoT mips error code
|
||||
CODE_MIPS_INVALID_RESULT = -10040
|
||||
# MIoT cert error code
|
||||
CODE_CERT_INVALID_CERT = -10050
|
||||
# MIoT spec error code, -10060
|
||||
# MIoT storage error code, -10070
|
||||
# MIoT ev error code, -10080
|
||||
# Mips service error code, -10090
|
||||
# Config flow error code, -10100
|
||||
CODE_CONFIG_INVALID_INPUT = -10100
|
||||
CODE_CONFIG_INVALID_STATE = -10101
|
||||
# Options flow error code , -10110
|
||||
# MIoT lan error code, -10120
|
||||
CODE_LAN_UNAVAILABLE = -10120
|
||||
|
||||
|
||||
class MIoTError(Exception):
|
||||
"""MIoT error."""
|
||||
code: MIoTErrorCode
|
||||
message: Any
|
||||
|
||||
def __init__(
|
||||
self, message: Any, code: MIoTErrorCode = MIoTErrorCode.CODE_UNKNOWN
|
||||
) -> None:
|
||||
self.message = message
|
||||
self.code = code
|
||||
super().__init__(self.message)
|
||||
|
||||
def to_str(self) -> str:
|
||||
return f'{{"code":{self.code.value},"message":"{self.message}"}}'
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
return {"code": self.code.value, "message": self.message}
|
||||
|
||||
|
||||
class MIoTOauthError(MIoTError):
|
||||
...
|
||||
|
||||
|
||||
class MIoTHttpError(MIoTError):
|
||||
...
|
||||
|
||||
|
||||
class MIoTMipsError(MIoTError):
|
||||
...
|
||||
|
||||
|
||||
class MIoTDeviceError(MIoTError):
|
||||
...
|
||||
|
||||
|
||||
class MIoTSpecError(MIoTError):
|
||||
...
|
||||
|
||||
|
||||
class MIoTStorageError(MIoTError):
|
||||
...
|
||||
|
||||
|
||||
class MIoTCertError(MIoTError):
|
||||
...
|
||||
|
||||
|
||||
class MIoTClientError(MIoTError):
|
||||
...
|
||||
|
||||
|
||||
class MIoTEvError(MIoTError):
|
||||
...
|
||||
|
||||
|
||||
class MipsServiceError(MIoTError):
|
||||
...
|
||||
|
||||
|
||||
class MIoTConfigError(MIoTError):
|
||||
...
|
||||
|
||||
|
||||
class MIoTOptionsError(MIoTError):
|
||||
...
|
||||
|
||||
|
||||
class MIoTLanError(MIoTError):
|
||||
...
|
||||
@@ -0,0 +1,110 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Copyright (C) 2024 Xiaomi Corporation.
|
||||
|
||||
The ownership and intellectual property rights of Xiaomi Home Assistant
|
||||
Integration and related Xiaomi cloud service API interface provided under this
|
||||
license, including source code and object code (collectively, "Licensed Work"),
|
||||
are owned by Xiaomi. Subject to the terms and conditions of this License, Xiaomi
|
||||
hereby grants you a personal, limited, non-exclusive, non-transferable,
|
||||
non-sublicensable, and royalty-free license to reproduce, use, modify, and
|
||||
distribute the Licensed Work only for your use of Home Assistant for
|
||||
non-commercial purposes. For the avoidance of doubt, Xiaomi does not authorize
|
||||
you to use the Licensed Work for any other purpose, including but not limited
|
||||
to use Licensed Work to develop applications (APP), Web services, and other
|
||||
forms of software.
|
||||
|
||||
You may reproduce and distribute copies of the Licensed Work, with or without
|
||||
modifications, whether in source or object form, provided that you must give
|
||||
any other recipients of the Licensed Work a copy of this License and retain all
|
||||
copyright and disclaimers.
|
||||
|
||||
Xiaomi provides the Licensed Work on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied, including, without
|
||||
limitation, any warranties, undertakes, or conditions of TITLE, NO ERROR OR
|
||||
OMISSION, CONTINUITY, RELIABILITY, NON-INFRINGEMENT, MERCHANTABILITY, or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. In any event, you are solely responsible
|
||||
for any direct, indirect, special, incidental, or consequential damages or
|
||||
losses arising from the use or inability to use the Licensed Work.
|
||||
|
||||
Xiaomi reserves all rights not expressly granted to you in this License.
|
||||
Except for the rights expressly granted by Xiaomi under this License, Xiaomi
|
||||
does not authorize you in any form to use the trademarks, copyrights, or other
|
||||
forms of intellectual property rights of Xiaomi and its affiliates, including,
|
||||
without limitation, without obtaining other written permission from Xiaomi, you
|
||||
shall not use "Xiaomi", "Mijia" and other words related to Xiaomi or words that
|
||||
may make the public associate with Xiaomi in any form to publicize or promote
|
||||
the software or hardware devices that use the Licensed Work.
|
||||
|
||||
Xiaomi has the right to immediately terminate all your authorization under this
|
||||
License in the event:
|
||||
1. You assert patent invalidation, litigation, or other claims against patents
|
||||
or other intellectual property rights of Xiaomi or its affiliates; or,
|
||||
2. You make, have made, manufacture, sell, or offer to sell products that knock
|
||||
off Xiaomi or its affiliates' products.
|
||||
|
||||
MIoT internationalization translation.
|
||||
"""
|
||||
import asyncio
|
||||
import logging
|
||||
import os
|
||||
from typing import Optional, Union
|
||||
|
||||
# pylint: disable=relative-beyond-top-level
|
||||
from .common import load_json_file
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class MIoTI18n:
|
||||
"""MIoT Internationalization Translation.
|
||||
Translate by Copilot, which does not guarantee the accuracy of the
|
||||
translation. If there is a problem with the translation, please submit
|
||||
the ISSUE feedback. After the review, we will modify it as soon as possible.
|
||||
"""
|
||||
_main_loop: asyncio.AbstractEventLoop
|
||||
_lang: str
|
||||
_data: dict
|
||||
|
||||
def __init__(
|
||||
self, lang: str, loop: Optional[asyncio.AbstractEventLoop]
|
||||
) -> None:
|
||||
self._main_loop = loop or asyncio.get_event_loop()
|
||||
self._lang = lang
|
||||
self._data = {}
|
||||
|
||||
async def init_async(self) -> None:
|
||||
if self._data:
|
||||
return
|
||||
data = None
|
||||
self._data = {}
|
||||
try:
|
||||
data = await self._main_loop.run_in_executor(
|
||||
None, load_json_file,
|
||||
os.path.join(
|
||||
os.path.dirname(os.path.abspath(__file__)),
|
||||
f'i18n/{self._lang}.json'))
|
||||
except Exception as err: # pylint: disable=broad-exception-caught
|
||||
_LOGGER.error('load file error, %s', err)
|
||||
return
|
||||
# Check if the file is a valid JSON file
|
||||
if not isinstance(data, dict):
|
||||
_LOGGER.error('valid file, %s', data)
|
||||
return
|
||||
self._data = data
|
||||
|
||||
async def deinit_async(self) -> None:
|
||||
self._data = {}
|
||||
|
||||
def translate(
|
||||
self, key: str, replace: Optional[dict[str, str]] = None
|
||||
) -> Union[str, dict, None]:
|
||||
result = self._data
|
||||
for item in key.split('.'):
|
||||
if item not in result:
|
||||
return None
|
||||
result = result[item]
|
||||
if isinstance(result, str) and replace:
|
||||
for k, v in replace.items():
|
||||
result = result.replace('{'+k+'}', str(v))
|
||||
return result or None
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,285 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Copyright (C) 2024 Xiaomi Corporation.
|
||||
|
||||
The ownership and intellectual property rights of Xiaomi Home Assistant
|
||||
Integration and related Xiaomi cloud service API interface provided under this
|
||||
license, including source code and object code (collectively, "Licensed Work"),
|
||||
are owned by Xiaomi. Subject to the terms and conditions of this License, Xiaomi
|
||||
hereby grants you a personal, limited, non-exclusive, non-transferable,
|
||||
non-sublicensable, and royalty-free license to reproduce, use, modify, and
|
||||
distribute the Licensed Work only for your use of Home Assistant for
|
||||
non-commercial purposes. For the avoidance of doubt, Xiaomi does not authorize
|
||||
you to use the Licensed Work for any other purpose, including but not limited
|
||||
to use Licensed Work to develop applications (APP), Web services, and other
|
||||
forms of software.
|
||||
|
||||
You may reproduce and distribute copies of the Licensed Work, with or without
|
||||
modifications, whether in source or object form, provided that you must give
|
||||
any other recipients of the Licensed Work a copy of this License and retain all
|
||||
copyright and disclaimers.
|
||||
|
||||
Xiaomi provides the Licensed Work on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied, including, without
|
||||
limitation, any warranties, undertakes, or conditions of TITLE, NO ERROR OR
|
||||
OMISSION, CONTINUITY, RELIABILITY, NON-INFRINGEMENT, MERCHANTABILITY, or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. In any event, you are solely responsible
|
||||
for any direct, indirect, special, incidental, or consequential damages or
|
||||
losses arising from the use or inability to use the Licensed Work.
|
||||
|
||||
Xiaomi reserves all rights not expressly granted to you in this License.
|
||||
Except for the rights expressly granted by Xiaomi under this License, Xiaomi
|
||||
does not authorize you in any form to use the trademarks, copyrights, or other
|
||||
forms of intellectual property rights of Xiaomi and its affiliates, including,
|
||||
without limitation, without obtaining other written permission from Xiaomi, you
|
||||
shall not use "Xiaomi", "Mijia" and other words related to Xiaomi or words that
|
||||
may make the public associate with Xiaomi in any form to publicize or promote
|
||||
the software or hardware devices that use the Licensed Work.
|
||||
|
||||
Xiaomi has the right to immediately terminate all your authorization under this
|
||||
License in the event:
|
||||
1. You assert patent invalidation, litigation, or other claims against patents
|
||||
or other intellectual property rights of Xiaomi or its affiliates; or,
|
||||
2. You make, have made, manufacture, sell, or offer to sell products that knock
|
||||
off Xiaomi or its affiliates' products.
|
||||
|
||||
MIoT central hub gateway service discovery.
|
||||
"""
|
||||
import asyncio
|
||||
import base64
|
||||
import binascii
|
||||
import copy
|
||||
from enum import Enum
|
||||
from typing import Callable, Coroutine, Optional
|
||||
import logging
|
||||
|
||||
from zeroconf import (
|
||||
DNSQuestionType,
|
||||
IPVersion,
|
||||
ServiceStateChange,
|
||||
Zeroconf)
|
||||
from zeroconf.asyncio import (
|
||||
AsyncServiceInfo,
|
||||
AsyncZeroconf,
|
||||
AsyncServiceBrowser)
|
||||
|
||||
# pylint: disable=relative-beyond-top-level
|
||||
from .miot_error import MipsServiceError
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
MIPS_MDNS_TYPE = '_miot-central._tcp.local.'
|
||||
MIPS_MDNS_REQUEST_TIMEOUT_MS = 5000
|
||||
MIPS_MDNS_UPDATE_INTERVAL_S = 600
|
||||
|
||||
|
||||
class MipsServiceState(Enum):
|
||||
ADDED = 1
|
||||
REMOVED = 2
|
||||
UPDATED = 3
|
||||
|
||||
|
||||
class MipsServiceData:
|
||||
"""Mips service data."""
|
||||
profile: str
|
||||
profile_bin: bytes
|
||||
|
||||
name: str
|
||||
addresses: list[str]
|
||||
port: int
|
||||
type: str
|
||||
server: str
|
||||
|
||||
did: str
|
||||
group_id: str
|
||||
role: int
|
||||
suite_mqtt: bool
|
||||
|
||||
def __init__(self, service_info: AsyncServiceInfo) -> None:
|
||||
if service_info is None:
|
||||
raise MipsServiceError('invalid params')
|
||||
properties: dict = service_info.decoded_properties
|
||||
if not properties:
|
||||
raise MipsServiceError('invalid service properties')
|
||||
self.profile = properties.get('profile', None)
|
||||
if self.profile is None:
|
||||
raise MipsServiceError('invalid service profile')
|
||||
self.profile_bin = base64.b64decode(self.profile)
|
||||
self.name = service_info.name
|
||||
self.addresses = service_info.parsed_addresses(
|
||||
version=IPVersion.V4Only)
|
||||
if not self.addresses:
|
||||
raise MipsServiceError('invalid addresses')
|
||||
if not service_info.port:
|
||||
raise MipsServiceError('invalid port')
|
||||
self.port = service_info.port
|
||||
self.type = service_info.type
|
||||
self.server = service_info.server or ''
|
||||
# Parse profile
|
||||
self.did = str(int.from_bytes(self.profile_bin[1:9], byteorder='big'))
|
||||
self.group_id = binascii.hexlify(
|
||||
self.profile_bin[9:17][::-1]).decode('utf-8')
|
||||
self.role = int(self.profile_bin[20] >> 4)
|
||||
self.suite_mqtt = ((self.profile_bin[22] >> 1) & 0x01) == 0x01
|
||||
|
||||
def valid_service(self) -> bool:
|
||||
if self.role != 1:
|
||||
return False
|
||||
return self.suite_mqtt
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
return {
|
||||
'name': self.name,
|
||||
'addresses': self.addresses,
|
||||
'port': self.port,
|
||||
'type': self.type,
|
||||
'server': self.server,
|
||||
'did': self.did,
|
||||
'group_id': self.group_id,
|
||||
'role': self.role,
|
||||
'suite_mqtt': self.suite_mqtt
|
||||
}
|
||||
|
||||
def __str__(self) -> str:
|
||||
return str(self.to_dict())
|
||||
|
||||
|
||||
class MipsService:
|
||||
"""MIPS service discovery."""
|
||||
_aiozc: AsyncZeroconf
|
||||
_main_loop: asyncio.AbstractEventLoop
|
||||
_aio_browser: AsyncServiceBrowser
|
||||
_services: dict[str, dict]
|
||||
# key = (key, group_id)
|
||||
_sub_list: dict[tuple[str, str], Callable[[
|
||||
str, MipsServiceState, dict], Coroutine]]
|
||||
|
||||
def __init__(
|
||||
self, aiozc: AsyncZeroconf,
|
||||
loop: Optional[asyncio.AbstractEventLoop] = None
|
||||
) -> None:
|
||||
self._aiozc = aiozc
|
||||
self._main_loop = loop or asyncio.get_running_loop()
|
||||
|
||||
self._services = {}
|
||||
self._sub_list = {}
|
||||
|
||||
async def init_async(self) -> None:
|
||||
await self._aiozc.zeroconf.async_wait_for_start()
|
||||
|
||||
self._aio_browser = AsyncServiceBrowser(
|
||||
zeroconf=self._aiozc.zeroconf,
|
||||
type_=MIPS_MDNS_TYPE,
|
||||
handlers=[self.__on_service_state_change],
|
||||
question_type=DNSQuestionType.QM)
|
||||
|
||||
async def deinit_async(self) -> None:
|
||||
await self._aio_browser.async_cancel()
|
||||
self._services = {}
|
||||
self._sub_list = {}
|
||||
|
||||
def get_services(self, group_id: Optional[str] = None) -> dict[str, dict]:
|
||||
"""get mips services.
|
||||
|
||||
Args:
|
||||
group_id (str, optional): _description_. Defaults to None.
|
||||
|
||||
Returns: {
|
||||
[group_id:str]: {
|
||||
"name": str,
|
||||
"addresses": list[str],
|
||||
"port": number,
|
||||
"type": str,
|
||||
"server": str,
|
||||
"version": int,
|
||||
"did": str,
|
||||
"group_id": str,
|
||||
"role": int,
|
||||
"suite_mqtt": bool
|
||||
}
|
||||
}
|
||||
"""
|
||||
if group_id:
|
||||
if group_id not in self._services:
|
||||
return {}
|
||||
return {group_id: copy.deepcopy(self._services[group_id])}
|
||||
return copy.deepcopy(self._services)
|
||||
|
||||
def sub_service_change(
|
||||
self, key: str, group_id: str,
|
||||
handler: Callable[[str, MipsServiceState, dict], Coroutine]
|
||||
) -> None:
|
||||
if key is None or group_id is None or handler is None:
|
||||
raise MipsServiceError('invalid params')
|
||||
self._sub_list[(key, group_id)] = handler
|
||||
|
||||
def unsub_service_change(self, key: str) -> None:
|
||||
if key is None:
|
||||
return
|
||||
for keys in list(self._sub_list.keys()):
|
||||
if key == keys[0]:
|
||||
self._sub_list.pop(keys, None)
|
||||
|
||||
def __on_service_state_change(
|
||||
self, zeroconf: Zeroconf, service_type: str, name: str,
|
||||
state_change: ServiceStateChange
|
||||
) -> None:
|
||||
_LOGGER.debug(
|
||||
'mdns discovery changed, %s, %s, %s',
|
||||
state_change, name, service_type)
|
||||
|
||||
if state_change is ServiceStateChange.Removed:
|
||||
for item in list(self._services.values()):
|
||||
if item['name'] != name:
|
||||
continue
|
||||
# Ignore mdns REMOVED package. Let the connection close by itself.
|
||||
# service_data = self._services.pop(item['group_id'], {})
|
||||
# self.__call_service_change(
|
||||
# state=MipsServiceState.REMOVED, data=service_data)
|
||||
return
|
||||
self._main_loop.create_task(
|
||||
self.__request_service_info_async(zeroconf, service_type, name))
|
||||
|
||||
async def __request_service_info_async(
|
||||
self, zeroconf: Zeroconf, service_type: str, name: str
|
||||
) -> None:
|
||||
info = AsyncServiceInfo(service_type, name)
|
||||
await info.async_request(
|
||||
zeroconf, MIPS_MDNS_REQUEST_TIMEOUT_MS,
|
||||
question_type=DNSQuestionType.QU)
|
||||
|
||||
try:
|
||||
service_data = MipsServiceData(info)
|
||||
if not service_data.valid_service():
|
||||
raise MipsServiceError(
|
||||
'no primary role, no support mqtt connection')
|
||||
if service_data.group_id in self._services:
|
||||
# Update mips service
|
||||
buffer_data = self._services[service_data.group_id]
|
||||
if (
|
||||
service_data.did != buffer_data['did']
|
||||
or service_data.addresses != buffer_data['addresses']
|
||||
or service_data.port != buffer_data['port']
|
||||
):
|
||||
self._services[service_data.group_id].update(
|
||||
service_data.to_dict())
|
||||
self.__call_service_change(
|
||||
state=MipsServiceState.UPDATED,
|
||||
data=service_data.to_dict())
|
||||
else:
|
||||
# Add mips service
|
||||
self._services[service_data.group_id] = service_data.to_dict()
|
||||
self.__call_service_change(
|
||||
state=MipsServiceState.ADDED,
|
||||
data=self._services[service_data.group_id])
|
||||
except MipsServiceError as error:
|
||||
_LOGGER.error('invalid mips service, %s, %s', error, info)
|
||||
|
||||
def __call_service_change(
|
||||
self, state: MipsServiceState, data: dict
|
||||
) -> None:
|
||||
_LOGGER.info('call service change, %s, %s', state, data)
|
||||
for keys in list(self._sub_list.keys()):
|
||||
if keys[1] in [data.get('group_id', None), '*']:
|
||||
self._main_loop.create_task(
|
||||
self._sub_list[keys](data['group_id'], state, data))
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,382 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Copyright (C) 2024 Xiaomi Corporation.
|
||||
|
||||
The ownership and intellectual property rights of Xiaomi Home Assistant
|
||||
Integration and related Xiaomi cloud service API interface provided under this
|
||||
license, including source code and object code (collectively, "Licensed Work"),
|
||||
are owned by Xiaomi. Subject to the terms and conditions of this License, Xiaomi
|
||||
hereby grants you a personal, limited, non-exclusive, non-transferable,
|
||||
non-sublicensable, and royalty-free license to reproduce, use, modify, and
|
||||
distribute the Licensed Work only for your use of Home Assistant for
|
||||
non-commercial purposes. For the avoidance of doubt, Xiaomi does not authorize
|
||||
you to use the Licensed Work for any other purpose, including but not limited
|
||||
to use Licensed Work to develop applications (APP), Web services, and other
|
||||
forms of software.
|
||||
|
||||
You may reproduce and distribute copies of the Licensed Work, with or without
|
||||
modifications, whether in source or object form, provided that you must give
|
||||
any other recipients of the Licensed Work a copy of this License and retain all
|
||||
copyright and disclaimers.
|
||||
|
||||
Xiaomi provides the Licensed Work on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied, including, without
|
||||
limitation, any warranties, undertakes, or conditions of TITLE, NO ERROR OR
|
||||
OMISSION, CONTINUITY, RELIABILITY, NON-INFRINGEMENT, MERCHANTABILITY, or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. In any event, you are solely responsible
|
||||
for any direct, indirect, special, incidental, or consequential damages or
|
||||
losses arising from the use or inability to use the Licensed Work.
|
||||
|
||||
Xiaomi reserves all rights not expressly granted to you in this License.
|
||||
Except for the rights expressly granted by Xiaomi under this License, Xiaomi
|
||||
does not authorize you in any form to use the trademarks, copyrights, or other
|
||||
forms of intellectual property rights of Xiaomi and its affiliates, including,
|
||||
without limitation, without obtaining other written permission from Xiaomi, you
|
||||
shall not use "Xiaomi", "Mijia" and other words related to Xiaomi or words that
|
||||
may make the public associate with Xiaomi in any form to publicize or promote
|
||||
the software or hardware devices that use the Licensed Work.
|
||||
|
||||
Xiaomi has the right to immediately terminate all your authorization under this
|
||||
License in the event:
|
||||
1. You assert patent invalidation, litigation, or other claims against patents
|
||||
or other intellectual property rights of Xiaomi or its affiliates; or,
|
||||
2. You make, have made, manufacture, sell, or offer to sell products that knock
|
||||
off Xiaomi or its affiliates' products.
|
||||
|
||||
MIoT network utilities.
|
||||
"""
|
||||
import asyncio
|
||||
import logging
|
||||
import platform
|
||||
import socket
|
||||
from dataclasses import dataclass
|
||||
from enum import Enum, auto
|
||||
import subprocess
|
||||
from typing import Callable, Coroutine, Optional
|
||||
import aiohttp
|
||||
import psutil
|
||||
import ipaddress
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class InterfaceStatus(Enum):
|
||||
"""Interface status."""
|
||||
ADD = 0
|
||||
UPDATE = auto()
|
||||
REMOVE = auto()
|
||||
|
||||
|
||||
@dataclass
|
||||
class NetworkInfo:
|
||||
"""Network information."""
|
||||
name: str
|
||||
ip: str
|
||||
netmask: str
|
||||
net_seg: str
|
||||
|
||||
|
||||
class MIoTNetwork:
|
||||
"""MIoT network utilities."""
|
||||
_IP_ADDRESS_LIST: list[str] = [
|
||||
'1.2.4.8', # CNNIC sDNS
|
||||
'8.8.8.8', # Google Public DNS
|
||||
'9.9.9.9' # Quad9
|
||||
]
|
||||
_URL_ADDRESS_LIST: list[str] = [
|
||||
'https://www.bing.com',
|
||||
'https://www.google.com',
|
||||
'https://www.baidu.com'
|
||||
]
|
||||
_REFRESH_INTERVAL = 30
|
||||
_DETECT_TIMEOUT = 6
|
||||
|
||||
_main_loop: asyncio.AbstractEventLoop
|
||||
|
||||
_ip_addr_map: dict[str, float]
|
||||
_http_addr_map: dict[str, float]
|
||||
_http_session: aiohttp.ClientSession
|
||||
|
||||
_refresh_interval: int
|
||||
_refresh_task: Optional[asyncio.Task]
|
||||
_refresh_timer: Optional[asyncio.TimerHandle]
|
||||
|
||||
_network_status: bool
|
||||
_network_info: dict[str, NetworkInfo]
|
||||
|
||||
_sub_list_network_status: dict[str, Callable[[bool], Coroutine]]
|
||||
_sub_list_network_info: dict[str, Callable[[
|
||||
InterfaceStatus, NetworkInfo], Coroutine]]
|
||||
_done_event: asyncio.Event
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
ip_addr_list: Optional[list[str]] = None,
|
||||
url_addr_list: Optional[list[str]] = None,
|
||||
refresh_interval: Optional[int] = None,
|
||||
loop: Optional[asyncio.AbstractEventLoop] = None
|
||||
) -> None:
|
||||
self._main_loop = loop or asyncio.get_running_loop()
|
||||
self._ip_addr_map = {
|
||||
ip: self._DETECT_TIMEOUT for ip in
|
||||
ip_addr_list or self._IP_ADDRESS_LIST}
|
||||
self._http_addr_map = {
|
||||
url: self._DETECT_TIMEOUT for url in
|
||||
url_addr_list or self._URL_ADDRESS_LIST}
|
||||
self._http_session = aiohttp.ClientSession()
|
||||
self._refresh_interval = refresh_interval or self._REFRESH_INTERVAL
|
||||
|
||||
self._refresh_task = None
|
||||
self._refresh_timer = None
|
||||
|
||||
self._network_status = False
|
||||
self._network_info = {}
|
||||
|
||||
self._sub_list_network_status = {}
|
||||
self._sub_list_network_info = {}
|
||||
|
||||
self._done_event = asyncio.Event()
|
||||
|
||||
async def init_async(self) -> bool:
|
||||
self.__refresh_timer_handler()
|
||||
# MUST get network info before starting
|
||||
return await self._done_event.wait()
|
||||
|
||||
async def deinit_async(self) -> None:
|
||||
if self._refresh_task:
|
||||
self._refresh_task.cancel()
|
||||
self._refresh_task = None
|
||||
if self._refresh_timer:
|
||||
self._refresh_timer.cancel()
|
||||
self._refresh_timer = None
|
||||
await self._http_session.close()
|
||||
|
||||
self._network_status = False
|
||||
self._network_info.clear()
|
||||
self._sub_list_network_status.clear()
|
||||
self._sub_list_network_info.clear()
|
||||
self._done_event.clear()
|
||||
|
||||
@property
|
||||
def network_status(self) -> bool:
|
||||
return self._network_status
|
||||
|
||||
@property
|
||||
def network_info(self) -> dict[str, NetworkInfo]:
|
||||
return self._network_info
|
||||
|
||||
async def update_addr_list_async(
|
||||
self,
|
||||
ip_addr_list: Optional[list[str]] = None,
|
||||
url_addr_list: Optional[list[str]] = None,
|
||||
) -> None:
|
||||
new_ip_map: dict = {}
|
||||
for ip in ip_addr_list or self._IP_ADDRESS_LIST:
|
||||
if ip in self._ip_addr_map:
|
||||
new_ip_map[ip] = self._ip_addr_map[ip]
|
||||
else:
|
||||
new_ip_map[ip] = self._DETECT_TIMEOUT
|
||||
self._ip_addr_map = new_ip_map
|
||||
new_url_map: dict = {}
|
||||
for url in url_addr_list or self._URL_ADDRESS_LIST:
|
||||
if url in self._http_addr_map:
|
||||
new_url_map[url] = self._http_addr_map[url]
|
||||
else:
|
||||
new_url_map[url] = self._DETECT_TIMEOUT
|
||||
self._http_addr_map = new_url_map
|
||||
|
||||
def sub_network_status(
|
||||
self, key: str, handler: Callable[[bool], Coroutine]
|
||||
) -> None:
|
||||
self._sub_list_network_status[key] = handler
|
||||
|
||||
def unsub_network_status(self, key: str) -> None:
|
||||
self._sub_list_network_status.pop(key, None)
|
||||
|
||||
def sub_network_info(
|
||||
self, key: str,
|
||||
handler: Callable[[InterfaceStatus, NetworkInfo], Coroutine]
|
||||
) -> None:
|
||||
self._sub_list_network_info[key] = handler
|
||||
|
||||
def unsub_network_info(self, key: str) -> None:
|
||||
self._sub_list_network_info.pop(key, None)
|
||||
|
||||
async def refresh_async(self) -> None:
|
||||
self.__refresh_timer_handler()
|
||||
|
||||
async def get_network_status_async(self) -> bool:
|
||||
try:
|
||||
ip_addr: str = ''
|
||||
ip_ts: float = self._DETECT_TIMEOUT
|
||||
for ip, ts in self._ip_addr_map.items():
|
||||
if ts < ip_ts:
|
||||
ip_addr = ip
|
||||
ip_ts = ts
|
||||
if (
|
||||
ip_ts < self._DETECT_TIMEOUT
|
||||
and await self.ping_multi_async(ip_list=[ip_addr])
|
||||
):
|
||||
return True
|
||||
url_addr: str = ''
|
||||
url_ts: float = self._DETECT_TIMEOUT
|
||||
for http, ts in self._http_addr_map.items():
|
||||
if ts < url_ts:
|
||||
url_addr = http
|
||||
url_ts = ts
|
||||
if (
|
||||
url_ts < self._DETECT_TIMEOUT
|
||||
and await self.http_multi_async(url_list=[url_addr])
|
||||
):
|
||||
return True
|
||||
# Detect all addresses
|
||||
results = await asyncio.gather(
|
||||
*[self.ping_multi_async(), self.http_multi_async()])
|
||||
return any(results)
|
||||
except Exception as err: # pylint: disable=broad-exception-caught
|
||||
_LOGGER.error('get network status error, %s', err)
|
||||
return False
|
||||
|
||||
async def get_network_info_async(self) -> dict[str, NetworkInfo]:
|
||||
return await self._main_loop.run_in_executor(
|
||||
None, self.__get_network_info)
|
||||
|
||||
async def ping_multi_async(
|
||||
self, ip_list: Optional[list[str]] = None
|
||||
) -> bool:
|
||||
addr_list = ip_list or list(self._ip_addr_map.keys())
|
||||
tasks = []
|
||||
for addr in addr_list:
|
||||
tasks.append(self.__ping_async(addr))
|
||||
results = await asyncio.gather(*tasks)
|
||||
for addr, ts in zip(addr_list, results):
|
||||
if addr in self._ip_addr_map:
|
||||
self._ip_addr_map[addr] = ts
|
||||
return any([ts < self._DETECT_TIMEOUT for ts in results])
|
||||
|
||||
async def http_multi_async(
|
||||
self, url_list: Optional[list[str]] = None
|
||||
) -> bool:
|
||||
addr_list = url_list or list(self._http_addr_map.keys())
|
||||
tasks = []
|
||||
for addr in addr_list:
|
||||
tasks.append(self.__http_async(url=addr))
|
||||
results = await asyncio.gather(*tasks)
|
||||
for addr, ts in zip(addr_list, results):
|
||||
if addr in self._http_addr_map:
|
||||
self._http_addr_map[addr] = ts
|
||||
return any([ts < self._DETECT_TIMEOUT for ts in results])
|
||||
|
||||
def __calc_network_address(self, ip: str, netmask: str) -> str:
|
||||
return str(ipaddress.IPv4Network(
|
||||
f'{ip}/{netmask}', strict=False).network_address)
|
||||
|
||||
async def __ping_async(self, address: Optional[str] = None) -> float:
|
||||
start_ts: float = self._main_loop.time()
|
||||
try:
|
||||
process = await asyncio.create_subprocess_exec(
|
||||
*(
|
||||
[
|
||||
'ping', '-n', '1', '-w',
|
||||
str(self._DETECT_TIMEOUT*1000), address]
|
||||
if platform.system().lower() == 'windows' else
|
||||
[
|
||||
'ping', '-c', '1', '-w',
|
||||
str(self._DETECT_TIMEOUT), address]),
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL
|
||||
)
|
||||
await process.communicate()
|
||||
if process.returncode == 0:
|
||||
return self._main_loop.time() - start_ts
|
||||
return self._DETECT_TIMEOUT
|
||||
except Exception as err: # pylint: disable=broad-exception-caught
|
||||
_LOGGER.debug('ping error, %s',err)
|
||||
return self._DETECT_TIMEOUT
|
||||
|
||||
async def __http_async(self, url: str) -> float:
|
||||
start_ts: float = self._main_loop.time()
|
||||
try:
|
||||
async with self._http_session.get(
|
||||
url, timeout=self._DETECT_TIMEOUT):
|
||||
return self._main_loop.time() - start_ts
|
||||
except Exception: # pylint: disable=broad-exception-caught
|
||||
pass
|
||||
return self._DETECT_TIMEOUT
|
||||
|
||||
def __get_network_info(self) -> dict[str, NetworkInfo]:
|
||||
interfaces = psutil.net_if_addrs()
|
||||
results: dict[str, NetworkInfo] = {}
|
||||
for name, addresses in interfaces.items():
|
||||
# Skip hassio and docker* interface
|
||||
if name == 'hassio' or name.startswith('docker'):
|
||||
continue
|
||||
for address in addresses:
|
||||
if (
|
||||
address.family != socket.AF_INET
|
||||
or not address.address
|
||||
or not address.netmask
|
||||
):
|
||||
continue
|
||||
# skip lo interface
|
||||
if address.address == '127.0.0.1':
|
||||
continue
|
||||
results[name] = NetworkInfo(
|
||||
name=name,
|
||||
ip=address.address,
|
||||
netmask=address.netmask,
|
||||
net_seg=self.__calc_network_address(
|
||||
address.address, address.netmask))
|
||||
return results
|
||||
|
||||
def __call_network_info_change(
|
||||
self, status: InterfaceStatus, info: NetworkInfo
|
||||
) -> None:
|
||||
for handler in self._sub_list_network_info.values():
|
||||
self._main_loop.create_task(handler(status, info))
|
||||
|
||||
async def __update_status_and_info_async(self) -> None:
|
||||
try:
|
||||
status: bool = await self.get_network_status_async()
|
||||
infos = await self.get_network_info_async()
|
||||
|
||||
if self._network_status != status:
|
||||
for handler in self._sub_list_network_status.values():
|
||||
self._main_loop.create_task(handler(status))
|
||||
self._network_status = status
|
||||
|
||||
for name in list(self._network_info.keys()):
|
||||
info = infos.pop(name, None)
|
||||
if info:
|
||||
# Update
|
||||
if (
|
||||
info.ip != self._network_info[name].ip
|
||||
or info.netmask != self._network_info[name].netmask
|
||||
):
|
||||
self._network_info[name] = info
|
||||
self.__call_network_info_change(
|
||||
InterfaceStatus.UPDATE, info)
|
||||
else:
|
||||
# Remove
|
||||
self.__call_network_info_change(
|
||||
InterfaceStatus.REMOVE,
|
||||
self._network_info.pop(name))
|
||||
# Add
|
||||
for name, info in infos.items():
|
||||
self._network_info[name] = info
|
||||
self.__call_network_info_change(InterfaceStatus.ADD, info)
|
||||
|
||||
if not self._done_event.is_set():
|
||||
self._done_event.set()
|
||||
except asyncio.CancelledError:
|
||||
_LOGGER.error('update_status_and_info task was cancelled')
|
||||
|
||||
def __refresh_timer_handler(self) -> None:
|
||||
if self._refresh_timer:
|
||||
self._refresh_timer.cancel()
|
||||
self._refresh_timer = None
|
||||
if self._refresh_task is None or self._refresh_task.done():
|
||||
self._refresh_task = self._main_loop.create_task(
|
||||
self.__update_status_and_info_async())
|
||||
self._refresh_timer = self._main_loop.call_later(
|
||||
self._refresh_interval, self.__refresh_timer_handler)
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,788 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Copyright (C) 2024 Xiaomi Corporation.
|
||||
|
||||
The ownership and intellectual property rights of Xiaomi Home Assistant
|
||||
Integration and related Xiaomi cloud service API interface provided under this
|
||||
license, including source code and object code (collectively, "Licensed Work"),
|
||||
are owned by Xiaomi. Subject to the terms and conditions of this License, Xiaomi
|
||||
hereby grants you a personal, limited, non-exclusive, non-transferable,
|
||||
non-sublicensable, and royalty-free license to reproduce, use, modify, and
|
||||
distribute the Licensed Work only for your use of Home Assistant for
|
||||
non-commercial purposes. For the avoidance of doubt, Xiaomi does not authorize
|
||||
you to use the Licensed Work for any other purpose, including but not limited
|
||||
to use Licensed Work to develop applications (APP), Web services, and other
|
||||
forms of software.
|
||||
|
||||
You may reproduce and distribute copies of the Licensed Work, with or without
|
||||
modifications, whether in source or object form, provided that you must give
|
||||
any other recipients of the Licensed Work a copy of this License and retain all
|
||||
copyright and disclaimers.
|
||||
|
||||
Xiaomi provides the Licensed Work on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied, including, without
|
||||
limitation, any warranties, undertakes, or conditions of TITLE, NO ERROR OR
|
||||
OMISSION, CONTINUITY, RELIABILITY, NON-INFRINGEMENT, MERCHANTABILITY, or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. In any event, you are solely responsible
|
||||
for any direct, indirect, special, incidental, or consequential damages or
|
||||
losses arising from the use or inability to use the Licensed Work.
|
||||
|
||||
Xiaomi reserves all rights not expressly granted to you in this License.
|
||||
Except for the rights expressly granted by Xiaomi under this License, Xiaomi
|
||||
does not authorize you in any form to use the trademarks, copyrights, or other
|
||||
forms of intellectual property rights of Xiaomi and its affiliates, including,
|
||||
without limitation, without obtaining other written permission from Xiaomi, you
|
||||
shall not use "Xiaomi", "Mijia" and other words related to Xiaomi or words that
|
||||
may make the public associate with Xiaomi in any form to publicize or promote
|
||||
the software or hardware devices that use the Licensed Work.
|
||||
|
||||
Xiaomi has the right to immediately terminate all your authorization under this
|
||||
License in the event:
|
||||
1. You assert patent invalidation, litigation, or other claims against patents
|
||||
or other intellectual property rights of Xiaomi or its affiliates; or,
|
||||
2. You make, have made, manufacture, sell, or offer to sell products that knock
|
||||
off Xiaomi or its affiliates' products.
|
||||
|
||||
MIoT storage and certificate management.
|
||||
"""
|
||||
import os
|
||||
import asyncio
|
||||
import binascii
|
||||
import json
|
||||
import shutil
|
||||
import time
|
||||
import traceback
|
||||
import hashlib
|
||||
from datetime import datetime, timezone
|
||||
from enum import Enum, auto
|
||||
from pathlib import Path
|
||||
from typing import Any, Optional, Union
|
||||
import logging
|
||||
from cryptography.hazmat.primitives import serialization
|
||||
from cryptography.hazmat.backends import default_backend
|
||||
from cryptography.x509.oid import NameOID
|
||||
from cryptography import x509
|
||||
from cryptography.hazmat.primitives import hashes
|
||||
from cryptography.hazmat.primitives.asymmetric import ed25519
|
||||
|
||||
|
||||
# pylint: disable=relative-beyond-top-level
|
||||
from .const import (
|
||||
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__)
|
||||
|
||||
|
||||
class MIoTStorageType(Enum):
|
||||
LOAD = auto()
|
||||
LOAD_FILE = auto()
|
||||
SAVE = auto()
|
||||
SAVE_FILE = auto()
|
||||
DEL = auto()
|
||||
DEL_FILE = auto()
|
||||
CLEAR = auto()
|
||||
|
||||
|
||||
class MIoTStorage:
|
||||
"""File management.
|
||||
|
||||
User data will be stored in the `.storage` directory of Home Assistant.
|
||||
"""
|
||||
_main_loop: asyncio.AbstractEventLoop
|
||||
_file_future: dict[str, tuple[MIoTStorageType, asyncio.Future]]
|
||||
|
||||
_root_path: str
|
||||
|
||||
def __init__(
|
||||
self, root_path: str,
|
||||
loop: Optional[asyncio.AbstractEventLoop] = None
|
||||
) -> None:
|
||||
"""Initialize with a root path."""
|
||||
self._main_loop = loop or asyncio.get_running_loop()
|
||||
self._file_future = {}
|
||||
|
||||
self._root_path = os.path.abspath(root_path)
|
||||
os.makedirs(self._root_path, exist_ok=True)
|
||||
|
||||
_LOGGER.debug('root path, %s', self._root_path)
|
||||
|
||||
def __get_full_path(self, domain: str, name: str, suffix: str) -> str:
|
||||
return os.path.join(
|
||||
self._root_path, domain, f'{name}.{suffix}')
|
||||
|
||||
def __add_file_future(
|
||||
self, key: str, op_type: MIoTStorageType, fut: asyncio.Future
|
||||
) -> None:
|
||||
def fut_done_callback(fut: asyncio.Future):
|
||||
del fut
|
||||
self._file_future.pop(key, None)
|
||||
|
||||
fut.add_done_callback(fut_done_callback)
|
||||
self._file_future[key] = op_type, fut
|
||||
|
||||
def __load(
|
||||
self, full_path: str, type_: type = bytes, with_hash_check: bool = True
|
||||
) -> Union[bytes, str, dict, list, None]:
|
||||
if not os.path.exists(full_path):
|
||||
_LOGGER.debug('load error, file does not exist, %s', full_path)
|
||||
return None
|
||||
if not os.access(full_path, os.R_OK):
|
||||
_LOGGER.error('load error, file not readable, %s', full_path)
|
||||
return None
|
||||
try:
|
||||
with open(full_path, 'rb') as r_file:
|
||||
r_data: bytes = r_file.read()
|
||||
if r_data is None:
|
||||
_LOGGER.error('load error, empty file, %s', full_path)
|
||||
return None
|
||||
data_bytes: bytes
|
||||
# Hash check
|
||||
if with_hash_check:
|
||||
if len(r_data) <= 32:
|
||||
return None
|
||||
data_bytes = r_data[:-32]
|
||||
hash_value = r_data[-32:]
|
||||
if hashlib.sha256(data_bytes).digest() != hash_value:
|
||||
_LOGGER.error(
|
||||
'load error, hash check failed, %s', full_path)
|
||||
return None
|
||||
else:
|
||||
data_bytes = r_data
|
||||
if type_ == bytes:
|
||||
return data_bytes
|
||||
if type_ == str:
|
||||
return str(data_bytes, 'utf-8')
|
||||
if type_ in [dict, list]:
|
||||
return json.loads(data_bytes)
|
||||
_LOGGER.error(
|
||||
'load error, unsupported data type, %s', type_.__name__)
|
||||
return None
|
||||
except (OSError, TypeError) as e:
|
||||
_LOGGER.error('load error, %s, %s', e, traceback.format_exc())
|
||||
return None
|
||||
|
||||
def load(
|
||||
self, domain: str, name: str, type_: type = bytes
|
||||
) -> Union[bytes, str, dict, list, None]:
|
||||
full_path = self.__get_full_path(
|
||||
domain=domain, name=name, suffix=type_.__name__)
|
||||
return self.__load(full_path=full_path, type_=type_)
|
||||
|
||||
async def load_async(
|
||||
self, domain: str, name: str, type_: type = bytes
|
||||
) -> Union[bytes, str, dict, list, None]:
|
||||
full_path = self.__get_full_path(
|
||||
domain=domain, name=name, suffix=type_.__name__)
|
||||
if full_path in self._file_future:
|
||||
# Waiting for the last task to be completed
|
||||
op_type, fut = self._file_future[full_path]
|
||||
if op_type == MIoTStorageType.LOAD:
|
||||
if not fut.done():
|
||||
return await fut
|
||||
else:
|
||||
await fut
|
||||
fut = self._main_loop.run_in_executor(
|
||||
None, self.__load, full_path, type_)
|
||||
if not fut.done():
|
||||
self.__add_file_future(full_path, MIoTStorageType.LOAD, fut)
|
||||
return await fut
|
||||
|
||||
def __save(
|
||||
self, full_path: str, data: Union[bytes, str, dict, list, None],
|
||||
cover: bool = True, with_hash: bool = True
|
||||
) -> bool:
|
||||
if data is None:
|
||||
_LOGGER.error('save error, save data is None')
|
||||
return False
|
||||
if os.path.exists(full_path):
|
||||
if not cover:
|
||||
_LOGGER.error('save error, file exists, cover is False')
|
||||
return False
|
||||
if not os.access(full_path, os.W_OK):
|
||||
_LOGGER.error('save error, file not writeable, %s', full_path)
|
||||
return False
|
||||
else:
|
||||
os.makedirs(os.path.dirname(full_path), exist_ok=True)
|
||||
try:
|
||||
w_bytes: bytes
|
||||
if isinstance(data, bytes):
|
||||
w_bytes = data
|
||||
elif isinstance(data, str):
|
||||
w_bytes = data.encode('utf-8')
|
||||
elif isinstance(data, (dict, list)):
|
||||
w_bytes = json.dumps(data).encode('utf-8')
|
||||
else:
|
||||
_LOGGER.error(
|
||||
'save error, unsupported data type, %s',
|
||||
type(data).__name__)
|
||||
return False
|
||||
with open(full_path, 'wb') as w_file:
|
||||
w_file.write(w_bytes)
|
||||
if with_hash:
|
||||
w_file.write(hashlib.sha256(w_bytes).digest())
|
||||
return True
|
||||
except (OSError, TypeError) as e:
|
||||
_LOGGER.error('save error, %s, %s', e, traceback.format_exc())
|
||||
return False
|
||||
|
||||
def save(
|
||||
self, domain: str, name: str, data: Union[bytes, str, dict, list, None]
|
||||
) -> bool:
|
||||
full_path = self.__get_full_path(
|
||||
domain=domain, name=name, suffix=type(data).__name__)
|
||||
return self.__save(full_path=full_path, data=data)
|
||||
|
||||
async def save_async(
|
||||
self, domain: str, name: str, data: Union[bytes, str, dict, list, None]
|
||||
) -> bool:
|
||||
full_path = self.__get_full_path(
|
||||
domain=domain, name=name, suffix=type(data).__name__)
|
||||
if full_path in self._file_future:
|
||||
# Waiting for the last task to be completed
|
||||
fut = self._file_future[full_path][1]
|
||||
await fut
|
||||
fut = self._main_loop.run_in_executor(
|
||||
None, self.__save, full_path, data)
|
||||
if not fut.done():
|
||||
self.__add_file_future(full_path, MIoTStorageType.SAVE, fut)
|
||||
return await fut
|
||||
|
||||
def __remove(self, full_path: str) -> bool:
|
||||
item = Path(full_path)
|
||||
if item.is_file() or item.is_symlink():
|
||||
item.unlink()
|
||||
return True
|
||||
|
||||
def remove(self, domain: str, name: str, type_: type) -> bool:
|
||||
full_path = self.__get_full_path(
|
||||
domain=domain, name=name, suffix=type_.__name__)
|
||||
return self.__remove(full_path=full_path)
|
||||
|
||||
async def remove_async(self, domain: str, name: str, type_: type) -> bool:
|
||||
full_path = self.__get_full_path(
|
||||
domain=domain, name=name, suffix=type_.__name__)
|
||||
if full_path in self._file_future:
|
||||
# Waiting for the last task to be completed
|
||||
op_type, fut = self._file_future[full_path]
|
||||
if op_type == MIoTStorageType.DEL:
|
||||
if not fut.done():
|
||||
return await fut
|
||||
else:
|
||||
await fut
|
||||
fut = self._main_loop.run_in_executor(None, self.__remove, full_path)
|
||||
if not fut.done():
|
||||
self.__add_file_future(full_path, MIoTStorageType.DEL, fut)
|
||||
return await fut
|
||||
|
||||
def __remove_domain(self, full_path: str) -> bool:
|
||||
path_obj = Path(full_path)
|
||||
if path_obj.exists():
|
||||
# Recursive deletion
|
||||
shutil.rmtree(path_obj)
|
||||
return True
|
||||
|
||||
def remove_domain(self, domain: str) -> bool:
|
||||
full_path = os.path.join(self._root_path, domain)
|
||||
return self.__remove_domain(full_path=full_path)
|
||||
|
||||
async def remove_domain_async(self, domain: str) -> bool:
|
||||
full_path = os.path.join(self._root_path, domain)
|
||||
if full_path in self._file_future:
|
||||
# Waiting for the last task to be completed
|
||||
op_type, fut = self._file_future[full_path]
|
||||
if op_type == MIoTStorageType.DEL:
|
||||
if not fut.done():
|
||||
return await fut
|
||||
else:
|
||||
await fut
|
||||
# Waiting domain tasks finish
|
||||
for path, value in self._file_future.items():
|
||||
if path.startswith(full_path):
|
||||
await value[1]
|
||||
fut = self._main_loop.run_in_executor(
|
||||
None, self.__remove_domain, full_path)
|
||||
if not fut.done():
|
||||
self.__add_file_future(full_path, MIoTStorageType.DEL, fut)
|
||||
return await fut
|
||||
|
||||
def get_names(self, domain: str, type_: type) -> list[str]:
|
||||
path: str = os.path.join(self._root_path, domain)
|
||||
type_str = f'.{type_.__name__}'
|
||||
names: list[str] = []
|
||||
for item in Path(path).glob(f'*{type_str}'):
|
||||
if not item.is_file() and not item.is_symlink():
|
||||
continue
|
||||
names.append(item.name.replace(type_str, ''))
|
||||
return names
|
||||
|
||||
def file_exists(self, domain: str, name_with_suffix: str) -> bool:
|
||||
return os.path.exists(
|
||||
os.path.join(self._root_path, domain, name_with_suffix))
|
||||
|
||||
def save_file(
|
||||
self, domain: str, name_with_suffix: str, data: bytes
|
||||
) -> bool:
|
||||
if not isinstance(data, bytes):
|
||||
_LOGGER.error('save file error, file must be bytes')
|
||||
return False
|
||||
full_path = os.path.join(self._root_path, domain, name_with_suffix)
|
||||
return self.__save(full_path=full_path, data=data, with_hash=False)
|
||||
|
||||
async def save_file_async(
|
||||
self, domain: str, name_with_suffix: str, data: bytes
|
||||
) -> bool:
|
||||
if not isinstance(data, bytes):
|
||||
_LOGGER.error('save file error, file must be bytes')
|
||||
return False
|
||||
full_path = os.path.join(self._root_path, domain, name_with_suffix)
|
||||
if full_path in self._file_future:
|
||||
# Waiting for the last task to be completed
|
||||
fut = self._file_future[full_path][1]
|
||||
await fut
|
||||
fut = self._main_loop.run_in_executor(
|
||||
None, self.__save, full_path, data, True, False)
|
||||
if not fut.done():
|
||||
self.__add_file_future(full_path, MIoTStorageType.SAVE_FILE, fut)
|
||||
return await fut
|
||||
|
||||
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) # type: ignore
|
||||
|
||||
async def load_file_async(
|
||||
self, domain: str, name_with_suffix: str
|
||||
) -> Optional[bytes]:
|
||||
full_path = os.path.join(self._root_path, domain, name_with_suffix)
|
||||
if full_path in self._file_future:
|
||||
# Waiting for the last task to be completed
|
||||
op_type, fut = self._file_future[full_path]
|
||||
if op_type == MIoTStorageType.LOAD_FILE:
|
||||
if not fut.done():
|
||||
return await fut
|
||||
else:
|
||||
await fut
|
||||
fut = self._main_loop.run_in_executor(
|
||||
None, self.__load, full_path, bytes, False)
|
||||
if not fut.done():
|
||||
self.__add_file_future(full_path, MIoTStorageType.LOAD_FILE, 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)
|
||||
return self.__remove(full_path=full_path)
|
||||
|
||||
async def remove_file_async(
|
||||
self, domain: str, name_with_suffix: str
|
||||
) -> bool:
|
||||
full_path = os.path.join(self._root_path, domain, name_with_suffix)
|
||||
if full_path in self._file_future:
|
||||
# Waiting for the last task to be completed
|
||||
op_type, fut = self._file_future[full_path]
|
||||
if op_type == MIoTStorageType.DEL_FILE:
|
||||
if not fut.done():
|
||||
return await fut
|
||||
else:
|
||||
await fut
|
||||
fut = self._main_loop.run_in_executor(None, self.__remove, full_path)
|
||||
if not fut.done():
|
||||
self.__add_file_future(full_path, MIoTStorageType.DEL_FILE, fut)
|
||||
return await fut
|
||||
|
||||
def clear(self) -> bool:
|
||||
root_path = Path(self._root_path)
|
||||
for item in root_path.iterdir():
|
||||
if item.is_file() or item.is_symlink():
|
||||
item.unlink()
|
||||
elif item.is_dir():
|
||||
shutil.rmtree(item)
|
||||
return True
|
||||
|
||||
async def clear_async(self) -> bool:
|
||||
if self._root_path in self._file_future:
|
||||
op_type, fut = self._file_future[self._root_path]
|
||||
if op_type == MIoTStorageType.CLEAR and not fut.done():
|
||||
return await fut
|
||||
# Waiting all future resolve
|
||||
for value in self._file_future.values():
|
||||
await value[1]
|
||||
|
||||
fut = self._main_loop.run_in_executor(None, self.clear)
|
||||
if not fut.done():
|
||||
self.__add_file_future(
|
||||
self._root_path, MIoTStorageType.CLEAR, fut)
|
||||
return await fut
|
||||
|
||||
def update_user_config(
|
||||
self, uid: str, cloud_server: str, config: Optional[dict[str, Any]],
|
||||
replace: bool = False
|
||||
) -> bool:
|
||||
if config is not None and len(config) == 0:
|
||||
# Do nothing
|
||||
return True
|
||||
|
||||
config_domain = 'miot_config'
|
||||
config_name = f'{uid}_{cloud_server}'
|
||||
if config is None:
|
||||
# Remove config file
|
||||
return self.remove(
|
||||
domain=config_domain, name=config_name, type_=dict)
|
||||
if replace:
|
||||
# Replace config file
|
||||
return self.save(
|
||||
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) # type: ignore
|
||||
return self.save(
|
||||
domain=config_domain, name=config_name, data=local_config)
|
||||
|
||||
async def update_user_config_async(
|
||||
self, uid: str, cloud_server: str, config: Optional[dict[str, Any]],
|
||||
replace: bool = False
|
||||
) -> bool:
|
||||
"""Update user configuration.
|
||||
|
||||
Args:
|
||||
uid (str): user_id
|
||||
config (Optional[dict[str]]):
|
||||
remove config file if config is None
|
||||
replace (bool, optional):
|
||||
replace all config item. Defaults to False.
|
||||
|
||||
Returns:
|
||||
bool: result code
|
||||
"""
|
||||
if config is not None and len(config) == 0:
|
||||
# Do nothing
|
||||
return True
|
||||
|
||||
config_domain = 'miot_config'
|
||||
config_name = f'{uid}_{cloud_server}'
|
||||
if config is None:
|
||||
# Remove config file
|
||||
return await self.remove_async(
|
||||
domain=config_domain, name=config_name, type_=dict)
|
||||
if replace:
|
||||
# Replace config file
|
||||
return await self.save_async(
|
||||
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) # 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 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))
|
||||
if not isinstance(local_config, dict):
|
||||
return {}
|
||||
if keys is None:
|
||||
return local_config
|
||||
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:
|
||||
"""Load user configuration.
|
||||
|
||||
Args:
|
||||
uid (str): user id
|
||||
keys (list[str]):
|
||||
query key list, return all config item if keys is None
|
||||
|
||||
Returns:
|
||||
dict[str, Any]: query result
|
||||
"""
|
||||
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))
|
||||
if not isinstance(local_config, dict):
|
||||
return {}
|
||||
if keys is None:
|
||||
return local_config
|
||||
return {
|
||||
key: local_config[key] for key in keys
|
||||
if key in local_config}
|
||||
|
||||
def gen_storage_path(
|
||||
self, domain: Optional[str] = None,
|
||||
name_with_suffix: Optional[str] = None
|
||||
) -> str:
|
||||
"""Generate file path."""
|
||||
result = self._root_path
|
||||
if domain:
|
||||
result = os.path.join(result, domain)
|
||||
if name_with_suffix:
|
||||
result = os.path.join(result, name_with_suffix)
|
||||
return result
|
||||
|
||||
|
||||
class MIoTCert:
|
||||
"""MIoT certificate file management."""
|
||||
CERT_DOMAIN: str = 'cert'
|
||||
CA_NAME: str = 'mihome_ca.cert'
|
||||
_loop: asyncio.AbstractEventLoop
|
||||
_storage: MIoTStorage
|
||||
_uid: str
|
||||
_cloud_server: str
|
||||
|
||||
_key_name: str
|
||||
_cert_name: str
|
||||
|
||||
def __init__(
|
||||
self, storage: MIoTStorage, uid: str, cloud_server: str,
|
||||
loop: Optional[asyncio.AbstractEventLoop] = None
|
||||
) -> None:
|
||||
if not isinstance(storage, MIoTStorage) or not isinstance(uid, str):
|
||||
raise MIoTError('invalid params')
|
||||
self._loop = loop or asyncio.get_running_loop()
|
||||
self._storage = storage
|
||||
self._uid = uid
|
||||
self._cloud_server = cloud_server
|
||||
self._key_name = f'{uid}_{cloud_server}.key'
|
||||
self._cert_name = f'{uid}_{cloud_server}.cert'
|
||||
|
||||
@property
|
||||
def ca_file(self) -> str:
|
||||
"""CA certificate file path."""
|
||||
return self._storage.gen_storage_path(
|
||||
domain=self.CERT_DOMAIN, name_with_suffix=self.CA_NAME)
|
||||
|
||||
@property
|
||||
def key_file(self) -> str:
|
||||
"""User private key file file path."""
|
||||
return self._storage.gen_storage_path(
|
||||
domain=self.CERT_DOMAIN, name_with_suffix=self._key_name)
|
||||
|
||||
@property
|
||||
def cert_file(self) -> str:
|
||||
"""User certificate file path."""
|
||||
return self._storage.gen_storage_path(
|
||||
domain=self.CERT_DOMAIN, name_with_suffix=self._cert_name)
|
||||
|
||||
async def verify_ca_cert_async(self) -> bool:
|
||||
"""Verify the integrity of the CA certificate file."""
|
||||
ca_data = await self._storage.load_file_async(
|
||||
domain=self.CERT_DOMAIN, name_with_suffix=self.CA_NAME)
|
||||
if ca_data is None:
|
||||
if not await self._storage.save_file_async(
|
||||
domain=self.CERT_DOMAIN,
|
||||
name_with_suffix=self.CA_NAME,
|
||||
data=MIHOME_CA_CERT_STR.encode('utf-8')):
|
||||
raise MIoTStorageError('ca cert save failed')
|
||||
ca_data = await self._storage.load_file_async(
|
||||
domain=self.CERT_DOMAIN, name_with_suffix=self.CA_NAME)
|
||||
if ca_data is None:
|
||||
raise MIoTStorageError('ca cert load failed')
|
||||
_LOGGER.debug('ca cert save success')
|
||||
# Compare the file sha256sum
|
||||
ca_cert_hash = hashlib.sha256(ca_data).digest()
|
||||
hash_str = binascii.hexlify(ca_cert_hash).decode('utf-8')
|
||||
if hash_str != MIHOME_CA_CERT_SHA256:
|
||||
return False
|
||||
return True
|
||||
|
||||
async def user_cert_remaining_time_async(
|
||||
self, cert_data: Optional[bytes] = None, did: Optional[str] = None
|
||||
) -> int:
|
||||
"""Get the remaining time of user certificate validity.
|
||||
|
||||
Returns:
|
||||
If the certificate is not valid, return 0.
|
||||
"""
|
||||
if cert_data is None:
|
||||
cert_data = await self._storage.load_file_async(
|
||||
domain=self.CERT_DOMAIN, name_with_suffix=self._cert_name)
|
||||
if cert_data is None:
|
||||
return 0
|
||||
# Check user cert
|
||||
try:
|
||||
user_cert: x509.Certificate = x509.load_pem_x509_certificate(
|
||||
cert_data, default_backend())
|
||||
cert_info = {}
|
||||
for attribute in user_cert.subject:
|
||||
if attribute.oid == x509.NameOID.COMMON_NAME:
|
||||
cert_info['CN'] = attribute.value
|
||||
elif attribute.oid == x509.NameOID.COUNTRY_NAME:
|
||||
cert_info['C'] = attribute.value
|
||||
elif attribute.oid == x509.NameOID.ORGANIZATION_NAME:
|
||||
cert_info['O'] = attribute.value
|
||||
|
||||
if len(cert_info) != 3:
|
||||
raise MIoTCertError('invalid cert info')
|
||||
if (
|
||||
did and cert_info['CN'] !=
|
||||
f'mips.{self._uid}.{self.__did_hash(did=did)}.2'
|
||||
):
|
||||
raise MIoTCertError('invalid COMMON_NAME')
|
||||
if 'C' not in cert_info or cert_info['C'] != 'CN':
|
||||
raise MIoTCertError('invalid COUNTRY_NAME')
|
||||
if 'O' not in cert_info or cert_info['O'] != 'Mijia Device':
|
||||
raise MIoTCertError('invalid ORGANIZATION_NAME')
|
||||
now_utc: datetime = datetime.now(timezone.utc)
|
||||
if (
|
||||
now_utc < user_cert.not_valid_before_utc or
|
||||
now_utc > user_cert.not_valid_after_utc
|
||||
):
|
||||
raise MIoTCertError('cert is not valid')
|
||||
return int((user_cert.not_valid_after_utc-now_utc).total_seconds())
|
||||
except (MIoTCertError, ValueError) as error:
|
||||
_LOGGER.error(
|
||||
'load_pem_x509_certificate failed, %s, %s',
|
||||
error, traceback.format_exc())
|
||||
return 0
|
||||
|
||||
def gen_user_key(self) -> str:
|
||||
"""Generate user private key."""
|
||||
private_key = ed25519.Ed25519PrivateKey.generate()
|
||||
return private_key.private_bytes(
|
||||
encoding=serialization.Encoding.PEM,
|
||||
format=serialization.PrivateFormat.PKCS8,
|
||||
encryption_algorithm=serialization.NoEncryption()
|
||||
).decode('utf-8')
|
||||
|
||||
def gen_user_csr(self, user_key: str, did: str) -> str:
|
||||
"""Generate CSR of user certificate."""
|
||||
private_key = serialization.load_pem_private_key(
|
||||
data=user_key.encode('utf-8'), password=None)
|
||||
did_hash = self.__did_hash(did=did)
|
||||
builder = x509.CertificateSigningRequestBuilder().subject_name(
|
||||
x509.Name([
|
||||
# Central hub gateway service is only supported in China.
|
||||
x509.NameAttribute(NameOID.COUNTRY_NAME, 'CN'),
|
||||
x509.NameAttribute(NameOID.ORGANIZATION_NAME, 'Mijia Device'),
|
||||
x509.NameAttribute(
|
||||
NameOID.COMMON_NAME, f'mips.{self._uid}.{did_hash}.2'),
|
||||
]))
|
||||
csr = builder.sign(
|
||||
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]:
|
||||
"""Load user private key."""
|
||||
data = await self._storage.load_file_async(
|
||||
domain=self.CERT_DOMAIN, name_with_suffix=self._key_name)
|
||||
return data.decode('utf-8') if data else None
|
||||
|
||||
async def update_user_key_async(self, key: str) -> bool:
|
||||
"""Update user private key."""
|
||||
return await self._storage.save_file_async(
|
||||
domain=self.CERT_DOMAIN,
|
||||
name_with_suffix=self._key_name,
|
||||
data=key.encode('utf-8'))
|
||||
|
||||
async def load_user_cert_async(self) -> Optional[str]:
|
||||
"""Load user certificate."""
|
||||
data = await self._storage.load_file_async(
|
||||
domain=self.CERT_DOMAIN, name_with_suffix=self._cert_name)
|
||||
return data.decode('utf-8') if data else None
|
||||
|
||||
async def update_user_cert_async(self, cert: str) -> bool:
|
||||
"""Update user certificate."""
|
||||
return await self._storage.save_file_async(
|
||||
domain=self.CERT_DOMAIN,
|
||||
name_with_suffix=self._cert_name,
|
||||
data=cert.encode('utf-8'))
|
||||
|
||||
async def remove_ca_cert_async(self) -> bool:
|
||||
"""Remove CA certificate."""
|
||||
return await self._storage.remove_file_async(
|
||||
domain=self.CERT_DOMAIN, name_with_suffix=self.CA_NAME)
|
||||
|
||||
async def remove_user_key_async(self) -> bool:
|
||||
"""Remove user private key."""
|
||||
return await self._storage.remove_file_async(
|
||||
domain=self.CERT_DOMAIN, name_with_suffix=self._key_name)
|
||||
|
||||
async def remove_user_cert_async(self) -> bool:
|
||||
"""Remove user certificate."""
|
||||
return await self._storage.remove_file_async(
|
||||
domain=self.CERT_DOMAIN, name_with_suffix=self._cert_name)
|
||||
|
||||
def __did_hash(self, did: str) -> str:
|
||||
sha1_hash = hashes.Hash(hashes.SHA1(), backend=default_backend())
|
||||
sha1_hash.update(did.encode('utf-8'))
|
||||
return binascii.hexlify(sha1_hash.finalize()).decode('utf-8')
|
||||
|
||||
|
||||
class DeviceManufacturer:
|
||||
"""Device manufacturer."""
|
||||
DOMAIN: str = 'miot_specs'
|
||||
_main_loop: asyncio.AbstractEventLoop
|
||||
_storage: MIoTStorage
|
||||
_data: dict
|
||||
|
||||
def __init__(
|
||||
self, storage: MIoTStorage,
|
||||
loop: Optional[asyncio.AbstractEventLoop] = None
|
||||
) -> None:
|
||||
self._main_loop = loop or asyncio.get_event_loop()
|
||||
self._storage = storage
|
||||
self._data = {}
|
||||
|
||||
async def init_async(self) -> None:
|
||||
if self._data:
|
||||
return
|
||||
data_cache = await self._storage.load_async(
|
||||
domain=self.DOMAIN, name='manufacturer', type_=dict)
|
||||
if (
|
||||
isinstance(data_cache, dict)
|
||||
and 'data' in data_cache
|
||||
and 'ts' in data_cache
|
||||
and (int(time.time()) - data_cache['ts']) <
|
||||
MANUFACTURER_EFFECTIVE_TIME
|
||||
):
|
||||
self._data = data_cache['data']
|
||||
_LOGGER.debug('load manufacturer data success')
|
||||
return
|
||||
|
||||
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',
|
||||
data={'data': data_cloud, 'ts': int(time.time())})
|
||||
self._data = data_cloud
|
||||
_LOGGER.debug('update manufacturer data success')
|
||||
else:
|
||||
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.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
|
||||
@@ -0,0 +1,136 @@
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="icon" href="https://cdn.web-global.fds.api.mi-img.com/mcfe--mi-account/static/favicon_new.ico">
|
||||
<link as="style"
|
||||
href="https://font.sec.miui.com/font/css?family=MiSans:300,400,500,600,700:Chinese_Simplify,Chinese_Traditional,Latin&display=swap"
|
||||
rel="preload">
|
||||
<title>TITLE_PLACEHOLDER</title>
|
||||
<style>
|
||||
body {
|
||||
background: white;
|
||||
color: black;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-family: MiSans, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Helvetica Neue, Arial, Noto Sans, sans-serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol, Noto Color Emoji;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
body {
|
||||
background: black;
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
|
||||
.frame {
|
||||
background: rgb(255 255 255 / 5%);
|
||||
width: 360px;
|
||||
padding: 40 45;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 20px 50px 0 hsla(0, 0%, 64%, .1);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.logo-frame {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.title-frame {
|
||||
margin: 20px 0 20px 0;
|
||||
font-size: 26px;
|
||||
font-weight: 500;
|
||||
line-height: 40px;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.content-frame {
|
||||
font-size: 17px;
|
||||
font-weight: 500;
|
||||
line-height: 20px;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
button {
|
||||
margin-top: 20px;
|
||||
background-color: #ff5c00;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
padding: 0 20px;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
display: inline-block;
|
||||
font-size: 18px;
|
||||
font-weight: 400;
|
||||
height: 60px;
|
||||
line-height: 60px;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
text-overflow: ellipsis;
|
||||
transition: all .3s cubic-bezier(.645, .045, .355, 1);
|
||||
vertical-align: top;
|
||||
white-space: nowrap;
|
||||
cursor: pointer;
|
||||
color: #fff;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="frame">
|
||||
<!-- XIAOMI LOGO-->
|
||||
<div class="logo-frame">
|
||||
<svg width="50" height="50" viewBox="0 0 193 193" xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<title>编组</title>
|
||||
<desc>Created with Sketch.</desc>
|
||||
<defs>
|
||||
<polygon id="path-1"
|
||||
points="1.78097075e-14 0.000125324675 192.540685 0.000125324675 192.540685 192.540058 1.78097075e-14 192.540058">
|
||||
</polygon>
|
||||
</defs>
|
||||
<g id="\u9875\u9762-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
||||
<g id="\u7F16\u7EC4">
|
||||
<mask id="mask-2" fill="white">
|
||||
<use xlink:href="#path-1"></use>
|
||||
</mask>
|
||||
<g id="Clip-2"></g>
|
||||
<path
|
||||
d="M172.473071,20.1164903 C154.306633,2.02148701 128.188344,-1.78097075e-14 96.2706558,-1.78097075e-14 C64.312237,-1.78097075e-14 38.155724,2.0452987 19.9974318,20.1872987 C1.84352597,38.3261656 1.78097075e-14,64.4406948 1.78097075e-14,96.3640227 C1.78097075e-14,128.286724 1.84352597,154.415039 20.0049513,172.556412 C38.1638701,190.704052 64.3141169,192.540058 96.2706558,192.540058 C128.225942,192.540058 154.376815,190.704052 172.53636,172.556412 C190.694653,154.409399 192.540685,128.286724 192.540685,96.3640227 C192.540685,64.3999643 190.672721,38.2553571 172.473071,20.1164903"
|
||||
id="Fill-1" fill="#FF6900" mask="url(#mask-2)"></path>
|
||||
<path
|
||||
d="M89.1841721,131.948836 C89.1841721,132.594885 88.640263,133.130648 87.9779221,133.130648 L71.5585097,133.130648 C70.8848896,133.130648 70.338474,132.594885 70.338474,131.948836 L70.338474,89.0100961 C70.338474,88.3584078 70.8848896,87.8251513 71.5585097,87.8251513 L87.9779221,87.8251513 C88.640263,87.8251513 89.1841721,88.3584078 89.1841721,89.0100961 L89.1841721,131.948836 Z"
|
||||
id="Fill-3" fill="#FFFFFF" mask="url(#mask-2)"></path>
|
||||
<path
|
||||
d="M121.332896,131.948836 C121.332896,132.594885 120.786481,133.130648 120.121633,133.130648 L104.492393,133.130648 C103.821906,133.130648 103.275491,132.594885 103.275491,131.948836 L103.275491,131.788421 L103.275491,94.9022357 C103.259198,88.4342292 102.889491,81.7863818 99.5502146,78.445226 C96.6790263,75.5652649 91.3251562,74.9054305 85.7557276,74.7669468 L57.4242049,74.7669468 C56.7555977,74.7669468 56.2154484,75.3045896 56.2154484,75.9512649 L56.2154484,128.074424 L56.2154484,131.948836 C56.2154484,132.594885 55.6640198,133.130648 54.9954127,133.130648 L39.3555198,133.130648 C38.6875393,133.130648 38.1498964,132.594885 38.1498964,131.948836 L38.1498964,60.5996188 C38.1498964,59.9447974 38.6875393,59.4121675 39.3555198,59.4121675 L84.4786692,59.4121675 C96.2717211,59.4121675 108.599909,59.9498104 114.680036,66.0380831 C120.786481,72.1533006 121.332896,84.4595571 121.332896,96.2657682 L121.332896,131.948836 Z"
|
||||
id="Fill-5" fill="#FFFFFF" mask="url(#mask-2)"></path>
|
||||
<path
|
||||
d="M153.53056,131.948836 C153.53056,132.594885 152.978505,133.130648 152.316164,133.130648 L136.678778,133.130648 C136.010797,133.130648 135.467515,132.594885 135.467515,131.948836 L135.467515,60.5996188 C135.467515,59.9447974 136.010797,59.4121675 136.678778,59.4121675 L152.316164,59.4121675 C152.978505,59.4121675 153.53056,59.9447974 153.53056,60.5996188 L153.53056,131.948836 Z"
|
||||
id="Fill-7" fill="#FFFFFF" mask="url(#mask-2)"></path>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
</div>
|
||||
<!-- TITLE -->
|
||||
<div class="title-frame">
|
||||
<a id="titleArea">TITLE_PLACEHOLDER</a>
|
||||
</div>
|
||||
<!-- CONTENT -->
|
||||
<div class="content-frame">
|
||||
<a id="contentArea">CONTENT_PLACEHOLDER</a>
|
||||
</div>
|
||||
<!-- BUTTON -->
|
||||
<button onClick="window.close();" id="buttonArea">BUTTON_PLACEHOLDER</button>
|
||||
</div>
|
||||
<script>
|
||||
if (STATUS_PLACEHOLDER) {
|
||||
window.opener = null;
|
||||
window.open('', '_self');
|
||||
window.close();
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
BIN
Binary file not shown.
@@ -0,0 +1,261 @@
|
||||
data:
|
||||
urn:miot-spec-v2:property:air-cooler:000000EB: open_close
|
||||
urn:miot-spec-v2:property:alarm:00000012: open_close
|
||||
urn:miot-spec-v2:property:anion:00000025: open_close
|
||||
urn:miot-spec-v2:property:anti-fake:00000130: yes_no
|
||||
urn:miot-spec-v2:property:arrhythmia:000000B4: yes_no
|
||||
urn:miot-spec-v2:property:auto-cleanup:00000124: open_close
|
||||
urn:miot-spec-v2:property:auto-deodorization:00000125: open_close
|
||||
urn:miot-spec-v2:property:auto-keep-warm:0000002B: open_close
|
||||
urn:miot-spec-v2:property:automatic-feeding:000000F0: open_close
|
||||
urn:miot-spec-v2:property:blow:000000CD: open_close
|
||||
urn:miot-spec-v2:property:card-insertion-state:00000106: yes_no
|
||||
urn:miot-spec-v2:property:contact-state:0000007C: contact_state
|
||||
urn:miot-spec-v2:property:current-physical-control-lock:00000099: open_close
|
||||
urn:miot-spec-v2:property:delay:0000014F: yes_no
|
||||
urn:miot-spec-v2:property:deodorization:000000C6: open_close
|
||||
urn:miot-spec-v2:property:dns-auto-mode:000000DC: open_close
|
||||
urn:miot-spec-v2:property:driving-status:000000B9: yes_no
|
||||
urn:miot-spec-v2:property:dryer:00000027: open_close
|
||||
urn:miot-spec-v2:property:eco:00000024: open_close
|
||||
urn:miot-spec-v2:property:glimmer-full-color:00000089: open_close
|
||||
urn:miot-spec-v2:property:guard-mode:000000B6: open_close
|
||||
urn:miot-spec-v2:property:heater:00000026: open_close
|
||||
urn:miot-spec-v2:property:heating:000000C7: open_close
|
||||
urn:miot-spec-v2:property:horizontal-swing:00000017: open_close
|
||||
urn:miot-spec-v2:property:hot-water-recirculation:0000011C: open_close
|
||||
urn:miot-spec-v2:property:image-distortion-correction:0000010F: open_close
|
||||
urn:miot-spec-v2:property:local-storage:0000011E: yes_no
|
||||
urn:miot-spec-v2:property:motion-detection:00000056: open_close
|
||||
urn:miot-spec-v2:property:motion-state:0000007D: motion_state
|
||||
urn:miot-spec-v2:property:motion-tracking:0000008A: open_close
|
||||
urn:miot-spec-v2:property:motor-reverse:00000072: yes_no
|
||||
urn:miot-spec-v2:property:mute:00000040: open_close
|
||||
urn:miot-spec-v2:property:off-delay:00000053: open_close
|
||||
urn:miot-spec-v2:property:on:00000006: open_close
|
||||
urn:miot-spec-v2:property:physical-controls-locked:0000001D: open_close
|
||||
urn:miot-spec-v2:property:plasma:00000132: yes_no
|
||||
urn:miot-spec-v2:property:preheat:00000103: open_close
|
||||
urn:miot-spec-v2:property:seating-state:000000B8: yes_no
|
||||
urn:miot-spec-v2:property:silent-execution:000000FB: yes_no
|
||||
urn:miot-spec-v2:property:sleep-aid-mode:0000010B: open_close
|
||||
urn:miot-spec-v2:property:sleep-mode:00000028: open_close
|
||||
urn:miot-spec-v2:property:snore-state:0000012A: yes_no
|
||||
urn:miot-spec-v2:property:soft-wind:000000CF: open_close
|
||||
urn:miot-spec-v2:property:speed-control:000000E8: open_close
|
||||
urn:miot-spec-v2:property:submersion-state:0000007E: yes_no
|
||||
urn:miot-spec-v2:property:time-watermark:00000087: open_close
|
||||
urn:miot-spec-v2:property:un-straight-blowing:00000100: open_close
|
||||
urn:miot-spec-v2:property:uv:00000029: open_close
|
||||
urn:miot-spec-v2:property:valve-switch:000000FE: open_close
|
||||
urn:miot-spec-v2:property:ventilation:000000CE: open_close
|
||||
urn:miot-spec-v2:property:vertical-swing:00000018: open_close
|
||||
urn:miot-spec-v2:property:wake-up-mode:00000107: open_close
|
||||
urn:miot-spec-v2:property:water-pump:000000F2: open_close
|
||||
urn:miot-spec-v2:property:watering:000000CC: open_close
|
||||
urn:miot-spec-v2:property:wdr-mode:00000088: open_close
|
||||
urn:miot-spec-v2:property:wet:0000002A: open_close
|
||||
urn:miot-spec-v2:property:wifi-band-combine:000000E0: open_close
|
||||
urn:miot-spec-v2:property:wifi-ssid-hidden:000000E3: yes_no
|
||||
urn:miot-spec-v2:property:wind-reverse:00000117: yes_no
|
||||
translate:
|
||||
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': Истина
|
||||
tr:
|
||||
'false': Yanlış
|
||||
'true': Doğru
|
||||
zh-Hans:
|
||||
'false': 假
|
||||
'true': 真
|
||||
zh-Hant:
|
||||
'false': 假
|
||||
'true': 真
|
||||
contact_state:
|
||||
de:
|
||||
'false': Kein Kontakt
|
||||
'true': Kontakt
|
||||
en:
|
||||
'false': No Contact
|
||||
'true': Contact
|
||||
es:
|
||||
'false': Sin contacto
|
||||
'true': Contacto
|
||||
fr:
|
||||
'false': Pas de contact
|
||||
'true': Contact
|
||||
it:
|
||||
'false': Nessun contatto
|
||||
'true': Contatto
|
||||
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': Контакт
|
||||
tr:
|
||||
'false': Temas Yok
|
||||
'true': Temas
|
||||
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': Обнаружено движение
|
||||
tr:
|
||||
'false': Hareket Algılanmadı
|
||||
'true': Hareket Algılandı
|
||||
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': Открыть
|
||||
tr:
|
||||
'false': Kapalı
|
||||
'true': Açık
|
||||
zh-Hans:
|
||||
'false': 关闭
|
||||
'true': 开启
|
||||
zh-Hant:
|
||||
'false': 關閉
|
||||
'true': 開啟
|
||||
yes_no:
|
||||
de:
|
||||
'false': Nein
|
||||
'true': Ja
|
||||
en:
|
||||
'false': 'No'
|
||||
'true': 'Yes'
|
||||
es:
|
||||
'false': 'No'
|
||||
'true': Sí
|
||||
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': Да
|
||||
tr:
|
||||
'false': Hayır
|
||||
'true': Evet
|
||||
zh-Hans:
|
||||
'false': 否
|
||||
'true': 是
|
||||
zh-Hant:
|
||||
'false': 否
|
||||
'true': 是
|
||||
@@ -0,0 +1,618 @@
|
||||
{
|
||||
"urn:miot-spec-v2:device:bath-heater:0000A028:yeelink-v10": {
|
||||
"en": {
|
||||
"service:003:property:001:valuelist:000": "Idle",
|
||||
"service:003:property:001:valuelist:001": "Dry"
|
||||
},
|
||||
"tr": {
|
||||
"service:003:property:001:valuelist:000": "Boşta",
|
||||
"service:003:property:001:valuelist:001": "Kurutma"
|
||||
}
|
||||
},
|
||||
"urn:miot-spec-v2:device:electronic-valve:0000A0A7:lxzn-02": {
|
||||
"tr": {
|
||||
"service:004:property:001": "Yüksek Güç - Eşik Ayarı"
|
||||
},
|
||||
"zh-Hans": {
|
||||
"service:004:property:001": "功率过高-阈值设置"
|
||||
}
|
||||
},
|
||||
"urn:miot-spec-v2:device:electronic-valve:0000A0A7:ykcn-cbcs": {
|
||||
"tr": {
|
||||
"service:004:property:001": "Yüksek Güç - Eşik Ayarı",
|
||||
"service:004:property:009": "Düşük Voltaj Alarmı - Eşik Ayarı"
|
||||
},
|
||||
"zh-Hans": {
|
||||
"service:004:property:001": "功率过高-阈值设置",
|
||||
"service:004:property:009": "欠压告警-阈值设置"
|
||||
}
|
||||
},
|
||||
"urn:miot-spec-v2:device:fan:0000A005:zhimi-za1": {
|
||||
"tr": {
|
||||
"service:002:property:005:valuelist:000": "Doğal Rüzgar",
|
||||
"service:002:property:005:valuelist:001": "Doğrudan Üfleme"
|
||||
},
|
||||
"zh-Hans": {
|
||||
"service:002:property:005:valuelist:000": "自然风",
|
||||
"service:002:property:005:valuelist:001": "直吹风"
|
||||
}
|
||||
},
|
||||
"urn:miot-spec-v2:device:gateway:0000A019:xiaomi-hub1": {
|
||||
"de": {
|
||||
"service:001": "Geräteinformationen",
|
||||
"service:001:property:003": "Geräte-ID",
|
||||
"service:001:property:005": "Seriennummer (SN)",
|
||||
"service:002": "Gateway",
|
||||
"service:002:event:001": "Netzwerk geändert",
|
||||
"service:002:event:002": "Netzwerk geändert",
|
||||
"service:002:property:001": "Zugriffsmethode",
|
||||
"service:002:property:001:valuelist:000": "Kabelgebunden",
|
||||
"service:002:property:001:valuelist:001": "5G Drahtlos",
|
||||
"service:002:property:001:valuelist:002": "2.4G Drahtlos",
|
||||
"service:002:property:002": "IP-Adresse",
|
||||
"service:002:property:003": "WiFi-Netzwerkname",
|
||||
"service:002:property:004": "Aktuelle Zeit",
|
||||
"service:002:property:005": "DHCP-Server-MAC-Adresse",
|
||||
"service:003": "Anzeigelampe",
|
||||
"service:003:property:001": "Schalter",
|
||||
"service:004": "Virtueller Dienst",
|
||||
"service:004:action:001": "Virtuelles Ereignis erzeugen",
|
||||
"service:004:event:001": "Virtuelles Ereignis aufgetreten",
|
||||
"service:004:property:001": "Ereignisname"
|
||||
},
|
||||
"en": {
|
||||
"service:001": "Device Information",
|
||||
"service:001:property:003": "Device ID",
|
||||
"service:001:property:005": "Serial Number (SN)",
|
||||
"service:002": "Gateway",
|
||||
"service:002:event:001": "Network Changed",
|
||||
"service:002:event:002": "Network Changed",
|
||||
"service:002:property:001": "Access Method",
|
||||
"service:002:property:001:valuelist:000": "Wired",
|
||||
"service:002:property:001:valuelist:001": "5G Wireless",
|
||||
"service:002:property:001:valuelist:002": "2.4G Wireless",
|
||||
"service:002:property:002": "IP Address",
|
||||
"service:002:property:003": "WiFi Network Name",
|
||||
"service:002:property:004": "Current Time",
|
||||
"service:002:property:005": "DHCP Server MAC Address",
|
||||
"service:003": "Indicator Light",
|
||||
"service:003:property:001": "Switch",
|
||||
"service:004": "Virtual Service",
|
||||
"service:004:action:001": "Generate Virtual Event",
|
||||
"service:004:event:001": "Virtual Event Occurred",
|
||||
"service:004:property:001": "Event Name"
|
||||
},
|
||||
"es": {
|
||||
"service:001": "Información del dispositivo",
|
||||
"service:001:property:003": "ID del dispositivo",
|
||||
"service:001:property:005": "Número de serie (SN)",
|
||||
"service:002": "Puerta de enlace",
|
||||
"service:002:event:001": "Cambio de red",
|
||||
"service:002:event:002": "Cambio de red",
|
||||
"service:002:property:001": "Método de acceso",
|
||||
"service:002:property:001:valuelist:000": "Cableado",
|
||||
"service:002:property:001:valuelist:001": "5G inalámbrico",
|
||||
"service:002:property:001:valuelist:002": "2.4G inalámbrico",
|
||||
"service:002:property:002": "Dirección IP",
|
||||
"service:002:property:003": "Nombre de red WiFi",
|
||||
"service:002:property:004": "Hora actual",
|
||||
"service:002:property:005": "Dirección MAC del servidor DHCP",
|
||||
"service:003": "Luz indicadora",
|
||||
"service:003:property:001": "Interruptor",
|
||||
"service:004": "Servicio virtual",
|
||||
"service:004:action:001": "Generar evento virtual",
|
||||
"service:004:event:001": "Ocurrió un evento virtual",
|
||||
"service:004:property:001": "Nombre del evento"
|
||||
},
|
||||
"fr": {
|
||||
"service:001": "Informations sur l'appareil",
|
||||
"service:001:property:003": "ID de l'appareil",
|
||||
"service:001:property:005": "Numéro de série (SN)",
|
||||
"service:002": "Passerelle",
|
||||
"service:002:event:001": "Changement de réseau",
|
||||
"service:002:event:002": "Changement de réseau",
|
||||
"service:002:property:001": "Méthode d'accès",
|
||||
"service:002:property:001:valuelist:000": "Câblé",
|
||||
"service:002:property:001:valuelist:001": "Sans fil 5G",
|
||||
"service:002:property:001:valuelist:002": "Sans fil 2.4G",
|
||||
"service:002:property:002": "Adresse IP",
|
||||
"service:002:property:003": "Nom du réseau WiFi",
|
||||
"service:002:property:004": "Heure actuelle",
|
||||
"service:002:property:005": "Adresse MAC du serveur DHCP",
|
||||
"service:003": "Voyant lumineux",
|
||||
"service:003:property:001": "Interrupteur",
|
||||
"service:004": "Service virtuel",
|
||||
"service:004:action:001": "Générer un événement virtuel",
|
||||
"service:004:event:001": "Événement virtuel survenu",
|
||||
"service:004:property:001": "Nom de l'événement"
|
||||
},
|
||||
"ja": {
|
||||
"service:001": "デバイス情報",
|
||||
"service:001:property:003": "デバイスID",
|
||||
"service:001:property:005": "シリアル番号 (SN)",
|
||||
"service:002": "ゲートウェイ",
|
||||
"service:002:event:001": "ネットワークが変更されました",
|
||||
"service:002:event:002": "ネットワークが変更されました",
|
||||
"service:002:property:001": "アクセス方法",
|
||||
"service:002:property:001:valuelist:000": "有線",
|
||||
"service:002:property:001:valuelist:001": "5G ワイヤレス",
|
||||
"service:002:property:001:valuelist:002": "2.4G ワイヤレス",
|
||||
"service:002:property:002": "IPアドレス",
|
||||
"service:002:property:003": "WiFiネットワーク名",
|
||||
"service:002:property:004": "現在の時間",
|
||||
"service:002:property:005": "DHCPサーバーMACアドレス",
|
||||
"service:003": "インジケータライト",
|
||||
"service:003:property:001": "スイッチ",
|
||||
"service:004": "バーチャルサービス",
|
||||
"service:004:action:001": "バーチャルイベントを生成",
|
||||
"service:004:event:001": "バーチャルイベントが発生しました",
|
||||
"service:004:property:001": "イベント名"
|
||||
},
|
||||
"ru": {
|
||||
"service:001": "Информация об устройстве",
|
||||
"service:001:property:003": "ID устройства",
|
||||
"service:001:property:005": "Серийный номер (SN)",
|
||||
"service:002": "Шлюз",
|
||||
"service:002:event:001": "Сеть изменена",
|
||||
"service:002:event:002": "Сеть изменена",
|
||||
"service:002:property:001": "Метод доступа",
|
||||
"service:002:property:001:valuelist:000": "Проводной",
|
||||
"service:002:property:001:valuelist:001": "5G Беспроводной",
|
||||
"service:002:property:001:valuelist:002": "2.4G Беспроводной",
|
||||
"service:002:property:002": "IP Адрес",
|
||||
"service:002:property:003": "Название WiFi сети",
|
||||
"service:002:property:004": "Текущее время",
|
||||
"service:002:property:005": "MAC адрес DHCP сервера",
|
||||
"service:003": "Световой индикатор",
|
||||
"service:003:property:001": "Переключатель",
|
||||
"service:004": "Виртуальная служба",
|
||||
"service:004:action:001": "Создать виртуальное событие",
|
||||
"service:004:event:001": "Произошло виртуальное событие",
|
||||
"service:004:property:001": "Название события"
|
||||
},
|
||||
"tr": {
|
||||
"service:001": "Cihaz Bilgileri",
|
||||
"service:001:property:003": "Cihaz ID",
|
||||
"service:001:property:005": "Seri Numarası (SN)",
|
||||
"service:002": "Ağ Geçidi",
|
||||
"service:002:event:001": "Ağ Değişti",
|
||||
"service:002:event:002": "Ağ Değişti",
|
||||
"service:002:property:001": "Erişim Yöntemi",
|
||||
"service:002:property:001:valuelist:000": "Kablolu",
|
||||
"service:002:property:001:valuelist:001": "5G Kablosuz",
|
||||
"service:002:property:001:valuelist:002": "2.4G Kablosuz",
|
||||
"service:002:property:002": "IP Adresi",
|
||||
"service:002:property:003": "WiFi Ağ Adı",
|
||||
"service:002:property:004": "Geçerli Zaman",
|
||||
"service:002:property:005": "DHCP Sunucusu MAC Adresi",
|
||||
"service:003": "Gösterge Işığı",
|
||||
"service:003:property:001": "Anahtar",
|
||||
"service:004": "Sanal Hizmet",
|
||||
"service:004:action:001": "Sanal Olay Oluştur",
|
||||
"service:004:event:001": "Sanal Olay Gerçekleşti",
|
||||
"service:004:property:001": "Olay Adı"
|
||||
},
|
||||
"zh-Hant": {
|
||||
"service:001": "設備信息",
|
||||
"service:001:property:003": "設備ID",
|
||||
"service:001:property:005": "序號 (SN)",
|
||||
"service:002": "網關",
|
||||
"service:002:event:001": "網路發生變化",
|
||||
"service:002:event:002": "網路發生變化",
|
||||
"service:002:property:001": "接入方式",
|
||||
"service:002:property:001:valuelist:000": "有線",
|
||||
"service:002:property:001:valuelist:001": "5G 無線",
|
||||
"service:002:property:001:valuelist:002": "2.4G 無線",
|
||||
"service:002:property:002": "IP地址",
|
||||
"service:002:property:003": "WiFi網路名稱",
|
||||
"service:002:property:004": "當前時間",
|
||||
"service:002:property:005": "DHCP伺服器MAC地址",
|
||||
"service:003": "指示燈",
|
||||
"service:003:property:001": "開關",
|
||||
"service:004": "虛擬服務",
|
||||
"service:004:action:001": "產生虛擬事件",
|
||||
"service:004:event:001": "虛擬事件發生",
|
||||
"service:004:property:001": "事件名稱"
|
||||
}
|
||||
},
|
||||
"urn:miot-spec-v2:device:lock:0000A038:loock-t2pv1": {
|
||||
"tr": {
|
||||
"service:003:property:1021:valuelist:000": "Kilitli",
|
||||
"service:003:property:1021:valuelist:001": "Kilitli (Çocuk Kilidi)",
|
||||
"service:003:property:1021:valuelist:002": "Kilitli (İçten Kilitli)",
|
||||
"service:003:property:1021:valuelist:003": "Kilitli (İçten Kilitli + Çocuk Kilidi)",
|
||||
"service:003:property:1021:valuelist:004": "Kilidi Açık",
|
||||
"service:003:property:1021:valuelist:008": "Kapı Kapalı Değil (Zaman Aşımı)",
|
||||
"service:003:property:1021:valuelist:012": "Kapı Aralık"
|
||||
},
|
||||
"zh-Hans": {
|
||||
"service:003:property:1021:valuelist:000": "已上锁",
|
||||
"service:003:property:1021:valuelist:001": "已上锁(童锁)",
|
||||
"service:003:property:1021:valuelist:002": "已上锁(反锁)",
|
||||
"service:003:property:1021:valuelist:003": "已上锁(反锁+童锁)",
|
||||
"service:003:property:1021:valuelist:004": "已开锁",
|
||||
"service:003:property:1021:valuelist:008": "门未关(门超时未关)",
|
||||
"service:003:property:1021:valuelist:012": "门虚掩"
|
||||
}
|
||||
},
|
||||
"urn:miot-spec-v2:device:plant-monitor:0000A030:hhcc-v1": {
|
||||
"en": {
|
||||
"service:002:property:001": "Soil Moisture"
|
||||
},
|
||||
"tr": {
|
||||
"service:002:property:001": "Toprak Nemi",
|
||||
"service:002:property:003": "Işık Yoğunluğu"
|
||||
},
|
||||
"zh-Hans": {
|
||||
"service:002:property:001": "土壤湿度",
|
||||
"service:002:property:003": "光照强度"
|
||||
}
|
||||
},
|
||||
"urn:miot-spec-v2:device:switch:0000A003:090615-x1tpm": {
|
||||
"en": {
|
||||
"service:027:property:001": "Fan Switch",
|
||||
"service:027:property:003": "Light Switch",
|
||||
"service:027:property:004": "Fan and Light Switch"
|
||||
},
|
||||
"tr": {
|
||||
"service:027:property:001": "Vantilatör Anahtarı",
|
||||
"service:027:property:003": "Işık Anahtarı",
|
||||
"service:027:property:004": "Vantilatör ve Işık Anahtarı"
|
||||
}
|
||||
},
|
||||
"urn:miot-spec-v2:device:switch:0000A003:lumi-acn040": {
|
||||
"en": {
|
||||
"service:011": "Right Button On and Off",
|
||||
"service:011:property:001": "Right Button On and Off",
|
||||
"service:015:action:001": "Left Button Identify",
|
||||
"service:016:action:001": "Middle Button Identify",
|
||||
"service:017:action:001": "Right Button Identify"
|
||||
},
|
||||
"tr": {
|
||||
"service:011": "Sağ Düğme Açma ve Kapama",
|
||||
"service:011:property:001": "Sağ Düğme Açma ve Kapama",
|
||||
"service:015:action:001": "Sol Düğme Tanımlama",
|
||||
"service:016:action:001": "Orta Düğme Tanımlama",
|
||||
"service:017:action:001": "Sağ Düğme Tanımlama"
|
||||
},
|
||||
"zh-Hans": {
|
||||
"service:015:action:001": "左键确认",
|
||||
"service:016:action:001": "中键确认",
|
||||
"service:017:action:001": "右键确认"
|
||||
}
|
||||
},
|
||||
"urn:miot-spec-v2:device:thermostat:0000A031:cubee-th123e": {
|
||||
"ru": {
|
||||
"service:002": "термостат",
|
||||
"service:002:property:001": "выключатель",
|
||||
"service:002:property:002": "режим нагрузки",
|
||||
"service:002:property:002:valuelist:000": "без подогрева",
|
||||
"service:002:property:002:valuelist:001": "нагрев",
|
||||
"service:002:property:003": "неисправность",
|
||||
"service:002:property:003:valuelist:000": "ошибка датчика",
|
||||
"service:002:property:003:valuelist:001": "без ошибок",
|
||||
"service:002:property:003:valuelist:002": "защита от высоких температур",
|
||||
"service:002:property:003:valuelist:003": "криогенная защита",
|
||||
"service:002:property:004": "режим",
|
||||
"service:002:property:004:valuelist:000": "ручной режим",
|
||||
"service:002:property:004:valuelist:001": "домашний режим",
|
||||
"service:002:property:004:valuelist:002": "режим выхода из дома",
|
||||
"service:002:property:004:valuelist:003": "автоматический режим",
|
||||
"service:002:property:004:valuelist:004": "Режим сна",
|
||||
"service:002:property:005": "температура цели",
|
||||
"service:002:property:007": "текущая температура",
|
||||
"service:004": "Пользовательские услуги",
|
||||
"service:004:property:001": "детский замок",
|
||||
"service:004:property:002": "тип датчика",
|
||||
"service:004:property:002:valuelist:000": "внутренний датчик",
|
||||
"service:004:property:002:valuelist:001": "выносной датчик",
|
||||
"service:004:property:002:valuelist:002": "встроенный и внешний датчик",
|
||||
"service:004:property:003": "пусковая разность температур",
|
||||
"service:004:property:004": "компенсационная температура",
|
||||
"service:004:property:005": "температура выносного датчика",
|
||||
"service:004:property:006": "максимальная температура цели",
|
||||
"service:004:property:007": "минимальная температура цели "
|
||||
},
|
||||
"tr": {
|
||||
"service:002": "Termostat",
|
||||
"service:002:property:001": "Anahtar",
|
||||
"service:002:property:002": "Yük Modu",
|
||||
"service:002:property:002:valuelist:000": "Isıtmasız",
|
||||
"service:002:property:002:valuelist:001": "Isıtma",
|
||||
"service:002:property:003": "Arıza",
|
||||
"service:002:property:003:valuelist:000": "Sensör Hatası",
|
||||
"service:002:property:003:valuelist:001": "Hata Yok",
|
||||
"service:002:property:003:valuelist:002": "Yüksek Sıcaklık Koruması",
|
||||
"service:002:property:003:valuelist:003": "Düşük Sıcaklık Koruması",
|
||||
"service:002:property:004": "Mod",
|
||||
"service:002:property:004:valuelist:000": "Manuel Mod",
|
||||
"service:002:property:004:valuelist:001": "Ev Modu",
|
||||
"service:002:property:004:valuelist:002": "Dışarıda Modu",
|
||||
"service:002:property:004:valuelist:003": "Otomatik Mod",
|
||||
"service:002:property:004:valuelist:004": "Uyku Modu",
|
||||
"service:002:property:005": "Hedef Sıcaklık",
|
||||
"service:002:property:007": "Geçerli Sıcaklık",
|
||||
"service:004": "Özel Hizmetler",
|
||||
"service:004:property:001": "Çocuk Kilidi",
|
||||
"service:004:property:002": "Sensör Tipi",
|
||||
"service:004:property:002:valuelist:000": "Dahili Sensör",
|
||||
"service:004:property:002:valuelist:001": "Harici Sensör",
|
||||
"service:004:property:002:valuelist:002": "Dahili ve Harici Sensör",
|
||||
"service:004:property:003": "Başlangıç Sıcaklık Farkı",
|
||||
"service:004:property:004": "Telafi Sıcaklığı",
|
||||
"service:004:property:005": "Harici Sensör Sıcaklığı",
|
||||
"service:004:property:006": "Maksimum Hedef Sıcaklık",
|
||||
"service:004:property:007": "Minimum Hedef Sıcaklık"
|
||||
}
|
||||
},
|
||||
"urn:miot-spec-v2:device:thermostat:0000A031:cubee-th123w": {
|
||||
"ru": {
|
||||
"service:002": "термостат",
|
||||
"service:002:property:001": "выключатель",
|
||||
"service:002:property:002": "режим нагрузки",
|
||||
"service:002:property:002:valuelist:000": "нагрев",
|
||||
"service:002:property:002:valuelist:001": "без подогрева",
|
||||
"service:002:property:003": "неисправность",
|
||||
"service:002:property:003:valuelist:000": "без ошибок",
|
||||
"service:002:property:003:valuelist:001": "ошибка датчика",
|
||||
"service:002:property:003:valuelist:002": "защита от высоких температур",
|
||||
"service:002:property:003:valuelist:003": "криогенная защита",
|
||||
"service:002:property:004": "режим",
|
||||
"service:002:property:004:valuelist:000": "ручной режим",
|
||||
"service:002:property:004:valuelist:001": "домашний режим",
|
||||
"service:002:property:004:valuelist:002": "режим выхода из дома",
|
||||
"service:002:property:004:valuelist:003": "автоматический режим",
|
||||
"service:002:property:004:valuelist:004": "Режим сна",
|
||||
"service:002:property:005": "температура цели",
|
||||
"service:002:property:007": "текущая температура",
|
||||
"service:004": "Пользовательские услуги",
|
||||
"service:004:property:001": "детский замок",
|
||||
"service:004:property:002": "тип датчика",
|
||||
"service:004:property:002:valuelist:000": "внутренний датчик",
|
||||
"service:004:property:002:valuelist:001": "выносной датчик",
|
||||
"service:004:property:002:valuelist:002": "встроенный и внешний датчик",
|
||||
"service:004:property:003": "пусковая разность температур",
|
||||
"service:004:property:004": "компенсационная температура",
|
||||
"service:004:property:005": "температура выносного датчика",
|
||||
"service:004:property:006": "максимальная температура цели",
|
||||
"service:004:property:007": "минимальная температура цели "
|
||||
},
|
||||
"tr": {
|
||||
"service:002": "Termostat",
|
||||
"service:002:property:001": "Anahtar",
|
||||
"service:002:property:002": "Yük Modu",
|
||||
"service:002:property:002:valuelist:000": "Isıtma",
|
||||
"service:002:property:002:valuelist:001": "Isıtmasız",
|
||||
"service:002:property:003": "Arıza",
|
||||
"service:002:property:003:valuelist:000": "Hata Yok",
|
||||
"service:002:property:003:valuelist:001": "Sensör Hatası",
|
||||
"service:002:property:003:valuelist:002": "Yüksek Sıcaklık Koruması",
|
||||
"service:002:property:003:valuelist:003": "Düşük Sıcaklık Koruması",
|
||||
"service:002:property:004": "Mod",
|
||||
"service:002:property:004:valuelist:000": "Manuel Mod",
|
||||
"service:002:property:004:valuelist:001": "Ev Modu",
|
||||
"service:002:property:004:valuelist:002": "Dışarıda Modu",
|
||||
"service:002:property:004:valuelist:003": "Otomatik Mod",
|
||||
"service:002:property:004:valuelist:004": "Uyku Modu",
|
||||
"service:002:property:005": "Hedef Sıcaklık",
|
||||
"service:002:property:007": "Geçerli Sıcaklık",
|
||||
"service:004": "Özel Hizmetler",
|
||||
"service:004:property:001": "Çocuk Kilidi",
|
||||
"service:004:property:002": "Sensör Tipi",
|
||||
"service:004:property:002:valuelist:000": "Dahili Sensör",
|
||||
"service:004:property:002:valuelist:001": "Harici Sensör",
|
||||
"service:004:property:002:valuelist:002": "Dahili ve Harici Sensör",
|
||||
"service:004:property:003": "Başlangıç Sıcaklık Farkı",
|
||||
"service:004:property:004": "Telafi Sıcaklığı",
|
||||
"service:004:property:005": "Harici Sensör Sıcaklığı",
|
||||
"service:004:property:006": "Maksimum Hedef Sıcaklık",
|
||||
"service:004:property:007": "Minimum Hedef Sıcaklık"
|
||||
}
|
||||
},
|
||||
"urn:miot-spec-v2:device:thermostat:0000A031:tofan-wk01": {
|
||||
"en": {
|
||||
"service:002": "Thermostat",
|
||||
"service:002:property:002": "Air Conditioner Mode",
|
||||
"service:004": "Air Conditioner"
|
||||
},
|
||||
"tr": {
|
||||
"service:002": "Yerden Isıtma",
|
||||
"service:002:property:002": "Klima Modu",
|
||||
"service:004": "Klima"
|
||||
},
|
||||
"zh-Hans": {
|
||||
"service:002": "地暖",
|
||||
"service:004": "空调"
|
||||
}
|
||||
},
|
||||
"urn:miot-spec-v2:device:vacuum:0000A006:ijai-v1": {
|
||||
"tr": {
|
||||
"service:007:property:005:valuelist:000": "Sessiz",
|
||||
"service:007:property:005:valuelist:001": "Standart",
|
||||
"service:007:property:005:valuelist:002": "Orta",
|
||||
"service:007:property:005:valuelist:003": "Güçlü"
|
||||
},
|
||||
"zh-Hans": {
|
||||
"service:007:property:005:valuelist:000": "安静",
|
||||
"service:007:property:005:valuelist:001": "标准",
|
||||
"service:007:property:005:valuelist:002": "中档",
|
||||
"service:007:property:005:valuelist:003": "强力"
|
||||
}
|
||||
},
|
||||
"urn:miot-spec-v2:device:vacuum:0000A006:narwa-001": {
|
||||
"tr": {
|
||||
"service:001": "Cihaz Bilgileri",
|
||||
"service:002": "Pil",
|
||||
"service:002:property:001": "Pil Seviyesi",
|
||||
"service:003": "Robot Süpürge",
|
||||
"service:003:property:001": "Çalışma Durumu",
|
||||
"service:004": "Temizleme",
|
||||
"service:004:property:001": "Temizlik Modu",
|
||||
"service:004:property:002": "Emme Gücü",
|
||||
"service:005": "Harita Yönetimi",
|
||||
"service:005:property:001": "Harita Listesi",
|
||||
"service:005:property:002": "Aktif Harita",
|
||||
"service:005:property:003": "Harita Adı",
|
||||
"service:006": "Tüketim Malzemeleri",
|
||||
"service:006:property:001": "Ana Fırça Ömrü",
|
||||
"service:006:property:002": "Yan Fırça Ömrü",
|
||||
"service:006:property:003": "Filtre Ömrü"
|
||||
}
|
||||
},
|
||||
"urn:miot-spec-v2:device:vacuum:0000A006:narwa-ax11": {
|
||||
"tr": {
|
||||
"service:001": "Cihaz Bilgileri",
|
||||
"service:002": "Pil",
|
||||
"service:002:property:001": "Pil Seviyesi",
|
||||
"service:003": "Robot Süpürge",
|
||||
"service:003:property:001": "Çalışma Durumu",
|
||||
"service:004": "Temizleme",
|
||||
"service:004:property:001": "Temizlik Modu",
|
||||
"service:004:property:002": "Emme Gücü",
|
||||
"service:005": "Harita Yönetimi",
|
||||
"service:005:property:001": "Harita Listesi",
|
||||
"service:005:property:002": "Aktif Harita",
|
||||
"service:005:property:003": "Harita Adı",
|
||||
"service:006": "Tüketim Malzemeleri",
|
||||
"service:006:property:001": "Ana Fırça Ömrü",
|
||||
"service:006:property:002": "Yan Fırça Ömrü",
|
||||
"service:006:property:003": "Filtre Ömrü"
|
||||
}
|
||||
},
|
||||
"urn:miot-spec-v2:device:vacuum:0000A006:roidmi-v60": {
|
||||
"tr": {
|
||||
"service:001": "Cihaz Bilgileri",
|
||||
"service:002": "Pil",
|
||||
"service:002:property:001": "Pil Seviyesi",
|
||||
"service:003": "Robot Süpürge",
|
||||
"service:003:property:001": "Çalışma Durumu",
|
||||
"service:004": "Temizleme",
|
||||
"service:004:property:001": "Temizlik Modu",
|
||||
"service:004:property:002": "Emme Gücü",
|
||||
"service:004:property:003": "Temizlik Süresi",
|
||||
"service:004:property:004": "Temizlenen Alan",
|
||||
"service:005": "Harita Yönetimi",
|
||||
"service:005:property:001": "Harita Listesi",
|
||||
"service:005:property:002": "Aktif Harita",
|
||||
"service:005:property:003": "Harita Adı",
|
||||
"service:006": "Tüketim Malzemeleri",
|
||||
"service:006:property:001": "Ana Fırça Ömrü",
|
||||
"service:006:property:002": "Yan Fırça Ömrü",
|
||||
"service:006:property:003": "Filtre Ömrü",
|
||||
"service:007": "Emme Gücü",
|
||||
"service:007:property:001": "Güç Seviyesi",
|
||||
"service:007:property:001:valuelist:000": "Sessiz",
|
||||
"service:007:property:001:valuelist:001": "Standart",
|
||||
"service:007:property:001:valuelist:002": "Orta",
|
||||
"service:007:property:001:valuelist:003": "Güçlü"
|
||||
}
|
||||
},
|
||||
"urn:miot-spec-v2:device:vacuum:0000A006:viomi-v38": {
|
||||
"tr": {
|
||||
"service:001": "Cihaz Bilgileri",
|
||||
"service:002": "Pil",
|
||||
"service:002:property:001": "Pil Seviyesi",
|
||||
"service:002:property:002": "Şarj Durumu",
|
||||
"service:003": "Robot Süpürge",
|
||||
"service:003:property:001": "Çalışma Durumu",
|
||||
"service:003:property:002": "Hata Kodu",
|
||||
"service:004": "Temizleme",
|
||||
"service:004:property:001": "Temizlik Modu",
|
||||
"service:004:property:002": "Emme Gücü",
|
||||
"service:004:property:003": "Su Seviyesi",
|
||||
"service:004:property:004": "Temizlik Süresi",
|
||||
"service:004:property:005": "Temizlenen Alan",
|
||||
"service:005": "Tüketim Malzemeleri",
|
||||
"service:005:property:001": "Ana Fırça Ömrü",
|
||||
"service:005:property:002": "Yan Fırça Ömrü",
|
||||
"service:005:property:003": "Filtre Ömrü",
|
||||
"service:005:property:004": "Sensör Ömrü",
|
||||
"service:005:property:005": "Paspas Bezi Ömrü",
|
||||
"service:006": "Harita Yönetimi",
|
||||
"service:006:property:001": "Harita Listesi",
|
||||
"service:006:property:002": "Aktif Harita",
|
||||
"service:006:property:003": "Harita Adı",
|
||||
"service:006:property:004": "Harita ID",
|
||||
"service:007": "Emme Gücü",
|
||||
"service:007:property:001": "Güç Seviyesi",
|
||||
"service:007:property:001:valuelist:000": "Sessiz",
|
||||
"service:007:property:001:valuelist:001": "Standart",
|
||||
"service:007:property:001:valuelist:002": "Orta",
|
||||
"service:007:property:001:valuelist:003": "Güçlü",
|
||||
"service:007:property:001:valuelist:004": "Maksimum",
|
||||
"service:008": "Su Tankı",
|
||||
"service:008:property:001": "Su Seviyesi",
|
||||
"service:008:property:001:valuelist:000": "Düşük",
|
||||
"service:008:property:001:valuelist:001": "Orta",
|
||||
"service:008:property:001:valuelist:002": "Yüksek",
|
||||
"service:009": "Bölge Temizliği",
|
||||
"service:009:property:001": "Oda Seçimi",
|
||||
"service:009:property:002": "Bölge Temizliği",
|
||||
"service:010": "Zamanlama",
|
||||
"service:010:property:001": "Zamanlayıcı",
|
||||
"service:010:property:002": "Temizlik Zamanı",
|
||||
"service:011": "Ses ve Bildirim",
|
||||
"service:011:property:001": "Ses Seviyesi",
|
||||
"service:011:property:002": "Sesli Bildirimler",
|
||||
"service:012": "Gelişmiş Ayarlar",
|
||||
"service:012:property:001": "Halı Modu",
|
||||
"service:012:property:002": "Tekrar Geçiş",
|
||||
"service:012:property:003": "Kenar Temizliği",
|
||||
"service:012:property:004": "Engel Algılama"
|
||||
}
|
||||
},
|
||||
"urn:miot-spec-v2:device:vacuum:0000A006:viomi-v5": {
|
||||
"tr": {
|
||||
"service:001": "Cihaz Bilgileri",
|
||||
"service:002": "Pil",
|
||||
"service:002:property:001": "Pil Seviyesi",
|
||||
"service:002:property:002": "Şarj Durumu",
|
||||
"service:003": "Robot Süpürge",
|
||||
"service:003:property:001": "Çalışma Durumu",
|
||||
"service:003:property:002": "Hata Kodu",
|
||||
"service:004": "Temizleme",
|
||||
"service:004:property:001": "Temizlik Modu",
|
||||
"service:004:property:002": "Emme Gücü",
|
||||
"service:004:property:003": "Su Seviyesi",
|
||||
"service:004:property:004": "Temizlik Süresi",
|
||||
"service:004:property:005": "Temizlenen Alan",
|
||||
"service:005": "Tüketim Malzemeleri",
|
||||
"service:005:property:001": "Ana Fırça Ömrü",
|
||||
"service:005:property:002": "Yan Fırça Ömrü",
|
||||
"service:005:property:003": "Filtre Ömrü",
|
||||
"service:005:property:004": "Sensör Ömrü",
|
||||
"service:005:property:005": "Paspas Bezi Ömrü",
|
||||
"service:006": "Harita Yönetimi",
|
||||
"service:006:property:001": "Harita Listesi",
|
||||
"service:006:property:002": "Aktif Harita",
|
||||
"service:006:property:003": "Harita Adı",
|
||||
"service:006:property:004": "Harita ID",
|
||||
"service:007": "Emme Gücü",
|
||||
"service:007:property:001": "Güç Seviyesi",
|
||||
"service:007:property:001:valuelist:000": "Sessiz",
|
||||
"service:007:property:001:valuelist:001": "Standart",
|
||||
"service:007:property:001:valuelist:002": "Orta",
|
||||
"service:007:property:001:valuelist:003": "Güçlü",
|
||||
"service:007:property:001:valuelist:004": "Maksimum",
|
||||
"service:008": "Su Tankı",
|
||||
"service:008:property:001": "Su Seviyesi",
|
||||
"service:008:property:001:valuelist:000": "Düşük",
|
||||
"service:008:property:001:valuelist:001": "Orta",
|
||||
"service:008:property:001:valuelist:002": "Yüksek",
|
||||
"service:009": "Bölge Temizliği",
|
||||
"service:009:property:001": "Oda Seçimi",
|
||||
"service:009:property:002": "Bölge Temizliği",
|
||||
"service:010": "Zamanlama",
|
||||
"service:010:property:001": "Zamanlayıcı",
|
||||
"service:010:property:002": "Temizlik Zamanı",
|
||||
"service:011": "Ses ve Bildirim",
|
||||
"service:011:property:001": "Ses Seviyesi",
|
||||
"service:011:property:002": "Sesli Bildirimler",
|
||||
"service:012": "Gelişmiş Ayarlar",
|
||||
"service:012:property:001": "Halı Modu",
|
||||
"service:012:property:002": "Tekrar Geçiş",
|
||||
"service:012:property:003": "Kenar Temizliği",
|
||||
"service:012:property:004": "Engel Algılama"
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,69 @@
|
||||
urn:miot-spec-v2:device:air-conditioner:0000A004:090615-ktf:
|
||||
services:
|
||||
- '4'
|
||||
urn:miot-spec-v2:device:air-conditioner:0000A004:759413-iez:
|
||||
properties:
|
||||
- '2.3'
|
||||
urn:miot-spec-v2:device:air-purifier:0000A007:zhimi-ma4:
|
||||
properties:
|
||||
- 9.*
|
||||
- 13.*
|
||||
- 15.*
|
||||
services:
|
||||
- '10'
|
||||
urn:miot-spec-v2:device:airer:0000A00D:hyd-lyjpro:
|
||||
properties:
|
||||
- '3.2'
|
||||
urn:miot-spec-v2:device:curtain:0000A00C:lumi-hmcn01:
|
||||
properties:
|
||||
- '5.1'
|
||||
services:
|
||||
- '4'
|
||||
- '7'
|
||||
- '8'
|
||||
urn:miot-spec-v2:device:gateway:0000A019:xiaomi-hub1:
|
||||
events:
|
||||
- '2.1'
|
||||
urn:miot-spec-v2:device:health-pot:0000A051:chunmi-a1:
|
||||
services:
|
||||
- '5'
|
||||
urn:miot-spec-v2:device:light:0000A001:philips-strip3:
|
||||
properties:
|
||||
- '2.2'
|
||||
services:
|
||||
- '1'
|
||||
- '3'
|
||||
urn:miot-spec-v2:device:light:0000A001:yeelink-color2:
|
||||
properties:
|
||||
- 3.*
|
||||
- '2.5'
|
||||
urn:miot-spec-v2:device:light:0000A001:yeelink-dnlight2:
|
||||
services:
|
||||
- '3'
|
||||
urn:miot-spec-v2:device:light:0000A001:yeelink-mbulb3:
|
||||
services:
|
||||
- '3'
|
||||
urn:miot-spec-v2:device:motion-sensor:0000A014:xiaomi-pir1:
|
||||
services:
|
||||
- '1'
|
||||
- '5'
|
||||
urn:miot-spec-v2:device:speaker:0000A015:xiaomi-l15a:
|
||||
properties:
|
||||
- '3.3'
|
||||
- '6.1'
|
||||
- '6.2'
|
||||
- '6.3'
|
||||
- '6.4'
|
||||
urn:miot-spec-v2:device:thermostat:0000A031:tofan-wk01:
|
||||
services:
|
||||
- '2'
|
||||
- '4'
|
||||
urn:miot-spec-v2:device:vacuum:0000A006:narwa-001:
|
||||
services:
|
||||
- '*'
|
||||
urn:miot-spec-v2:device:vacuum:0000A006:narwa-ax11:
|
||||
services:
|
||||
- '*'
|
||||
urn:miot-spec-v2:device:vacuum:0000A006:roidmi-v60:
|
||||
actions:
|
||||
- '2.3'
|
||||
@@ -0,0 +1,615 @@
|
||||
urn:miot-spec-v2:device:air-condition-outlet:0000A045:lumi-mcn04:1:
|
||||
prop.3.4:
|
||||
format: uint8
|
||||
urn:miot-spec-v2:device:air-conditioner:0000A004:daikin-k2:1:
|
||||
prop.2.1:
|
||||
name: ac-on
|
||||
format: string
|
||||
access:
|
||||
- read
|
||||
- notify
|
||||
prop.2.2:
|
||||
name: ac-mode
|
||||
format: string
|
||||
access:
|
||||
- read
|
||||
- notify
|
||||
prop.3.1:
|
||||
name: ac-fan-level
|
||||
format: string
|
||||
access:
|
||||
- read
|
||||
- notify
|
||||
urn:miot-spec-v2:device:air-conditioner:0000A004:qdhkl-a42:1:
|
||||
prop.2.2:
|
||||
value-list:
|
||||
- value: 1
|
||||
description: Cool
|
||||
- value: 2
|
||||
description: Dry
|
||||
- value: 4
|
||||
description: Fan
|
||||
- value: 8
|
||||
description: Heat
|
||||
- value: 9
|
||||
description: Auto
|
||||
- value: 10
|
||||
description: Heat_cool
|
||||
urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-c17:1:
|
||||
prop.10.6:
|
||||
unit: none
|
||||
urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-c17:2: urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-c17:1
|
||||
urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-c20:1:
|
||||
prop.10.6:
|
||||
unit: none
|
||||
urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-c20:2: urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-c20:1
|
||||
urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-c24:1:
|
||||
prop.8.6:
|
||||
name: power-consumption
|
||||
unit: kWh
|
||||
prop.10.6:
|
||||
unit: none
|
||||
urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-c24:2: urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-c24:1
|
||||
urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-c35:1:
|
||||
prop.10.6:
|
||||
unit: none
|
||||
urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-c35:2: urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-c35:1
|
||||
urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-h09h00:4:
|
||||
prop.10.6:
|
||||
unit: none
|
||||
urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-h40h00:1:
|
||||
prop.10.6:
|
||||
unit: none
|
||||
urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-h43h00:1:
|
||||
prop.10.6:
|
||||
unit: none
|
||||
urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-h43h00:2: urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-h43h00:1
|
||||
urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-m16:1:
|
||||
prop.10.6:
|
||||
unit: none
|
||||
urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-m16:2: urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-m16:1
|
||||
urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-m16:3: urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-m16:1
|
||||
urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-m16:4: urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-m16:1
|
||||
urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-m9:1: urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-m9:6
|
||||
urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-m9:2: urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-m9:6
|
||||
urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-m9:3: urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-m9:6
|
||||
urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-m9:4: urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-m9:6
|
||||
urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-m9:5: urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-m9:6
|
||||
urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-m9:6:
|
||||
prop.10.6:
|
||||
unit: none
|
||||
urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-m9:7: urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-m9:6
|
||||
urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-mt0:1:
|
||||
prop.10.6:
|
||||
unit: none
|
||||
urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-mt0:2: urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-mt0:1
|
||||
urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-rr0r00:1:
|
||||
prop.10.6:
|
||||
unit: none
|
||||
prop.3.12:
|
||||
name: vertical-swing-left-up
|
||||
prop.3.13:
|
||||
name: vertical-swing-left-down
|
||||
prop.3.14:
|
||||
name: vertical-swing-right-up
|
||||
prop.3.15:
|
||||
name: vertical-swing-right-down
|
||||
prop.3.20:
|
||||
name: horizontal-swing-left
|
||||
prop.3.22:
|
||||
name: horizontal-swing-right
|
||||
urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-rr0r00:2: urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-rr0r00:1
|
||||
urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-rr0r00:3: urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-rr0r00:1
|
||||
urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-rr0r00:4: urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-rr0r00:1
|
||||
urn:miot-spec-v2:device:air-fresh:0000A012:daikin-k33:1:
|
||||
prop.2.1:
|
||||
name: ac-on
|
||||
format: string
|
||||
access:
|
||||
- read
|
||||
- notify
|
||||
prop.2.3:
|
||||
name: ac-mode
|
||||
format: string
|
||||
access:
|
||||
- read
|
||||
- notify
|
||||
prop.2.5:
|
||||
name: ac-fan-level
|
||||
format: string
|
||||
access:
|
||||
- read
|
||||
- notify
|
||||
urn:miot-spec-v2:device:air-monitor:0000A008:cgllc-cgd1st:1:
|
||||
prop.3.7:
|
||||
value-range:
|
||||
- -30
|
||||
- 100
|
||||
- 0.1
|
||||
urn:miot-spec-v2:device:air-monitor:0000A008:cgllc-s1:1:
|
||||
prop.2.5:
|
||||
name: voc-density
|
||||
urn:miot-spec-v2:device:air-purifier:0000A007:zhimi-ua1a:1: urn:miot-spec-v2:device:air-purifier:0000A007:zhimi-ua1a:3
|
||||
urn:miot-spec-v2:device:air-purifier:0000A007:zhimi-ua1a:2: urn:miot-spec-v2:device:air-purifier:0000A007:zhimi-ua1a:3
|
||||
urn:miot-spec-v2:device:air-purifier:0000A007:zhimi-ua1a:3:
|
||||
prop.3.5:
|
||||
expr: (src_value*6)
|
||||
urn:miot-spec-v2:device:airer:0000A00D:hyd-lyjpro:1:
|
||||
prop.2.3:
|
||||
name: current-position-a
|
||||
prop.2.8:
|
||||
name: target-position-a
|
||||
prop.2.9:
|
||||
name: target-position-b
|
||||
prop.2.11:
|
||||
expr: (100-src_value)
|
||||
urn:miot-spec-v2:device:airer:0000A00D:hyd-znlyj5:1:
|
||||
prop.2.3:
|
||||
value-range:
|
||||
- 0
|
||||
- 1
|
||||
- 1
|
||||
urn:miot-spec-v2:device:airer:0000A00D:hyd-znlyj5:2: urn:miot-spec-v2:device:airer:0000A00D:hyd-znlyj5:1
|
||||
urn:miot-spec-v2:device:airer:0000A00D:mrbond-m1t:1:
|
||||
prop.2.3:
|
||||
name: current-position-a
|
||||
urn:miot-spec-v2:device:airer:0000A00D:mrbond-m33a:1:
|
||||
prop.2.3:
|
||||
name: current-position-a
|
||||
prop.2.11:
|
||||
name: current-position-b
|
||||
urn:miot-spec-v2:device:bath-heater:0000A028:mike-2:1:
|
||||
prop.3.1:
|
||||
name: mode-a
|
||||
prop.3.11:
|
||||
name: mode-b
|
||||
prop.3.12:
|
||||
name: mode-c
|
||||
urn:miot-spec-v2:device:bath-heater:0000A028:opple-acmoto:1:
|
||||
prop.5.2:
|
||||
value-list:
|
||||
- value: 1
|
||||
description: low
|
||||
- value: 128
|
||||
description: medium
|
||||
- value: 255
|
||||
description: high
|
||||
urn:miot-spec-v2:device:bath-heater:0000A028:xiaomi-s1:1:
|
||||
prop.4.4:
|
||||
name: fan-level-ventilation
|
||||
urn:miot-spec-v2:device:curtain:0000A00C:bjkcz-kczble:1:0000D031:
|
||||
prop.2.2:
|
||||
name: status-a
|
||||
urn:miot-spec-v2:device:dehumidifier:0000A02D:xiaomi-lite:1:
|
||||
prop.3.2:
|
||||
value-range:
|
||||
- -30
|
||||
- 100
|
||||
- 0.1
|
||||
urn:miot-spec-v2:device:electronic-valve:0000A0A7:lxzn-02:1:0000C833:
|
||||
prop.3.1:
|
||||
format: float
|
||||
value-range:
|
||||
- 0
|
||||
- 999999
|
||||
- 0.01
|
||||
expr: (src_value/100)
|
||||
prop.3.2:
|
||||
unit: mA
|
||||
prop.3.3:
|
||||
format: float
|
||||
value-range:
|
||||
- 0
|
||||
- 65535
|
||||
- 0.1
|
||||
expr: (src_value/10)
|
||||
prop.4.1:
|
||||
unit: kW
|
||||
urn:miot-spec-v2:device:electronic-valve:0000A0A7:sanmei-s1:1:
|
||||
prop.3.1:
|
||||
format: float
|
||||
value-range:
|
||||
- 0
|
||||
- 99999999
|
||||
- 0.01
|
||||
expr: round(src_value/100, 2)
|
||||
prop.3.2:
|
||||
format: float
|
||||
value-range:
|
||||
- 0
|
||||
- 16777216
|
||||
- 0.01
|
||||
expr: round(src_value/100, 2)
|
||||
prop.3.3:
|
||||
format: float
|
||||
value-range:
|
||||
- 0
|
||||
- 65535
|
||||
- 0.1
|
||||
expr: round(src_value/10, 1)
|
||||
urn:miot-spec-v2:device:electronic-valve:0000A0A7:ykcn-cbcs:1:0000C833:
|
||||
prop.3.1:
|
||||
format: float
|
||||
value-range:
|
||||
- 0
|
||||
- 99999999
|
||||
- 0.01
|
||||
expr: round(src_value/100, 2)
|
||||
prop.3.2:
|
||||
unit: mA
|
||||
prop.3.3:
|
||||
format: float
|
||||
value-range:
|
||||
- 0
|
||||
- 65535
|
||||
- 0.1
|
||||
expr: round(src_value/10, 1)
|
||||
prop.4.1:
|
||||
unit: kW
|
||||
urn:miot-spec-v2:device:fan:0000A005:dmaker-p33:1:
|
||||
prop.2.2:
|
||||
name: fan-level-a
|
||||
prop.2.6:
|
||||
name: fan-level
|
||||
access:
|
||||
- read
|
||||
- write
|
||||
- notify
|
||||
urn:miot-spec-v2:device:fan:0000A005:dmaker-p5:1:
|
||||
prop.2.4:
|
||||
name: fan-level-a
|
||||
urn:miot-spec-v2:device:fan:0000A005:xiaomi-p43:1:
|
||||
prop.2.2:
|
||||
name: fan-level-a
|
||||
urn:miot-spec-v2:device:fan:0000A005:xiaomi-p45:1:0000D062:
|
||||
prop.2.4:
|
||||
name: fan-level-a
|
||||
urn:miot-spec-v2:device:fan:0000A005:xiaomi-p51:1:
|
||||
prop.2.2:
|
||||
name: fan-level-a
|
||||
urn:miot-spec-v2:device:fan:0000A005:xiaomi-p69:1:0000D062:
|
||||
prop.2.4:
|
||||
name: fan-level-a
|
||||
urn:miot-spec-v2:device:fan:0000A005:xiaomi-p70:1:0000D062:
|
||||
prop.2.4:
|
||||
name: fan-level-a
|
||||
urn:miot-spec-v2:device:fan:0000A005:xiaomi-p76:1:0000D062:
|
||||
prop.2.4:
|
||||
name: fan-level-a
|
||||
urn:miot-spec-v2:device:fan:0000A005:zhimi-sa1:3:
|
||||
prop.2.2:
|
||||
name: fan-level-a
|
||||
urn:miot-spec-v2:device:fan:0000A005:zhimi-v3:3:
|
||||
prop.2.2:
|
||||
name: fan-level-a
|
||||
urn:miot-spec-v2:device:fan:0000A005:zhimi-za4:3:
|
||||
prop.2.2:
|
||||
name: fan-level-a
|
||||
urn:miot-spec-v2:device:gateway:0000A019:lumi-mcn001:1:
|
||||
prop.2.1:
|
||||
access:
|
||||
- read
|
||||
- notify
|
||||
prop.2.2:
|
||||
icon: mdi:ip
|
||||
prop.2.3:
|
||||
access:
|
||||
- read
|
||||
- notify
|
||||
prop.2.5:
|
||||
access:
|
||||
- read
|
||||
- notify
|
||||
urn:miot-spec-v2:device:gateway:0000A019:xiaomi-hub1:1:
|
||||
prop.2.1:
|
||||
name: access-mode
|
||||
access:
|
||||
- read
|
||||
- notify
|
||||
prop.2.2:
|
||||
name: ip-address
|
||||
icon: mdi:ip
|
||||
prop.2.3:
|
||||
name: wifi-ssid
|
||||
access:
|
||||
- read
|
||||
- notify
|
||||
urn:miot-spec-v2:device:gateway:0000A019:xiaomi-hub1:2: urn:miot-spec-v2:device:gateway:0000A019:xiaomi-hub1:1
|
||||
urn:miot-spec-v2:device:gateway:0000A019:xiaomi-hub1:3: urn:miot-spec-v2:device:gateway:0000A019:xiaomi-hub1:1
|
||||
urn:miot-spec-v2:device:hood:0000A01B:cykj-jyj22:1: urn:miot-spec-v2:device:hood:0000A01B:cykj-jyj22:3
|
||||
urn:miot-spec-v2:device:hood:0000A01B:cykj-jyj22:2: urn:miot-spec-v2:device:hood:0000A01B:cykj-jyj22:3
|
||||
urn:miot-spec-v2:device:hood:0000A01B:cykj-jyj22:3:
|
||||
prop.3.1:
|
||||
name: on-ventilation
|
||||
urn:miot-spec-v2:device:hood:0000A01B:cykj-jyj22:4: urn:miot-spec-v2:device:hood:0000A01B:cykj-jyj22:3
|
||||
urn:miot-spec-v2:device:humidifier:0000A00E:zhimi-ca4:2:
|
||||
prop.2.7:
|
||||
unit: percentage
|
||||
expr: round(src_value*0.83)
|
||||
urn:miot-spec-v2:device:kettle:0000A009:yunmi-r3:1:
|
||||
prop.3.1:
|
||||
unit: ppm
|
||||
urn:miot-spec-v2:device:light:0000A001:shhf-sfla10:1:
|
||||
prop.8.9:
|
||||
name: wind-reverse
|
||||
urn:miot-spec-v2:device:light:0000A001:shhf-sfla12:1:
|
||||
prop.8.11:
|
||||
name: on-a
|
||||
urn:miot-spec-v2:device:light:0000A001:shhf-sflt11:1:0000C802:
|
||||
prop.11.14:
|
||||
name: on-power
|
||||
urn:miot-spec-v2:device:magnet-sensor:0000A016:linp-m1:1:
|
||||
prop.2.1004:
|
||||
name: contact-state
|
||||
value-list:
|
||||
- value: 0
|
||||
description: open
|
||||
- value: 1
|
||||
description: closed
|
||||
expr: (src_value!=1)
|
||||
urn:miot-spec-v2:device:motion-sensor:0000A014:lumi-acn001:1:
|
||||
prop.3.2:
|
||||
access:
|
||||
- read
|
||||
- notify
|
||||
unit: mV
|
||||
urn:miot-spec-v2:device:motion-sensor:0000A014:lumi-bmgl01:1:
|
||||
prop.2.2:
|
||||
value-list:
|
||||
- value: 0
|
||||
description: 0 Seconds
|
||||
- value: 2
|
||||
description: 2 Minutes
|
||||
- value: 5
|
||||
description: 5 Minutes
|
||||
urn:miot-spec-v2:device:motor-controller:0000A01D:adp-adswb4:1:0000C837:
|
||||
prop.2.1:
|
||||
name: motor-switch
|
||||
urn:miot-spec-v2:device:occupancy-sensor:0000A0BF:ainice-3b:1: urn:miot-spec-v2:device:occupancy-sensor:0000A0BF:ainice-3b:2
|
||||
urn:miot-spec-v2:device:occupancy-sensor:0000A0BF:ainice-3b:2:
|
||||
prop.2.5:
|
||||
name: people-number
|
||||
prop.2.8:
|
||||
name: people-number
|
||||
prop.2.11:
|
||||
name: people-number
|
||||
prop.2.14:
|
||||
name: people-number
|
||||
prop.2.17:
|
||||
name: people-number
|
||||
urn:miot-spec-v2:device:occupancy-sensor:0000A0BF:izq-24:2:0000C824:
|
||||
prop.2.6:
|
||||
unit: cm
|
||||
urn:miot-spec-v2:device:occupancy-sensor:0000A0BF:linp-hb01:2:0000C824:
|
||||
prop.3.3:
|
||||
unit: m
|
||||
urn:miot-spec-v2:device:outlet:0000A002:chuangmi-212a01:1: urn:miot-spec-v2:device:outlet:0000A002:chuangmi-212a01:3
|
||||
urn:miot-spec-v2:device:outlet:0000A002:chuangmi-212a01:2: urn:miot-spec-v2:device:outlet:0000A002:chuangmi-212a01:3
|
||||
urn:miot-spec-v2:device:outlet:0000A002:chuangmi-212a01:3:
|
||||
prop.5.1:
|
||||
format: float
|
||||
value-range:
|
||||
- 0
|
||||
- 65535
|
||||
- 0.01
|
||||
expr: round(src_value*6/1000000, 2)
|
||||
urn:miot-spec-v2:device:outlet:0000A002:cuco-cp1md:1:
|
||||
prop.2.2:
|
||||
format: float
|
||||
value-range:
|
||||
- 0
|
||||
- 65535
|
||||
- 0.01
|
||||
expr: round(src_value/1000, 2)
|
||||
prop.2.3:
|
||||
format: float
|
||||
value-range:
|
||||
- 0
|
||||
- 3000
|
||||
- 0.1
|
||||
expr: round(src_value/10, 1)
|
||||
prop.2.4:
|
||||
unit: mA
|
||||
urn:miot-spec-v2:device:outlet:0000A002:cuco-cp2:1: urn:miot-spec-v2:device:outlet:0000A002:cuco-cp2:2
|
||||
urn:miot-spec-v2:device:outlet:0000A002:cuco-cp2:2:
|
||||
prop.2.3:
|
||||
format: float
|
||||
value-range:
|
||||
- 0
|
||||
- 3000
|
||||
- 0.1
|
||||
expr: round(src_value/10, 1)
|
||||
prop.2.4:
|
||||
unit: mA
|
||||
prop.3.2:
|
||||
format: float
|
||||
value-range:
|
||||
- 0
|
||||
- 65535
|
||||
- 0.1
|
||||
expr: round(src_value/10, 1)
|
||||
urn:miot-spec-v2:device:outlet:0000A002:cuco-cp2d:1:
|
||||
prop.3.2:
|
||||
unit: mA
|
||||
urn:miot-spec-v2:device:outlet:0000A002:cuco-cp7pd:1:
|
||||
prop.11.1:
|
||||
unit: Wh
|
||||
value-range:
|
||||
- 0
|
||||
- 65535
|
||||
- 0.001
|
||||
expr: (src_value*1000)
|
||||
prop.11.4:
|
||||
value-range:
|
||||
- 0
|
||||
- 10000
|
||||
- 0.01
|
||||
urn:miot-spec-v2:device:outlet:0000A002:cuco-v3:1:
|
||||
prop.11.1:
|
||||
format: float
|
||||
value-range:
|
||||
- 0
|
||||
- 65535
|
||||
- 0.01
|
||||
expr: round(src_value/100, 2)
|
||||
urn:miot-spec-v2:device:outlet:0000A002:cuco-v3:2: urn:miot-spec-v2:device:outlet:0000A002:cuco-v3:1
|
||||
urn:miot-spec-v2:device:outlet:0000A002:giot-v8icm:1:0000C816:
|
||||
prop.4.1:
|
||||
unit: mWh
|
||||
urn:miot-spec-v2:device:outlet:0000A002:qmi-psv3:1:0000C816:
|
||||
prop.3.3:
|
||||
unit: mV
|
||||
prop.3.4:
|
||||
unit: mA
|
||||
urn:miot-spec-v2:device:outlet:0000A002:yutai-fsov8m:1:0000C816:
|
||||
prop.4.1:
|
||||
format: float
|
||||
value-range:
|
||||
- 0
|
||||
- 429497
|
||||
- 0.01
|
||||
expr: round(src_value/10000, 2)
|
||||
urn:miot-spec-v2:device:outlet:0000A002:zimi-zncz01:1:0000C816: urn:miot-spec-v2:device:outlet:0000A002:zimi-zncz01:2:0000C816
|
||||
urn:miot-spec-v2:device:outlet:0000A002:zimi-zncz01:2:0000C816:
|
||||
prop.3.1:
|
||||
format: float
|
||||
value-range:
|
||||
- 0
|
||||
- 350000
|
||||
- 0.01
|
||||
expr: round(src_value/100, 2)
|
||||
urn:miot-spec-v2:device:plant-monitor:0000A030:hhcc-v1:1:
|
||||
prop.2.1:
|
||||
name: soil-moisture
|
||||
icon: mdi:watering-can
|
||||
prop.2.2:
|
||||
name: soil-ec
|
||||
icon: mdi:sprout-outline
|
||||
unit: μS/cm
|
||||
urn:miot-spec-v2:device:relay:0000A03D:lumi-c2acn01:1:
|
||||
prop.4.1:
|
||||
unit: kWh
|
||||
urn:miot-spec-v2:device:router:0000A036:xiaomi-rd08:1:
|
||||
prop.2.1:
|
||||
name: download-speed
|
||||
icon: mdi:download
|
||||
unit: B/s
|
||||
prop.2.2:
|
||||
name: upload-speed
|
||||
icon: mdi:upload
|
||||
unit: B/s
|
||||
urn:miot-spec-v2:device:safe-box:0000A042:loock-v1:1:
|
||||
prop.5.1:
|
||||
name: contact-state
|
||||
expr: (src_value!=1)
|
||||
urn:miot-spec-v2:device:speaker:0000A015:xiaomi-l04m:2:
|
||||
prop.3.1:
|
||||
access:
|
||||
- read
|
||||
- notify
|
||||
urn:miot-spec-v2:device:speaker:0000A015:xiaomi-lx04:2:
|
||||
prop.3.1:
|
||||
access:
|
||||
- read
|
||||
- notify
|
||||
urn:miot-spec-v2:device:speaker:0000A015:xiaomi-lx06:2:
|
||||
prop.3.1:
|
||||
access:
|
||||
- read
|
||||
- notify
|
||||
urn:miot-spec-v2:device:speaker:0000A015:xiaomi-x08c:2:
|
||||
prop.2.1:
|
||||
access:
|
||||
- read
|
||||
- notify
|
||||
urn:miot-spec-v2:device:speaker:0000A015:xiaomi-x08e:1:
|
||||
prop.3.1:
|
||||
name: playing-state-a
|
||||
urn:miot-spec-v2:device:switch:0000A003:090615-x1tpm:1:0000D042:
|
||||
prop.27.3:
|
||||
name: light-on
|
||||
prop.27.4:
|
||||
name: light-fan-on
|
||||
urn:miot-spec-v2:device:switch:0000A003:lxzn-cbcsmj:1:0000D00D:
|
||||
prop.3.1:
|
||||
format: float
|
||||
value-range:
|
||||
- 0
|
||||
- 99999999
|
||||
- 0.01
|
||||
expr: round(src_value/100, 2)
|
||||
prop.3.2:
|
||||
unit: mA
|
||||
prop.3.3:
|
||||
format: float
|
||||
value-range:
|
||||
- 0
|
||||
- 65535
|
||||
- 0.1
|
||||
expr: round(src_value/10, 1)
|
||||
urn:miot-spec-v2:device:thermostat:0000A031:suittc-wk168:1:
|
||||
prop.2.3:
|
||||
value-list:
|
||||
- value: 1
|
||||
description: '1'
|
||||
- value: 2
|
||||
description: '2'
|
||||
- value: 3
|
||||
description: '3'
|
||||
- value: 4
|
||||
description: '4'
|
||||
- value: 5
|
||||
description: '5'
|
||||
- value: 6
|
||||
description: '6'
|
||||
- value: 7
|
||||
description: '7'
|
||||
- value: 8
|
||||
description: '8'
|
||||
- value: 9
|
||||
description: '9'
|
||||
- value: 10
|
||||
description: '10'
|
||||
- value: 11
|
||||
description: '11'
|
||||
- value: 12
|
||||
description: '12'
|
||||
- value: 13
|
||||
description: '13'
|
||||
- value: 14
|
||||
description: '14'
|
||||
- value: 15
|
||||
description: '15'
|
||||
- value: 16
|
||||
description: '16'
|
||||
urn:miot-spec-v2:device:toothbrush:0000A07E:xiaomi-p001:1:
|
||||
prop.4.1041:
|
||||
unit: days
|
||||
urn:miot-spec-v2:device:water-purifier:0000A013:roswan-lte01:1:0000D05A:
|
||||
prop.4.1:
|
||||
unit: ppm
|
||||
prop.4.2:
|
||||
unit: ppm
|
||||
urn:miot-spec-v2:device:water-purifier:0000A013:xiaomi-s1200g:1:0000D05A:
|
||||
prop.3.2:
|
||||
unit: days
|
||||
prop.3.3:
|
||||
unit: days
|
||||
prop.3.4:
|
||||
unit: L
|
||||
prop.3.5:
|
||||
unit: L
|
||||
prop.5.2:
|
||||
unit: days
|
||||
prop.5.3:
|
||||
unit: days
|
||||
prop.5.4:
|
||||
unit: L
|
||||
prop.5.5:
|
||||
unit: L
|
||||
urn:miot-spec-v2:device:water-purifier:0000A013:xiaomi-s1200g:2:0000D05A: urn:miot-spec-v2:device:water-purifier:0000A013:xiaomi-s1200g:1:0000D05A
|
||||
urn:miot-spec-v2:device:water-purifier:0000A013:yunmi-s20:1:
|
||||
prop.4.1:
|
||||
unit: ppm
|
||||
prop.4.2:
|
||||
unit: ppm
|
||||
@@ -0,0 +1,716 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Copyright (C) 2024 Xiaomi Corporation.
|
||||
|
||||
The ownership and intellectual property rights of Xiaomi Home Assistant
|
||||
Integration and related Xiaomi cloud service API interface provided under this
|
||||
license, including source code and object code (collectively, "Licensed Work"),
|
||||
are owned by Xiaomi. Subject to the terms and conditions of this License, Xiaomi
|
||||
hereby grants you a personal, limited, non-exclusive, non-transferable,
|
||||
non-sublicensable, and royalty-free license to reproduce, use, modify, and
|
||||
distribute the Licensed Work only for your use of Home Assistant for
|
||||
non-commercial purposes. For the avoidance of doubt, Xiaomi does not authorize
|
||||
you to use the Licensed Work for any other purpose, including but not limited
|
||||
to use Licensed Work to develop applications (APP), Web services, and other
|
||||
forms of software.
|
||||
|
||||
You may reproduce and distribute copies of the Licensed Work, with or without
|
||||
modifications, whether in source or object form, provided that you must give
|
||||
any other recipients of the Licensed Work a copy of this License and retain all
|
||||
copyright and disclaimers.
|
||||
|
||||
Xiaomi provides the Licensed Work on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied, including, without
|
||||
limitation, any warranties, undertakes, or conditions of TITLE, NO ERROR OR
|
||||
OMISSION, CONTINUITY, RELIABILITY, NON-INFRINGEMENT, MERCHANTABILITY, or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. In any event, you are solely responsible
|
||||
for any direct, indirect, special, incidental, or consequential damages or
|
||||
losses arising from the use or inability to use the Licensed Work.
|
||||
|
||||
Xiaomi reserves all rights not expressly granted to you in this License.
|
||||
Except for the rights expressly granted by Xiaomi under this License, Xiaomi
|
||||
does not authorize you in any form to use the trademarks, copyrights, or other
|
||||
forms of intellectual property rights of Xiaomi and its affiliates, including,
|
||||
without limitation, without obtaining other written permission from Xiaomi, you
|
||||
shall not use "Xiaomi", "Mijia" and other words related to Xiaomi or words that
|
||||
may make the public associate with Xiaomi in any form to publicize or promote
|
||||
the software or hardware devices that use the Licensed Work.
|
||||
|
||||
Xiaomi has the right to immediately terminate all your authorization under this
|
||||
License in the event:
|
||||
1. You assert patent invalidation, litigation, or other claims against patents
|
||||
or other intellectual property rights of Xiaomi or its affiliates; or,
|
||||
2. You make, have made, manufacture, sell, or offer to sell products that knock
|
||||
off Xiaomi or its affiliates' products.
|
||||
|
||||
Conversion rules of MIoT-Spec-V2 instance to Home Assistant entity.
|
||||
"""
|
||||
from homeassistant.components.sensor import SensorDeviceClass
|
||||
from homeassistant.components.sensor import SensorStateClass
|
||||
from homeassistant.components.event import EventDeviceClass
|
||||
from homeassistant.components.binary_sensor import BinarySensorDeviceClass
|
||||
|
||||
from homeassistant.const import (CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
EntityCategory, LIGHT_LUX, UnitOfEnergy,
|
||||
UnitOfPower, UnitOfElectricCurrent,
|
||||
UnitOfElectricPotential, UnitOfTemperature,
|
||||
UnitOfPressure, PERCENTAGE)
|
||||
|
||||
# pylint: disable=pointless-string-statement
|
||||
"""SPEC_DEVICE_TRANS_MAP
|
||||
{
|
||||
'<device instance name>':{
|
||||
'required':{
|
||||
'<service instance name>':{
|
||||
'required':{
|
||||
'properties': {
|
||||
'<property instance name>': set<property access: str>
|
||||
},
|
||||
'events': set<event instance name: str>,
|
||||
'actions': set<action instance name: str>
|
||||
},
|
||||
'optional':{
|
||||
'properties': set<property instance name: str>,
|
||||
'events': set<event instance name: str>,
|
||||
'actions': set<action instance name: str>
|
||||
}
|
||||
}
|
||||
},
|
||||
'optional':{
|
||||
'<service instance name>':{
|
||||
'required':{
|
||||
'properties': {
|
||||
'<property instance name>': set<property access: str>
|
||||
},
|
||||
'events': set<event instance name: str>,
|
||||
'actions': set<action instance name: str>
|
||||
},
|
||||
'optional':{
|
||||
'properties': set<property instance name: str>,
|
||||
'events': set<event instance name: str>,
|
||||
'actions': set<action instance name: str>
|
||||
}
|
||||
}
|
||||
},
|
||||
'entity': str
|
||||
}
|
||||
}
|
||||
"""
|
||||
SPEC_DEVICE_TRANS_MAP: dict = {
|
||||
'humidifier': {
|
||||
'required': {
|
||||
'humidifier': {
|
||||
'required': {
|
||||
'properties': {
|
||||
'on': {'read', 'write'}
|
||||
}
|
||||
},
|
||||
'optional': {
|
||||
'properties': {'mode', 'target-humidity'}
|
||||
}
|
||||
}
|
||||
},
|
||||
'optional': {
|
||||
'environment': {
|
||||
'required': {
|
||||
'properties': {
|
||||
'relative-humidity': {'read'}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
'entity': 'humidifier'
|
||||
},
|
||||
'dehumidifier': {
|
||||
'required': {
|
||||
'dehumidifier': {
|
||||
'required': {
|
||||
'properties': {
|
||||
'on': {'read', 'write'}
|
||||
}
|
||||
},
|
||||
'optional': {
|
||||
'properties': {'mode', 'target-humidity'}
|
||||
}
|
||||
}
|
||||
},
|
||||
'optional': {
|
||||
'environment': {
|
||||
'required': {
|
||||
'properties': {
|
||||
'relative-humidity': {'read'}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
'entity': 'dehumidifier'
|
||||
},
|
||||
'vacuum': {
|
||||
'required': {
|
||||
'vacuum': {
|
||||
'required': {
|
||||
'actions': {'start-sweep', 'stop-sweeping'},
|
||||
},
|
||||
'optional': {
|
||||
'properties': {'status', 'fan-level'},
|
||||
'actions': {
|
||||
'pause-sweeping', 'continue-sweep', 'stop-and-gocharge'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
'optional': {
|
||||
'identify': {
|
||||
'required': {
|
||||
'actions': {'identify'}
|
||||
}
|
||||
},
|
||||
'battery': {
|
||||
'required': {
|
||||
'actions': {
|
||||
'start-charge'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
'entity': 'vacuum'
|
||||
},
|
||||
'air-conditioner': {
|
||||
'required': {
|
||||
'air-conditioner': {
|
||||
'required': {
|
||||
'properties': {
|
||||
'on': {'read', 'write'},
|
||||
'mode': {'read', 'write'},
|
||||
'target-temperature': {'read', 'write'}
|
||||
}
|
||||
},
|
||||
'optional': {
|
||||
'properties': {'target-humidity'}
|
||||
}
|
||||
}
|
||||
},
|
||||
'optional': {
|
||||
'fan-control': {
|
||||
'required': {},
|
||||
'optional': {
|
||||
'properties': {
|
||||
'on', 'fan-level', 'horizontal-swing', 'vertical-swing'
|
||||
}
|
||||
}
|
||||
},
|
||||
'environment': {
|
||||
'required': {},
|
||||
'optional': {
|
||||
'properties': {'temperature', 'relative-humidity'}
|
||||
}
|
||||
},
|
||||
'air-condition-outlet-matching': {
|
||||
'required': {},
|
||||
'optional': {
|
||||
'properties': {'ac-state'}
|
||||
}
|
||||
}
|
||||
},
|
||||
'entity': 'air-conditioner'
|
||||
},
|
||||
'air-condition-outlet': 'air-conditioner',
|
||||
'thermostat': {
|
||||
'required': {
|
||||
'thermostat': {
|
||||
'required': {
|
||||
'properties': {
|
||||
'on': {'read', 'write'}
|
||||
}
|
||||
},
|
||||
'optional': {
|
||||
'properties': {
|
||||
'target-temperature', 'mode', 'fan-level', 'temperature'
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
'optional': {
|
||||
'environment': {
|
||||
'required': {},
|
||||
'optional': {
|
||||
'properties': {'temperature', 'relative-humidity'}
|
||||
}
|
||||
}
|
||||
},
|
||||
'entity': 'thermostat'
|
||||
},
|
||||
'heater': {
|
||||
'required': {
|
||||
'heater': {
|
||||
'required': {
|
||||
'properties': {
|
||||
'on': {'read', 'write'}
|
||||
}
|
||||
},
|
||||
'optional': {
|
||||
'properties': {'target-temperature', 'heat-level'}
|
||||
}
|
||||
}
|
||||
},
|
||||
'optional': {
|
||||
'environment': {
|
||||
'required': {},
|
||||
'optional': {
|
||||
'properties': {'temperature', 'relative-humidity'}
|
||||
}
|
||||
}
|
||||
},
|
||||
'entity': 'heater'
|
||||
},
|
||||
'bath-heater': {
|
||||
'required': {
|
||||
'ptc-bath-heater': {
|
||||
'required': {
|
||||
'properties': {
|
||||
'mode': {'read', 'write'}
|
||||
}
|
||||
},
|
||||
'optional': {
|
||||
'properties': {'target-temperature', 'temperature'}
|
||||
}
|
||||
}
|
||||
},
|
||||
'optional': {
|
||||
'fan-control': {
|
||||
'required': {},
|
||||
'optional': {
|
||||
'properties': {
|
||||
'on', 'fan-level', 'horizontal-swing', 'vertical-swing'
|
||||
}
|
||||
}
|
||||
},
|
||||
'environment': {
|
||||
'required': {},
|
||||
'optional': {
|
||||
'properties': {'temperature'}
|
||||
}
|
||||
}
|
||||
},
|
||||
'entity': 'bath-heater',
|
||||
},
|
||||
'electric-blanket': {
|
||||
'required': {
|
||||
'electric-blanket': {
|
||||
'required': {
|
||||
'properties': {
|
||||
'on': {'read', 'write'},
|
||||
'target-temperature': {'read', 'write'}
|
||||
}
|
||||
},
|
||||
'optional': {
|
||||
'properties': {'mode', 'temperature'}
|
||||
}
|
||||
}
|
||||
},
|
||||
'optional': {},
|
||||
'entity': 'electric-blanket'
|
||||
},
|
||||
'speaker': {
|
||||
'required': {
|
||||
'speaker': {
|
||||
'required': {
|
||||
'properties': {
|
||||
'volume': {'read', 'write'}
|
||||
}
|
||||
},
|
||||
'optional': {
|
||||
'properties': {'mute'}
|
||||
}
|
||||
},
|
||||
'play-control': {
|
||||
'required': {
|
||||
'properties': {
|
||||
'playing-state': {'read'}
|
||||
},
|
||||
'actions': {'play'}
|
||||
},
|
||||
'optional': {
|
||||
'properties': {'play-loop-mode'},
|
||||
'actions': {'pause', 'stop', 'next', 'previous'}
|
||||
}
|
||||
}
|
||||
},
|
||||
'optional': {},
|
||||
'entity': 'wifi-speaker'
|
||||
},
|
||||
'television': {
|
||||
'required': {
|
||||
'speaker': {
|
||||
'required': {
|
||||
'properties': {
|
||||
'volume': {'read', 'write'}
|
||||
}
|
||||
},
|
||||
'optional': {
|
||||
'properties': {'mute'}
|
||||
}
|
||||
},
|
||||
'television': {
|
||||
'required': {
|
||||
'actions': {'turn-off'}
|
||||
},
|
||||
'optional': {
|
||||
'properties': {'input-control'},
|
||||
'actions': {'turn-on'}
|
||||
}
|
||||
}
|
||||
},
|
||||
'optional': {
|
||||
'play-control': {
|
||||
'required': {
|
||||
'properties': {
|
||||
'playing-state': {'read'}
|
||||
}
|
||||
},
|
||||
'optional': {
|
||||
'properties': {'play-loop-mode'},
|
||||
'actions': {'play', 'pause', 'stop', 'next', 'previous'}
|
||||
}
|
||||
}
|
||||
},
|
||||
'entity': 'television'
|
||||
},
|
||||
'tv-box':{
|
||||
'required': {
|
||||
'speaker': {
|
||||
'required': {
|
||||
'properties': {
|
||||
'volume': {'read', 'write'}
|
||||
}
|
||||
},
|
||||
'optional': {
|
||||
'properties': {'mute'}
|
||||
}
|
||||
},
|
||||
'tv-box': {
|
||||
'required': {
|
||||
'actions': {'turn-off'}
|
||||
},
|
||||
'optional': {
|
||||
'actions': {'turn-on'}
|
||||
}
|
||||
}
|
||||
},
|
||||
'optional': {
|
||||
'play-control': {
|
||||
'required': {
|
||||
'properties': {
|
||||
'playing-state': {'read'}
|
||||
}
|
||||
},
|
||||
'optional': {
|
||||
'properties': {'play-loop-mode'},
|
||||
'actions': {'play', 'pause', 'stop', 'next', 'previous'}
|
||||
}
|
||||
}
|
||||
},
|
||||
'entity': 'television'
|
||||
},
|
||||
'watch': {
|
||||
'required': {
|
||||
'watch': {
|
||||
'required': {
|
||||
'properties': {
|
||||
'longitude': {'read'},
|
||||
'latitude': {'read'}
|
||||
}
|
||||
},
|
||||
'optional': {
|
||||
'properties': {'area-id'}
|
||||
}
|
||||
}
|
||||
},
|
||||
'optional': {
|
||||
'battery': {
|
||||
'required': {
|
||||
'properties': {
|
||||
'battery-level': {'read'}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
'entity': 'device_tracker'
|
||||
}
|
||||
}
|
||||
|
||||
"""SPEC_SERVICE_TRANS_MAP
|
||||
{
|
||||
'<service instance name>':{
|
||||
'required':{
|
||||
'properties': {
|
||||
'<property instance name>': set<property access: str>
|
||||
},
|
||||
'events': set<event instance name: str>,
|
||||
'actions': set<action instance name: str>
|
||||
},
|
||||
'optional':{
|
||||
'properties': set<property instance name: str>,
|
||||
'events': set<event instance name: str>,
|
||||
'actions': set<action instance name: str>
|
||||
},
|
||||
'entity': str,
|
||||
'entity_category'?: str
|
||||
}
|
||||
}
|
||||
"""
|
||||
SPEC_SERVICE_TRANS_MAP: dict = {
|
||||
'light': {
|
||||
'required': {
|
||||
'properties': {
|
||||
'on': {'read', 'write'}
|
||||
}
|
||||
},
|
||||
'optional': {
|
||||
'properties': {'mode', 'brightness', 'color', 'color-temperature'}
|
||||
},
|
||||
'entity': 'light'
|
||||
},
|
||||
'ambient-light': 'light',
|
||||
'night-light': 'light',
|
||||
'white-light': 'light',
|
||||
'indicator-light': {
|
||||
'required': {
|
||||
'properties': {
|
||||
'on': {'read', 'write'}
|
||||
}
|
||||
},
|
||||
'optional': {
|
||||
'properties': {
|
||||
'mode',
|
||||
'brightness',
|
||||
}
|
||||
},
|
||||
'entity': 'light',
|
||||
'entity_category': EntityCategory.CONFIG
|
||||
},
|
||||
'fan': {
|
||||
'required': {
|
||||
'properties': {
|
||||
'on': {'read', 'write'},
|
||||
'fan-level': {'read', 'write'}
|
||||
}
|
||||
},
|
||||
'optional': {
|
||||
'properties': {'mode', 'horizontal-swing', 'wind-reverse'}
|
||||
},
|
||||
'entity': 'fan'
|
||||
},
|
||||
'fan-control': 'fan',
|
||||
'ceiling-fan': 'fan',
|
||||
'air-fresh': 'fan',
|
||||
'air-purifier': 'fan',
|
||||
'water-heater': {
|
||||
'required': {
|
||||
'properties': {
|
||||
'on': {'read', 'write'}
|
||||
}
|
||||
},
|
||||
'optional': {
|
||||
'properties': {'temperature', 'target-temperature', 'mode'}
|
||||
},
|
||||
'entity': 'water_heater'
|
||||
},
|
||||
'curtain': {
|
||||
'required': {
|
||||
'properties': {
|
||||
'motor-control': {'write'}
|
||||
}
|
||||
},
|
||||
'optional': {
|
||||
'properties': {'status', 'current-position', 'target-position'}
|
||||
},
|
||||
'entity': 'cover'
|
||||
},
|
||||
'window-opener': 'curtain',
|
||||
'motor-controller': 'curtain',
|
||||
'airer': 'curtain',
|
||||
'air-conditioner': {
|
||||
'required': {
|
||||
'properties': {
|
||||
'on': {'read', 'write'},
|
||||
'mode': {'read', 'write'},
|
||||
'target-temperature': {'read', 'write'}
|
||||
}
|
||||
},
|
||||
'optional': {
|
||||
'properties': {'target-humidity'}
|
||||
},
|
||||
'entity': 'air-conditioner'
|
||||
}
|
||||
}
|
||||
|
||||
"""SPEC_PROP_TRANS_MAP
|
||||
{
|
||||
'entities':{
|
||||
'<entity name>':{
|
||||
'format': set<str>,
|
||||
'access': set<str>
|
||||
}
|
||||
},
|
||||
'properties': {
|
||||
'<property instance name>':{
|
||||
'device_class': str,
|
||||
'entity': str,
|
||||
'state_class'?: str,
|
||||
'unit_of_measurement'?: str
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
SPEC_PROP_TRANS_MAP: dict = {
|
||||
'entities': {
|
||||
'sensor': {
|
||||
'format': {'int', 'float'},
|
||||
'access': {'read'}
|
||||
},
|
||||
'binary_sensor': {
|
||||
'format': {'bool', 'int'},
|
||||
'access': {'read'}
|
||||
},
|
||||
'switch': {
|
||||
'format': {'bool'},
|
||||
'access': {'read', 'write'}
|
||||
}
|
||||
},
|
||||
'properties': {
|
||||
'submersion-state': {
|
||||
'device_class': BinarySensorDeviceClass.MOISTURE,
|
||||
'entity': 'binary_sensor'
|
||||
},
|
||||
'contact-state': {
|
||||
'device_class': BinarySensorDeviceClass.DOOR,
|
||||
'entity': 'binary_sensor'
|
||||
},
|
||||
'occupancy-status': {
|
||||
'device_class': BinarySensorDeviceClass.OCCUPANCY,
|
||||
'entity': 'binary_sensor',
|
||||
},
|
||||
'temperature': {
|
||||
'device_class': SensorDeviceClass.TEMPERATURE,
|
||||
'entity': 'sensor',
|
||||
'state_class': SensorStateClass.MEASUREMENT,
|
||||
'unit_of_measurement': UnitOfTemperature.CELSIUS
|
||||
},
|
||||
'relative-humidity': {
|
||||
'device_class': SensorDeviceClass.HUMIDITY,
|
||||
'entity': 'sensor',
|
||||
'state_class': SensorStateClass.MEASUREMENT,
|
||||
'unit_of_measurement': PERCENTAGE
|
||||
},
|
||||
'air-quality-index': {
|
||||
'device_class': SensorDeviceClass.AQI,
|
||||
'entity': 'sensor',
|
||||
'state_class': SensorStateClass.MEASUREMENT,
|
||||
},
|
||||
'pm2.5-density': {
|
||||
'device_class': SensorDeviceClass.PM25,
|
||||
'entity': 'sensor',
|
||||
'state_class': SensorStateClass.MEASUREMENT,
|
||||
'unit_of_measurement': CONCENTRATION_MICROGRAMS_PER_CUBIC_METER
|
||||
},
|
||||
'pm10-density': {
|
||||
'device_class': SensorDeviceClass.PM10,
|
||||
'entity': 'sensor',
|
||||
'state_class': SensorStateClass.MEASUREMENT,
|
||||
'unit_of_measurement': CONCENTRATION_MICROGRAMS_PER_CUBIC_METER
|
||||
},
|
||||
'pm1': {
|
||||
'device_class': SensorDeviceClass.PM1,
|
||||
'entity': 'sensor',
|
||||
'state_class': SensorStateClass.MEASUREMENT,
|
||||
'unit_of_measurement': CONCENTRATION_MICROGRAMS_PER_CUBIC_METER
|
||||
},
|
||||
'atmospheric-pressure': {
|
||||
'device_class': SensorDeviceClass.ATMOSPHERIC_PRESSURE,
|
||||
'entity': 'sensor',
|
||||
'state_class': SensorStateClass.MEASUREMENT,
|
||||
'unit_of_measurement': UnitOfPressure.PA
|
||||
},
|
||||
'tvoc-density': {
|
||||
'device_class': SensorDeviceClass.VOLATILE_ORGANIC_COMPOUNDS,
|
||||
'entity': 'sensor',
|
||||
'state_class': SensorStateClass.MEASUREMENT
|
||||
},
|
||||
'voc-density': {
|
||||
'device_class': SensorDeviceClass.VOLATILE_ORGANIC_COMPOUNDS_PARTS,
|
||||
'entity': 'sensor',
|
||||
'state_class': SensorStateClass.MEASUREMENT
|
||||
},
|
||||
'battery-level': {
|
||||
'device_class': SensorDeviceClass.BATTERY,
|
||||
'entity': 'sensor',
|
||||
'state_class': SensorStateClass.MEASUREMENT,
|
||||
'unit_of_measurement': PERCENTAGE
|
||||
},
|
||||
'voltage': {
|
||||
'device_class': SensorDeviceClass.VOLTAGE,
|
||||
'entity': 'sensor',
|
||||
'state_class': SensorStateClass.MEASUREMENT,
|
||||
'unit_of_measurement': UnitOfElectricPotential.VOLT
|
||||
},
|
||||
'electric-current': {
|
||||
'device_class': SensorDeviceClass.CURRENT,
|
||||
'entity': 'sensor',
|
||||
'state_class': SensorStateClass.MEASUREMENT,
|
||||
'unit_of_measurement': UnitOfElectricCurrent.AMPERE
|
||||
},
|
||||
'illumination': {
|
||||
'device_class': SensorDeviceClass.ILLUMINANCE,
|
||||
'entity': 'sensor',
|
||||
'state_class': SensorStateClass.MEASUREMENT,
|
||||
'unit_of_measurement': LIGHT_LUX
|
||||
},
|
||||
'no-one-determine-time': {
|
||||
'device_class': SensorDeviceClass.DURATION,
|
||||
'entity': 'sensor'
|
||||
},
|
||||
'has-someone-duration': 'no-one-determine-time',
|
||||
'no-one-duration': 'no-one-determine-time',
|
||||
'electric-power': {
|
||||
'device_class': SensorDeviceClass.POWER,
|
||||
'entity': 'sensor',
|
||||
'state_class': SensorStateClass.MEASUREMENT,
|
||||
'unit_of_measurement': UnitOfPower.WATT
|
||||
},
|
||||
'surge-power': {
|
||||
'device_class': SensorDeviceClass.POWER,
|
||||
'entity': 'sensor',
|
||||
'state_class': SensorStateClass.MEASUREMENT,
|
||||
'unit_of_measurement': UnitOfPower.WATT
|
||||
},
|
||||
'power-consumption': {
|
||||
'device_class': SensorDeviceClass.ENERGY,
|
||||
'entity': 'sensor',
|
||||
'state_class': SensorStateClass.TOTAL_INCREASING,
|
||||
'unit_of_measurement': UnitOfEnergy.KILO_WATT_HOUR
|
||||
},
|
||||
'power': {
|
||||
'device_class': SensorDeviceClass.POWER,
|
||||
'entity': 'sensor',
|
||||
'state_class': SensorStateClass.MEASUREMENT,
|
||||
'unit_of_measurement': UnitOfPower.WATT
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
"""SPEC_EVENT_TRANS_MAP
|
||||
{
|
||||
'<event instance name>': str
|
||||
}
|
||||
"""
|
||||
SPEC_EVENT_TRANS_MAP: dict[str, str] = {
|
||||
'click': EventDeviceClass.BUTTON,
|
||||
'double-click': EventDeviceClass.BUTTON,
|
||||
'long-press': EventDeviceClass.BUTTON,
|
||||
'motion-detected': EventDeviceClass.MOTION,
|
||||
'no-motion': EventDeviceClass.MOTION,
|
||||
'doorbell-ring': EventDeviceClass.DOORBELL
|
||||
}
|
||||
|
||||
SPEC_ACTION_TRANS_MAP = {}
|
||||
@@ -0,0 +1,76 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Copyright (C) 2024 Xiaomi Corporation.
|
||||
|
||||
The ownership and intellectual property rights of Xiaomi Home Assistant
|
||||
Integration and related Xiaomi cloud service API interface provided under this
|
||||
license, including source code and object code (collectively, "Licensed Work"),
|
||||
are owned by Xiaomi. Subject to the terms and conditions of this License, Xiaomi
|
||||
hereby grants you a personal, limited, non-exclusive, non-transferable,
|
||||
non-sublicensable, and royalty-free license to reproduce, use, modify, and
|
||||
distribute the Licensed Work only for your use of Home Assistant for
|
||||
non-commercial purposes. For the avoidance of doubt, Xiaomi does not authorize
|
||||
you to use the Licensed Work for any other purpose, including but not limited
|
||||
to use Licensed Work to develop applications (APP), Web services, and other
|
||||
forms of software.
|
||||
|
||||
You may reproduce and distribute copies of the Licensed Work, with or without
|
||||
modifications, whether in source or object form, provided that you must give
|
||||
any other recipients of the Licensed Work a copy of this License and retain all
|
||||
copyright and disclaimers.
|
||||
|
||||
Xiaomi provides the Licensed Work on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied, including, without
|
||||
limitation, any warranties, undertakes, or conditions of TITLE, NO ERROR OR
|
||||
OMISSION, CONTINUITY, RELIABILITY, NON-INFRINGEMENT, MERCHANTABILITY, or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. In any event, you are solely responsible
|
||||
for any direct, indirect, special, incidental, or consequential damages or
|
||||
losses arising from the use or inability to use the Licensed Work.
|
||||
|
||||
Xiaomi reserves all rights not expressly granted to you in this License.
|
||||
Except for the rights expressly granted by Xiaomi under this License, Xiaomi
|
||||
does not authorize you in any form to use the trademarks, copyrights, or other
|
||||
forms of intellectual property rights of Xiaomi and its affiliates, including,
|
||||
without limitation, without obtaining other written permission from Xiaomi, you
|
||||
shall not use "Xiaomi", "Mijia" and other words related to Xiaomi or words that
|
||||
may make the public associate with Xiaomi in any form to publicize or promote
|
||||
the software or hardware devices that use the Licensed Work.
|
||||
|
||||
Xiaomi has the right to immediately terminate all your authorization under this
|
||||
License in the event:
|
||||
1. You assert patent invalidation, litigation, or other claims against patents
|
||||
or other intellectual property rights of Xiaomi or its affiliates; or,
|
||||
2. You make, have made, manufacture, sell, or offer to sell products that knock
|
||||
off Xiaomi or its affiliates' products.
|
||||
|
||||
MIoT redirect web pages.
|
||||
"""
|
||||
|
||||
import os
|
||||
import asyncio
|
||||
|
||||
web_template = ''
|
||||
|
||||
|
||||
def _load_page_template():
|
||||
path = os.path.join(
|
||||
os.path.dirname(os.path.abspath(__file__)),
|
||||
'resource/oauth_redirect_page.html')
|
||||
with open(path, 'r', encoding='utf-8') as f:
|
||||
global web_template
|
||||
web_template = f.read()
|
||||
|
||||
|
||||
async def oauth_redirect_page(
|
||||
title: str, content: str, button: str, success: bool
|
||||
) -> str:
|
||||
"""Return oauth redirect page."""
|
||||
if web_template == '':
|
||||
await asyncio.get_running_loop().run_in_executor(
|
||||
None, _load_page_template)
|
||||
web_page = web_template.replace('TITLE_PLACEHOLDER', title)
|
||||
web_page = web_page.replace('CONTENT_PLACEHOLDER', content)
|
||||
web_page = web_page.replace('BUTTON_PLACEHOLDER', button)
|
||||
web_page = web_page.replace(
|
||||
'STATUS_PLACEHOLDER', 'true' if success else 'false')
|
||||
return web_page
|
||||
@@ -0,0 +1,155 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Copyright (C) 2024 Xiaomi Corporation.
|
||||
|
||||
The ownership and intellectual property rights of Xiaomi Home Assistant
|
||||
Integration and related Xiaomi cloud service API interface provided under this
|
||||
license, including source code and object code (collectively, "Licensed Work"),
|
||||
are owned by Xiaomi. Subject to the terms and conditions of this License, Xiaomi
|
||||
hereby grants you a personal, limited, non-exclusive, non-transferable,
|
||||
non-sublicensable, and royalty-free license to reproduce, use, modify, and
|
||||
distribute the Licensed Work only for your use of Home Assistant for
|
||||
non-commercial purposes. For the avoidance of doubt, Xiaomi does not authorize
|
||||
you to use the Licensed Work for any other purpose, including but not limited
|
||||
to use Licensed Work to develop applications (APP), Web services, and other
|
||||
forms of software.
|
||||
|
||||
You may reproduce and distribute copies of the Licensed Work, with or without
|
||||
modifications, whether in source or object form, provided that you must give
|
||||
any other recipients of the Licensed Work a copy of this License and retain all
|
||||
copyright and disclaimers.
|
||||
|
||||
Xiaomi provides the Licensed Work on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied, including, without
|
||||
limitation, any warranties, undertakes, or conditions of TITLE, NO ERROR OR
|
||||
OMISSION, CONTINUITY, RELIABILITY, NON-INFRINGEMENT, MERCHANTABILITY, or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. In any event, you are solely responsible
|
||||
for any direct, indirect, special, incidental, or consequential damages or
|
||||
losses arising from the use or inability to use the Licensed Work.
|
||||
|
||||
Xiaomi reserves all rights not expressly granted to you in this License.
|
||||
Except for the rights expressly granted by Xiaomi under this License, Xiaomi
|
||||
does not authorize you in any form to use the trademarks, copyrights, or other
|
||||
forms of intellectual property rights of Xiaomi and its affiliates, including,
|
||||
without limitation, without obtaining other written permission from Xiaomi, you
|
||||
shall not use "Xiaomi", "Mijia" and other words related to Xiaomi or words that
|
||||
may make the public associate with Xiaomi in any form to publicize or promote
|
||||
the software or hardware devices that use the Licensed Work.
|
||||
|
||||
Xiaomi has the right to immediately terminate all your authorization under this
|
||||
License in the event:
|
||||
1. You assert patent invalidation, litigation, or other claims against patents
|
||||
or other intellectual property rights of Xiaomi or its affiliates; or,
|
||||
2. You make, have made, manufacture, sell, or offer to sell products that knock
|
||||
off Xiaomi or its affiliates' products.
|
||||
|
||||
Notify entities for Xiaomi Home.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
import logging
|
||||
from typing import Any, Optional
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.components.notify import NotifyEntity
|
||||
from homeassistant.util import yaml
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
|
||||
from .miot.miot_spec import MIoTSpecAction
|
||||
from .miot.miot_device import MIoTDevice, MIoTActionEntity
|
||||
from .miot.const import DOMAIN
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: ConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up a config entry."""
|
||||
device_list: list[MIoTDevice] = hass.data[DOMAIN]['devices'][
|
||||
config_entry.entry_id]
|
||||
|
||||
new_entities = []
|
||||
for miot_device in device_list:
|
||||
for action in miot_device.action_list.get('notify', []):
|
||||
new_entities.append(Notify(miot_device=miot_device, spec=action))
|
||||
|
||||
if new_entities:
|
||||
async_add_entities(new_entities)
|
||||
|
||||
|
||||
class Notify(MIoTActionEntity, NotifyEntity):
|
||||
"""Notify entities for Xiaomi Home."""
|
||||
# pylint: disable=unused-argument
|
||||
|
||||
def __init__(self, miot_device: MIoTDevice, spec: MIoTSpecAction) -> None:
|
||||
"""Initialize the Notify."""
|
||||
super().__init__(miot_device=miot_device, spec=spec)
|
||||
self._attr_extra_state_attributes = {}
|
||||
action_in: str = ', '.join([
|
||||
f'{prop.description_trans}({prop.format_.__name__})'
|
||||
for prop in self.spec.in_])
|
||||
self._attr_extra_state_attributes['action params'] = f'[{action_in}]'
|
||||
|
||||
async def async_send_message(
|
||||
self, message: str, title: Optional[str] = None
|
||||
) -> None:
|
||||
"""Send a message."""
|
||||
if not message:
|
||||
_LOGGER.error(
|
||||
'action exec failed, %s(%s), empty action params',
|
||||
self.name, self.entity_id)
|
||||
return
|
||||
in_list: Any = None
|
||||
try:
|
||||
# YAML will convert yes, no, on, off, true, false to the bool type,
|
||||
# and if it is a string, quotation marks need to be added.
|
||||
in_list = yaml.parse_yaml(content=message)
|
||||
except HomeAssistantError:
|
||||
_LOGGER.error(
|
||||
'action exec failed, %s(%s), invalid action params format, %s',
|
||||
self.name, self.entity_id, message)
|
||||
return
|
||||
if len(self.spec.in_) == 1 and not isinstance(in_list, list):
|
||||
in_list = [in_list]
|
||||
if not isinstance(in_list, list) or len(in_list) != len(self.spec.in_):
|
||||
_LOGGER.error(
|
||||
'action exec failed, %s(%s), invalid action params, %s',
|
||||
self.name, self.entity_id, message)
|
||||
return
|
||||
in_value: list[dict] = []
|
||||
for index, prop in enumerate(self.spec.in_):
|
||||
if prop.format_ == str:
|
||||
if isinstance(in_list[index], (bool, int, float, str)):
|
||||
in_value.append(
|
||||
{'piid': prop.iid, 'value': str(in_list[index])})
|
||||
continue
|
||||
elif prop.format_ == bool:
|
||||
if isinstance(in_list[index], (bool, int)):
|
||||
# yes, no, on, off, true, false and other bool types
|
||||
# will also be parsed as 0 and 1 of int.
|
||||
in_value.append(
|
||||
{'piid': prop.iid, 'value': bool(in_list[index])})
|
||||
continue
|
||||
elif prop.format_ == float:
|
||||
if isinstance(in_list[index], (int, float)):
|
||||
in_value.append(
|
||||
{'piid': prop.iid, 'value': in_list[index]})
|
||||
continue
|
||||
elif prop.format_ == int:
|
||||
if isinstance(in_list[index], int):
|
||||
in_value.append(
|
||||
{'piid': prop.iid, 'value': in_list[index]})
|
||||
continue
|
||||
# Invalid params type, raise error.
|
||||
_LOGGER.error(
|
||||
'action exec failed, %s(%s), invalid params item, '
|
||||
'which item(%s) in the list must be %s, %s type was %s, %s',
|
||||
self.name, self.entity_id, prop.description_trans,
|
||||
prop.format_, in_list[index], type(
|
||||
in_list[index]).__name__, message)
|
||||
return
|
||||
await self.action_async(in_list=in_value)
|
||||
@@ -0,0 +1,106 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Copyright (C) 2024 Xiaomi Corporation.
|
||||
|
||||
The ownership and intellectual property rights of Xiaomi Home Assistant
|
||||
Integration and related Xiaomi cloud service API interface provided under this
|
||||
license, including source code and object code (collectively, "Licensed Work"),
|
||||
are owned by Xiaomi. Subject to the terms and conditions of this License, Xiaomi
|
||||
hereby grants you a personal, limited, non-exclusive, non-transferable,
|
||||
non-sublicensable, and royalty-free license to reproduce, use, modify, and
|
||||
distribute the Licensed Work only for your use of Home Assistant for
|
||||
non-commercial purposes. For the avoidance of doubt, Xiaomi does not authorize
|
||||
you to use the Licensed Work for any other purpose, including but not limited
|
||||
to use Licensed Work to develop applications (APP), Web services, and other
|
||||
forms of software.
|
||||
|
||||
You may reproduce and distribute copies of the Licensed Work, with or without
|
||||
modifications, whether in source or object form, provided that you must give
|
||||
any other recipients of the Licensed Work a copy of this License and retain all
|
||||
copyright and disclaimers.
|
||||
|
||||
Xiaomi provides the Licensed Work on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied, including, without
|
||||
limitation, any warranties, undertakes, or conditions of TITLE, NO ERROR OR
|
||||
OMISSION, CONTINUITY, RELIABILITY, NON-INFRINGEMENT, MERCHANTABILITY, or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. In any event, you are solely responsible
|
||||
for any direct, indirect, special, incidental, or consequential damages or
|
||||
losses arising from the use or inability to use the Licensed Work.
|
||||
|
||||
Xiaomi reserves all rights not expressly granted to you in this License.
|
||||
Except for the rights expressly granted by Xiaomi under this License, Xiaomi
|
||||
does not authorize you in any form to use the trademarks, copyrights, or other
|
||||
forms of intellectual property rights of Xiaomi and its affiliates, including,
|
||||
without limitation, without obtaining other written permission from Xiaomi, you
|
||||
shall not use "Xiaomi", "Mijia" and other words related to Xiaomi or words that
|
||||
may make the public associate with Xiaomi in any form to publicize or promote
|
||||
the software or hardware devices that use the Licensed Work.
|
||||
|
||||
Xiaomi has the right to immediately terminate all your authorization under this
|
||||
License in the event:
|
||||
1. You assert patent invalidation, litigation, or other claims against patents
|
||||
or other intellectual property rights of Xiaomi or its affiliates; or,
|
||||
2. You make, have made, manufacture, sell, or offer to sell products that knock
|
||||
off Xiaomi or its affiliates' products.
|
||||
|
||||
Number entities for Xiaomi Home.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
from typing import Optional
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.components.number import NumberEntity
|
||||
|
||||
from .miot.const import DOMAIN
|
||||
from .miot.miot_spec import MIoTSpecProperty
|
||||
from .miot.miot_device import MIoTDevice, MIoTPropertyEntity
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: ConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up a config entry."""
|
||||
device_list: list[MIoTDevice] = hass.data[DOMAIN]['devices'][
|
||||
config_entry.entry_id]
|
||||
|
||||
new_entities = []
|
||||
for miot_device in device_list:
|
||||
for prop in miot_device.prop_list.get('number', []):
|
||||
new_entities.append(Number(miot_device=miot_device, spec=prop))
|
||||
|
||||
if new_entities:
|
||||
async_add_entities(new_entities)
|
||||
|
||||
|
||||
class Number(MIoTPropertyEntity, NumberEntity):
|
||||
"""Number entities for Xiaomi Home."""
|
||||
|
||||
def __init__(self, miot_device: MIoTDevice, spec: MIoTSpecProperty) -> None:
|
||||
"""Initialize the Notify."""
|
||||
super().__init__(miot_device=miot_device, spec=spec)
|
||||
# Set device_class
|
||||
self._attr_device_class = spec.device_class
|
||||
# Set unit
|
||||
if self.spec.external_unit:
|
||||
self._attr_native_unit_of_measurement = self.spec.external_unit
|
||||
# Set icon
|
||||
if self.spec.icon and not self.device_class:
|
||||
self._attr_icon = self.spec.icon
|
||||
# Set value range
|
||||
if self._value_range:
|
||||
self._attr_native_min_value = self._value_range.min_
|
||||
self._attr_native_max_value = self._value_range.max_
|
||||
self._attr_native_step = self._value_range.step
|
||||
|
||||
@property
|
||||
def native_value(self) -> Optional[float]:
|
||||
"""Return the current value of the number."""
|
||||
return self._value
|
||||
|
||||
async def async_set_native_value(self, value: float) -> None:
|
||||
"""Update the current value."""
|
||||
await self.set_property_async(value=value)
|
||||
@@ -0,0 +1,96 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Copyright (C) 2024 Xiaomi Corporation.
|
||||
|
||||
The ownership and intellectual property rights of Xiaomi Home Assistant
|
||||
Integration and related Xiaomi cloud service API interface provided under this
|
||||
license, including source code and object code (collectively, "Licensed Work"),
|
||||
are owned by Xiaomi. Subject to the terms and conditions of this License, Xiaomi
|
||||
hereby grants you a personal, limited, non-exclusive, non-transferable,
|
||||
non-sublicensable, and royalty-free license to reproduce, use, modify, and
|
||||
distribute the Licensed Work only for your use of Home Assistant for
|
||||
non-commercial purposes. For the avoidance of doubt, Xiaomi does not authorize
|
||||
you to use the Licensed Work for any other purpose, including but not limited
|
||||
to use Licensed Work to develop applications (APP), Web services, and other
|
||||
forms of software.
|
||||
|
||||
You may reproduce and distribute copies of the Licensed Work, with or without
|
||||
modifications, whether in source or object form, provided that you must give
|
||||
any other recipients of the Licensed Work a copy of this License and retain all
|
||||
copyright and disclaimers.
|
||||
|
||||
Xiaomi provides the Licensed Work on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied, including, without
|
||||
limitation, any warranties, undertakes, or conditions of TITLE, NO ERROR OR
|
||||
OMISSION, CONTINUITY, RELIABILITY, NON-INFRINGEMENT, MERCHANTABILITY, or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. In any event, you are solely responsible
|
||||
for any direct, indirect, special, incidental, or consequential damages or
|
||||
losses arising from the use or inability to use the Licensed Work.
|
||||
|
||||
Xiaomi reserves all rights not expressly granted to you in this License.
|
||||
Except for the rights expressly granted by Xiaomi under this License, Xiaomi
|
||||
does not authorize you in any form to use the trademarks, copyrights, or other
|
||||
forms of intellectual property rights of Xiaomi and its affiliates, including,
|
||||
without limitation, without obtaining other written permission from Xiaomi, you
|
||||
shall not use "Xiaomi", "Mijia" and other words related to Xiaomi or words that
|
||||
may make the public associate with Xiaomi in any form to publicize or promote
|
||||
the software or hardware devices that use the Licensed Work.
|
||||
|
||||
Xiaomi has the right to immediately terminate all your authorization under this
|
||||
License in the event:
|
||||
1. You assert patent invalidation, litigation, or other claims against patents
|
||||
or other intellectual property rights of Xiaomi or its affiliates; or,
|
||||
2. You make, have made, manufacture, sell, or offer to sell products that knock
|
||||
off Xiaomi or its affiliates' products.
|
||||
|
||||
Select entities for Xiaomi Home.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
from typing import Optional
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.components.select import SelectEntity
|
||||
|
||||
from .miot.const import DOMAIN
|
||||
from .miot.miot_device import MIoTDevice, MIoTPropertyEntity
|
||||
from .miot.miot_spec import MIoTSpecProperty
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: ConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up a config entry."""
|
||||
device_list: list[MIoTDevice] = hass.data[DOMAIN]['devices'][
|
||||
config_entry.entry_id]
|
||||
|
||||
new_entities = []
|
||||
for miot_device in device_list:
|
||||
for prop in miot_device.prop_list.get('select', []):
|
||||
new_entities.append(Select(miot_device=miot_device, spec=prop))
|
||||
|
||||
if new_entities:
|
||||
async_add_entities(new_entities)
|
||||
|
||||
|
||||
class Select(MIoTPropertyEntity, SelectEntity):
|
||||
"""Select entities for Xiaomi Home."""
|
||||
|
||||
def __init__(self, miot_device: MIoTDevice, spec: MIoTSpecProperty) -> None:
|
||||
"""Initialize the Select."""
|
||||
super().__init__(miot_device=miot_device, spec=spec)
|
||||
if self._value_list:
|
||||
self._attr_options = self._value_list.descriptions
|
||||
|
||||
async def async_select_option(self, option: str) -> None:
|
||||
"""Change the selected option."""
|
||||
await self.set_property_async(
|
||||
value=self.get_vlist_value(description=option))
|
||||
|
||||
@property
|
||||
def current_option(self) -> Optional[str]:
|
||||
"""Return the current selected option."""
|
||||
return self.get_vlist_description(value=self._value)
|
||||
@@ -0,0 +1,137 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Copyright (C) 2024 Xiaomi Corporation.
|
||||
|
||||
The ownership and intellectual property rights of Xiaomi Home Assistant
|
||||
Integration and related Xiaomi cloud service API interface provided under this
|
||||
license, including source code and object code (collectively, "Licensed Work"),
|
||||
are owned by Xiaomi. Subject to the terms and conditions of this License, Xiaomi
|
||||
hereby grants you a personal, limited, non-exclusive, non-transferable,
|
||||
non-sublicensable, and royalty-free license to reproduce, use, modify, and
|
||||
distribute the Licensed Work only for your use of Home Assistant for
|
||||
non-commercial purposes. For the avoidance of doubt, Xiaomi does not authorize
|
||||
you to use the Licensed Work for any other purpose, including but not limited
|
||||
to use Licensed Work to develop applications (APP), Web services, and other
|
||||
forms of software.
|
||||
|
||||
You may reproduce and distribute copies of the Licensed Work, with or without
|
||||
modifications, whether in source or object form, provided that you must give
|
||||
any other recipients of the Licensed Work a copy of this License and retain all
|
||||
copyright and disclaimers.
|
||||
|
||||
Xiaomi provides the Licensed Work on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied, including, without
|
||||
limitation, any warranties, undertakes, or conditions of TITLE, NO ERROR OR
|
||||
OMISSION, CONTINUITY, RELIABILITY, NON-INFRINGEMENT, MERCHANTABILITY, or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. In any event, you are solely responsible
|
||||
for any direct, indirect, special, incidental, or consequential damages or
|
||||
losses arising from the use or inability to use the Licensed Work.
|
||||
|
||||
Xiaomi reserves all rights not expressly granted to you in this License.
|
||||
Except for the rights expressly granted by Xiaomi under this License, Xiaomi
|
||||
does not authorize you in any form to use the trademarks, copyrights, or other
|
||||
forms of intellectual property rights of Xiaomi and its affiliates, including,
|
||||
without limitation, without obtaining other written permission from Xiaomi, you
|
||||
shall not use "Xiaomi", "Mijia" and other words related to Xiaomi or words that
|
||||
may make the public associate with Xiaomi in any form to publicize or promote
|
||||
the software or hardware devices that use the Licensed Work.
|
||||
|
||||
Xiaomi has the right to immediately terminate all your authorization under this
|
||||
License in the event:
|
||||
1. You assert patent invalidation, litigation, or other claims against patents
|
||||
or other intellectual property rights of Xiaomi or its affiliates; or,
|
||||
2. You make, have made, manufacture, sell, or offer to sell products that knock
|
||||
off Xiaomi or its affiliates' products.
|
||||
|
||||
Sensor entities for Xiaomi Home.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
import logging
|
||||
from typing import Any
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.components.sensor import SensorEntity, SensorDeviceClass
|
||||
from homeassistant.components.sensor import DEVICE_CLASS_UNITS
|
||||
|
||||
from .miot.miot_device import MIoTDevice, MIoTPropertyEntity
|
||||
from .miot.miot_spec import MIoTSpecProperty
|
||||
from .miot.const import DOMAIN
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: ConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up a config entry."""
|
||||
device_list: list[MIoTDevice] = hass.data[DOMAIN]['devices'][
|
||||
config_entry.entry_id]
|
||||
|
||||
new_entities = []
|
||||
for miot_device in device_list:
|
||||
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)
|
||||
|
||||
|
||||
class Sensor(MIoTPropertyEntity, SensorEntity):
|
||||
"""Sensor entities for Xiaomi Home."""
|
||||
|
||||
def __init__(self, miot_device: MIoTDevice, spec: MIoTSpecProperty) -> None:
|
||||
"""Initialize the Sensor."""
|
||||
super().__init__(miot_device=miot_device, spec=spec)
|
||||
# Set device_class
|
||||
if self._value_list:
|
||||
self._attr_device_class = SensorDeviceClass.ENUM
|
||||
self._attr_icon = 'mdi:format-text'
|
||||
self._attr_native_unit_of_measurement = None
|
||||
self._attr_options = self._value_list.descriptions
|
||||
else:
|
||||
self._attr_device_class = spec.device_class
|
||||
if spec.external_unit:
|
||||
self._attr_native_unit_of_measurement = spec.external_unit
|
||||
else:
|
||||
# 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) # type: ignore
|
||||
self._attr_native_unit_of_measurement = list(
|
||||
unit_sets)[0] if unit_sets else None
|
||||
# Set suggested precision
|
||||
if spec.format_ == float:
|
||||
self._attr_suggested_display_precision = spec.precision
|
||||
# Set state_class
|
||||
if spec.state_class:
|
||||
self._attr_state_class = spec.state_class
|
||||
# Set icon
|
||||
if spec.icon and not self.device_class:
|
||||
self._attr_icon = spec.icon
|
||||
|
||||
@property
|
||||
def native_value(self) -> Any:
|
||||
"""Return the current value of the sensor."""
|
||||
if self._value_range and isinstance(self._value, (int, float)):
|
||||
if (
|
||||
self._value < self._value_range.min_
|
||||
or self._value > self._value_range.max_
|
||||
):
|
||||
_LOGGER.info(
|
||||
'%s, data exception, out of range, %s, %s',
|
||||
self.entity_id, self._value, self._value_range)
|
||||
if self._value_list:
|
||||
return self.get_vlist_description(self._value)
|
||||
if isinstance(self._value, str):
|
||||
return self._value[:255]
|
||||
return self._value
|
||||
@@ -0,0 +1,105 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Copyright (C) 2024 Xiaomi Corporation.
|
||||
|
||||
The ownership and intellectual property rights of Xiaomi Home Assistant
|
||||
Integration and related Xiaomi cloud service API interface provided under this
|
||||
license, including source code and object code (collectively, "Licensed Work"),
|
||||
are owned by Xiaomi. Subject to the terms and conditions of this License, Xiaomi
|
||||
hereby grants you a personal, limited, non-exclusive, non-transferable,
|
||||
non-sublicensable, and royalty-free license to reproduce, use, modify, and
|
||||
distribute the Licensed Work only for your use of Home Assistant for
|
||||
non-commercial purposes. For the avoidance of doubt, Xiaomi does not authorize
|
||||
you to use the Licensed Work for any other purpose, including but not limited
|
||||
to use Licensed Work to develop applications (APP), Web services, and other
|
||||
forms of software.
|
||||
|
||||
You may reproduce and distribute copies of the Licensed Work, with or without
|
||||
modifications, whether in source or object form, provided that you must give
|
||||
any other recipients of the Licensed Work a copy of this License and retain all
|
||||
copyright and disclaimers.
|
||||
|
||||
Xiaomi provides the Licensed Work on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied, including, without
|
||||
limitation, any warranties, undertakes, or conditions of TITLE, NO ERROR OR
|
||||
OMISSION, CONTINUITY, RELIABILITY, NON-INFRINGEMENT, MERCHANTABILITY, or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. In any event, you are solely responsible
|
||||
for any direct, indirect, special, incidental, or consequential damages or
|
||||
losses arising from the use or inability to use the Licensed Work.
|
||||
|
||||
Xiaomi reserves all rights not expressly granted to you in this License.
|
||||
Except for the rights expressly granted by Xiaomi under this License, Xiaomi
|
||||
does not authorize you in any form to use the trademarks, copyrights, or other
|
||||
forms of intellectual property rights of Xiaomi and its affiliates, including,
|
||||
without limitation, without obtaining other written permission from Xiaomi, you
|
||||
shall not use "Xiaomi", "Mijia" and other words related to Xiaomi or words that
|
||||
may make the public associate with Xiaomi in any form to publicize or promote
|
||||
the software or hardware devices that use the Licensed Work.
|
||||
|
||||
Xiaomi has the right to immediately terminate all your authorization under this
|
||||
License in the event:
|
||||
1. You assert patent invalidation, litigation, or other claims against patents
|
||||
or other intellectual property rights of Xiaomi or its affiliates; or,
|
||||
2. You make, have made, manufacture, sell, or offer to sell products that knock
|
||||
off Xiaomi or its affiliates' products.
|
||||
|
||||
Switch entities for Xiaomi Home.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
from typing import Any
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.components.switch import SwitchEntity
|
||||
|
||||
from .miot.miot_device import MIoTDevice
|
||||
from .miot.miot_spec import MIoTSpecProperty
|
||||
from .miot.miot_device import MIoTPropertyEntity
|
||||
from .miot.const import DOMAIN
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: ConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up a config entry."""
|
||||
device_list: list[MIoTDevice] = hass.data[DOMAIN]['devices'][
|
||||
config_entry.entry_id]
|
||||
|
||||
new_entities = []
|
||||
for miot_device in device_list:
|
||||
for prop in miot_device.prop_list.get('switch', []):
|
||||
new_entities.append(Switch(miot_device=miot_device, spec=prop))
|
||||
|
||||
if new_entities:
|
||||
async_add_entities(new_entities)
|
||||
|
||||
|
||||
class Switch(MIoTPropertyEntity, SwitchEntity):
|
||||
"""Switch entities for Xiaomi Home."""
|
||||
# pylint: disable=unused-argument
|
||||
|
||||
def __init__(self, miot_device: MIoTDevice, spec: MIoTSpecProperty) -> None:
|
||||
"""Initialize the Switch."""
|
||||
super().__init__(miot_device=miot_device, spec=spec)
|
||||
# Set device_class
|
||||
self._attr_device_class = spec.device_class
|
||||
|
||||
@property
|
||||
def is_on(self) -> bool:
|
||||
"""On/Off state."""
|
||||
return self._value is True
|
||||
|
||||
async def async_turn_on(self, **kwargs: Any) -> None:
|
||||
"""Turn the switch on."""
|
||||
await self.set_property_async(value=True)
|
||||
|
||||
async def async_turn_off(self, **kwargs: Any) -> None:
|
||||
"""Turn the switch off."""
|
||||
await self.set_property_async(value=False)
|
||||
|
||||
async def async_toggle(self, **kwargs: Any) -> None:
|
||||
"""Toggle the switch."""
|
||||
await self.set_property_async(value=not self.is_on)
|
||||
@@ -0,0 +1,180 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Copyright (C) 2024 Xiaomi Corporation.
|
||||
|
||||
The ownership and intellectual property rights of Xiaomi Home Assistant
|
||||
Integration and related Xiaomi cloud service API interface provided under this
|
||||
license, including source code and object code (collectively, "Licensed Work"),
|
||||
are owned by Xiaomi. Subject to the terms and conditions of this License, Xiaomi
|
||||
hereby grants you a personal, limited, non-exclusive, non-transferable,
|
||||
non-sublicensable, and royalty-free license to reproduce, use, modify, and
|
||||
distribute the Licensed Work only for your use of Home Assistant for
|
||||
non-commercial purposes. For the avoidance of doubt, Xiaomi does not authorize
|
||||
you to use the Licensed Work for any other purpose, including but not limited
|
||||
to use Licensed Work to develop applications (APP), Web services, and other
|
||||
forms of software.
|
||||
|
||||
You may reproduce and distribute copies of the Licensed Work, with or without
|
||||
modifications, whether in source or object form, provided that you must give
|
||||
any other recipients of the Licensed Work a copy of this License and retain all
|
||||
copyright and disclaimers.
|
||||
|
||||
Xiaomi provides the Licensed Work on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied, including, without
|
||||
limitation, any warranties, undertakes, or conditions of TITLE, NO ERROR OR
|
||||
OMISSION, CONTINUITY, RELIABILITY, NON-INFRINGEMENT, MERCHANTABILITY, or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. In any event, you are solely responsible
|
||||
for any direct, indirect, special, incidental, or consequential damages or
|
||||
losses arising from the use or inability to use the Licensed Work.
|
||||
|
||||
Xiaomi reserves all rights not expressly granted to you in this License.
|
||||
Except for the rights expressly granted by Xiaomi under this License, Xiaomi
|
||||
does not authorize you in any form to use the trademarks, copyrights, or other
|
||||
forms of intellectual property rights of Xiaomi and its affiliates, including,
|
||||
without limitation, without obtaining other written permission from Xiaomi, you
|
||||
shall not use "Xiaomi", "Mijia" and other words related to Xiaomi or words that
|
||||
may make the public associate with Xiaomi in any form to publicize or promote
|
||||
the software or hardware devices that use the Licensed Work.
|
||||
|
||||
Xiaomi has the right to immediately terminate all your authorization under this
|
||||
License in the event:
|
||||
1. You assert patent invalidation, litigation, or other claims against patents
|
||||
or other intellectual property rights of Xiaomi or its affiliates; or,
|
||||
2. You make, have made, manufacture, sell, or offer to sell products that knock
|
||||
off Xiaomi or its affiliates' products.
|
||||
|
||||
Text entities for Xiaomi Home.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
import logging
|
||||
from typing import Any, Optional
|
||||
|
||||
from homeassistant.config_entries import ConfigEntry
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddEntitiesCallback
|
||||
from homeassistant.components.text import TextEntity
|
||||
from homeassistant.util import yaml
|
||||
from homeassistant.exceptions import HomeAssistantError
|
||||
|
||||
from .miot.const import DOMAIN
|
||||
from .miot.miot_spec import MIoTSpecAction, MIoTSpecProperty
|
||||
from .miot.miot_device import MIoTActionEntity, MIoTDevice, MIoTPropertyEntity
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
config_entry: ConfigEntry,
|
||||
async_add_entities: AddEntitiesCallback,
|
||||
) -> None:
|
||||
"""Set up a config entry."""
|
||||
device_list: list[MIoTDevice] = hass.data[DOMAIN]['devices'][
|
||||
config_entry.entry_id]
|
||||
new_entities = []
|
||||
for miot_device in device_list:
|
||||
for prop in miot_device.prop_list.get('text', []):
|
||||
new_entities.append(Text(miot_device=miot_device, spec=prop))
|
||||
|
||||
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)
|
||||
|
||||
|
||||
class Text(MIoTPropertyEntity, TextEntity):
|
||||
"""Text entities for Xiaomi Home."""
|
||||
|
||||
def __init__(self, miot_device: MIoTDevice, spec: MIoTSpecProperty) -> None:
|
||||
"""Initialize the Text."""
|
||||
super().__init__(miot_device=miot_device, spec=spec)
|
||||
|
||||
@property
|
||||
def native_value(self) -> Optional[str]:
|
||||
"""Return the current text value."""
|
||||
if isinstance(self._value, str):
|
||||
return self._value[:255]
|
||||
return self._value
|
||||
|
||||
async def async_set_value(self, value: str) -> None:
|
||||
"""Set the text value."""
|
||||
await self.set_property_async(value=value)
|
||||
|
||||
|
||||
class ActionText(MIoTActionEntity, TextEntity):
|
||||
"""Text entities for Xiaomi Home."""
|
||||
|
||||
def __init__(self, miot_device: MIoTDevice, spec: MIoTSpecAction) -> None:
|
||||
super().__init__(miot_device=miot_device, spec=spec)
|
||||
self._attr_extra_state_attributes = {}
|
||||
self._attr_native_value = ''
|
||||
action_in: str = ', '.join([
|
||||
f'{prop.description_trans}({prop.format_.__name__})'
|
||||
for prop in self.spec.in_])
|
||||
self._attr_extra_state_attributes['action params'] = f'[{action_in}]'
|
||||
|
||||
async def async_set_value(self, value: str) -> None:
|
||||
if not value:
|
||||
return
|
||||
in_list: Any = None
|
||||
try:
|
||||
in_list = yaml.parse_yaml(content=value)
|
||||
except HomeAssistantError as e:
|
||||
_LOGGER.error(
|
||||
'action exec failed, %s(%s), invalid action params format, %s',
|
||||
self.name, self.entity_id, value)
|
||||
raise ValueError(
|
||||
f'action exec failed, {self.name}({self.entity_id}), '
|
||||
f'invalid action params format, {value}') from e
|
||||
if len(self.spec.in_) == 1 and not isinstance(in_list, list):
|
||||
in_list = [in_list]
|
||||
if not isinstance(in_list, list) or len(in_list) != len(self.spec.in_):
|
||||
_LOGGER.error(
|
||||
'action exec failed, %s(%s), invalid action params, %s',
|
||||
self.name, self.entity_id, value)
|
||||
raise ValueError(
|
||||
f'action exec failed, {self.name}({self.entity_id}), '
|
||||
f'invalid action params, {value}')
|
||||
in_value: list[dict] = []
|
||||
for index, prop in enumerate(self.spec.in_):
|
||||
if prop.format_ == str:
|
||||
if isinstance(in_list[index], (bool, int, float, str)):
|
||||
in_value.append(
|
||||
{'piid': prop.iid, 'value': str(in_list[index])})
|
||||
continue
|
||||
elif prop.format_ == bool:
|
||||
if isinstance(in_list[index], (bool, int)):
|
||||
# yes, no, on, off, true, false and other bool types
|
||||
# will also be parsed as 0 and 1 of int.
|
||||
in_value.append(
|
||||
{'piid': prop.iid, 'value': bool(in_list[index])})
|
||||
continue
|
||||
elif prop.format_ == float:
|
||||
if isinstance(in_list[index], (int, float)):
|
||||
in_value.append(
|
||||
{'piid': prop.iid, 'value': in_list[index]})
|
||||
continue
|
||||
elif prop.format_ == int:
|
||||
if isinstance(in_list[index], int):
|
||||
in_value.append(
|
||||
{'piid': prop.iid, 'value': in_list[index]})
|
||||
continue
|
||||
# Invalid params type, raise error.
|
||||
_LOGGER.error(
|
||||
'action exec failed, %s(%s), invalid params item, '
|
||||
'which item(%s) in the list must be %s, %s type was %s, %s',
|
||||
self.name, self.entity_id, prop.description_trans,
|
||||
prop.format_, in_list[index], type(
|
||||
in_list[index]).__name__, value)
|
||||
raise ValueError(
|
||||
f'action exec failed, {self.name}({self.entity_id}), '
|
||||
f'invalid params item, which item({prop.description_trans}) '
|
||||
f'in the list must be {prop.format_}, {in_list[index]} type '
|
||||
f'was {type(in_list[index]).__name__}, {value}')
|
||||
|
||||
self._attr_native_value = value
|
||||
if await self.action_async(in_list=in_value):
|
||||
self.async_write_ha_state()
|
||||
@@ -0,0 +1,225 @@
|
||||
{
|
||||
"config": {
|
||||
"flow_title": "Xiaomi Home Integration",
|
||||
"step": {
|
||||
"eula": {
|
||||
"title": "Risikohinweis",
|
||||
"description": "1. Ihre **Xiaomi-Benutzerinformationen und Geräteinformationen** werden in Ihrem Home Assistant-System gespeichert. **Xiaomi kann die Sicherheit des Home Assistant-Speichermechanismus nicht garantieren**. Sie sind dafür verantwortlich, Ihre Informationen vor Diebstahl zu schützen.\r\n2. Diese Integration wird von der Open-Source-Community unterstützt und gewartet. Es können jedoch Stabilitätsprobleme oder andere Probleme auftreten. Wenn Sie auf ein Problem stoßen, das mit dieser Integration zusammenhängt, sollten Sie **die Open-Source-Community um Hilfe bitten, anstatt sich an den Xiaomi Home Kundendienst zu wenden**.\r\n3. Sie benötigen bestimmte technische Fähigkeiten, um Ihre lokale Laufzeitumgebung zu warten. Diese Integration ist für Anfänger nicht geeignet.\r\n4. Bevor Sie diese Integration verwenden, lesen Sie bitte die **README-Datei sorgfältig durch**.\r\n5. Um eine stabile Nutzung der Integration zu gewährleisten und Missbrauch der Schnittstelle zu verhindern, **darf diese Integration nur in Home Assistant verwendet werden. Weitere Informationen finden Sie in der LICENSE**.",
|
||||
"data": {
|
||||
"eula": "Ich habe das oben genannte Risiko zur Kenntnis genommen und übernehme freiwillig die damit verbundenen Risiken durch die Verwendung der Integration."
|
||||
}
|
||||
},
|
||||
"auth_config": {
|
||||
"title": "Grundkonfiguration",
|
||||
"description": "### Anmeldegebiet\r\nWählen Sie das Gebiet, in dem sich Ihr Xiaomi Home-Konto befindet. Sie können es in der Xiaomi Home App unter `Mein (unten im Menü) > Weitere Einstellungen > Über Xiaomi Home` überprüfen.\r\n### Sprache\r\nWählen Sie die Sprache, in der Geräte und Entitätsnamen angezeigt werden. Teile von Sätzen, die nicht übersetzt sind, werden in Englisch angezeigt.\r\n### OAuth2-Authentifizierungs-Umleitungs-URL\r\nDie Umleitungs-URL für die OAuth2-Authentifizierung lautet **[http://homeassistant.local:8123](http://homeassistant.local:8123)**. Home Assistant muss im selben lokalen Netzwerk wie das aktuelle Betriebsterminal (z. B. ein persönlicher Computer) und das Betriebsterminal muss über diese Adresse auf die Home Assistant-Homepage zugreifen können. Andernfalls kann die Anmeldeauthentifizierung fehlschlagen.\r\n### Integrierte Netzwerkkonfiguration\r\nÜberprüfen Sie, ob das lokale Netzwerk normal funktioniert und ob die zugehörigen Netzwerkressourcen zugänglich sind. **Es wird empfohlen, dies beim ersten Hinzufügen auszuwählen.**\r\n### Hinweis\r\n- Für Benutzer mit Hunderten oder mehr Mi Home-Geräten wird das erste Hinzufügen der Integration einige Zeit in Anspruch nehmen. Bitte haben Sie Geduld.\r\n- Wenn Home Assistant in einer Docker-Umgebung läuft, stellen Sie bitte sicher, dass der Docker-Netzwerkmodus auf host eingestellt ist, da sonst die lokale Steuerungsfunktion möglicherweise nicht richtig funktioniert.\r\n- Die lokale Steuerungsfunktion der Integration hat einige Abhängigkeiten. Bitte lesen Sie das README sorgfältig.",
|
||||
"data": {
|
||||
"cloud_server": "Anmeldegebiet",
|
||||
"integration_language": "Sprache",
|
||||
"oauth_redirect_url": "OAuth2-Authentifizierungs-Umleitungs-URL",
|
||||
"network_detect_config": "Integrierte Netzwerkkonfiguration"
|
||||
}
|
||||
},
|
||||
"network_detect_config": {
|
||||
"title": "Integrierte Netzwerkkonfiguration",
|
||||
"description": "## Gebrauchsanweisung\r\n### Netzwerk-Erkennungsadresse\r\nWird verwendet, um zu überprüfen, ob das Netzwerk normal funktioniert. Wenn nicht festgelegt, wird die Standardadresse des Systems verwendet. Wenn die Standardadressprüfung fehlschlägt, können Sie versuchen, eine benutzerdefinierte Adresse einzugeben.\r\n- Sie können mehrere Erkennungsadressen eingeben, getrennt durch ein Komma, z. B. `8.8.8.8,https://www.bing.com`\r\n- Wenn es sich um eine IP-Adresse handelt, wird die Erkennung durch Ping durchgeführt. Wenn es sich um eine HTTP(s)-Adresse handelt, wird die Erkennung durch einen HTTP GET-Aufruf durchgeführt.\r\n- Wenn Sie die Standarderkennungsadresse des Systems wiederherstellen möchten, geben Sie ein Komma `,` ein und klicken Sie auf 'Weiter'.\r\n- **Diese Konfiguration ist global und Änderungen wirken sich auf andere Integrationsinstanzen aus. Bitte ändern Sie sie mit Vorsicht.**\r\n### Überprüfung der Netzwerkabhängigkeiten\r\nÜberprüfen Sie nacheinander, ob die folgenden Netzwerkabhängigkeiten zugänglich sind. Wenn die entsprechenden Adressen nicht zugänglich sind, führt dies zu Integrationsfehlern.\r\n- OAuth2-Authentifizierungsadresse: `https://account.xiaomi.com/oauth2/authorize`.\r\n- Xiaomi HTTP API-Adresse: `https://{http_host}/app/v2/ha/oauth/get_token`.\r\n- Xiaomi SPEC API-Adresse: `https://miot-spec.org/miot-spec-v2/template/list/device`.\r\n- Xiaomi MQTT Broker-Adresse: `mqtts://{broker_host}`.",
|
||||
"data": {
|
||||
"network_detect_addr": "Netzwerkerkennungsadresse",
|
||||
"check_network_deps": "Überprüfung der Netzwerkabhängigkeiten"
|
||||
}
|
||||
},
|
||||
"oauth_error": {
|
||||
"title": "Fehler bei der Anmeldung",
|
||||
"description": "Klicken Sie auf \"Weiter\", um es erneut zu versuchen."
|
||||
},
|
||||
"homes_select": {
|
||||
"title": "Familie und Geräte auswählen",
|
||||
"description": "## Gebrauchsanweisung\r\n### Familienimport für importierte Geräte\r\nDie Integration fügt Geräte aus den ausgewählten Familien hinzu.\r\n### Raumnamensynchronisationsmodus\r\nWenn Geräte von der Xiaomi Home App zu Home Assistant synchronisiert werden, wird die Bezeichnung des Bereichs, in dem sich die Geräte in Home Assistant befinden, nach folgenden Regeln benannt. Beachten Sie, dass das Synchronisieren von Geräten den von Xiaomi Home App festgelegten Familien- und Raum-Einstellungen nicht ändert.\r\n- Nicht synchronisieren: Das Gerät wird keinem Bereich hinzugefügt.\r\n- Andere Optionen: Der Bereich, in den das Gerät aufgenommen wird, wird nach dem Namen der Familie oder des Raums in der Xiaomi Home App benannt.\r\n### Erweiterte Einstellungen\r\nZeigen Sie erweiterte Einstellungen an, um die professionellen Konfigurationsoptionen der Integration zu ändern.\r\n\r\n \r\n### {nick_name} Hallo! Bitte wählen Sie die Familie aus, zu der Sie das Gerät hinzufügen möchten.",
|
||||
"data": {
|
||||
"home_infos": "Familienimport für importierte Geräte",
|
||||
"area_name_rule": "Raumnamensynchronisationsmodus",
|
||||
"advanced_options": "Erweiterte Einstellungen"
|
||||
}
|
||||
},
|
||||
"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### 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"
|
||||
}
|
||||
},
|
||||
"devices_filter": {
|
||||
"title": "Geräte filtern",
|
||||
"description": "## Gebrauchsanweisung\r\nUnterstützt das Filtern von Geräten nach Raumnamen, Gerätezugriffstyp und Gerätemodell, und unterstützt auch das Filtern nach Gerätegröße. Die Filterlogik ist wie folgt:\r\n- Zuerst wird gemäß der statistischen Logik die Vereinigung oder der Schnittpunkt aller eingeschlossenen Elemente ermittelt, dann der Schnittpunkt oder die Vereinigung der ausgeschlossenen Elemente, und schließlich wird das [eingeschlossene Gesamtergebnis] vom [ausgeschlossenen Gesamtergebnis] subtrahiert, um das [Filterergebnis] zu erhalten.\r\n- Wenn keine eingeschlossenen Elemente ausgewählt sind, bedeutet dies, dass alle eingeschlossen sind.\r\n### Filtermodus\r\n- Ausschließen: Unerwünschte Elemente entfernen.\r\n- Einschließen: Gewünschte Elemente einschließen.\r\n### Statistische Logik\r\n- UND-Logik: Den Schnittpunkt aller Elemente im gleichen Modus nehmen.\r\n- ODER-Logik: Die Vereinigung aller Elemente im gleichen Modus nehmen.\r\n\r\nSie können auch zur Seite [Konfiguration > Geräteliste aktualisieren] des Integrationselements gehen, [Geräte filtern] auswählen, um erneut zu filtern.",
|
||||
"data": {
|
||||
"room_filter_mode": "Familienraum filtern",
|
||||
"room_list": "Familienraum",
|
||||
"type_filter_mode": "Gerätetyp filtern",
|
||||
"type_list": "Gerätetyp",
|
||||
"model_filter_mode": "Gerätemodell filtern",
|
||||
"model_list": "Gerätemodell",
|
||||
"devices_filter_mode": "Geräte filtern",
|
||||
"device_list": "Geräteliste",
|
||||
"statistics_logic": "Statistiklogik"
|
||||
}
|
||||
}
|
||||
},
|
||||
"progress": {
|
||||
"oauth": "### {link_left}Klicken Sie hier, um sich anzumelden{link_right}\r\n(Sie werden nach erfolgreicher Anmeldung automatisch zur nächsten Seite weitergeleitet)"
|
||||
},
|
||||
"error": {
|
||||
"eula_not_agree": "Bitte lesen Sie den Risikohinweis.",
|
||||
"get_token_error": "Fehler beim Abrufen von Anmeldeinformationen (OAuth-Token).",
|
||||
"get_homeinfo_error": "Fehler beim Abrufen von Familieninformationen.",
|
||||
"mdns_discovery_error": "Lokaler Geräteerkennungsdienst ist nicht verfügbar.",
|
||||
"get_cert_error": "Fehler beim Abrufen des Gateway-Zertifikats.",
|
||||
"no_family_selected": "Keine Familie ausgewählt.",
|
||||
"no_devices": "Im ausgewählten Haushalt sind keine Geräte vorhanden. Bitte wählen Sie einen Haushalt mit Geräten aus und fahren Sie fort.",
|
||||
"no_filter_devices": "Gefilterte Geräte sind leer. Bitte wählen Sie gültige Filterkriterien aus und fahren Sie fort.",
|
||||
"no_central_device": "Im Modus \"Xiaomi Central Hub Gateway\" muss ein verfügbares Xiaomi Central Hub Gateway im lokalen Netzwerk von Home Assistant vorhanden sein. Stellen Sie sicher, dass die ausgewählte Familie diese Anforderungen erfüllt.",
|
||||
"invalid_network_addr": "Ungültige IP-Adresse oder HTTP-Adresse vorhanden, bitte geben Sie eine gültige Adresse ein.",
|
||||
"invalid_ip_addr": "Unzugängliche IP-Adresse vorhanden, bitte geben Sie eine gültige IP-Adresse ein.",
|
||||
"invalid_http_addr": "Unzugängliche HTTP-Adresse vorhanden, bitte geben Sie eine gültige HTTP-Adresse ein.",
|
||||
"invalid_default_addr": "Die Standard-Netzwerkerkennungsadresse ist nicht erreichbar, bitte überprüfen Sie die Netzwerkkonfiguration oder verwenden Sie eine benutzerdefinierte Netzwerkerkennungsadresse.",
|
||||
"unreachable_oauth2_host": "OAuth2-Authentifizierungsadresse ist nicht erreichbar, bitte überprüfen Sie die Netzwerkkonfiguration.",
|
||||
"unreachable_http_host": "Xiaomi HTTP API-Adresse ist nicht erreichbar, bitte überprüfen Sie die Netzwerkkonfiguration.",
|
||||
"unreachable_spec_host": "Xiaomi SPEC API-Adresse ist nicht erreichbar, bitte überprüfen Sie die Netzwerkkonfiguration.",
|
||||
"unreachable_mqtt_broker": "Xiaomi MQTT Broker-Adresse ist nicht erreichbar, bitte überprüfen Sie die Netzwerkkonfiguration."
|
||||
},
|
||||
"abort": {
|
||||
"ha_uuid_get_failed": "Fehler beim Abrufen der Home Assistant-UUID.",
|
||||
"network_connect_error": "Konfiguration fehlgeschlagen. Netzwerkverbindung fehlgeschlagen. Überprüfen Sie die Netzwerkkonfiguration des Geräts.",
|
||||
"already_configured": "Dieser Benutzer hat die Konfiguration bereits abgeschlossen. Gehen Sie zur Integrationsseite und klicken Sie auf die Schaltfläche \"Konfiguration\", um die Konfiguration zu ändern.",
|
||||
"invalid_auth_info": "Authentifizierungsinformationen sind abgelaufen. Gehen Sie zur Integrationsseite und klicken Sie auf die Schaltfläche \"Konfiguration\", um die Authentifizierung erneut durchzuführen.",
|
||||
"config_flow_error": "Integrationskonfigurationsfehler: {error}"
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"step": {
|
||||
"auth_config": {
|
||||
"title": "Authentifizierungskonfiguration",
|
||||
"description": "Lokale Authentifizierungsinformationen sind abgelaufen. Starten Sie die Authentifizierung erneut.\r\n### Aktuelles Anmeldegebiet: {cloud_server}\r\n### OAuth2-Authentifizierungs-Umleitungs-URL\r\nDie Umleitungs-URL für die OAuth2-Authentifizierung lautet **[http://homeassistant.local:8123](http://homeassistant.local:8123)**. Home Assistant muss im selben lokalen Netzwerk wie das aktuelle Betriebsterminal (z. B. ein persönlicher Computer) und das Betriebsterminal muss über diese Adresse auf die Home Assistant-Homepage zugreifen können. Andernfalls kann die Anmeldeauthentifizierung fehlschlagen.",
|
||||
"data": {
|
||||
"oauth_redirect_url": "OAuth2-Authentifizierungs-Umleitungs-URL"
|
||||
}
|
||||
},
|
||||
"oauth_error": {
|
||||
"title": "Fehler bei der Anmeldung",
|
||||
"description": "Klicken Sie auf \"Weiter\", um es erneut zu versuchen."
|
||||
},
|
||||
"config_options": {
|
||||
"title": "Konfigurationsoptionen",
|
||||
"description": "### Hallo {nick_name}!\r\n\r\nXiaomi Home-Konto-ID: {uid}\r\nAktuelles Anmeldegebiet: {cloud_server}\r\nIntegrationsinstanz-ID: {instance_id}\r\n\r\nWählen Sie die Optionen aus, die Sie erneut konfigurieren möchten, und klicken Sie dann auf \"Weiter\".",
|
||||
"data": {
|
||||
"integration_language": "Integrationsprache",
|
||||
"update_user_info": "Benutzerinformationen aktualisieren",
|
||||
"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",
|
||||
"network_detect_config": "Integrierte Netzwerkkonfiguration",
|
||||
"cover_dead_zone_width": "Die Breite des toten Winkels des Vorhangs"
|
||||
}
|
||||
},
|
||||
"update_user_info": {
|
||||
"title": "Benutzernamen aktualisieren",
|
||||
"description": "{nick_name}! Bitte geben Sie unten Ihren Benutzernamen ein.",
|
||||
"data": {
|
||||
"nick_name": "Benutzername"
|
||||
}
|
||||
},
|
||||
"homes_select": {
|
||||
"title": "Familie und Geräte neu auswählen",
|
||||
"description": "## Gebrauchsanweisung\r\n### Familienimport für importierte Geräte\r\nDie Integration fügt Geräte aus den ausgewählten Familien hinzu.\r\n### Geräte filtern\r\nUnterstützt das Filtern von Geräten nach Raumnamen, Gerätezugriffstyp und Gerätemodell, und unterstützt auch das Filtern nach Gerätegröße. Es wurden **{local_count}** Geräte gefiltert.\r\n### Steuerungsmodus\r\n- Automatisch: Wenn im lokalen Netzwerk ein verfügbarer Xiaomi-Zentralgateway vorhanden ist, wird Home Assistant bevorzugt Steuerbefehle über den Zentralgateway senden, um eine lokale Steuerung zu ermöglichen. Wenn im lokalen Netzwerk kein Zentralgateway vorhanden ist, wird versucht, Steuerbefehle über das Xiaomi-OT-Protokoll zu senden, um eine lokale Steuerung zu ermöglichen. Nur wenn die oben genannten Bedingungen für die lokale Steuerung nicht erfüllt sind, werden die Steuerbefehle über die Cloud gesendet.\r\n- Cloud: Steuerbefehle werden nur über die Cloud gesendet.",
|
||||
"data": {
|
||||
"home_infos": "Familienimport für importierte Geräte",
|
||||
"devices_filter": "Geräte filtern",
|
||||
"ctrl_mode": "Steuerungsmodus"
|
||||
}
|
||||
},
|
||||
"devices_filter": {
|
||||
"title": "Geräte filtern",
|
||||
"description": "## Gebrauchsanweisung\r\nUnterstützt das Filtern von Geräten nach Raumnamen, Gerätezugriffstyp und Gerätemodell, und unterstützt auch das Filtern nach Gerätegröße. Die Filterlogik ist wie folgt:\r\n- Zuerst wird gemäß der statistischen Logik die Vereinigung oder der Schnittpunkt aller eingeschlossenen Elemente ermittelt, dann der Schnittpunkt oder die Vereinigung der ausgeschlossenen Elemente, und schließlich wird das [eingeschlossene Gesamtergebnis] vom [ausgeschlossenen Gesamtergebnis] subtrahiert, um das [Filterergebnis] zu erhalten.\r\n- Wenn keine eingeschlossenen Elemente ausgewählt sind, bedeutet dies, dass alle eingeschlossen sind.\r\n### Filtermodus\r\n- Ausschließen: Unerwünschte Elemente entfernen.\r\n- Einschließen: Gewünschte Elemente einschließen.\r\n### Statistische Logik\r\n- UND-Logik: Den Schnittpunkt aller Elemente im gleichen Modus nehmen.\r\n- ODER-Logik: Die Vereinigung aller Elemente im gleichen Modus nehmen.\r\n\r\nSie können auch zur Seite [Konfiguration > Geräteliste aktualisieren] des Integrationselements gehen, [Geräte filtern] auswählen, um erneut zu filtern.",
|
||||
"data": {
|
||||
"room_filter_mode": "Familienraum filtern",
|
||||
"room_list": "Familienraum",
|
||||
"type_filter_mode": "Gerätetyp filtern",
|
||||
"type_list": "Gerätetyp",
|
||||
"model_filter_mode": "Gerätemodell filtern",
|
||||
"model_list": "Gerätemodell",
|
||||
"devices_filter_mode": "Geräte filtern",
|
||||
"device_list": "Geräteliste",
|
||||
"statistics_logic": "Statistiklogik"
|
||||
}
|
||||
},
|
||||
"update_trans_rules": {
|
||||
"title": "Entitätskonvertierungsregeln aktualisieren",
|
||||
"description": "## Gebrauchsanweisung\r\n- Aktualisieren Sie die Entitätsinformationen der Geräte im aktuellen Integrationsinstanz, einschließlich der mehrsprachigen SPEC-Konfiguration, der SPEC-Booleschen Übersetzung und der SPEC-Modellfilterung.\r\n- **Warnung: Diese Konfiguration ist eine globale Konfiguration** und aktualisiert direkt den lokalen Cache. Wenn in anderen Integrationsinstanzen Geräte desselben Modells vorhanden sind, werden diese nach dem Neuladen der entsprechenden Instanzen ebenfalls aktualisiert.\r\n- Dieser Vorgang kann einige Zeit in Anspruch nehmen, bitte haben Sie Geduld. Wählen Sie \"Bestätigen Sie das Update\" und klicken Sie auf \"Weiter\", um **{urn_count}** Regeln zu aktualisieren, andernfalls überspringen Sie das Update.",
|
||||
"data": {
|
||||
"confirm": "Bestätigen"
|
||||
}
|
||||
},
|
||||
"update_lan_ctrl_config": {
|
||||
"title": "LAN-Steuerungskonfiguration aktualisieren",
|
||||
"description": "## Gebrauchsanweisung\r\nAktualisieren Sie die Konfigurationsinformationen für **LAN-Steuerung von Xiaomi Home-Geräten**. Wenn die Cloud und das zentrale Gateway die Geräte nicht steuern können, versucht die Integration, die Geräte über das LAN zu steuern; wenn keine Netzwerkkarte ausgewählt ist, wird die LAN-Steuerung nicht aktiviert.\r\n- Derzeit werden nur **SPEC v2** WiFi-Geräte im LAN unterstützt. Einige ältere Geräte unterstützen möglicherweise keine Steuerung oder Eigenschaftssynchronisierung.\r\n- Bitte wählen Sie die Netzwerkkarte(n) im selben Netzwerk wie die Geräte aus (mehrere Auswahlen werden unterstützt). Wenn die ausgewählte Netzwerkkarte zwei oder mehr Verbindungen im selben Netzwerk hat, wird empfohlen, die mit der besten Netzwerkverbindung auszuwählen, da sonst die **normale Verwendung der Geräte beeinträchtigt werden kann**.\r\n- **Wenn es im LAN Endgeräte (Gateways, Mobiltelefone usw.) gibt, die lokale Steuerung unterstützen, kann das Aktivieren des LAN-Abonnements lokale Automatisierung oder Geräteanomalien verursachen. Bitte verwenden Sie es mit Vorsicht**.\r\n- **Warnung: Diese Konfiguration ist global und Änderungen wirken sich auf andere Integrationsinstanzen aus. Bitte ändern Sie sie mit Vorsicht**.\r\n{notice_net_dup}",
|
||||
"data": {
|
||||
"net_interfaces": "Bitte wählen Sie die zu verwendende Netzwerkkarte aus",
|
||||
"enable_subscribe": "LAN-Abonnement aktivieren"
|
||||
}
|
||||
},
|
||||
"network_detect_config": {
|
||||
"title": "Integrierte Netzwerkkonfiguration",
|
||||
"description": "## Gebrauchsanweisung\r\n### Netzwerk-Erkennungsadresse\r\nWird verwendet, um zu überprüfen, ob das Netzwerk normal funktioniert. Wenn nicht festgelegt, wird die Standardadresse des Systems verwendet. Wenn die Standardadressprüfung fehlschlägt, können Sie versuchen, eine benutzerdefinierte Adresse einzugeben.\r\n- Sie können mehrere Erkennungsadressen eingeben, getrennt durch ein Komma, z. B. `8.8.8.8,https://www.bing.com`\r\n- Wenn es sich um eine IP-Adresse handelt, wird die Erkennung durch Ping durchgeführt. Wenn es sich um eine HTTP(s)-Adresse handelt, wird die Erkennung durch einen HTTP GET-Aufruf durchgeführt.\r\n- Wenn Sie die Standarderkennungsadresse des Systems wiederherstellen möchten, geben Sie ein Komma `,` ein und klicken Sie auf 'Weiter'.\r\n- **Diese Konfiguration ist global und Änderungen wirken sich auf andere Integrationsinstanzen aus. Bitte ändern Sie sie mit Vorsicht.**\r\n### Überprüfung der Netzwerkabhängigkeiten\r\nÜberprüfen Sie nacheinander, ob die folgenden Netzwerkabhängigkeiten zugänglich sind. Wenn die entsprechenden Adressen nicht zugänglich sind, führt dies zu Integrationsfehlern.\r\n- OAuth2-Authentifizierungsadresse: `https://account.xiaomi.com/oauth2/authorize`.\r\n- Xiaomi HTTP API-Adresse: `https://{http_host}/app/v2/ha/oauth/get_token`.\r\n- Xiaomi SPEC API-Adresse: `https://miot-spec.org/miot-spec-v2/template/list/device`.\r\n- Xiaomi MQTT Broker-Adresse: `mqtts://{broker_host}`.",
|
||||
"data": {
|
||||
"network_detect_addr": "Netzwerkerkennungsadresse",
|
||||
"check_network_deps": "Überprüfung der Netzwerkabhängigkeiten"
|
||||
}
|
||||
},
|
||||
"config_confirm": {
|
||||
"title": "Bestätigen Sie die Konfiguration",
|
||||
"description": "**{nick_name}**, bitte bestätigen Sie die neuesten Konfigurationsinformationen und klicken Sie dann auf \"Senden\". Die Integration wird mit den aktualisierten Konfigurationen erneut geladen.\r\n\r\nIntegrationsprache:\t{lang_new}\r\nBenutzername:\t{nick_name_new}\r\nAction-Debug-Modus:\t{action_debug}\r\nVerstecke Nicht-Standard-Entitäten:\t{hide_non_standard_entities}\r\nDie Breite des toten Winkels des Vorhangs:\t{cover_width_new}\r\nGerätestatusänderungen anzeigen:\t{display_devices_changed_notify}\r\nGeräteänderungen:\t{devices_add} neue Geräte hinzufügen, {devices_remove} Geräte entfernen\r\nKonvertierungsregeländerungen:\tInsgesamt {trans_rules_count} Regeln, aktualisiert {trans_rules_count_success} Regeln",
|
||||
"data": {
|
||||
"confirm": "Änderungen bestätigen"
|
||||
}
|
||||
}
|
||||
},
|
||||
"progress": {
|
||||
"oauth": "### {link_left}Klicken Sie hier, um sich erneut anzumelden{link_right}"
|
||||
},
|
||||
"error": {
|
||||
"not_auth": "Nicht authentifiziert. Klicken Sie auf den Authentifizierungslink, um die Benutzeridentität zu authentifizieren.",
|
||||
"get_token_error": "Fehler beim Abrufen von Anmeldeinformationen (OAuth-Token).",
|
||||
"get_homeinfo_error": "Fehler beim Abrufen von Home-Informationen.",
|
||||
"get_cert_error": "Fehler beim Abrufen des Zentralzertifikats.",
|
||||
"no_family_selected": "Keine Familie ausgewählt.",
|
||||
"no_devices": "Im ausgewählten Haushalt sind keine Geräte vorhanden. Bitte wählen Sie einen Haushalt mit Geräten aus und fahren Sie fort.",
|
||||
"no_filter_devices": "Gefilterte Geräte sind leer. Bitte wählen Sie gültige Filterkriterien aus und fahren Sie fort.",
|
||||
"no_central_device": "Der Modus \"Zentral Gateway\" erfordert ein verfügbares Xiaomi-Zentral-Gateway im lokalen Netzwerk, in dem Home Assistant installiert ist. Überprüfen Sie, ob die ausgewählte Familie diese Anforderung erfüllt.",
|
||||
"mdns_discovery_error": "Lokaler Geräteerkennungsdienstfehler.",
|
||||
"update_config_error": "Fehler beim Aktualisieren der Konfigurationsinformationen.",
|
||||
"not_confirm": "Änderungen wurden nicht bestätigt. Bitte bestätigen Sie die Auswahl, bevor Sie sie einreichen.",
|
||||
"invalid_network_addr": "Ungültige IP-Adresse oder HTTP-Adresse vorhanden, bitte geben Sie eine gültige Adresse ein.",
|
||||
"invalid_ip_addr": "Unzugängliche IP-Adresse vorhanden, bitte geben Sie eine gültige IP-Adresse ein.",
|
||||
"invalid_http_addr": "Unzugängliche HTTP-Adresse vorhanden, bitte geben Sie eine gültige HTTP-Adresse ein.",
|
||||
"invalid_default_addr": "Die Standard-Netzwerkerkennungsadresse ist nicht erreichbar, bitte überprüfen Sie die Netzwerkkonfiguration oder verwenden Sie eine benutzerdefinierte Netzwerkerkennungsadresse.",
|
||||
"unreachable_oauth2_host": "OAuth2-Authentifizierungsadresse ist nicht erreichbar, bitte überprüfen Sie die Netzwerkkonfiguration.",
|
||||
"unreachable_http_host": "Xiaomi HTTP API-Adresse ist nicht erreichbar, bitte überprüfen Sie die Netzwerkkonfiguration.",
|
||||
"unreachable_spec_host": "Xiaomi SPEC API-Adresse ist nicht erreichbar, bitte überprüfen Sie die Netzwerkkonfiguration.",
|
||||
"unreachable_mqtt_broker": "Xiaomi MQTT Broker-Adresse ist nicht erreichbar, bitte überprüfen Sie die Netzwerkkonfiguration."
|
||||
},
|
||||
"abort": {
|
||||
"network_connect_error": "Konfiguration fehlgeschlagen. Netzwerkverbindungsfehler. Überprüfen Sie die Netzwerkkonfiguration des Geräts.",
|
||||
"options_flow_error": "Integrationsneukonfigurationsfehler: {error}",
|
||||
"re_add": "Fügen Sie die Integration erneut hinzu. Fehlermeldung: {error}",
|
||||
"storage_error": "Integrations-Speichermodulfehler. Bitte versuchen Sie es erneut oder fügen Sie die Integration erneut hinzu: {error}",
|
||||
"inconsistent_account": "Kontoinformationen sind inkonsistent. Bitte melden Sie sich mit den richtigen Kontoinformationen an."
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,225 @@
|
||||
{
|
||||
"config": {
|
||||
"flow_title": "Xiaomi Home Integration",
|
||||
"step": {
|
||||
"eula": {
|
||||
"title": "Risk Notice",
|
||||
"description": "1. Your Xiaomi user information and device information will be stored in the Home Assistant system. **Xiaomi cannot guarantee the security of the Home Assistant storage mechanism**. You are responsible for preventing your information from being stolen.\r\n2. This integration is maintained by the open-source community. There may be stability issues or other problems. When encountering issues or bugs of this integration, **you should seek help from the open-source community rather than contacting Xiaomi customer service**.\r\n3. You need some technical ability to maintain your local operating environment. The integration is not user-friendly for beginners.\r\n4. Please read the README file before starting.\n\n5. To ensure stable use of the integration and prevent interface abuse, **this integration is only allowed to be used in Home Assistant. For details, please refer to the LICENSE**.",
|
||||
"data": {
|
||||
"eula": "I am aware of the above risks and willing to voluntarily assume any risks associated with the use of the integration."
|
||||
}
|
||||
},
|
||||
"auth_config": {
|
||||
"title": "Basic configuration",
|
||||
"description": "### Login Region\r\nSelect the region of your Xiaomi account. You can find it in the Xiaomi Home APP > Profile (located in the menu at the bottom) > Additional settings > About Xiaomi Home.\r\n### Language\r\nSelect the language of the device and entity names. Some sentences without translation will be displayed in English.\r\n### OAuth2 Redirect URL\r\nThe OAuth2 authentication redirect address is **[http://homeassistant.local:8123](http://homeassistant.local:8123)**. The Home Assistant needs to be in the same local area network as the current operating terminal (e.g., the personal computer) and the operating terminal can access the Home Assistant home page through this address. Otherwise, the login authentication may fail.\r\n### Integrated Network Configuration\r\nCheck if the local network is functioning properly and if the related network resources are accessible. **It is recommended to select this when adding for the first time.**\r\n### Note\r\n- For users with hundreds or more Mi Home devices, the initial addition of the integration will take some time. Please be patient.\r\n- If Home Assistant is running in a Docker environment, please ensure that the Docker network mode is set to host, otherwise local control functionality may not work properly.\r\n- The local control functionality of the integration has some dependencies. Please read the README carefully.",
|
||||
"data": {
|
||||
"cloud_server": "Login Region",
|
||||
"integration_language": "Language",
|
||||
"oauth_redirect_url": "OAuth2 Redirect URL",
|
||||
"network_detect_config": "Integrated Network Configuration"
|
||||
}
|
||||
},
|
||||
"network_detect_config": {
|
||||
"title": "Integrated Network Configuration",
|
||||
"description": "## Usage Introduction\r\n### Network Detection Address\r\nUsed to check if the network is functioning properly. If not set, the system default address will be used. If the default address check fails, you can try entering a custom address.\r\n- You can enter multiple detection addresses, separated by commas, such as `8.8.8.8,https://www.bing.com`\r\n- If it is an IP address, detection will be done via ping. If it is an HTTP(s) address, detection will be done via HTTP GET request.\r\n- If you want to restore the system default detection address, please enter a comma `,` and click 'Next'.\r\n- **This configuration is global, and changes will affect other integration instances. Please modify with caution.**\r\n### Check Network Dependencies\r\nCheck the following network dependencies one by one to see if they are accessible. If the related addresses are not accessible, it will cause integration issues.\r\n- OAuth2 Authentication Address: `https://account.xiaomi.com/oauth2/authorize`.\r\n- Xiaomi HTTP API Address: `https://{http_host}/app/v2/ha/oauth/get_token`.\r\n- Xiaomi SPEC API Address: `https://miot-spec.org/miot-spec-v2/template/list/device`.\r\n- Xiaomi MQTT Broker Address: `mqtts://{broker_host}`.",
|
||||
"data": {
|
||||
"network_detect_addr": "Network Detection Address",
|
||||
"check_network_deps": "Check Network Dependencies"
|
||||
}
|
||||
},
|
||||
"oauth_error": {
|
||||
"title": "Login Error",
|
||||
"description": "Click NEXT to try again."
|
||||
},
|
||||
"homes_select": {
|
||||
"title": "Select Family and Device",
|
||||
"description": "## Introduction\r\n### Import Device's Family\r\nThe integration will add devices from the selected family.\r\n### Room Name Sync Mode\r\nWhen syncing devices from the Mi Home APP to Home Assistant, the naming of the area in Home Assistant will follow the rules below. Note that the sync process will not change the family and room settings in the Mi Home APP.\r\n- Do not sync: The device will not be added to any area.\r\n- Other options: The area to which the device is added will be named after the family or room name in the Mi Home APP.\r\n### Advanced Settings\r\nShow advanced settings to modify the professional configuration options of the integration.\r\n\r\n \r\n### {nick_name} Hello! Please select the family to which you want to add the device.",
|
||||
"data": {
|
||||
"home_infos": "Import Device's Family",
|
||||
"area_name_rule": "Room Name Sync Mode",
|
||||
"advanced_options": "Advanced Settings"
|
||||
}
|
||||
},
|
||||
"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### 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"
|
||||
}
|
||||
},
|
||||
"devices_filter": {
|
||||
"title": "Filter Devices",
|
||||
"description": "## Usage Instructions\r\nSupports filtering devices by home room name, device access type, and device model, and also supports device dimension filtering. The filtering logic is as follows:\r\n- First, according to the statistical logic, get the union or intersection of all included items, then get the intersection or union of the excluded items, and finally subtract the [included summary result] from the [excluded summary result] to get the [filter result].\r\n- If no included items are selected, it means all are included.\r\n### Filter Mode\r\n- Exclude: Remove unwanted items.\r\n- Include: Include desired items.\r\n### Statistical Logic\r\n- AND logic: Take the intersection of all items in the same mode.\r\n- OR logic: Take the union of all items in the same mode.\r\n\r\nYou can also go to the [Configuration > Update Device List] page of the integration item, check [Filter Devices] to re-filter.",
|
||||
"data": {
|
||||
"room_filter_mode": "Filter Family Rooms",
|
||||
"room_list": "Family Rooms",
|
||||
"type_filter_mode": "Filter Device Connect Type",
|
||||
"type_list": "Device Connect Type",
|
||||
"model_filter_mode": "Filter Device Model",
|
||||
"model_list": "Device Model",
|
||||
"devices_filter_mode": "Filter Devices",
|
||||
"device_list": "Device List",
|
||||
"statistics_logic": "Statistics Logic"
|
||||
}
|
||||
}
|
||||
},
|
||||
"progress": {
|
||||
"oauth": "### {link_left}Click here to login{link_right}\r\n(You will be automatically redirected to the next page after a successful login)"
|
||||
},
|
||||
"error": {
|
||||
"eula_not_agree": "Please read the risk notice.",
|
||||
"get_token_error": "Failed to retrieve login authorization information (OAuth token).",
|
||||
"get_homeinfo_error": "Failed to retrieve home information.",
|
||||
"mdns_discovery_error": "Local device discovery service exception.",
|
||||
"get_cert_error": "Failed to retrieve the central hub gateway certificate.",
|
||||
"no_family_selected": "No home selected.",
|
||||
"no_devices": "There are no devices in the selected home. Please select a home with devices and continue.",
|
||||
"no_filter_devices": "Filtered devices are empty. Please select valid filter criteria and continue.",
|
||||
"no_central_device": "[Central Hub Gateway Mode] requires a Xiaomi central hub gateway available in the local network where Home Assistant exists. Please check if the selected home meets the requirement.",
|
||||
"invalid_network_addr": "Invalid IP address or HTTP address detected, please enter a valid address.",
|
||||
"invalid_ip_addr": "Unreachable IP address detected, please enter a valid IP address.",
|
||||
"invalid_http_addr": "Unreachable HTTP address detected, please enter a valid HTTP address.",
|
||||
"invalid_default_addr": "Default network detection address is unreachable, please check network configuration or use a custom network detection address.",
|
||||
"unreachable_oauth2_host": "Unable to reach OAuth2 authentication address, please check network configuration.",
|
||||
"unreachable_http_host": "Unable to reach Xiaomi HTTP API address, please check network configuration.",
|
||||
"unreachable_spec_host": "Unable to reach Xiaomi SPEC API address, please check network configuration.",
|
||||
"unreachable_mqtt_broker": "Unable to reach Xiaomi MQTT Broker address, please check network configuration."
|
||||
},
|
||||
"abort": {
|
||||
"ha_uuid_get_failed": "Failed to get Home Assistant UUID.",
|
||||
"network_connect_error": "Configuration failed. The network connection is abnormal. Please check the equipment network configuration.",
|
||||
"already_configured": "Configuration for this user is already completed. Please go to the integration page and click the CONFIGURE button for modifications.",
|
||||
"invalid_auth_info": "Authentication information has expired. Please go to the integration page and click the CONFIGURE button to re-authenticate.",
|
||||
"config_flow_error": "Integration configuration error: {error}."
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"step": {
|
||||
"auth_config": {
|
||||
"title": "Authentication Configuration",
|
||||
"description": "Local authentication information has expired. Please restart the authentication process.\r\n### Current Login Region: {cloud_server}\r\n### OAuth2 Redirect URL\r\nThe OAuth2 authentication redirect address is **[http://homeassistant.local:8123](http://homeassistant.local:8123)**. The Home Assistant needs to be in the same local area network as the current operating terminal (e.g., the personal computer) and the operating terminal can access the Home Assistant home page through this address. Otherwise, the login authentication may fail.",
|
||||
"data": {
|
||||
"oauth_redirect_url": "OAuth2 Redirect URL"
|
||||
}
|
||||
},
|
||||
"oauth_error": {
|
||||
"title": "An error occurred during login.",
|
||||
"description": "Click NEXT to retry."
|
||||
},
|
||||
"config_options": {
|
||||
"title": "Configuration Options",
|
||||
"description": "### Hello, {nick_name}\r\n\r\nXiaomi ID: {uid}\r\nCurrent Login Region: {cloud_server}\r\nIntegration Instance ID: {instance_id}\r\n\r\nPlease select the options you need to configure, then click NEXT.",
|
||||
"data": {
|
||||
"integration_language": "Integration Language",
|
||||
"update_user_info": "Update user information",
|
||||
"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",
|
||||
"network_detect_config": "Integrated network configuration",
|
||||
"cover_dead_zone_width": "Cover dead zone width"
|
||||
}
|
||||
},
|
||||
"update_user_info": {
|
||||
"title": "Update User Nickname",
|
||||
"description": "Hello {nick_name}, you can modify your custom nickname below.",
|
||||
"data": {
|
||||
"nick_name": "Nick Name"
|
||||
}
|
||||
},
|
||||
"homes_select": {
|
||||
"title": "Re-select Home and Devices",
|
||||
"description": "## Usage Instructions\r\n### Import devices from home\r\nThe integration will add devices from the selected homes.\r\n### Filter Devices\r\nSupports filtering devices by home room name, device access type, and device model, and also supports device dimension filtering. **{local_count}** devices have been filtered.\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 LAN control function. 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.",
|
||||
"data": {
|
||||
"home_infos": "Import devices from home",
|
||||
"devices_filter": "Filter devices",
|
||||
"ctrl_mode": "Control mode"
|
||||
}
|
||||
},
|
||||
"devices_filter": {
|
||||
"title": "Filter Devices",
|
||||
"description": "## Usage Instructions\r\nSupports filtering devices by home room name, device access type, and device model, and also supports device dimension filtering. The filtering logic is as follows:\r\n- First, according to the statistical logic, get the union or intersection of all included items, then get the intersection or union of the excluded items, and finally subtract the [included summary result] from the [excluded summary result] to get the [filter result].\r\n- If no included items are selected, it means all are included.\r\n### Filter Mode\r\n- Exclude: Remove unwanted items.\r\n- Include: Include desired items.\r\n### Statistical Logic\r\n- AND logic: Take the intersection of all items in the same mode.\r\n- OR logic: Take the union of all items in the same mode.\r\n\r\nYou can also go to the [Configuration > Update Device List] page of the integration item, check [Filter Devices] to re-filter.",
|
||||
"data": {
|
||||
"room_filter_mode": "Filter Family Rooms",
|
||||
"room_list": "Family Rooms",
|
||||
"type_filter_mode": "Filter Device Connect Type",
|
||||
"type_list": "Device Connect Type",
|
||||
"model_filter_mode": "Filter Device Model",
|
||||
"model_list": "Device Model",
|
||||
"devices_filter_mode": "Filter Devices",
|
||||
"device_list": "Device List",
|
||||
"statistics_logic": "Statistics Logic"
|
||||
}
|
||||
},
|
||||
"update_trans_rules": {
|
||||
"title": "Update Entities Transformation Rules",
|
||||
"description": "## Usage Instructions\r\n- Update the entity information of devices in the current integration instance, including MIoT-Spec-V2 multilingual configuration, boolean translation, and model filtering.\r\n- **Warning**: This is a global configuration and will update the local cache. It will affect all integration instances.\r\n- This operation will take some time, please be patient. Check \"Confirm Update\" and click \"Next\" to start updating **{urn_count}** rules, otherwise skip the update.",
|
||||
"data": {
|
||||
"confirm": "Confirm the update"
|
||||
}
|
||||
},
|
||||
"update_lan_ctrl_config": {
|
||||
"title": "Update lan control configuration",
|
||||
"description": "## Usage Instructions\r\nUpdate the configurations for Xiaomi LAN control function. When the cloud and the central hub gateway cannot control the devices, the integration will attempt to control the devices through the LAN. If no network card is selected, the LAN control function will not take effect.\r\n- Only MIoT-Spec-V2 compatible IP devices in the LAN are supported. Some devices produced before 2020 may not support LAN control or LAN subscription.\r\n- Please select the network card(s) on the same network as the devices to be controlled. Multiple network cards can be selected. If Home Assistant have two or more connections to the local area network because of the multiple selection of the network cards, it is recommended to select the one with the best network connection, otherwise it may have bad effect on the devices.\r\n- If there are terminal devices (Xiaomi speaker with screen, mobile phone, etc.) in the LAN that support local control, enabling LAN subscription may cause local automation and device anomalies.\r\n- **Warning**: This is a global configuration. It will affect all integration instances. Please use it with caution.\r\n{notice_net_dup}",
|
||||
"data": {
|
||||
"net_interfaces": "Please select the network card to use",
|
||||
"enable_subscribe": "Enable LAN subscription"
|
||||
}
|
||||
},
|
||||
"network_detect_config": {
|
||||
"title": "Integrated Network Configuration",
|
||||
"description": "## Usage Introduction\r\n### Network Detection Address\r\nUsed to check if the network is functioning properly. If not set, the system default address will be used. If the default address check fails, you can try entering a custom address.\r\n- You can enter multiple detection addresses, separated by commas, such as `8.8.8.8,https://www.bing.com`\r\n- If it is an IP address, detection will be done via ping. If it is an HTTP(s) address, detection will be done via HTTP GET request.\r\n- If you want to restore the system default detection address, please enter a comma `,` and click 'Next'.\r\n- **This configuration is global, and changes will affect other integration instances. Please modify with caution.**\r\n### Check Network Dependencies\r\nCheck the following network dependencies one by one to see if they are accessible. If the related addresses are not accessible, it will cause integration issues.\r\n- OAuth2 Authentication Address: `https://account.xiaomi.com/oauth2/authorize`.\r\n- Xiaomi HTTP API Address: `https://{http_host}/app/v2/ha/oauth/get_token`.\r\n- Xiaomi SPEC API Address: `https://miot-spec.org/miot-spec-v2/template/list/device`.\r\n- Xiaomi MQTT Broker Address: `mqtts://{broker_host}`.",
|
||||
"data": {
|
||||
"network_detect_addr": "Network Detection Address",
|
||||
"check_network_deps": "Check Network Dependencies"
|
||||
}
|
||||
},
|
||||
"config_confirm": {
|
||||
"title": "Confirm Configuration",
|
||||
"description": "Hello **{nick_name}**, please confirm the latest configuration information and then Click SUBMIT.\r\nThe integration will reload using the updated configuration.\r\n\r\nIntegration Language:\t{lang_new}\r\nNickname:\t{nick_name_new}\r\nDebug mode for action:\t{action_debug}\r\nHide non-standard created entities:\t{hide_non_standard_entities}\r\nCover dead zone width:\t{cover_width_new}\r\nDisplay device status change notifications:\t{display_devices_changed_notify}\r\nDevice Changes:\tAdd **{devices_add}** devices, Remove **{devices_remove}** devices\r\nTransformation rules change:\tThere are a total of **{trans_rules_count}** rules, and updated **{trans_rules_count_success}** rules",
|
||||
"data": {
|
||||
"confirm": "Confirm the change"
|
||||
}
|
||||
}
|
||||
},
|
||||
"progress": {
|
||||
"oauth": "### {link_left}Please click here to re-login{link_right}"
|
||||
},
|
||||
"error": {
|
||||
"not_auth": "Not authenticated. Please click the authentication link to authenticate user identity.",
|
||||
"get_token_error": "Failed to retrieve login authorization information (OAuth token).",
|
||||
"get_homeinfo_error": "Failed to retrieve home information.",
|
||||
"get_cert_error": "Failed to retrieve the central hub gateway certificate.",
|
||||
"no_devices": "There are no devices in the selected home. Please select a home with devices and continue.",
|
||||
"no_filter_devices": "Filtered devices are empty. Please select valid filter criteria and continue.",
|
||||
"no_family_selected": "No home selected.",
|
||||
"no_central_device": "[Central Hub Gateway Mode] requires a Xiaomi central hub gateway available in the local network where Home Assistant exists. Please check if the selected home meets the requirement.",
|
||||
"mdns_discovery_error": "Local device discovery service exception.",
|
||||
"update_config_error": "Failed to update configuration information.",
|
||||
"not_confirm": "Changes are not confirmed. Please confirm the change before submitting.",
|
||||
"invalid_network_addr": "Invalid IP address or HTTP address detected, please enter a valid address.",
|
||||
"invalid_ip_addr": "Unreachable IP address detected, please enter a valid IP address.",
|
||||
"invalid_http_addr": "Unreachable HTTP address detected, please enter a valid HTTP address.",
|
||||
"invalid_default_addr": "Default network detection address is unreachable, please check network configuration or use a custom network detection address.",
|
||||
"unreachable_oauth2_host": "Unable to reach OAuth2 authentication address, please check network configuration.",
|
||||
"unreachable_http_host": "Unable to reach Xiaomi HTTP API address, please check network configuration.",
|
||||
"unreachable_spec_host": "Unable to reach Xiaomi SPEC API address, please check network configuration.",
|
||||
"unreachable_mqtt_broker": "Unable to reach Xiaomi MQTT Broker address, please check network configuration."
|
||||
},
|
||||
"abort": {
|
||||
"network_connect_error": "Configuration failed. The network connection is abnormal. Please check the equipment network configuration.",
|
||||
"options_flow_error": "Integration re-configuration error: {error}",
|
||||
"re_add": "Please re-add the integration. Error message: {error}",
|
||||
"storage_error": "Integration storage module exception. Please try again or re-add the integration: {error}",
|
||||
"inconsistent_account": "Account information is inconsistent. Please login with the correct account."
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,225 @@
|
||||
{
|
||||
"config": {
|
||||
"flow_title": "Integración de Xiaomi Home",
|
||||
"step": {
|
||||
"eula": {
|
||||
"title": "Aviso de riesgo",
|
||||
"description": "1. Su **información de usuario de Xiaomi e información del dispositivo** se almacenará en su sistema Home Assistant. **Xiaomi no puede garantizar la seguridad del mecanismo de almacenamiento de Home Assistant**. Usted es responsable de evitar que su información sea robada.\r\n2. Esta integración es mantenida por la comunidad de código abierto y puede haber problemas de estabilidad u otros problemas. Cuando tenga problemas relacionados con el uso de esta integración, **busque ayuda en la comunidad de código abierto en lugar de contactar al servicio al cliente de Xiaomi**.\r\n3. Es necesario tener ciertas habilidades técnicas para mantener su entorno de ejecución local, esta integración no es amigable para los usuarios novatos.\r\n4. Antes de utilizar esta integración, por favor **lea detenidamente el archivo README**.\r\n5. Para garantizar el uso estable de la integración y prevenir el abuso de la interfaz, **esta integración solo está permitida en Home Assistant. Para más detalles, consulte la LICENSE**.",
|
||||
"data": {
|
||||
"eula": "He leído y entiendo los riesgos anteriores, y estoy dispuesto a asumir cualquier riesgo relacionado con el uso de esta integración."
|
||||
}
|
||||
},
|
||||
"auth_config": {
|
||||
"title": "Configuración básica",
|
||||
"description": "### Región de inicio de sesión\r\nSeleccione la región donde se encuentra su cuenta de Xiaomi. Puede consultar esta información en `Xiaomi Home APP > Yo (ubicado en el menú inferior) > Más ajustes > Acerca de Xiaomi Home`.\r\n### Idioma\r\nSeleccione el idioma utilizado para los nombres de los dispositivos y entidades. Las partes de las frases que no están traducidas se mostrarán en inglés.\r\n### Dirección de redireccionamiento de autenticación de OAuth2\r\nLa dirección de redireccionamiento de autenticación de OAuth2 es **[http://homeassistant.local:8123](http://homeassistant.local:8123)**. Home Assistant debe estar en la misma red local que el terminal de operación actual (por ejemplo, una computadora personal) y el terminal de operación debe poder acceder a la página de inicio de Home Assistant a través de esta dirección, de lo contrario, la autenticación de inicio de sesión podría fallar.\r\n### Configuración de Red Integrada\r\nVerifique si la red local funciona correctamente y si los recursos de red relacionados son accesibles. **Se recomienda seleccionar esto al agregar por primera vez.**\r\n### Nota\r\n- Para los usuarios con cientos o más dispositivos Mi Home, la adición inicial de la integración tomará algún tiempo. Por favor, sea paciente.\r\n- Si Home Assistant se está ejecutando en un entorno Docker, asegúrese de que el modo de red de Docker esté configurado en host, de lo contrario, la funcionalidad de control local puede no funcionar correctamente.\r\n- La funcionalidad de control local de la integración tiene algunas dependencias. Por favor, lea el README cuidadosamente.",
|
||||
"data": {
|
||||
"cloud_server": "Región de inicio de sesión",
|
||||
"integration_language": "Idioma",
|
||||
"oauth_redirect_url": "Dirección de redireccionamiento de autenticación de OAuth2",
|
||||
"network_detect_config": "Configuración de Red Integrada"
|
||||
}
|
||||
},
|
||||
"network_detect_config": {
|
||||
"title": "Configuración de Red Integrada",
|
||||
"description": "## Introducción al Uso\r\n### Dirección de Detección de Red\r\nSe utiliza para verificar si la red funciona correctamente. Si no se establece, se utilizará la dirección predeterminada del sistema. Si la verificación de la dirección predeterminada falla, puede intentar ingresar una dirección personalizada.\r\n- Puede ingresar varias direcciones de detección, separadas por comas, como `8.8.8.8,https://www.bing.com`\r\n- Si es una dirección IP, la detección se realizará mediante ping. Si es una dirección HTTP(s), la detección se realizará mediante una solicitud HTTP GET.\r\n- Si desea restaurar la dirección de detección predeterminada del sistema, ingrese una coma `,` y haga clic en 'Siguiente'.\r\n- **Esta configuración es global y los cambios afectarán a otras instancias de integración. Modifique con precaución.**\r\n### Verificar Dependencias de Red\r\nVerifique una por una las siguientes dependencias de red para ver si son accesibles. Si las direcciones relacionadas no son accesibles, causará problemas de integración.\r\n- Dirección de Autenticación OAuth2: `https://account.xiaomi.com/oauth2/authorize`.\r\n- Dirección de API HTTP de Xiaomi: `https://{http_host}/app/v2/ha/oauth/get_token`.\r\n- Dirección de API SPEC de Xiaomi: `https://miot-spec.org/miot-spec-v2/template/list/device`.\r\n- Dirección del Broker MQTT de Xiaomi: `mqtts://{broker_host}`.",
|
||||
"data": {
|
||||
"network_detect_addr": "Dirección de Detección de Red",
|
||||
"check_network_deps": "Verificar Dependencias de Red"
|
||||
}
|
||||
},
|
||||
"oauth_error": {
|
||||
"title": "Error de inicio de sesión",
|
||||
"description": "Haga clic en \"Siguiente\" para volver a intentarlo"
|
||||
},
|
||||
"homes_select": {
|
||||
"title": "Seleccionar familia y dispositivo",
|
||||
"description": "## Introducción\r\n### Importar la familia del dispositivo\r\nLa integración añadirá dispositivos de la familia seleccionada.\r\n### Modo de sincronización del nombre de la habitación\r\nAl sincronizar dispositivos desde la APP Mi Home a Home Assistant, el nombre del área en Home Assistant seguirá las siguientes reglas. Tenga en cuenta que el proceso de sincronización no cambiará la configuración de la familia y la habitación en la APP Mi Home.\r\n- No sincronizar: El dispositivo no se añadirá a ninguna área.\r\n- Otras opciones: El área a la que se añade el dispositivo se nombrará según el nombre de la familia o la habitación en la APP Mi Home.\r\n### Configuración avanzada\r\nMostrar configuración avanzada para modificar las opciones de configuración profesional de la integración.\r\n\r\n \r\n### {nick_name} ¡Hola! Por favor, seleccione la familia a la que desea añadir el dispositivo.",
|
||||
"data": {
|
||||
"home_infos": "Importar la familia del dispositivo",
|
||||
"area_name_rule": "Modo de sincronización del nombre de la habitación",
|
||||
"advanced_options": "Configuración avanzada"
|
||||
}
|
||||
},
|
||||
"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### 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"
|
||||
}
|
||||
},
|
||||
"devices_filter": {
|
||||
"title": "Filtrar Dispositivos",
|
||||
"description": "## Instrucciones de uso\r\nAdmite la filtración de dispositivos por nombre de habitación, tipo de acceso del dispositivo y modelo de dispositivo, y también admite la filtración por dimensión del dispositivo. La lógica de filtración es la siguiente:\r\n- Primero, de acuerdo con la lógica estadística, obtenga la unión o intersección de todos los elementos incluidos, luego obtenga la intersección o unión de los elementos excluidos, y finalmente reste el [resultado del resumen incluido] del [resultado del resumen excluido] para obtener el [resultado del filtro].\r\n- Si no se seleccionan elementos incluidos, significa que todos están incluidos.\r\n### Modo de Filtración\r\n- Excluir: Eliminar elementos no deseados.\r\n- Incluir: Incluir elementos deseados.\r\n### Lógica Estadística\r\n- Lógica Y: Tomar la intersección de todos los elementos en el mismo modo.\r\n- Lógica O: Tomar la unión de todos los elementos en el mismo modo.\r\n\r\nTambién puede ir a la página [Configuración > Actualizar lista de dispositivos] del elemento de integración, marcar [Filtrar dispositivos] para volver a filtrar.",
|
||||
"data": {
|
||||
"room_filter_mode": "Filtrar Habitaciones de la Familia",
|
||||
"room_list": "Habitaciones de la Familia",
|
||||
"type_filter_mode": "Filtrar Tipo de Dispositivo",
|
||||
"type_list": "Tipo de Dispositivo",
|
||||
"model_filter_mode": "Filtrar Modelo de Dispositivo",
|
||||
"model_list": "Modelo de Dispositivo",
|
||||
"devices_filter_mode": "Filtrar Dispositivos",
|
||||
"device_list": "Lista de Dispositivos",
|
||||
"statistics_logic": "Lógica de Estadísticas"
|
||||
}
|
||||
}
|
||||
},
|
||||
"progress": {
|
||||
"oauth": "### {link_left}Haga clic aquí para iniciar sesión de nuevo{link_right}\r\n(Será redirigido automáticamente a la siguiente página después de un inicio de sesión exitoso)"
|
||||
},
|
||||
"error": {
|
||||
"eula_not_agree": "Lea el texto de aviso de riesgo.",
|
||||
"get_token_error": "Error al obtener la información de autorización de inicio de sesión (token OAuth).",
|
||||
"get_homeinfo_error": "Error al obtener la información del hogar.",
|
||||
"mdns_discovery_error": "Error en el servicio de descubrimiento de dispositivos locales.",
|
||||
"get_cert_error": "Error al obtener el certificado de la puerta de enlace.",
|
||||
"no_family_selected": "No se ha seleccionado ningún hogar.",
|
||||
"no_devices": "No hay dispositivos en el hogar seleccionado. Por favor, seleccione un hogar con dispositivos y continúe.",
|
||||
"no_filter_devices": "Los dispositivos filtrados están vacíos. Por favor, seleccione criterios de filtro válidos y continúe.",
|
||||
"no_central_device": "【Modo de puerta de enlace central】Se requiere una puerta de enlace Xiaomi disponible en la red local donde se encuentra Home Assistant. Verifique si el hogar seleccionado cumple con este requisito.",
|
||||
"invalid_network_addr": "Se detectó una dirección IP o HTTP no válida, por favor ingrese una dirección válida.",
|
||||
"invalid_ip_addr": "Se detectó una dirección IP inaccesible, por favor ingrese una dirección IP válida.",
|
||||
"invalid_http_addr": "Se detectó una dirección HTTP inaccesible, por favor ingrese una dirección HTTP válida.",
|
||||
"invalid_default_addr": "La dirección de detección de red predeterminada no es accesible, por favor verifique la configuración de la red o use una dirección de detección de red personalizada.",
|
||||
"unreachable_oauth2_host": "No se puede acceder a la dirección de autenticación OAuth2, por favor verifique la configuración de la red.",
|
||||
"unreachable_http_host": "No se puede acceder a la dirección de la API HTTP de Xiaomi, por favor verifique la configuración de la red.",
|
||||
"unreachable_spec_host": "No se puede acceder a la dirección de la API SPEC de Xiaomi, por favor verifique la configuración de la red.",
|
||||
"unreachable_mqtt_broker": "No se puede acceder a la dirección del Broker MQTT de Xiaomi, por favor verifique la configuración de la red."
|
||||
},
|
||||
"abort": {
|
||||
"ha_uuid_get_failed": "Error al obtener el UUID de Home Assistant.",
|
||||
"network_connect_error": "La configuración ha fallado. Existe un problema con la conexión de red, verifique la configuración de red del dispositivo.",
|
||||
"already_configured": "Esta cuenta ya ha finalizado la configuración. Ingrese a la página de integración y haga clic en el botón \"Configurar\" para modificar la configuración.",
|
||||
"invalid_auth_info": "La información de autorización ha caducado. Ingrese a la página de integración y haga clic en el botón \"Configurar\" para volver a autenticarse.",
|
||||
"config_flow_error": "Error de configuración de integración: {error}"
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"step": {
|
||||
"auth_config": {
|
||||
"title": "Configuración de autorización",
|
||||
"description": "Se detectó que la información de autenticación local ha caducado, vuelva a autenticarse\r\n### Región de inicio de sesión actual: {cloud_server}\r\n### Dirección de redireccionamiento de autenticación de OAuth2\r\nLa dirección de redireccionamiento de autenticación de OAuth2 es **[http://homeassistant.local:8123](http://homeassistant.local:8123)**. Home Assistant debe estar en la misma red local que el terminal de operación actual (por ejemplo, una computadora personal) y el terminal de operación debe poder acceder a la página de inicio de Home Assistant a través de esta dirección, de lo contrario, la autenticación de inicio de sesión podría fallar.",
|
||||
"data": {
|
||||
"oauth_redirect_url": "Dirección de redireccionamiento de autenticación de OAuth2"
|
||||
}
|
||||
},
|
||||
"oauth_error": {
|
||||
"title": "Error de inicio de sesión",
|
||||
"description": "Haga clic en \"Siguiente\" para volver a intentarlo"
|
||||
},
|
||||
"config_options": {
|
||||
"title": "Opciones de configuración",
|
||||
"description": "### ¡Hola, {nick_name}!\r\n\r\nID de cuenta de Xiaomi: {uid}\r\nRegión de inicio de sesión actual: {cloud_server}\r\nID de Instancia de Integración: {instance_id}\r\n\r\nSeleccione las opciones que desea reconfigurar y haga clic en \"Siguiente\".",
|
||||
"data": {
|
||||
"integration_language": "Idioma de la integración",
|
||||
"update_user_info": "Actualizar información de usuario",
|
||||
"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",
|
||||
"network_detect_config": "Configuración de Red Integrada",
|
||||
"cover_dead_zone_width": "Anchura del punto ciego de la cortina"
|
||||
}
|
||||
},
|
||||
"update_user_info": {
|
||||
"title": "Actualizar apodo de usuario",
|
||||
"description": "¡Hola, {nick_name}! Modifique su apodo de usuario a continuación.",
|
||||
"data": {
|
||||
"nick_name": "Apodo de usuario"
|
||||
}
|
||||
},
|
||||
"homes_select": {
|
||||
"title": "Recomendar hogares y dispositivos",
|
||||
"description": "## Instrucciones de uso\r\n### Hogares de dispositivos importados\r\nLa integración agregará los dispositivos en los hogares seleccionados.\r\n### Filtrar dispositivos\r\nAdmite la filtración de dispositivos por nombre de habitación, tipo de acceso del dispositivo y modelo de dispositivo, y también admite la filtración por dimensión del dispositivo. Se han filtrado **{local_count}** dispositivos.\r\n### Modo de control\r\n- Automático: Cuando hay un gateway central de Xiaomi disponible en la red local, Home Assistant priorizará el envío de comandos de control de dispositivos a través del gateway central para lograr un control localizado. Si no hay un gateway central en la red local, intentará enviar comandos de control a través del protocolo Xiaomi OT para lograr un control localizado. Solo cuando no se cumplan las condiciones anteriores de control localizado, los comandos de control del dispositivo 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.",
|
||||
"data": {
|
||||
"home_infos": "Hogares de dispositivos importados",
|
||||
"devices_filter": "Filtrar dispositivos",
|
||||
"ctrl_mode": "Modo de control"
|
||||
}
|
||||
},
|
||||
"devices_filter": {
|
||||
"title": "Filtrar Dispositivos",
|
||||
"description": "## Instrucciones de uso\r\nAdmite la filtración de dispositivos por nombre de habitación, tipo de acceso del dispositivo y modelo de dispositivo, y también admite la filtración por dimensión del dispositivo. La lógica de filtración es la siguiente:\r\n- Primero, de acuerdo con la lógica estadística, obtenga la unión o intersección de todos los elementos incluidos, luego obtenga la intersección o unión de los elementos excluidos, y finalmente reste el [resultado del resumen incluido] del [resultado del resumen excluido] para obtener el [resultado del filtro].\r\n- Si no se seleccionan elementos incluidos, significa que todos están incluidos.\r\n### Modo de Filtración\r\n- Excluir: Eliminar elementos no deseados.\r\n- Incluir: Incluir elementos deseados.\r\n### Lógica Estadística\r\n- Lógica Y: Tomar la intersección de todos los elementos en el mismo modo.\r\n- Lógica O: Tomar la unión de todos los elementos en el mismo modo.\r\n\r\nTambién puede ir a la página [Configuración > Actualizar lista de dispositivos] del elemento de integración, marcar [Filtrar dispositivos] para volver a filtrar.",
|
||||
"data": {
|
||||
"room_filter_mode": "Filtrar Habitaciones de la Familia",
|
||||
"room_list": "Habitaciones de la Familia",
|
||||
"type_filter_mode": "Filtrar Tipo de Dispositivo",
|
||||
"type_list": "Tipo de Dispositivo",
|
||||
"model_filter_mode": "Filtrar Modelo de Dispositivo",
|
||||
"model_list": "Modelo de Dispositivo",
|
||||
"devices_filter_mode": "Filtrar Dispositivos",
|
||||
"device_list": "Lista de Dispositivos",
|
||||
"statistics_logic": "Lógica de Estadísticas"
|
||||
}
|
||||
},
|
||||
"update_trans_rules": {
|
||||
"title": "Actualizar reglas de conversión de entidad",
|
||||
"description": "## Instrucciones de uso\r\n- Actualice la información de la entidad de los dispositivos en la instancia de integración actual, incluida la configuración multilingüe de SPEC, la traducción booleana de SPEC y el filtrado de modelos de SPEC.\r\n- **Advertencia: Esta configuración es una configuración global** y actualizará directamente la caché local. Si hay dispositivos del mismo modelo en otras instancias de integración, las instancias relevantes también se actualizarán después de recargarlas.\r\n- Esta operación tomará algún tiempo, por favor sea paciente. Marque \"Confirmar actualización\" y haga clic en \"Siguiente\" para comenzar a actualizar **{urn_count}** reglas, de lo contrario, omita la actualización.",
|
||||
"data": {
|
||||
"confirm": "Confirmar actualización"
|
||||
}
|
||||
},
|
||||
"update_lan_ctrl_config": {
|
||||
"title": "Actualizar configuración de control LAN",
|
||||
"description": "## Instrucciones de uso\r\nActualice la información de configuración para **control LAN de dispositivos Xiaomi Home**. Cuando la nube y la puerta de enlace central no puedan controlar los dispositivos, la integración intentará controlar los dispositivos a través de la LAN; si no se selecciona ninguna tarjeta de red, el control LAN no se habilitará.\r\n- Actualmente, solo se admiten dispositivos WiFi **SPEC v2** en la LAN. Algunos dispositivos más antiguos pueden no admitir el control o la sincronización de propiedades.\r\n- Seleccione la(s) tarjeta(s) de red en la misma red que los dispositivos (se admiten múltiples selecciones). Si la tarjeta de red seleccionada tiene dos o más conexiones en la misma red, se recomienda seleccionar la que tenga la mejor conexión de red, de lo contrario, puede **afectar el uso normal de los dispositivos**.\r\n- **Si hay dispositivos terminales (puertas de enlace, teléfonos móviles, etc.) en la LAN que admiten el control local, habilitar la suscripción LAN puede causar automatización local o anomalías en los dispositivos. Úselo con precaución**.\r\n- **Advertencia: Esta configuración es global y los cambios afectarán a otras instancias de integración. Modifique con precaución**.\r\n{notice_net_dup}",
|
||||
"data": {
|
||||
"net_interfaces": "Por favor, seleccione la tarjeta de red a utilizar",
|
||||
"enable_subscribe": "Habilitar suscripción LAN"
|
||||
}
|
||||
},
|
||||
"network_detect_config": {
|
||||
"title": "Configuración de Red Integrada",
|
||||
"description": "## Introducción al Uso\r\n### Dirección de Detección de Red\r\nSe utiliza para verificar si la red funciona correctamente. Si no se establece, se utilizará la dirección predeterminada del sistema. Si la verificación de la dirección predeterminada falla, puede intentar ingresar una dirección personalizada.\r\n- Puede ingresar varias direcciones de detección, separadas por comas, como `8.8.8.8,https://www.bing.com`\r\n- Si es una dirección IP, la detección se realizará mediante ping. Si es una dirección HTTP(s), la detección se realizará mediante una solicitud HTTP GET.\r\n- Si desea restaurar la dirección de detección predeterminada del sistema, ingrese una coma `,` y haga clic en 'Siguiente'.\r\n- **Esta configuración es global y los cambios afectarán a otras instancias de integración. Modifique con precaución.**\r\n### Verificar Dependencias de Red\r\nVerifique una por una las siguientes dependencias de red para ver si son accesibles. Si las direcciones relacionadas no son accesibles, causará problemas de integración.\r\n- Dirección de Autenticación OAuth2: `https://account.xiaomi.com/oauth2/authorize`.\r\n- Dirección de API HTTP de Xiaomi: `https://{http_host}/app/v2/ha/oauth/get_token`.\r\n- Dirección de API SPEC de Xiaomi: `https://miot-spec.org/miot-spec-v2/template/list/device`.\r\n- Dirección del Broker MQTT de Xiaomi: `mqtts://{broker_host}`.",
|
||||
"data": {
|
||||
"network_detect_addr": "Dirección de Detección de Red",
|
||||
"check_network_deps": "Verificar Dependencias de Red"
|
||||
}
|
||||
},
|
||||
"config_confirm": {
|
||||
"title": "Confirmar configuración",
|
||||
"description": "¡Hola, **{nick_name}**! Por favor, confirme la última información de configuración y haga clic en \"Enviar\" para finalizar la configuración.\r\nLa integración se volverá a cargar con la nueva configuración.\r\n\r\nIdioma de la integración:\t{lang_new}\r\nApodo de usuario:\t{nick_name_new}\r\nModo de depuración de Action:\t{action_debug}\r\nOcultar entidades generadas no estándar:\t{hide_non_standard_entities}\r\nAnchura del punto ciego de la cortina:\t{cover_width_new}\r\nMostrar notificaciones de cambio de estado del dispositivo:\t{display_devices_changed_notify}\r\nCambios de dispositivos:\t{devices_add} dispositivos agregados, {devices_remove} dispositivos eliminados\r\nCambios en las reglas de conversión:\t{trans_rules_count} reglas en total, {trans_rules_count_success} reglas actualizadas",
|
||||
"data": {
|
||||
"confirm": "Confirmar modificación"
|
||||
}
|
||||
}
|
||||
},
|
||||
"progress": {
|
||||
"oauth": "### {link_left}Haga clic aquí para iniciar sesión de nuevo{link_right}"
|
||||
},
|
||||
"error": {
|
||||
"not_auth": "Usuario no autenticado. Haga clic en el enlace de autenticación para autenticarse.",
|
||||
"get_token_error": "Error al obtener la información de autorización de inicio de sesión (token OAuth).",
|
||||
"get_homeinfo_error": "Error al obtener la información del hogar.",
|
||||
"get_cert_error": "Error al obtener el certificado de la puerta de enlace.",
|
||||
"no_family_selected": "No se ha seleccionado ningún hogar.",
|
||||
"no_devices": "No hay dispositivos en el hogar seleccionado. Por favor, seleccione un hogar con dispositivos y continúe.",
|
||||
"no_filter_devices": "Los dispositivos filtrados están vacíos. Por favor, seleccione criterios de filtro válidos y continúe.",
|
||||
"no_central_device": "【Modo de puerta de enlace central】Se requiere una puerta de enlace Xiaomi disponible en la red local donde se encuentra Home Assistant. Verifique si el hogar seleccionado cumple con este requisito.",
|
||||
"mdns_discovery_error": "Error en el servicio de descubrimiento de dispositivos locales.",
|
||||
"update_config_error": "Error al actualizar la información de configuración.",
|
||||
"not_confirm": "No se ha confirmado la opción de modificación. Seleccione y confirme la opción antes de enviar.",
|
||||
"invalid_network_addr": "Se detectó una dirección IP o HTTP no válida, por favor ingrese una dirección válida.",
|
||||
"invalid_ip_addr": "Se detectó una dirección IP inaccesible, por favor ingrese una dirección IP válida.",
|
||||
"invalid_http_addr": "Se detectó una dirección HTTP inaccesible, por favor ingrese una dirección HTTP válida.",
|
||||
"invalid_default_addr": "La dirección de detección de red predeterminada no es accesible, por favor verifique la configuración de la red o use una dirección de detección de red personalizada.",
|
||||
"unreachable_oauth2_host": "No se puede acceder a la dirección de autenticación OAuth2, por favor verifique la configuración de la red.",
|
||||
"unreachable_http_host": "No se puede acceder a la dirección de la API HTTP de Xiaomi, por favor verifique la configuración de la red.",
|
||||
"unreachable_spec_host": "No se puede acceder a la dirección de la API SPEC de Xiaomi, por favor verifique la configuración de la red.",
|
||||
"unreachable_mqtt_broker": "No se puede acceder a la dirección del Broker MQTT de Xiaomi, por favor verifique la configuración de la red."
|
||||
},
|
||||
"abort": {
|
||||
"network_connect_error": "La configuración ha fallado. Existe un problema con la conexión de red, verifique la configuración de red del dispositivo.",
|
||||
"options_flow_error": "Error al reconfigurar la integración: {error}",
|
||||
"re_add": "Agregue la integración de nuevo, mensaje de error: {error}",
|
||||
"storage_error": "Error en el módulo de almacenamiento de integración. Intente de nuevo o agregue la integración de nuevo: {error}",
|
||||
"inconsistent_account": "La información de la cuenta no coincide. Inicie sesión con la cuenta correcta."
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,225 @@
|
||||
{
|
||||
"config": {
|
||||
"flow_title": "Intégration Xiaomi Home",
|
||||
"step": {
|
||||
"eula": {
|
||||
"title": "Notification de risques",
|
||||
"description": "1. Vos **informations utilisateur Xiaomi et informations sur l'appareil** seront stockées dans votre système Home Assistant. **Xiaomi ne peut garantir la sécurité du mécanisme de stockage de Home Assistant**. Vous êtes responsable de la protection de vos informations contre le vol.\r\n2. Cette intégration est maintenue par la communauté open source et peut rencontrer des problèmes de stabilité ou autres problèmes. Si vous rencontrez des problèmes liés à l'utilisation de cette intégration, vous devez **demander de l'aide à la communauté open source plutôt que de contacter le service client Xiaomi**.\r\n3. Vous avez besoin d'un certain niveau de compétences techniques pour maintenir votre environnement d'exécution local. Cette intégration n'est pas conviviale pour les utilisateurs novices.\r\n4. Avant d'utiliser cette intégration, veuillez **lire attentivement le README**.\r\n5. Pour garantir une utilisation stable de l'intégration et prévenir les abus d'interface, **cette intégration n'est autorisée qu'à être utilisée dans Home Assistant. Pour plus de détails, veuillez consulter la LICENSE**.",
|
||||
"data": {
|
||||
"eula": "Je suis informé des risques ci-dessus et j'accepte volontairement les risques associés à l'utilisation de cette intégration."
|
||||
}
|
||||
},
|
||||
"auth_config": {
|
||||
"title": "Configuration de base",
|
||||
"description": "### Région de connexion\r\nSélectionnez la région où se trouve votre compte Xiaomi. Vous pouvez le trouver dans `Xiaomi Home APP > Mon (situé dans le menu inférieur) > Plus de paramètres > À propos de Xiaomi Home`.\r\n### Langue\r\nChoisissez la langue utilisée pour les noms de périphériques et d'entités. Les parties de phrases sans traduction seront affichées en anglais.\r\n### Adresse de redirection de l'authentification OAuth2\r\nL'adresse de redirection de l'authentification OAuth2 est **[http://homeassistant.local:8123](http://homeassistant.local:8123)**. Home Assistant doit être dans le même réseau local que le terminal de l'opération actuelle (par exemple, un ordinateur personnel) et le terminal de l'opération doit pouvoir accéder à la page d'accueil de Home Assistant via cette adresse. Sinon, l'authentification de connexion peut échouer.\r\n### Configuration Réseau Intégrée\r\nVérifiez si le réseau local fonctionne correctement et si les ressources réseau associées sont accessibles. **Il est recommandé de sélectionner cela lors du premier ajout.**\r\n### Remarque\r\n- Pour les utilisateurs ayant des centaines ou plus d'appareils Mi Home, l'ajout initial de l'intégration prendra un certain temps. Veuillez être patient.\r\n- Si Home Assistant fonctionne dans un environnement Docker, veuillez vous assurer que le mode réseau Docker est réglé sur host, sinon la fonctionnalité de contrôle local peut ne pas fonctionner correctement.\r\n- La fonctionnalité de contrôle local de l'intégration a quelques dépendances. Veuillez lire attentivement le README.",
|
||||
"data": {
|
||||
"cloud_server": "Région de connexion",
|
||||
"integration_language": "Langue",
|
||||
"oauth_redirect_url": "Adresse de redirection de l'authentification",
|
||||
"network_detect_config": "Configuration Réseau Intégrée"
|
||||
}
|
||||
},
|
||||
"network_detect_config": {
|
||||
"title": "Configuration Réseau Intégrée",
|
||||
"description": "## Introduction à l'Utilisation\r\n### Adresse de Détection Réseau\r\nUtilisé pour vérifier si le réseau fonctionne correctement. Si non défini, l'adresse par défaut du système sera utilisée. Si la vérification de l'adresse par défaut échoue, vous pouvez essayer de saisir une adresse personnalisée.\r\n- Vous pouvez entrer plusieurs adresses de détection, séparées par des virgules, telles que `8.8.8.8,https://www.bing.com`\r\n- S'il s'agit d'une adresse IP, la détection se fera par ping. S'il s'agit d'une adresse HTTP(s), la détection se fera par une requête HTTP GET.\r\n- Si vous souhaitez rétablir l'adresse de détection par défaut du système, veuillez entrer une virgule `,` et cliquer sur 'Suivant'.\r\n- **Cette configuration est globale et les modifications affecteront les autres instances d'intégration. Veuillez modifier avec prudence.**\r\n### Vérification des Dépendances Réseau\r\nVérifiez une par une les dépendances réseau suivantes pour voir si elles sont accessibles. Si les adresses associées ne sont pas accessibles, cela entraînera des problèmes d'intégration.\r\n- Adresse d'Authentification OAuth2: `https://account.xiaomi.com/oauth2/authorize`.\r\n- Adresse de l'API HTTP de Xiaomi: `https://{http_host}/app/v2/ha/oauth/get_token`.\r\n- Adresse de l'API SPEC de Xiaomi: `https://miot-spec.org/miot-spec-v2/template/list/device`.\r\n- Adresse du Broker MQTT de Xiaomi: `mqtts://{broker_host}`.",
|
||||
"data": {
|
||||
"network_detect_addr": "Adresse de Détection Réseau",
|
||||
"check_network_deps": "Vérification des Dépendances Réseau"
|
||||
}
|
||||
},
|
||||
"oauth_error": {
|
||||
"title": "Erreur de connexion",
|
||||
"description": "Cliquez sur \"Suivant\" pour réessayer"
|
||||
},
|
||||
"homes_select": {
|
||||
"title": "Sélectionner la famille et l'appareil",
|
||||
"description": "## Introduction\r\n### Importer la famille de l'appareil\r\nL'intégration ajoutera des appareils de la famille sélectionnée.\r\n### Mode de synchronisation du nom de la pièce\r\nLors de la synchronisation des appareils de l'application Mi Home avec Home Assistant, le nom de la zone dans Home Assistant suivra les règles ci-dessous. Notez que le processus de synchronisation ne modifiera pas les paramètres de la famille et de la pièce dans l'application Mi Home.\r\n- Ne pas synchroniser : L'appareil ne sera ajouté à aucune zone.\r\n- Autres options : La zone à laquelle l'appareil est ajouté sera nommée d'après le nom de la famille ou de la pièce dans l'application Mi Home.\r\n### Paramètres avancés\r\nAfficher les paramètres avancés pour modifier les options de configuration professionnelle de l'intégration.\r\n\r\n \r\n### {nick_name} Bonjour ! Veuillez sélectionner la famille à laquelle vous souhaitez ajouter l'appareil.",
|
||||
"data": {
|
||||
"home_infos": "Importer la famille de l'appareil",
|
||||
"area_name_rule": "Mode de synchronisation du nom de la pièce",
|
||||
"advanced_options": "Paramètres avancés"
|
||||
}
|
||||
},
|
||||
"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 d’Actions\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 d’Actions",
|
||||
"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"
|
||||
}
|
||||
},
|
||||
"devices_filter": {
|
||||
"title": "Filtrer les Appareils",
|
||||
"description": "## Instructions d'utilisation\r\nPrend en charge le filtrage des appareils par nom de pièce de la maison, type d'accès de l'appareil et modèle d'appareil, et prend également en charge le filtrage par dimension de l'appareil. La logique de filtrage est la suivante :\r\n- Tout d'abord, selon la logique statistique, obtenez l'union ou l'intersection de tous les éléments inclus, puis obtenez l'intersection ou l'union des éléments exclus, et enfin soustrayez le [résultat du résumé inclus] du [résultat du résumé exclu] pour obtenir le [résultat du filtre].\r\n- Si aucun élément inclus n'est sélectionné, cela signifie que tous sont inclus.\r\n### Mode de Filtrage\r\n- Exclure : Supprimer les éléments indésirables.\r\n- Inclure : Inclure les éléments souhaités.\r\n### Logique Statistique\r\n- Logique ET : Prendre l'intersection de tous les éléments dans le même mode.\r\n- Logique OU : Prendre l'union de tous les éléments dans le même mode.\r\n\r\nVous pouvez également aller à la page [Configuration > Mettre à jour la liste des appareils] de l'élément d'intégration, cocher [Filtrer les appareils] pour re-filtrer.",
|
||||
"data": {
|
||||
"room_filter_mode": "Filtrer les Pièces",
|
||||
"room_list": "Pièces",
|
||||
"type_filter_mode": "Filtrer les Types d'Appareils",
|
||||
"type_list": "Types d'Appareils",
|
||||
"model_filter_mode": "Filtrer les Modèles d'Appareils",
|
||||
"model_list": "Modèles d'Appareils",
|
||||
"devices_filter_mode": "Filtrer les Appareils",
|
||||
"device_list": "Liste des Appareils",
|
||||
"statistics_logic": "Logique de Statistiques"
|
||||
}
|
||||
}
|
||||
},
|
||||
"progress": {
|
||||
"oauth": "### {link_left}Veuillez cliquer ici pour vous reconnecter{link_right}\r\n(Vous serez automatiquement redirigé vers la page suivante après une connexion réussie)"
|
||||
},
|
||||
"error": {
|
||||
"eula_not_agree": "Veuillez lire le texte de notification de risques.",
|
||||
"get_token_error": "Échec de la récupération des informations d'autorisation de connexion (jeton OAuth).",
|
||||
"get_homeinfo_error": "Échec de la récupération des informations de la maison.",
|
||||
"mdns_discovery_error": "Le service de découverte de périphériques locaux est anormal.",
|
||||
"get_cert_error": "Échec de l'obtention du certificat de la passerelle.",
|
||||
"no_family_selected": "Aucune maison sélectionnée.",
|
||||
"no_devices": "Il n'y a pas d'appareils dans la maison sélectionnée. Veuillez sélectionner une maison avec des appareils et continuer.",
|
||||
"no_filter_devices": "Les appareils filtrés sont vides. Veuillez sélectionner des critères de filtre valides et continuer.",
|
||||
"no_central_device": "Le mode gateway central a besoin d'un Xiaomi Gateway disponible dans le réseau local où se trouve Home Assistant. Veuillez vérifier si la maison sélectionnée répond à cette exigence.",
|
||||
"invalid_network_addr": "Adresse IP ou HTTP invalide détectée, veuillez entrer une adresse valide.",
|
||||
"invalid_ip_addr": "Adresse IP inaccessible détectée, veuillez entrer une adresse IP valide.",
|
||||
"invalid_http_addr": "Adresse HTTP inaccessible détectée, veuillez entrer une adresse HTTP valide.",
|
||||
"invalid_default_addr": "L'adresse de détection réseau par défaut est inaccessible, veuillez vérifier la configuration réseau ou utiliser une adresse de détection réseau personnalisée.",
|
||||
"unreachable_oauth2_host": "Impossible d'atteindre l'adresse d'authentification OAuth2, veuillez vérifier la configuration réseau.",
|
||||
"unreachable_http_host": "Impossible d'atteindre l'adresse de l'API HTTP de Xiaomi, veuillez vérifier la configuration réseau.",
|
||||
"unreachable_spec_host": "Impossible d'atteindre l'adresse de l'API SPEC de Xiaomi, veuillez vérifier la configuration réseau.",
|
||||
"unreachable_mqtt_broker": "Impossible d'atteindre l'adresse du Broker MQTT de Xiaomi, veuillez vérifier la configuration réseau."
|
||||
},
|
||||
"abort": {
|
||||
"ha_uuid_get_failed": "Échec de l'obtention de l'UUID de Home Assistant.",
|
||||
"network_connect_error": "La configuration a échoué. Erreur de connexion réseau. Veuillez vérifier la configuration du réseau de l'appareil.",
|
||||
"already_configured": "Cet utilisateur a déjà terminé la configuration. Veuillez accéder à la page d'intégration et cliquer sur le bouton \"Configurer\" pour modifier la configuration.",
|
||||
"invalid_auth_info": "Les informations d'authentification ont expiré. Veuillez accéder à la page d'intégration et cliquer sur le bouton \"Configurer\" pour vous authentifier à nouveau.",
|
||||
"config_flow_error": "Erreur de configuration de l'intégration : {error}"
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"step": {
|
||||
"auth_config": {
|
||||
"title": "Configuration d'authentification",
|
||||
"description": "Les informations d'authentification locales ont expiré. Veuillez recommencer l'authentification\r\n### Région de connexion actuelle : {cloud_server}\r\n### Adresse de redirection de l'authentification OAuth2\r\nL'adresse de redirection de l'authentification OAuth2 est **[http://homeassistant.local:8123](http://homeassistant.local:8123)**. Home Assistant doit être dans le même réseau local que le terminal de l'opération actuelle (par exemple, un ordinateur personnel) et le terminal de l'opération doit pouvoir accéder à la page d'accueil de Home Assistant via cette adresse. Sinon, l'authentification de connexion peut échouer.",
|
||||
"data": {
|
||||
"oauth_redirect_url": "Adresse de redirection de l'authentification"
|
||||
}
|
||||
},
|
||||
"oauth_error": {
|
||||
"title": "Erreur de connexion",
|
||||
"description": "Cliquez sur \"Suivant\" pour réessayer"
|
||||
},
|
||||
"config_options": {
|
||||
"title": "Options de configuration",
|
||||
"description": "### {nick_name} Bonjour !\r\n\r\nID de compte Xiaomi : {uid}\r\nRégion de connexion actuelle : {cloud_server}\r\nID d'Instance d'Intégration: {instance_id}\r\n\r\nVeuillez sélectionner les options que vous devez reconfigurer et cliquer sur \"Suivant\".",
|
||||
"data": {
|
||||
"integration_language": "Langue d'intégration",
|
||||
"update_user_info": "Mettre à jour les informations utilisateur",
|
||||
"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",
|
||||
"network_detect_config": "Configuration Réseau Intégrée",
|
||||
"cover_dead_zone_width": "Largeur de la zone aveugle du rideau"
|
||||
}
|
||||
},
|
||||
"update_user_info": {
|
||||
"title": "Mettre à jour le pseudo de l'utilisateur",
|
||||
"description": "{nick_name} Bonjour ! Veuillez modifier votre pseudo utilisateur ci-dessous.",
|
||||
"data": {
|
||||
"nick_name": "Pseudo utilisateur"
|
||||
}
|
||||
},
|
||||
"homes_select": {
|
||||
"title": "Re-sélectionner une maison et des appareils",
|
||||
"description": "## Instructions d'utilisation\r\n### Importer une maison pour les appareils\r\nL'intégration ajoutera les appareils de la maison sélectionnée.\r\n### Filtrer les appareils\r\nPrend en charge le filtrage des appareils par nom de pièce de la maison, type d'accès de l'appareil et modèle d'appareil, et prend également en charge le filtrage par dimension de l'appareil. **{local_count}** appareils ont été filtrés.\r\n### Mode de contrôle\r\n- Automatique: Lorsqu'il y a une passerelle centrale Xiaomi disponible dans le réseau local, Home Assistant priorisera l'envoi des commandes de contrôle des appareils via la passerelle centrale pour réaliser un contrôle localisé. S'il n'y a pas de passerelle centrale dans le réseau local, il tentera d'envoyer des commandes de contrôle via le protocole Xiaomi OT pour réaliser un contrôle localisé. Ce n'est que lorsque les conditions de contrôle localisé ci-dessus ne sont pas remplies que les commandes de contrôle des appareils seront envoyées via le cloud.\r\n- Cloud: Les commandes de contrôle ne sont envoyées que via le cloud.",
|
||||
"data": {
|
||||
"home_infos": "Importer une maison pour les appareils",
|
||||
"devices_filter": "Filtrer les Appareils",
|
||||
"ctrl_mode": "Mode de contrôle"
|
||||
}
|
||||
},
|
||||
"devices_filter": {
|
||||
"title": "Filtrer les Appareils",
|
||||
"description": "## Instructions d'utilisation\r\nPrend en charge le filtrage des appareils par nom de pièce de la maison, type d'accès de l'appareil et modèle d'appareil, et prend également en charge le filtrage par dimension de l'appareil. La logique de filtrage est la suivante :\r\n- Tout d'abord, selon la logique statistique, obtenez l'union ou l'intersection de tous les éléments inclus, puis obtenez l'intersection ou l'union des éléments exclus, et enfin soustrayez le [résultat du résumé inclus] du [résultat du résumé exclu] pour obtenir le [résultat du filtre].\r\n- Si aucun élément inclus n'est sélectionné, cela signifie que tous sont inclus.\r\n### Mode de Filtrage\r\n- Exclure : Supprimer les éléments indésirables.\r\n- Inclure : Inclure les éléments souhaités.\r\n### Logique Statistique\r\n- Logique ET : Prendre l'intersection de tous les éléments dans le même mode.\r\n- Logique OU : Prendre l'union de tous les éléments dans le même mode.\r\n\r\nVous pouvez également aller à la page [Configuration > Mettre à jour la liste des appareils] de l'élément d'intégration, cocher [Filtrer les appareils] pour re-filtrer.",
|
||||
"data": {
|
||||
"room_filter_mode": "Filtrer les Pièces",
|
||||
"room_list": "Pièces",
|
||||
"type_filter_mode": "Filtrer les Types d'Appareils",
|
||||
"type_list": "Types d'Appareils",
|
||||
"model_filter_mode": "Filtrer les Modèles d'Appareils",
|
||||
"model_list": "Modèles d'Appareils",
|
||||
"devices_filter_mode": "Filtrer les Appareils",
|
||||
"device_list": "Liste des Appareils",
|
||||
"statistics_logic": "Logique de Statistiques"
|
||||
}
|
||||
},
|
||||
"update_trans_rules": {
|
||||
"title": "Mettre à jour les règles de conversion d'entités",
|
||||
"description": "## Instructions d'utilisation\r\n- Mettez à jour les informations d'entité des appareils dans l'instance d'intégration actuelle, y compris la configuration multilingue SPEC, la traduction booléenne SPEC et le filtrage de modèle SPEC.\r\n- **Avertissement: Cette configuration est une configuration globale** et mettra directement à jour le cache local. S'il y a des appareils du même modèle dans d'autres instances d'intégration, les instances pertinentes seront également mises à jour après rechargement.\r\n- Cette opération prendra du temps, veuillez être patient. Cochez \"Confirmer la mise à jour\" et cliquez sur \"Suivant\" pour commencer à mettre à jour **{urn_count}** règles, sinon passez la mise à jour.",
|
||||
"data": {
|
||||
"confirm": "Confirmer la mise à jour"
|
||||
}
|
||||
},
|
||||
"update_lan_ctrl_config": {
|
||||
"title": "Mettre à jour la configuration réseau de contrôle LAN",
|
||||
"description": "## Instructions d'utilisation\r\nMettez à jour les informations de configuration pour **le contrôle LAN des appareils Xiaomi Home**. Lorsque le cloud et la passerelle centrale ne peuvent pas contrôler les appareils, l'intégration tentera de contrôler les appareils via le LAN ; si aucune carte réseau n'est sélectionnée, le contrôle LAN ne sera pas activé.\r\n- Actuellement, seuls les appareils WiFi **SPEC v2** dans le LAN sont pris en charge. Certains anciens appareils peuvent ne pas prendre en charge le contrôle ou la synchronisation des propriétés.\r\n- Veuillez sélectionner la ou les cartes réseau sur le même réseau que les appareils (plusieurs sélections sont prises en charge). Si la carte réseau sélectionnée a deux ou plusieurs connexions sur le même réseau, il est recommandé de sélectionner celle avec la meilleure connexion réseau, sinon cela peut **affecter l'utilisation normale des appareils**.\r\n- **S'il y a des appareils terminaux (passerelles, téléphones mobiles, etc.) dans le LAN qui prennent en charge le contrôle local, l'activation de l'abonnement LAN peut provoquer des automatisations locales ou des anomalies des appareils. Veuillez l'utiliser avec prudence**.\r\n- **Avertissement : Cette configuration est globale et les modifications affecteront d'autres instances d'intégration. Veuillez modifier avec prudence**.\r\n{notice_net_dup}",
|
||||
"data": {
|
||||
"net_interfaces": "Veuillez sélectionner la carte réseau à utiliser",
|
||||
"enable_subscribe": "Activer la souscription"
|
||||
}
|
||||
},
|
||||
"network_detect_config": {
|
||||
"title": "Configuration Réseau Intégrée",
|
||||
"description": "## Introduction à l'Utilisation\r\n### Adresse de Détection Réseau\r\nUtilisé pour vérifier si le réseau fonctionne correctement. Si non défini, l'adresse par défaut du système sera utilisée. Si la vérification de l'adresse par défaut échoue, vous pouvez essayer de saisir une adresse personnalisée.\r\n- Vous pouvez entrer plusieurs adresses de détection, séparées par des virgules, telles que `8.8.8.8,https://www.bing.com`\r\n- S'il s'agit d'une adresse IP, la détection se fera par ping. S'il s'agit d'une adresse HTTP(s), la détection se fera par une requête HTTP GET.\r\n- Si vous souhaitez rétablir l'adresse de détection par défaut du système, veuillez entrer une virgule `,` et cliquer sur 'Suivant'.\r\n- **Cette configuration est globale et les modifications affecteront les autres instances d'intégration. Veuillez modifier avec prudence.**\r\n### Vérification des Dépendances Réseau\r\nVérifiez une par une les dépendances réseau suivantes pour voir si elles sont accessibles. Si les adresses associées ne sont pas accessibles, cela entraînera des problèmes d'intégration.\r\n- Adresse d'Authentification OAuth2: `https://account.xiaomi.com/oauth2/authorize`.\r\n- Adresse de l'API HTTP de Xiaomi: `https://{http_host}/app/v2/ha/oauth/get_token`.\r\n- Adresse de l'API SPEC de Xiaomi: `https://miot-spec.org/miot-spec-v2/template/list/device`.\r\n- Adresse du Broker MQTT de Xiaomi: `mqtts://{broker_host}`.",
|
||||
"data": {
|
||||
"network_detect_addr": "Adresse de Détection Réseau",
|
||||
"check_network_deps": "Vérification des Dépendances Réseau"
|
||||
}
|
||||
},
|
||||
"config_confirm": {
|
||||
"title": "Confirmer la configuration",
|
||||
"description": "**{nick_name}** Bonjour ! Veuillez confirmer les dernières informations de configuration et cliquer sur \"Soumettre\".\r\nL'intégration rechargera avec la nouvelle configuration.\r\n\r\nLangue d'intégration : {lang_new}\r\nPseudo utilisateur : {nick_name_new}\r\nMode de débogage d'action : {action_debug}\r\nMasquer les entités générées non standard : {hide_non_standard_entities}\r\nLargeur de la zone aveugle du rideau:\t{cover_width_new}\r\nAfficher les notifications de changement d'état de l'appareil:\t{display_devices_changed_notify}\r\nModifications des appareils : Ajouter **{devices_add}** appareils, supprimer **{devices_remove}** appareils\r\nModifications des règles de conversion : **{trans_rules_count}** règles au total, mise à jour de **{trans_rules_count_success}** règles",
|
||||
"data": {
|
||||
"confirm": "Confirmer la modification"
|
||||
}
|
||||
}
|
||||
},
|
||||
"progress": {
|
||||
"oauth": "### {link_left}Veuillez cliquer ici pour vous reconnecter{link_right}"
|
||||
},
|
||||
"error": {
|
||||
"not_auth": "L'utilisateur n'est pas authentifié. Veuillez cliquer sur le lien d'authentification pour vous identifier.",
|
||||
"get_token_error": "Impossible d'obtenir les informations d'authentification (jeton OAuth).",
|
||||
"get_homeinfo_error": "Impossible d'obtenir les informations de la maison.",
|
||||
"get_cert_error": "Impossible d'obtenir le certificat central.",
|
||||
"no_family_selected": "Aucune maison sélectionnée.",
|
||||
"no_devices": "Il n'y a pas d'appareils dans la maison sélectionnée. Veuillez sélectionner une maison avec des appareils et continuer.",
|
||||
"no_filter_devices": "Les appareils filtrés sont vides. Veuillez sélectionner des critères de filtre valides et continuer.",
|
||||
"no_central_device": "Le mode passerelle centrale nécessite une passerelle Xiaomi disponible dans le réseau local où est installé Home Assistant. Veuillez vérifier que la maison sélectionnée répond à cette exigence.",
|
||||
"mdns_discovery_error": "Service de découverte de périphérique local en panne.",
|
||||
"update_config_error": "Échec de la mise à jour des informations de configuration.",
|
||||
"not_confirm": "La modification n'a pas été confirmée. Veuillez cocher la case de confirmation avant de soumettre.",
|
||||
"invalid_network_addr": "Adresse IP ou HTTP invalide détectée, veuillez entrer une adresse valide.",
|
||||
"invalid_ip_addr": "Adresse IP inaccessible détectée, veuillez entrer une adresse IP valide.",
|
||||
"invalid_http_addr": "Adresse HTTP inaccessible détectée, veuillez entrer une adresse HTTP valide.",
|
||||
"invalid_default_addr": "L'adresse de détection réseau par défaut est inaccessible, veuillez vérifier la configuration réseau ou utiliser une adresse de détection réseau personnalisée.",
|
||||
"unreachable_oauth2_host": "Impossible d'atteindre l'adresse d'authentification OAuth2, veuillez vérifier la configuration réseau.",
|
||||
"unreachable_http_host": "Impossible d'atteindre l'adresse de l'API HTTP de Xiaomi, veuillez vérifier la configuration réseau.",
|
||||
"unreachable_spec_host": "Impossible d'atteindre l'adresse de l'API SPEC de Xiaomi, veuillez vérifier la configuration réseau.",
|
||||
"unreachable_mqtt_broker": "Impossible d'atteindre l'adresse du Broker MQTT de Xiaomi, veuillez vérifier la configuration réseau."
|
||||
},
|
||||
"abort": {
|
||||
"network_connect_error": "Échec de la configuration. Problème de connexion réseau, veuillez vérifier la configuration du périphérique.",
|
||||
"options_flow_error": "Erreur de réinitialisation de la configuration de l'intégration : {error}",
|
||||
"re_add": "Veuillez réajouter l'intégration, message d'erreur : {error}",
|
||||
"storage_error": "Erreur de stockage pour l'intégration. Veuillez réessayer ou réajouter l'intégration : {error}",
|
||||
"inconsistent_account": "Les informations de compte sont incohérentes. Veuillez vous connecter avec les informations de compte correctes."
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,225 @@
|
||||
{
|
||||
"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://{broker_host}`.",
|
||||
"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 \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\nID istanza di integrazione: {instance_id}\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",
|
||||
"cover_dead_zone_width": "Larghezza dell’angolo cieco della tenda"
|
||||
}
|
||||
},
|
||||
"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://{broker_host}`.",
|
||||
"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\nLarghezza dell’angolo cieco della tenda:\t{cover_width_new}\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."
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,225 @@
|
||||
{
|
||||
"config": {
|
||||
"flow_title": "Xiaomi Home インテグレーション",
|
||||
"step": {
|
||||
"eula": {
|
||||
"title": "リスク告知",
|
||||
"description": "1. あなたの**Xiaomiユーザー情報とデバイス情報**は、Home Assistantシステムに保存されます。**XiaomiはHome Assistantの保存メカニズムの安全性を保証できません**。情報が盗まれないようにする責任はあなたにあります。\r\n2. このインテグレーションはオープンソースコミュニティによって管理されています。安定性の問題やその他の問題が発生する可能性があります。問題が発生した場合は、 **Xiaomi カスタマーサポートに連絡するのではなく、オープンソースコミュニティに助けを求める必要があります**。\r\n3. あなたはある程度の技術力を持っている必要があります。このインテグレーションは初心者には友好的ではありません。\r\n4. このインテグレーションを使用する前に、 **README をよく読んでください**。\r\n5. 統合の安定した使用を確保し、インターフェースの乱用を防ぐために、**この統合はHome Assistantでのみ使用することが許可されています。詳細についてはLICENSEを参照してください**。",
|
||||
"data": {
|
||||
"eula": "私は上記のリスクを理解し、インテグレーションを使用することによる関連するリスクを自己責任で引き受けます。"
|
||||
}
|
||||
},
|
||||
"auth_config": {
|
||||
"title": "基本設定",
|
||||
"description": "### ログインエリア\r\nXiaomi アカウントが属する地域を選択します。 `Xiaomi Home アプリ> マイ(ボトムメニューにあります)> その他の設定> Xiaomi Home について` で確認できます。\r\n### 言語\r\nデバイスおよびエンティティ名に使用される言語を選択します。一部の翻訳が欠落している場合、英語が表示されます。\r\n### OAuth2 認証リダイレクトアドレス\r\nOAuth2 認証リダイレクトアドレスは **[http://homeassistant.local:8123](http://homeassistant.local:8123)** です。Home Assistant は、現在の操作端末(たとえば、パーソナルコンピュータ)と同じ LAN 内にあり、操作端末がこのアドレスで Home Assistant ホームページにアクセスできる場合にのみログイン認証が成功する場合があります。\r\n### 統合ネットワーク構成\r\nローカルネットワークが正常に機能しているかどうか、および関連するネットワークリソースにアクセスできるかどうかを確認します。**初めて追加する場合は、これを選択することをお勧めします。**\r\n### 注意事項\r\n- 数百台以上のMi Homeデバイスをお持ちのユーザーの場合、統合の初回追加には時間がかかります。しばらくお待ちください。\r\n- Home AssistantがDocker環境で実行されている場合は、Dockerのネットワークモードがhostに設定されていることを確認してください。そうしないと、ローカル制御機能が正しく動作しない可能性があります。\r\n- 統合のローカル制御機能にはいくつかの依存関係があります。READMEを注意深く読んでください。",
|
||||
"data": {
|
||||
"cloud_server": "ログインエリア",
|
||||
"integration_language": "言語",
|
||||
"oauth_redirect_url": "認証リダイレクトアドレス",
|
||||
"network_detect_config": "統合ネットワーク構成"
|
||||
}
|
||||
},
|
||||
"network_detect_config": {
|
||||
"title": "統合ネットワーク構成",
|
||||
"description": "## 使用方法の紹介\r\n### ネットワーク検出アドレス\r\nネットワークが正常に機能しているかどうかを確認するために使用されます。設定されていない場合、システムのデフォルトアドレスが使用されます。デフォルトアドレスのチェックが失敗した場合は、カスタムアドレスを入力してみてください。\r\n- 複数の検出アドレスを入力できます。アドレスはコンマで区切ります。例:`8.8.8.8,https://www.bing.com`\r\n- IPアドレスの場合、pingによる検出が行われます。HTTP(s)アドレスの場合、HTTP GETリクエストによる検出が行われます。\r\n- システムのデフォルト検出アドレスを復元する場合は、カンマ `,` を入力して「次へ」をクリックしてください。\r\n- **この設定はグローバルであり、変更は他の統合インスタンスに影響を与えます。慎重に変更してください。**\r\n### ネットワーク依存関係のチェック\r\n次のネットワーク依存関係がアクセス可能かどうかを順番に確認します。関連するアドレスにアクセスできない場合、統合に問題が発生します。\r\n- OAuth2 認証アドレス: `https://account.xiaomi.com/oauth2/authorize`.\r\n- Xiaomi HTTP API アドレス: `https://{http_host}/app/v2/ha/oauth/get_token`.\r\n- Xiaomi SPEC API アドレス: `https://miot-spec.org/miot-spec-v2/template/list/device`.\r\n- Xiaomi MQTT ブローカーアドレス: `mqtts://{broker_host}`.",
|
||||
"data": {
|
||||
"network_detect_addr": "ネットワーク検出アドレス",
|
||||
"check_network_deps": "ネットワーク依存関係のチェック"
|
||||
}
|
||||
},
|
||||
"oauth_error": {
|
||||
"title": "ログインエラー",
|
||||
"description": "「次へ」をクリックして再試行してください"
|
||||
},
|
||||
"homes_select": {
|
||||
"title": "家族とデバイスを選択",
|
||||
"description": "## 紹介\r\n### デバイスの家族をインポート\r\n統合は選択された家族のデバイスを追加します。\r\n### 部屋の名前の同期モード\r\nMi HomeアプリからHome Assistantにデバイスを同期する際、Home Assistantのエリアの名前は以下のルールに従います。同期プロセスはMi Homeアプリの家族と部屋の設定を変更しないことに注意してください。\r\n- 同期しない:デバイスはどのエリアにも追加されません。\r\n- その他のオプション:デバイスが追加されるエリアはMi Homeアプリの家族または部屋の名前にちなんで命名されます。\r\n### 高度な設定\r\n統合のプロフェッショナルな設定オプションを変更するために高度な設定を表示します。\r\n\r\n \r\n### {nick_name} こんにちは!デバイスを追加したい家族を選択してください。",
|
||||
"data": {
|
||||
"home_infos": "デバイスの家族をインポート",
|
||||
"area_name_rule": "部屋の名前の同期モード",
|
||||
"advanced_options": "高度な設定"
|
||||
}
|
||||
},
|
||||
"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\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": "デバイスの状態変化通知を表示"
|
||||
}
|
||||
},
|
||||
"devices_filter": {
|
||||
"title": "デバイスをフィルタリング",
|
||||
"description": "## 使用方法\r\n家庭の部屋の名前、デバイスの接続タイプ、デバイスのモデルでデバイスをフィルタリングすることをサポートし、デバイスの次元フィルタリングもサポートします。フィルタリングロジックは次のとおりです:\r\n- まず、統計ロジックに従って、すべての含まれる項目の和集合または交差を取得し、次に除外される項目の交差または和集合を取得し、最後に[含まれる集計結果]から[除外される集計結果]を引いて[フィルタ結果]を取得します。\r\n- 含まれる項目が選択されていない場合、すべてが含まれることを意味します。\r\n### フィルターモード\r\n- 除外:不要な項目を削除します。\r\n- 含む:必要な項目を含めます。\r\n### 統計ロジック\r\n- ANDロジック:同じモードのすべての項目の交差を取ります。\r\n- ORロジック:同じモードのすべての項目の和集合を取ります。\r\n\r\n統合項目の[設定 > デバイスリストの更新]ページに移動し、[デバイスをフィルタリング]を選択して再フィルタリングすることもできます。",
|
||||
"data": {
|
||||
"room_filter_mode": "家族の部屋をフィルタリング",
|
||||
"room_list": "家族の部屋",
|
||||
"type_filter_mode": "デバイスタイプをフィルタリング",
|
||||
"type_list": "デバイスタイプ",
|
||||
"model_filter_mode": "デバイスモデルをフィルタリング",
|
||||
"model_list": "デバイスモデル",
|
||||
"devices_filter_mode": "デバイスをフィルタリング",
|
||||
"device_list": "デバイスリスト",
|
||||
"statistics_logic": "統計ロジック"
|
||||
}
|
||||
}
|
||||
},
|
||||
"progress": {
|
||||
"oauth": "### {link_left}ここをクリックして再度ログインしてください{link_right}\r\n(ログインに成功すると、自動的に次のページにリダイレクトされます)"
|
||||
},
|
||||
"error": {
|
||||
"eula_not_agree": "リスク告知文書を読んでください。",
|
||||
"get_token_error": "ログイン認証情報(OAuth トークン)を取得できませんでした。",
|
||||
"get_homeinfo_error": "ホーム情報を取得できませんでした。",
|
||||
"mdns_discovery_error": "ローカルデバイス検出サービスに異常があります。",
|
||||
"get_cert_error": "ゲートウェイ証明書を取得できませんでした。",
|
||||
"no_family_selected": "家庭が選択されていません。",
|
||||
"no_devices": "選択した家庭にはデバイスがありません。デバイスがある家庭を選択して続行してください。",
|
||||
"no_filter_devices": "フィルタリングされたデバイスが空です。有効なフィルター条件を選択して続行してください。",
|
||||
"no_central_device": "【中央ゲートウェイモード】Home Assistant が存在する LAN 内に使用可能な Xiaomi 中央ゲートウェイがある必要があります。選択された家庭がこの要件を満たしているかどうかを確認してください。",
|
||||
"invalid_network_addr": "無効なIPアドレスまたはHTTPアドレスが検出されました。有効なアドレスを入力してください。",
|
||||
"invalid_ip_addr": "アクセスできないIPアドレスが検出されました。有効なIPアドレスを入力してください。",
|
||||
"invalid_http_addr": "アクセスできないHTTPアドレスが検出されました。有効なHTTPアドレスを入力してください。",
|
||||
"invalid_default_addr": "デフォルトのネットワーク検出アドレスにアクセスできません。ネットワーク設定を確認するか、カスタムネットワーク検出アドレスを使用してください。",
|
||||
"unreachable_oauth2_host": "OAuth2 認証アドレスにアクセスできません。ネットワーク設定を確認してください。",
|
||||
"unreachable_http_host": "Xiaomi HTTP API アドレスにアクセスできません。ネットワーク設定を確認してください。",
|
||||
"unreachable_spec_host": "Xiaomi SPEC API アドレスにアクセスできません。ネットワーク設定を確認してください。",
|
||||
"unreachable_mqtt_broker": "Xiaomi MQTT ブローカーアドレスにアクセスできません。ネットワーク設定を確認してください。"
|
||||
},
|
||||
"abort": {
|
||||
"ha_uuid_get_failed": "Home Assistant インスタンスIDを取得できませんでした。",
|
||||
"network_connect_error": "設定に失敗しました。ネットワーク接続に異常があります。デバイスのネットワーク設定を確認してください。",
|
||||
"already_configured": "このユーザーはすでに設定が完了しています。統合ページにアクセスして、「設定」ボタンをクリックして設定を変更してください。",
|
||||
"invalid_auth_info": "認証情報が期限切れになりました。統合ページにアクセスして、「設定」ボタンをクリックして再度認証してください。",
|
||||
"config_flow_error": "統合設定エラー:{error}"
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"step": {
|
||||
"auth_config": {
|
||||
"title": "認証構成",
|
||||
"description": "ローカル認証情報が期限切れになっています。認証を再開してください。\r\n### 現在のログインエリア:{cloud_server}\r\n### OAuth2 認証リダイレクトアドレス\r\nOAuth2 認証リダイレクトアドレスは **[http://homeassistant.local:8123](http://homeassistant.local:8123)** です。Home Assistant は、現在の操作端末(たとえば、パーソナルコンピュータ)と同じ LAN 内にあり、操作端末がこのアドレスで Home Assistant ホームページにアクセスできる場合にのみログイン認証が成功する場合があります。",
|
||||
"data": {
|
||||
"oauth_redirect_url": "認証リダイレクトアドレス"
|
||||
}
|
||||
},
|
||||
"oauth_error": {
|
||||
"title": "ログインエラー",
|
||||
"description": "「次へ」をクリックして再試行してください"
|
||||
},
|
||||
"config_options": {
|
||||
"title": "設定オプション",
|
||||
"description": "### {nick_name} さん、こんにちは!\r\n\r\nXiaomi アカウントID:{uid}\r\n現在のログインエリア:{cloud_server}\r\n統合インスタンスID: {instance_id}\r\n\r\n必要な構成オプションを選択して、[次へ] をクリックしてください。",
|
||||
"data": {
|
||||
"integration_language": "統合言語",
|
||||
"update_user_info": "ユーザー情報を更新する",
|
||||
"update_devices": "デバイスリストを更新する",
|
||||
"action_debug": "Action デバッグモード",
|
||||
"hide_non_standard_entities": "非標準生成エンティティを非表示にする",
|
||||
"display_binary_mode": "バイナリセンサー表示モード",
|
||||
"display_devices_changed_notify": "デバイスの状態変化通知を表示",
|
||||
"update_trans_rules": "エンティティ変換ルールを更新する",
|
||||
"update_lan_ctrl_config": "LAN制御構成を更新する",
|
||||
"network_detect_config": "統合ネットワーク構成",
|
||||
"cover_dead_zone_width": "カーテンの死角幅"
|
||||
}
|
||||
},
|
||||
"update_user_info": {
|
||||
"title": "ユーザー名を更新する",
|
||||
"description": "{nick_name} さん、こんにちは! 下のボックスからユーザー名を変更してください。",
|
||||
"data": {
|
||||
"nick_name": "ユーザー名"
|
||||
}
|
||||
},
|
||||
"homes_select": {
|
||||
"title": "ホームとデバイスを再度選択",
|
||||
"description": "## 使用方法\r\n### 導入されたデバイスのホーム\r\n統合は、選択された家庭にあるデバイスを追加します。\r\n### デバイスをフィルタリング\r\n家庭の部屋の名前、デバイスの接続タイプ、デバイスのモデルでデバイスをフィルタリングすることをサポートし、デバイスの次元フィルタリングもサポートします。**{local_count}** 個のデバイスがフィルタリングされました。\r\n### 制御モード\r\n- 自動: ローカルエリアネットワーク内に利用可能なXiaomi中央ゲートウェイが存在する場合、Home Assistantは中央ゲートウェイを介してデバイス制御コマンドを優先的に送信し、ローカル制御機能を実現します。ローカルエリアネットワーク内に中央ゲートウェイが存在しない場合、Xiaomi OTプロトコルを介して制御コマンドを送信し、ローカル制御機能を実現しようとします。上記のローカル制御条件が満たされない場合にのみ、デバイス制御コマンドはクラウドを介して送信されます。\r\n- クラウド: 制御コマンドはクラウドを介してのみ送信されます。",
|
||||
"data": {
|
||||
"home_infos": "導入されたデバイスのホーム",
|
||||
"devices_filter": "デバイスをフィルタリング",
|
||||
"ctrl_mode": "制御モード"
|
||||
}
|
||||
},
|
||||
"devices_filter": {
|
||||
"title": "デバイスをフィルタリング",
|
||||
"description": "## 使用方法\r\n家庭の部屋の名前、デバイスの接続タイプ、デバイスのモデルでデバイスをフィルタリングすることをサポートし、デバイスの次元フィルタリングもサポートします。フィルタリングロジックは次のとおりです:\r\n- まず、統計ロジックに従って、すべての含まれる項目の和集合または交差を取得し、次に除外される項目の交差または和集合を取得し、最後に[含まれる集計結果]から[除外される集計結果]を引いて[フィルタ結果]を取得します。\r\n- 含まれる項目が選択されていない場合、すべてが含まれることを意味します。\r\n### フィルターモード\r\n- 除外:不要な項目を削除します。\r\n- 含む:必要な項目を含めます。\r\n### 統計ロジック\r\n- ANDロジック:同じモードのすべての項目の交差を取ります。\r\n- ORロジック:同じモードのすべての項目の和集合を取ります。\r\n\r\n統合項目の[設定 > デバイスリストの更新]ページに移動し、[デバイスをフィルタリング]を選択して再フィルタリングすることもできます。",
|
||||
"data": {
|
||||
"room_filter_mode": "家族の部屋をフィルタリング",
|
||||
"room_list": "家族の部屋",
|
||||
"type_filter_mode": "デバイスタイプをフィルタリング",
|
||||
"type_list": "デバイスタイプ",
|
||||
"model_filter_mode": "デバイスモデルをフィルタリング",
|
||||
"model_list": "デバイスモデル",
|
||||
"devices_filter_mode": "デバイスをフィルタリング",
|
||||
"device_list": "デバイスリスト",
|
||||
"statistics_logic": "統計ロジック"
|
||||
}
|
||||
},
|
||||
"update_trans_rules": {
|
||||
"title": "エンティティ変換ルールを更新する",
|
||||
"description": "## 使用方法\r\n- 現在の統合インスタンス内のデバイスのエンティティ情報を更新します。これには、SPEC多言語設定、SPECブール値翻訳、SPECモデルフィルタリングが含まれます。\r\n- **警告: この設定はグローバル設定**であり、ローカルキャッシュを直接更新します。他の統合インスタンスに同じモデルのデバイスがある場合、関連するインスタンスを再読み込みした後に更新されます。\r\n- この操作には時間がかかるため、しばらくお待ちください。「更新を確認」を選択し、「次へ」をクリックして **{urn_count}** ルールの更新を開始します。そうでない場合は、更新をスキップします。",
|
||||
"data": {
|
||||
"confirm": "確認する"
|
||||
}
|
||||
},
|
||||
"update_lan_ctrl_config": {
|
||||
"title": "LAN制御構成を更新する",
|
||||
"description": "## 使用方法\r\n**Xiaomi HomeデバイスのLAN制御**の設定情報を更新します。クラウドと中央ゲートウェイがデバイスを制御できない場合、統合はLANを介してデバイスを制御しようとします。ネットワークカードが選択されていない場合、LAN制御は有効になりません。\r\n- 現在、LAN内の**SPEC v2** WiFiデバイスのみがサポートされています。一部の古いデバイスは、制御やプロパティの同期をサポートしていない場合があります。\r\n- デバイスと同じネットワーク上のネットワークカードを選択してください(複数選択がサポートされています)。選択したネットワークカードが同じネットワークに2つ以上の接続を持っている場合は、最適なネットワーク接続を持つものを選択することをお勧めします。そうしないと、デバイスの正常な使用に**影響を与える可能性があります**。\r\n- **LAN内にローカル制御をサポートする端末デバイス(ゲートウェイ、携帯電話など)が存在する場合、LANサブスクリプションを有効にすると、ローカルオートメーションやデバイスの異常が発生する可能性があります。慎重に使用してください**。\r\n- **警告:この設定はグローバル設定であり、変更は他の統合インスタンスに影響を与えます。慎重に変更してください**。\r\n{notice_net_dup}",
|
||||
"data": {
|
||||
"net_interfaces": "使用するネットワークカードを選択してください",
|
||||
"enable_subscribe": "LANサブスクリプションを有効にする"
|
||||
}
|
||||
},
|
||||
"network_detect_config": {
|
||||
"title": "統合ネットワーク構成",
|
||||
"description": "## 使用方法の紹介\r\n### ネットワーク検出アドレス\r\nネットワークが正常に機能しているかどうかを確認するために使用されます。設定されていない場合、システムのデフォルトアドレスが使用されます。デフォルトアドレスのチェックが失敗した場合は、カスタムアドレスを入力してみてください。\r\n- 複数の検出アドレスを入力できます。アドレスはコンマで区切ります。例:`8.8.8.8,https://www.bing.com`\r\n- IPアドレスの場合、pingによる検出が行われます。HTTP(s)アドレスの場合、HTTP GETリクエストによる検出が行われます。\r\n- システムのデフォルト検出アドレスを復元する場合は、カンマ `,` を入力して「次へ」をクリックしてください。\r\n- **この設定はグローバルであり、変更は他の統合インスタンスに影響を与えます。慎重に変更してください。**\r\n### ネットワーク依存関係のチェック\r\n次のネットワーク依存関係がアクセス可能かどうかを順番に確認します。関連するアドレスにアクセスできない場合、統合に問題が発生します。\r\n- OAuth2 認証アドレス: `https://account.xiaomi.com/oauth2/authorize`.\r\n- Xiaomi HTTP API アドレス: `https://{http_host}/app/v2/ha/oauth/get_token`.\r\n- Xiaomi SPEC API アドレス: `https://miot-spec.org/miot-spec-v2/template/list/device`.\r\n- Xiaomi MQTT ブローカーアドレス: `mqtts://{broker_host}`.",
|
||||
"data": {
|
||||
"network_detect_addr": "ネットワーク検出アドレス",
|
||||
"check_network_deps": "ネットワーク依存関係のチェック"
|
||||
}
|
||||
},
|
||||
"config_confirm": {
|
||||
"title": "構成を確認する",
|
||||
"description": "**{nick_name}** さん、こんにちは! 最新の構成情報を確認してください。[送信] をクリックして、更新された構成を使用して再度読み込みます。\r\n\r\n統合言語:\t{lang_new}\r\nユーザー名:\t{nick_name_new}\r\nAction デバッグモード:\t{action_debug}\r\n非標準生成エンティティを非表示にする:\t{hide_non_standard_entities}\r\nカーテンの死角幅:\t{cover_width_new}\r\nデバイスの状態変化通知を表示:\t{display_devices_changed_notify}\r\nデバイス変更:\t追加 **{devices_add}** 個のデバイス、削除 **{devices_remove}** 個のデバイス\r\n変換ルール変更:\t合計 **{trans_rules_count}** 個の規則、更新 **{trans_rules_count_success}** 個の規則",
|
||||
"data": {
|
||||
"confirm": "変更を確認する"
|
||||
}
|
||||
}
|
||||
},
|
||||
"progress": {
|
||||
"oauth": "### {link_left}ここをクリックして再度ログインしてください{link_right}"
|
||||
},
|
||||
"error": {
|
||||
"not_auth": "ユーザーが認証されていません。認証リンクをクリックしてユーザーの身元を確認してください。",
|
||||
"get_token_error": "ログイン認証情報(OAuthトークン)の取得に失敗しました。",
|
||||
"get_homeinfo_error": "家庭情報の取得に失敗しました。",
|
||||
"get_cert_error": "中枢証明書の取得に失敗しました。",
|
||||
"no_family_selected": "家族が選択されていません。",
|
||||
"no_devices": "選択した家庭にはデバイスがありません。デバイスがある家庭を選択して続行してください。",
|
||||
"no_filter_devices": "フィルタリングされたデバイスが空です。有効なフィルター条件を選択して続行してください。",
|
||||
"no_central_device": "【中枢ゲートウェイモード】には、Home Assistantが存在するローカルネットワークに使用可能なXiaomi Central Hub Gatewayが存在する必要があります。選択された家庭がこの要件を満たしているかどうかを確認してください。",
|
||||
"mdns_discovery_error": "ローカルデバイス発見サービスが異常です。",
|
||||
"update_config_error": "構成情報の更新に失敗しました。",
|
||||
"not_confirm": "変更を確認していません。確認をチェックしてから送信してください。",
|
||||
"invalid_network_addr": "無効なIPアドレスまたはHTTPアドレスが検出されました。有効なアドレスを入力してください。",
|
||||
"invalid_ip_addr": "アクセスできないIPアドレスが検出されました。有効なIPアドレスを入力してください。",
|
||||
"invalid_http_addr": "アクセスできないHTTPアドレスが検出されました。有効なHTTPアドレスを入力してください。",
|
||||
"invalid_default_addr": "デフォルトのネットワーク検出アドレスにアクセスできません。ネットワーク設定を確認するか、カスタムネットワーク検出アドレスを使用してください。",
|
||||
"unreachable_oauth2_host": "OAuth2 認証アドレスにアクセスできません。ネットワーク設定を確認してください。",
|
||||
"unreachable_http_host": "Xiaomi HTTP API アドレスにアクセスできません。ネットワーク設定を確認してください。",
|
||||
"unreachable_spec_host": "Xiaomi SPEC API アドレスにアクセスできません。ネットワーク設定を確認してください。",
|
||||
"unreachable_mqtt_broker": "Xiaomi MQTT ブローカーアドレスにアクセスできません。ネットワーク設定を確認してください。"
|
||||
},
|
||||
"abort": {
|
||||
"network_connect_error": "構成に失敗しました。ネットワーク接続に異常があります。デバイスのネットワーク構成を確認してください。",
|
||||
"options_flow_error": "統合の再設定エラー:{error}",
|
||||
"re_add": "統合を再度追加してください。エラーメッセージ:{error}",
|
||||
"storage_error": "統合ストレージモジュールに異常があります。再試行するか、統合を再度追加してください:{error}",
|
||||
"inconsistent_account": "アカウント情報が一致しません。正しいアカウントでログインしてください。"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,225 @@
|
||||
{
|
||||
"config": {
|
||||
"flow_title": "Xiaomi Home Integratie",
|
||||
"step": {
|
||||
"eula": {
|
||||
"title": "Risiconotitie",
|
||||
"description": "1. Uw Xiaomi-gebruikersinformatie en apparaatinformatie worden opgeslagen in het Home Assistant-systeem. **Xiaomi kan de beveiliging van het opslagmechanisme van Home Assistant niet garanderen**. U bent verantwoordelijk voor het voorkomen dat uw informatie wordt gestolen.\r\n2. Deze integratie wordt onderhouden door de open-sourcegemeenschap. Er kunnen stabiliteitsproblemen of andere problemen optreden. Bij problemen of fouten met deze integratie, **moet u hulp zoeken bij de open-sourcegemeenschap in plaats van contact op te nemen met de Xiaomi klantenservice**.\r\n3. U heeft enige technische vaardigheden nodig om uw lokale werkomgeving te onderhouden. De integratie is niet gebruiksvriendelijk voor beginners.\r\n4. Lees het README-bestand voordat u begint.\n\n5. Om een stabiel gebruik van de integratie te waarborgen en misbruik van de interface te voorkomen, **mag deze integratie alleen worden gebruikt in Home Assistant. Voor details, zie de LICENSE**.",
|
||||
"data": {
|
||||
"eula": "Ik ben me bewust van de bovenstaande risico's en bereid om vrijwillig alle risico's die gepaard gaan met het gebruik van de integratie te aanvaarden."
|
||||
}
|
||||
},
|
||||
"auth_config": {
|
||||
"title": "Basisconfiguratie",
|
||||
"description": "### Inlogregio\r\nSelecteer de regio van uw Xiaomi-account. U kunt deze vinden in de Xiaomi Home APP > Profiel (onderin het menu) > Extra instellingen > Over Xiaomi Home.\r\n### Taal\r\nKies de taal voor de apparaats- en entiteitsnamen. Sommige zinnen zonder vertaling worden in het Engels weergegeven.\r\n### OAuth2 Omleidings-URL\r\nHet OAuth2 authenticatie omleidingsadres is **[http://homeassistant.local:8123](http://homeassistant.local:8123)**. Home Assistant moet zich in hetzelfde lokale netwerk bevinden als de huidige werkterminal (bijv. de persoonlijke computer) en de werkterminal moet toegang hebben tot de startpagina van Home Assistant via dit adres. Anders kan de inlogauthenticatie mislukken.\r\n### Geïntegreerde Netwerkconfiguratie\r\nControleer of het lokale netwerk correct functioneert en of de gerelateerde netwerkbronnen toegankelijk zijn. **Het wordt aanbevolen om dit te selecteren bij het eerste toevoegen.**\r\n### Opmerking\r\n- Voor gebruikers met honderden of meer Mi Home-apparaten kan het aanvankelijke toevoegen van de integratie enige tijd duren. Wees geduldig.\r\n- Als Home Assistant draait in een Docker-omgeving, zorg er dan voor dat de Docker-netwerkmodus is ingesteld op host, anders werkt de lokale controlefunctionaliteit mogelijk niet correct.\r\n- De lokale controlefunctionaliteit van de integratie heeft enkele afhankelijkheden. Lees het README zorgvuldig.",
|
||||
"data": {
|
||||
"cloud_server": "Inlogregio",
|
||||
"integration_language": "Taal",
|
||||
"oauth_redirect_url": "OAuth2 Omleidings-URL",
|
||||
"network_detect_config": "Geïntegreerde Netwerkconfiguratie"
|
||||
}
|
||||
},
|
||||
"network_detect_config": {
|
||||
"title": "Geïntegreerde Netwerkconfiguratie",
|
||||
"description": "## Gebruiksinstructie\r\n### Netwerkdetectieadres\r\nWordt gebruikt om te controleren of het netwerk correct functioneert. Als dit niet is ingesteld, wordt het standaardadres van het systeem gebruikt. Als de standaardadrescontrole mislukt, kunt u proberen een aangepast adres in te voeren.\r\n- U kunt meerdere detectieadressen invoeren, gescheiden door komma's, zoals `8.8.8.8,https://www.bing.com`\r\n- Als het een IP-adres is, wordt de detectie uitgevoerd via ping. Als het een HTTP(s)-adres is, wordt de detectie uitgevoerd via een HTTP GET-verzoek.\r\n- Als u het standaarddetectieadres van het systeem wilt herstellen, voert u een komma `,` in en klikt u op 'Volgende'.\r\n- **Deze configuratie is globaal en wijzigingen zullen andere integratie-instanties beïnvloeden. Wijzig met voorzichtigheid.**\r\n### Controleer Netwerkafhankelijkheden\r\nControleer een voor een de volgende netwerkafhankelijkheden om te zien of ze toegankelijk zijn. Als de gerelateerde adressen niet toegankelijk zijn, zal dit integratieproblemen veroorzaken.\r\n- OAuth2-authenticatieadres: `https://account.xiaomi.com/oauth2/authorize`.\r\n- Xiaomi HTTP API-adres: `https://{http_host}/app/v2/ha/oauth/get_token`.\r\n- Xiaomi SPEC API-adres: `https://miot-spec.org/miot-spec-v2/template/list/device`.\r\n- Xiaomi MQTT Broker-adres: `mqtts://{broker_host}`.",
|
||||
"data": {
|
||||
"network_detect_addr": "Netwerkdetectieadres",
|
||||
"check_network_deps": "Controleer Netwerkafhankelijkheden"
|
||||
}
|
||||
},
|
||||
"oauth_error": {
|
||||
"title": "Inlogfout",
|
||||
"description": "Klik OP VOLGENDE om het opnieuw te proberen."
|
||||
},
|
||||
"homes_select": {
|
||||
"title": "Selecteer Familie en Apparaat",
|
||||
"description": "## Inleiding\r\n### Importeer de familie van het apparaat\r\nDe integratie voegt apparaten toe uit de geselecteerde familie.\r\n### Kamernaam Synchronisatiemodus\r\nBij het synchroniseren van apparaten van de Mi Home-app naar Home Assistant, wordt de naam van het gebied in Home Assistant volgens de volgende regels genoemd. Houd er rekening mee dat het synchronisatieproces de instellingen van familie en kamer in de Mi Home-app niet zal wijzigen.\r\n- Niet synchroniseren: Het apparaat wordt niet aan een gebied toegevoegd.\r\n- Andere opties: Het gebied waaraan het apparaat wordt toegevoegd, wordt genoemd naar de familie- of kamernaam in de Mi Home-app.\r\n### Geavanceerde instellingen\r\nToon geavanceerde instellingen om de professionele configuratie-opties van de integratie te wijzigen.\r\n\r\n \r\n### {nick_name} Hallo! Selecteer de familie waaraan u het apparaat wilt toevoegen.",
|
||||
"data": {
|
||||
"home_infos": "Importeer de familie van het apparaat",
|
||||
"area_name_rule": "Kamernaam Synchronisatiemodus",
|
||||
"advanced_options": "Geavanceerde instellingen"
|
||||
}
|
||||
},
|
||||
"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### 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"
|
||||
}
|
||||
},
|
||||
"devices_filter": {
|
||||
"title": "Apparaten filteren",
|
||||
"description": "## Gebruiksinstructies\r\nOndersteunt het filteren van apparaten op kamernaam, apparaattoegangstype en apparaattype, en ondersteunt ook het filteren op apparaatdimensie. De filterlogica is als volgt:\r\n- Eerst, volgens de statistische logica, de vereniging of doorsnede van alle opgenomen items verkrijgen, vervolgens de doorsnede of vereniging van de uitgesloten items verkrijgen, en ten slotte het [opgenomen samenvattingsresultaat] aftrekken van het [uitgesloten samenvattingsresultaat] om het [filterresultaat] te verkrijgen.\r\n- Als er geen opgenomen items zijn geselecteerd, betekent dit dat alles is opgenomen.\r\n### Filtermodus\r\n- Uitsluiten: Ongewenste items verwijderen.\r\n- Opnemen: Gewenste items opnemen.\r\n### Statistische Logica\r\n- EN-logica: Neem de doorsnede van alle items in dezelfde modus.\r\n- OF-logica: Neem de vereniging van alle items in dezelfde modus.\r\n\r\nU kunt ook naar de pagina [Configuratie > Apparaatlijst bijwerken] van het integratie-item gaan, [Apparaten filteren] aanvinken om opnieuw te filteren.",
|
||||
"data": {
|
||||
"room_filter_mode": "Kamerfiltermodus",
|
||||
"room_list": "Kamers",
|
||||
"type_filter_mode": "Apparaattypen filteren",
|
||||
"type_list": "Apparaattypen",
|
||||
"model_filter_mode": "Apparaatmodel filteren",
|
||||
"model_list": "Apparaatmodellen",
|
||||
"devices_filter_mode": "Apparaten filteren",
|
||||
"device_list": "Apparaatlijst",
|
||||
"statistics_logic": "Statistische logica"
|
||||
}
|
||||
}
|
||||
},
|
||||
"progress": {
|
||||
"oauth": "### {link_left}Klik hier om in te loggen{link_right}\r\n(U wordt automatisch doorgestuurd naar de volgende pagina na succesvolle inlog)"
|
||||
},
|
||||
"error": {
|
||||
"eula_not_agree": "Lees de risiconotitie.",
|
||||
"get_token_error": "Mislukt bij het ophalen van inlogautorisatie-informatie (OAuth-token).",
|
||||
"get_homeinfo_error": "Mislukt bij het ophalen van huisinformatie.",
|
||||
"mdns_discovery_error": "Lokaal apparaatsontdekkingsservice-exceptie.",
|
||||
"get_cert_error": "Mislukt bij het ophalen van het certificaat van de centrale hubgateway.",
|
||||
"no_family_selected": "Geen huis geselecteerd.",
|
||||
"no_devices": "Er zijn geen apparaten in het geselecteerde huis. Selecteer een huis met apparaten en ga verder.",
|
||||
"no_filter_devices": "Gefilterde apparaten zijn leeg. Selecteer geldige filtercriteria en ga verder.",
|
||||
"no_central_device": "[Centrale Hub Gateway Modus] vereist een beschikbare Xiaomi centrale hubgateway in het lokale netwerk waar Home Assistant zich bevindt. Controleer of het geselecteerde huis aan deze vereiste voldoet.",
|
||||
"invalid_network_addr": "Ongeldig IP-adres of HTTP-adres gedetecteerd, voer een geldig adres in.",
|
||||
"invalid_ip_addr": "Onbereikbaar IP-adres gedetecteerd, voer een geldig IP-adres in.",
|
||||
"invalid_http_addr": "Onbereikbaar HTTP-adres gedetecteerd, voer een geldig HTTP-adres in.",
|
||||
"invalid_default_addr": "Standaard netwerkdetectieadres is onbereikbaar, controleer de netwerkconfiguratie of gebruik een aangepast netwerkdetectieadres.",
|
||||
"unreachable_oauth2_host": "Kan OAuth2-authenticatieadres niet bereiken, controleer de netwerkconfiguratie.",
|
||||
"unreachable_http_host": "Kan Xiaomi HTTP API-adres niet bereiken, controleer de netwerkconfiguratie.",
|
||||
"unreachable_spec_host": "Kan Xiaomi SPEC API-adres niet bereiken, controleer de netwerkconfiguratie.",
|
||||
"unreachable_mqtt_broker": "Kan Xiaomi MQTT Broker-adres niet bereiken, controleer de netwerkconfiguratie."
|
||||
},
|
||||
"abort": {
|
||||
"ha_uuid_get_failed": "Mislukt bij het ophalen van Home Assistant UUID.",
|
||||
"network_connect_error": "Configuratie mislukt. De netwerkverbinding is abnormaal. Controleer de netwerkinstellingen van de apparatuur.",
|
||||
"already_configured": "Configuratie voor deze gebruiker is al voltooid. Ga naar de integratiepagina en klik op de CONFIGUREER-knop om wijzigingen aan te brengen.",
|
||||
"invalid_auth_info": "Authenticatie-informatie is verlopen. Ga naar de integratiepagina en klik op de CONFIGUREER-knop om opnieuw te authentiseren.",
|
||||
"config_flow_error": "Integratie configuratiefout: {error}."
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"step": {
|
||||
"auth_config": {
|
||||
"title": "Authenticatieconfiguratie",
|
||||
"description": "Lokale authenticatie-informatie is verlopen. Begin alstublieft het authenticatieproces opnieuw.\r\n### Huidige inlogregio: {cloud_server}\r\n### OAuth2 Omleidings-URL\r\nHet OAuth2 authenticatie omleidingsadres is **[http://homeassistant.local:8123](http://homeassistant.local:8123)**. Home Assistant moet zich in hetzelfde lokale netwerk bevinden als de huidige werkterminal (bijv. de persoonlijke computer) en de werkterminal moet toegang hebben tot de startpagina van Home Assistant via dit adres. Anders kan de inlogauthenticatie mislukken.",
|
||||
"data": {
|
||||
"oauth_redirect_url": "OAuth2 Omleidings-URL"
|
||||
}
|
||||
},
|
||||
"oauth_error": {
|
||||
"title": "Er is een fout opgetreden tijdens het inloggen.",
|
||||
"description": "Klik OP VOLGENDE om opnieuw te proberen."
|
||||
},
|
||||
"config_options": {
|
||||
"title": "Configuratie-opties",
|
||||
"description": "### Hallo, {nick_name}\r\n\r\nXiaomi ID: {uid}\r\nHuidige inlogregio: {cloud_server}\r\nIntegratie-instantie-ID: {instance_id}\r\n\r\nKies de opties die u wilt configureren en klik vervolgens op VOLGENDE.",
|
||||
"data": {
|
||||
"integration_language": "Integratietaal",
|
||||
"update_user_info": "Werk gebruikersinformatie bij",
|
||||
"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",
|
||||
"network_detect_config": "Geïntegreerde Netwerkconfiguratie",
|
||||
"cover_dead_zone_width": "Breedte van de dode hoek van het gordijn"
|
||||
}
|
||||
},
|
||||
"update_user_info": {
|
||||
"title": "Bijwerken van gebruikersnickname",
|
||||
"description": "Hallo {nick_name}, u kunt uw aangepaste bijnaam hieronder wijzigen.",
|
||||
"data": {
|
||||
"nick_name": "Bijnaam"
|
||||
}
|
||||
},
|
||||
"homes_select": {
|
||||
"title": "Huis en Apparaten opnieuw selecteren",
|
||||
"description": "## Gebruiksinstructies\r\n### Importeer apparaten uit huis\r\nDe integratie voegt apparaten toe van de geselecteerde huizen.\r\n### Apparaten filteren\r\nOndersteunt het filteren van apparaten op kamernaam, apparaattoegangstype en apparaattype, en ondersteunt ook het filteren op apparaatdimensie. **{local_count}** apparaten zijn gefilterd.\r\n### Controlemodus\r\n- Auto: Wanneer er een beschikbare Xiaomi centrale hubgateway in het lokale netwerk is, geeft Home Assistant de voorkeur aan het verzenden van apparaatbedieningscommando's via de centrale hubgateway om lokale controle te bereiken. Als er geen centrale hubgateway in het lokale netwerk is, zal het proberen bedieningscommando's te verzenden via de Xiaomi LAN-controlefunctie. Alleen wanneer de bovenstaande lokale controlevoorwaarden niet zijn vervuld, worden de apparaatbedieningscommando's via de cloud verzonden.\r\n- Cloud: Alle bedieningscommando's worden via de cloud verzonden.",
|
||||
"data": {
|
||||
"home_infos": "Importeer apparaten uit huis",
|
||||
"devices_filter": "Apparaten filteren",
|
||||
"ctrl_mode": "Controlemodus"
|
||||
}
|
||||
},
|
||||
"devices_filter": {
|
||||
"title": "Apparaten filteren",
|
||||
"description": "## Gebruiksinstructies\r\nOndersteunt het filteren van apparaten op kamernaam, apparaattoegangstype en apparaattype, en ondersteunt ook het filteren op apparaatdimensie. De filterlogica is als volgt:\r\n- Eerst, volgens de statistische logica, de vereniging of doorsnede van alle opgenomen items verkrijgen, vervolgens de doorsnede of vereniging van de uitgesloten items verkrijgen, en ten slotte het [opgenomen samenvattingsresultaat] aftrekken van het [uitgesloten samenvattingsresultaat] om het [filterresultaat] te verkrijgen.\r\n- Als er geen opgenomen items zijn geselecteerd, betekent dit dat alles is opgenomen.\r\n### Filtermodus\r\n- Uitsluiten: Ongewenste items verwijderen.\r\n- Opnemen: Gewenste items opnemen.\r\n### Statistische Logica\r\n- EN-logica: Neem de doorsnede van alle items in dezelfde modus.\r\n- OF-logica: Neem de vereniging van alle items in dezelfde modus.\r\n\r\nU kunt ook naar de pagina [Configuratie > Apparaatlijst bijwerken] van het integratie-item gaan, [Apparaten filteren] aanvinken om opnieuw te filteren.",
|
||||
"data": {
|
||||
"room_filter_mode": "Kamerfiltermodus",
|
||||
"room_list": "Kamers",
|
||||
"type_filter_mode": "Apparaattypen filteren",
|
||||
"type_list": "Apparaattypen",
|
||||
"model_filter_mode": "Apparaatmodel filteren",
|
||||
"model_list": "Apparaatmodellen",
|
||||
"devices_filter_mode": "Apparaten filteren",
|
||||
"device_list": "Apparaatlijst",
|
||||
"statistics_logic": "Statistische logica"
|
||||
}
|
||||
},
|
||||
"update_trans_rules": {
|
||||
"title": "Bijwerken van entiteiten transformateregels",
|
||||
"description": "## Gebruiksinstructies\r\n- Werk de entiteitsinformatie van apparaten in de huidige integratie-instantie bij, inclusief MIoT-Spec-V2 meertalige configuratie, booleanvertaling en modelfiltering.\r\n- **Waarschuwing**: Dit is een globale configuratie en zal de lokale cache bijwerken. Dit zal alle integratie-instanties beïnvloeden.\r\n- Deze handeling duurt enige tijd, wees geduldig. Vink \"Bevestig bijwerken\" aan en klik op \"Volgende\" om **{urn_count}** regels bij te werken, anders overslaan.",
|
||||
"data": {
|
||||
"confirm": "Bevestig de update"
|
||||
}
|
||||
},
|
||||
"update_lan_ctrl_config": {
|
||||
"title": "Update LAN controleconfiguratie",
|
||||
"description": "## Gebruiksinstructies\r\nWerk de configuraties voor de Xiaomi LAN controlefunctie bij. Wanneer de cloud en de centrale hubgateway de apparaten niet kunnen bedienen, zal de integratie proberen de apparaten via het LAN te bedienen. Als er geen netwerkkaart is geselecteerd, zal de LAN controlefunctie niet werken.\r\n- Alleen MIoT-Spec-V2 compatibele IP-apparaten in het LAN worden ondersteund. Sommige apparaten die vóór 2020 zijn geproduceerd, ondersteunen mogelijk geen LAN controle of LAN abonnement.\r\n- Selecteer de netwerkkaart(en) op hetzelfde netwerk als de te bedienen apparaten. Meerdere netwerkkaarten kunnen worden geselecteerd. Als Home Assistant vanwege de meervoudige selectie van de netwerkkaarten twee of meer verbindingen heeft met het lokale netwerk, wordt aanbevolen om de verbinding met de beste netwerkverbinding te selecteren, anders kan dit een negatief effect hebben op de apparaten.\r\n- Als er terminalapparaten (Xiaomi-luidsprekers met scherm, mobiele telefoons, enz.) in het LAN zijn die lokale controle ondersteunen, kan het inschakelen van LAN-abonnement leiden tot lokale automatisering- en apparaatanomalieën.\r\n- **Waarschuwing**: Dit is een globale configuratie. Het zal alle integratie-instanties beïnvloeden. Gebruik het met voorzichtigheid.\r\n{notice_net_dup}",
|
||||
"data": {
|
||||
"net_interfaces": "Selecteer alstublieft de te gebruiken netwerkkaart",
|
||||
"enable_subscribe": "Zet LAN-abonnement aan"
|
||||
}
|
||||
},
|
||||
"network_detect_config": {
|
||||
"title": "Geïntegreerde Netwerkconfiguratie",
|
||||
"description": "## Gebruiksinstructie\r\n### Netwerkdetectieadres\r\nWordt gebruikt om te controleren of het netwerk correct functioneert. Als dit niet is ingesteld, wordt het standaardadres van het systeem gebruikt. Als de standaardadrescontrole mislukt, kunt u proberen een aangepast adres in te voeren.\r\n- U kunt meerdere detectieadressen invoeren, gescheiden door komma's, zoals `8.8.8.8,https://www.bing.com`\r\n- Als het een IP-adres is, wordt de detectie uitgevoerd via ping. Als het een HTTP(s)-adres is, wordt de detectie uitgevoerd via een HTTP GET-verzoek.\r\n- Als u het standaarddetectieadres van het systeem wilt herstellen, voert u een komma `,` in en klikt u op 'Volgende'.\r\n- **Deze configuratie is globaal en wijzigingen zullen andere integratie-instanties beïnvloeden. Wijzig met voorzichtigheid.**\r\n### Controleer Netwerkafhankelijkheden\r\nControleer een voor een de volgende netwerkafhankelijkheden om te zien of ze toegankelijk zijn. Als de gerelateerde adressen niet toegankelijk zijn, zal dit integratieproblemen veroorzaken.\r\n- OAuth2-authenticatieadres: `https://account.xiaomi.com/oauth2/authorize`.\r\n- Xiaomi HTTP API-adres: `https://{http_host}/app/v2/ha/oauth/get_token`.\r\n- Xiaomi SPEC API-adres: `https://miot-spec.org/miot-spec-v2/template/list/device`.\r\n- Xiaomi MQTT Broker-adres: `mqtts://{broker_host}`.",
|
||||
"data": {
|
||||
"network_detect_addr": "Netwerkdetectieadres",
|
||||
"check_network_deps": "Controleer Netwerkafhankelijkheden"
|
||||
}
|
||||
},
|
||||
"config_confirm": {
|
||||
"title": "Bevestig Configuratie",
|
||||
"description": "Hallo **{nick_name}**, bevestig alstublieft de nieuwste configuratie-informatie en klik vervolgens op INDENKEN.\r\nDe integratie zal opnieuw laden met de bijgewerkte configuratie.\r\n\r\nIntegratietaal:\t{lang_new}\r\nBijnaam:\t{nick_name_new}\r\nDebugmodus voor actie:\t{action_debug}\r\nVerberg niet-standaard gemaakte entiteiten:\t{hide_non_standard_entities}\r\nBreedte van de dode hoek van het gordijn:\t{cover_width_new}\r\nApparaatstatuswijzigingen weergeven:\t{display_devices_changed_notify}\r\nWijzigingen in apparaten:\tVoeg **{devices_add}** apparaten toe, Verwijder **{devices_remove}** apparaten\r\nWijzigingen in transformateregels:\tEr zijn in totaal **{trans_rules_count}** regels, en **{trans_rules_count_success}** regels zijn bijgewerkt",
|
||||
"data": {
|
||||
"confirm": "Bevestig de wijziging"
|
||||
}
|
||||
}
|
||||
},
|
||||
"progress": {
|
||||
"oauth": "### {link_left}Klik hier om opnieuw in te loggen{link_right}"
|
||||
},
|
||||
"error": {
|
||||
"not_auth": "Niet geauthenticeerd. Klik op de authenticatielink om de gebruikersidentiteit te verifiëren.",
|
||||
"get_token_error": "Mislukt bij het ophalen van inlogautorisatie-informatie (OAuth-token).",
|
||||
"get_homeinfo_error": "Mislukt bij het ophalen van huisinformatie.",
|
||||
"get_cert_error": "Mislukt bij het ophalen van het certificaat van de centrale hubgateway.",
|
||||
"no_devices": "Er zijn geen apparaten in het geselecteerde huis. Selecteer een huis met apparaten en ga verder.",
|
||||
"no_filter_devices": "Gefilterde apparaten zijn leeg. Selecteer geldige filtercriteria en ga verder.",
|
||||
"no_family_selected": "Geen huis geselecteerd.",
|
||||
"no_central_device": "[Centrale Hub Gateway Modus] vereist een beschikbare Xiaomi centrale hubgateway in het lokale netwerk waar Home Assistant zich bevindt. Controleer of het geselecteerde huis aan deze vereiste voldoet.",
|
||||
"mdns_discovery_error": "Lokaal apparaatsontdekkingsservice-exceptie.",
|
||||
"update_config_error": "Mislukt bij het bijwerken van configuratie-informatie.",
|
||||
"not_confirm": "Wijzigingen zijn niet bevestigd. Bevestig de wijziging voordat u deze indient.",
|
||||
"invalid_network_addr": "Ongeldig IP-adres of HTTP-adres gedetecteerd, voer een geldig adres in.",
|
||||
"invalid_ip_addr": "Onbereikbaar IP-adres gedetecteerd, voer een geldig IP-adres in.",
|
||||
"invalid_http_addr": "Onbereikbaar HTTP-adres gedetecteerd, voer een geldig HTTP-adres in.",
|
||||
"invalid_default_addr": "Standaard netwerkdetectieadres is onbereikbaar, controleer de netwerkconfiguratie of gebruik een aangepast netwerkdetectieadres.",
|
||||
"unreachable_oauth2_host": "Kan OAuth2-authenticatieadres niet bereiken, controleer de netwerkconfiguratie.",
|
||||
"unreachable_http_host": "Kan Xiaomi HTTP API-adres niet bereiken, controleer de netwerkconfiguratie.",
|
||||
"unreachable_spec_host": "Kan Xiaomi SPEC API-adres niet bereiken, controleer de netwerkconfiguratie.",
|
||||
"unreachable_mqtt_broker": "Kan Xiaomi MQTT Broker-adres niet bereiken, controleer de netwerkconfiguratie."
|
||||
},
|
||||
"abort": {
|
||||
"network_connect_error": "Configuratie mislukt. De netwerkverbinding is abnormaal. Controleer de netwerkinstellingen van de apparatuur.",
|
||||
"options_flow_error": "Integratie herconfiguratiefout: {error}",
|
||||
"re_add": "Voeg de integratie opnieuw toe. Foutmelding: {error}",
|
||||
"storage_error": "Integratie opslagmodule-exceptie. Probeer het opnieuw of voeg de integratie opnieuw toe: {error}",
|
||||
"inconsistent_account": "Accountinformatie is inconsistent. Log in met het juiste account."
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,225 @@
|
||||
{
|
||||
"config": {
|
||||
"flow_title": "Integração Xiaomi Home",
|
||||
"step": {
|
||||
"eula": {
|
||||
"title": "Aviso de risco",
|
||||
"description": "1. Suas informações de usuário Xiaomi e informações dos dispositivos serão armazenadas no sistema Home Assistant. **A Xiaomi não pode garantir a segurança do mecanismo de armazenamento do Home Assistant**. Você é responsável por evitar que suas informações sejam roubadas.\r\n2. Esta integração é mantida pela comunidade open-source. Podem haver problemas de estabilidade ou outros problemas. Ao encontrar falhas ou erros nesta integração, **você deve buscar ajuda da comunidade open-source em vez de contatar o suporte da Xiaomi**.\r\n3. Você precisará de certa habilidade técnica para manter seu ambiente operacional local. Esta integração não é amigável para iniciantes.\r\n4. Por favor, leia o arquivo README antes de começar.\n\n5. Para garantir o uso estável da integração e evitar abusos da interface, **esta integração só é permitida para uso no Home Assistant. Para mais detalhes, consulte a LICENSE**.",
|
||||
"data": {
|
||||
"eula": "Estou ciente dos riscos acima e disposto(a) a assumi-los voluntariamente ao utilizar a integração."
|
||||
}
|
||||
},
|
||||
"auth_config": {
|
||||
"title": "Configuração básica",
|
||||
"description": "### Região de Login\r\nSelecione a região da sua conta Xiaomi. Você pode encontrá-la no aplicativo Xiaomi Home > Perfil (localizado no menu inferior) > Configurações adicionais > Sobre o Xiaomi Home.\r\n### Idioma\r\nSelecione o idioma dos nomes dos dispositivos e entidades. Algumas frases sem tradução serão exibidas em inglês.\r\n### URL de Redirecionamento OAuth2\r\nO endereço de redirecionamento da autenticação OAuth2 é **[http://homeassistant.local:8123](http://homeassistant.local:8123)**. O Home Assistant precisa estar na mesma rede local que o terminal atual (por exemplo, o computador pessoal) e o terminal precisa acessar a página inicial do Home Assistant através desse endereço. Caso contrário, a autenticação de login pode falhar.\r\n### Configuração de Rede Integrada\r\nVerifique se a rede local está funcionando corretamente e se os recursos de rede relacionados estão acessíveis. **Recomenda-se selecionar isso ao adicionar pela primeira vez.**\r\n### Observações\r\n- Para usuários com centenas ou mais dispositivos Mi Home, a adição inicial da integração levará algum tempo. Seja paciente.\r\n- Se o Home Assistant estiver sendo executado em um ambiente Docker, certifique-se de que o modo de rede do Docker esteja definido como host, caso contrário a funcionalidade de controle local pode não funcionar corretamente.\r\n- A funcionalidade de controle local da integração tem algumas dependências. Por favor, leia o README atentamente.",
|
||||
"data": {
|
||||
"cloud_server": "Região de Login",
|
||||
"integration_language": "Idioma",
|
||||
"oauth_redirect_url": "URL de Redirecionamento OAuth2",
|
||||
"network_detect_config": "Configuração de Rede Integrada"
|
||||
}
|
||||
},
|
||||
"network_detect_config": {
|
||||
"title": "Configuração de Detecção de Rede",
|
||||
"description": "## Introdução ao Uso\r\n### Endereço de Detecção de Rede\r\nUsado para verificar se a rede está funcionando corretamente. Se não for definido, o endereço padrão do sistema será usado. Se a verificação do endereço padrão falhar, você pode tentar inserir um endereço personalizado.\r\n- Você pode inserir vários endereços de detecção, separados por vírgulas, como `8.8.8.8,https://www.bing.com`\r\n- Se for um endereço IP, a detecção será feita via ping. Se for um endereço HTTP(s), a detecção será feita via solicitação HTTP GET.\r\n- Se você deseja restaurar o endereço de detecção padrão do sistema, insira uma vírgula `,` e clique em 'Próximo'.\r\n- **Esta configuração é global e as alterações afetarão outras instâncias de integração. Modifique com cautela.**\r\n### Verificar Dependências de Rede\r\nVerifique uma por uma as seguintes dependências de rede para ver se são acessíveis. Se os endereços relacionados não forem acessíveis, isso causará problemas de integração.\r\n- Endereço de Autenticação OAuth2: `https://account.xiaomi.com/oauth2/authorize`.\r\n- Endereço da API HTTP da Xiaomi: `https://{http_host}/app/v2/ha/oauth/get_token`.\r\n- Endereço da API SPEC da Xiaomi: `https://miot-spec.org/miot-spec-v2/template/list/device`.\r\n- Endereço do Broker MQTT da Xiaomi: `mqtts://{broker_host}`.",
|
||||
"data": {
|
||||
"network_detect_addr": "Endereço de Detecção de Rede",
|
||||
"check_network_deps": "Verificar Dependências de Rede"
|
||||
}
|
||||
},
|
||||
"oauth_error": {
|
||||
"title": "Erro de Login",
|
||||
"description": "Clique em AVANÇAR para tentar novamente."
|
||||
},
|
||||
"homes_select": {
|
||||
"title": "Selecionar Família e Dispositivo",
|
||||
"description": "## Introdução\r\n### Importar a Família do Dispositivo\r\nA integração adicionará dispositivos da família selecionada.\r\n### Modo de Sincronização do Nome da Sala\r\nAo sincronizar dispositivos do APP Mi Home para o Home Assistant, a nomeação da área no Home Assistant seguirá as regras abaixo. Observe que o processo de sincronização não alterará as configurações de família e sala no APP Mi Home.\r\n- Não sincronizar: O dispositivo não será adicionado a nenhuma área.\r\n- Outras opções: A área à qual o dispositivo é adicionado será nomeada de acordo com o nome da família ou da sala no APP Mi Home.\r\n### Configurações Avançadas\r\nMostrar configurações avançadas para modificar as opções de configuração profissional da integração.\r\n\r\n \r\n### {nick_name} Olá! Por favor, selecione a família à qual você deseja adicionar o dispositivo.",
|
||||
"data": {
|
||||
"home_infos": "Importar a Família do Dispositivo",
|
||||
"area_name_rule": "Modo de Sincronização do Nome da Sala",
|
||||
"advanced_options": "Configurações Avançadas"
|
||||
}
|
||||
},
|
||||
"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### 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"
|
||||
}
|
||||
},
|
||||
"devices_filter": {
|
||||
"title": "Filtrar Dispositivos",
|
||||
"description": "## Instruções de Uso\r\nSuporta a filtragem de dispositivos por nome da sala, tipo de acesso do dispositivo e modelo do dispositivo, e também suporta a filtragem por dimensão do dispositivo. A lógica de filtragem é a seguinte:\r\n- Primeiro, de acordo com a lógica estatística, obtenha a união ou interseção de todos os itens incluídos, depois obtenha a interseção ou união dos itens excluídos, e finalmente subtraia o [resultado do resumo incluído] do [resultado do resumo excluído] para obter o [resultado do filtro].\r\n- Se nenhum item incluído for selecionado, significa que todos estão incluídos.\r\n### Modo de Filtragem\r\n- Excluir: Remover itens indesejados.\r\n- Incluir: Incluir itens desejados.\r\n### Lógica Estatística\r\n- Lógica E: Pegue a interseção de todos os itens no mesmo modo.\r\n- Lógica OU: Pegue a união de todos os itens no mesmo modo.\r\n\r\nVocê também pode ir para a página [Configuração > Atualizar Lista de Dispositivos] do item de integração, marcar [Filtrar Dispositivos] para refiltrar.",
|
||||
"data": {
|
||||
"room_filter_mode": "Filtrar por Sala",
|
||||
"room_list": "Salas",
|
||||
"type_filter_mode": "Filtrar por Tipo de Dispositivo",
|
||||
"type_list": "Tipos de Dispositivo",
|
||||
"model_filter_mode": "Filtrar por Modelo de Dispositivo",
|
||||
"model_list": "Modelos de Dispositivo",
|
||||
"devices_filter_mode": "Filtrar Dispositivos",
|
||||
"device_list": "Lista de Dispositivos",
|
||||
"statistics_logic": "Lógica de Estatísticas"
|
||||
}
|
||||
}
|
||||
},
|
||||
"progress": {
|
||||
"oauth": "### {link_left}Clique aqui para fazer login{link_right}\r\n(Você será redirecionado automaticamente para a próxima página após um login bem-sucedido)"
|
||||
},
|
||||
"error": {
|
||||
"eula_not_agree": "Por favor, leia o aviso de risco.",
|
||||
"get_token_error": "Falha ao obter as informações de autorização de login (token OAuth).",
|
||||
"get_homeinfo_error": "Falha ao obter as informações da casa.",
|
||||
"mdns_discovery_error": "Exceção no serviço de descoberta de dispositivos locais.",
|
||||
"get_cert_error": "Falha ao obter o certificado do gateway central.",
|
||||
"no_family_selected": "Nenhuma casa selecionada.",
|
||||
"no_devices": "Não há dispositivos na casa selecionada. Por favor, selecione uma casa com dispositivos e continue.",
|
||||
"no_filter_devices": "Os dispositivos filtrados estão vazios. Por favor, selecione critérios de filtro válidos e continue.",
|
||||
"no_central_device": "[Modo Gateway Central] requer um gateway central Xiaomi disponível na rede local onde o Home Assistant está. Verifique se a casa selecionada atende a esse requisito.",
|
||||
"invalid_network_addr": "Endereço IP ou HTTP inválido detectado, por favor insira um endereço válido.",
|
||||
"invalid_ip_addr": "Endereço IP inacessível detectado, por favor insira um endereço IP válido.",
|
||||
"invalid_http_addr": "Endereço HTTP inacessível detectado, por favor insira um endereço HTTP válido.",
|
||||
"invalid_default_addr": "O endereço de detecção de rede padrão está inacessível, por favor verifique a configuração da rede ou use um endereço de detecção de rede personalizado.",
|
||||
"unreachable_oauth2_host": "Não é possível acessar o endereço de autenticação OAuth2, verifique a configuração da rede.",
|
||||
"unreachable_http_host": "Não é possível acessar o endereço da API HTTP da Xiaomi, verifique a configuração da rede.",
|
||||
"unreachable_spec_host": "Não é possível acessar o endereço da API SPEC da Xiaomi, verifique a configuração da rede.",
|
||||
"unreachable_mqtt_broker": "Não é possível acessar o endereço do Broker MQTT da Xiaomi, verifique a configuração da rede."
|
||||
},
|
||||
"abort": {
|
||||
"ha_uuid_get_failed": "Falha ao obter o UUID do Home Assistant.",
|
||||
"network_connect_error": "Configuração falhou. A conexão de rede está anormal. Verifique a configuração de rede do equipamento.",
|
||||
"already_configured": "A configuração para este usuário já foi concluída. Vá para a página de integrações e clique no botão CONFIGURAR para modificações.",
|
||||
"invalid_auth_info": "As informações de autenticação expiraram. Vá para a página de integrações e clique em CONFIGURAR para reautenticar.",
|
||||
"config_flow_error": "Erro na configuração da integração: {error}."
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"step": {
|
||||
"auth_config": {
|
||||
"title": "Configuração de Autenticação",
|
||||
"description": "As informações de autenticação local expiraram. Por favor, reinicie o processo de autenticação.\r\n### Região de Login Atual: {cloud_server}\r\n### URL de Redirecionamento OAuth2\r\nO endereço de redirecionamento da autenticação OAuth2 é **[http://homeassistant.local:8123](http://homeassistant.local:8123)**. O Home Assistant precisa estar na mesma rede local que o terminal atual (por exemplo, o computador pessoal) e o terminal precisa acessar a página inicial do Home Assistant através desse endereço. Caso contrário, a autenticação de login pode falhar.",
|
||||
"data": {
|
||||
"oauth_redirect_url": "URL de Redirecionamento OAuth2"
|
||||
}
|
||||
},
|
||||
"oauth_error": {
|
||||
"title": "Ocorreu um erro durante o login.",
|
||||
"description": "Clique em AVANÇAR para tentar novamente."
|
||||
},
|
||||
"config_options": {
|
||||
"title": "Opções de Configuração",
|
||||
"description": "### Olá, {nick_name}\r\n\r\nID Xiaomi: {uid}\r\nRegião de Login Atual: {cloud_server}\r\nID da Instância de Integração: {instance_id}\r\n\r\nSelecione as opções que você deseja configurar e clique em AVANÇAR.",
|
||||
"data": {
|
||||
"integration_language": "Idioma da Integração",
|
||||
"update_user_info": "Atualizar informações do usuário",
|
||||
"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",
|
||||
"network_detect_config": "Configuração de Rede Integrada",
|
||||
"cover_dead_zone_width": "Largura da área cega da cortina"
|
||||
}
|
||||
},
|
||||
"update_user_info": {
|
||||
"title": "Atualizar Apelido do Usuário",
|
||||
"description": "Olá {nick_name}, você pode modificar seu apelido personalizado abaixo.",
|
||||
"data": {
|
||||
"nick_name": "Apelido"
|
||||
}
|
||||
},
|
||||
"homes_select": {
|
||||
"title": "Selecionar novamente Casa e Dispositivos",
|
||||
"description": "## Instruções de Uso\r\n### Importar dispositivos da casa\r\nA integração adicionará dispositivos das casas selecionadas.\r\n### Filtrar Dispositivos\r\nSuporta a filtragem de dispositivos por nome da sala, tipo de acesso do dispositivo e modelo do dispositivo, e também suporta a filtragem por dimensão do dispositivo. **{local_count}** dispositivos foram filtrados.\r\n### Modo de controle\r\n- Auto: Quando houver um gateway central Xiaomi disponível na rede local, o Home Assistant priorizará o envio de comandos através dele para obter controle local. Caso não haja, tentará enviar comandos através da função de controle LAN da Xiaomi. Somente se as condições anteriores não forem atendidas, o controle será feito pela nuvem.\r\n- Nuvem: Todos os comandos de controle são enviados pela nuvem.",
|
||||
"data": {
|
||||
"home_infos": "Importar dispositivos da casa",
|
||||
"devices_filter": "Filtrar Dispositivos",
|
||||
"ctrl_mode": "Modo de controle"
|
||||
}
|
||||
},
|
||||
"devices_filter": {
|
||||
"title": "Filtrar Dispositivos",
|
||||
"description": "## Instruções de Uso\r\nSuporta a filtragem de dispositivos por nome da sala, tipo de acesso do dispositivo e modelo do dispositivo, e também suporta a filtragem por dimensão do dispositivo. A lógica de filtragem é a seguinte:\r\n- Primeiro, de acordo com a lógica estatística, obtenha a união ou interseção de todos os itens incluídos, depois obtenha a interseção ou união dos itens excluídos, e finalmente subtraia o [resultado do resumo incluído] do [resultado do resumo excluído] para obter o [resultado do filtro].\r\n- Se nenhum item incluído for selecionado, significa que todos estão incluídos.\r\n### Modo de Filtragem\r\n- Excluir: Remover itens indesejados.\r\n- Incluir: Incluir itens desejados.\r\n### Lógica Estatística\r\n- Lógica E: Pegue a interseção de todos os itens no mesmo modo.\r\n- Lógica OU: Pegue a união de todos os itens no mesmo modo.\r\n\r\nVocê também pode ir para a página [Configuração > Atualizar Lista de Dispositivos] do item de integração, marcar [Filtrar Dispositivos] para refiltrar.",
|
||||
"data": {
|
||||
"room_filter_mode": "Filtrar por Sala",
|
||||
"room_list": "Salas",
|
||||
"type_filter_mode": "Filtrar por Tipo de Dispositivo",
|
||||
"type_list": "Tipos de Dispositivo",
|
||||
"model_filter_mode": "Filtrar por Modelo de Dispositivo",
|
||||
"model_list": "Modelos de Dispositivo",
|
||||
"devices_filter_mode": "Filtrar Dispositivos",
|
||||
"device_list": "Lista de Dispositivos",
|
||||
"statistics_logic": "Lógica de Estatísticas"
|
||||
}
|
||||
},
|
||||
"update_trans_rules": {
|
||||
"title": "Atualizar Regras de Transformação de Entidades",
|
||||
"description": "## Instruções de Uso\r\n- Atualiza as informações das entidades dos dispositivos na instância atual da integração, incluindo configuração multilíngue MIoT-Spec-V2, tradução de booleanos e filtragem de modelos.\r\n- **Aviso**: Esta é uma configuração global e atualizará o cache local. Ela afetará todas as instâncias da integração.\r\n- Esta operação levará algum tempo, seja paciente. Marque \"Confirmar atualização\" e clique em \"Avançar\" para iniciar a atualização de **{urn_count}** regras, caso contrário, pule.\r\n",
|
||||
"data": {
|
||||
"confirm": "Confirmar a atualização"
|
||||
}
|
||||
},
|
||||
"update_lan_ctrl_config": {
|
||||
"title": "Atualizar configuração de controle LAN",
|
||||
"description": "## Instruções de Uso\r\nAtualize as configurações para a função de controle LAN da Xiaomi. Quando a nuvem e o gateway central não puderem controlar os dispositivos, a integração tentará controlá-los através da LAN. Se nenhuma placa de rede for selecionada, o controle LAN não terá efeito.\r\n- Somente dispositivos compatíveis com MIoT-Spec-V2 conectados via IP na LAN são suportados. Alguns dispositivos produzidos antes de 2020 podem não suportar controle LAN ou assinatura LAN.\r\n- Selecione a(s) placa(s) de rede que estão na mesma rede que os dispositivos a serem controlados. É possível selecionar várias placas. Se o Home Assistant tiver duas ou mais conexões com a rede local devido a múltiplas placas, recomenda-se selecionar a que tiver melhor conexão de rede. Caso contrário, isso pode afetar o desempenho.\r\n- Se houver dispositivos terminais (alto-falantes Xiaomi com tela, celular, etc.) na LAN que suportem controle local, habilitar a assinatura LAN pode causar comportamentos anormais em automações e dispositivos locais.\r\n- **Aviso**: Esta é uma configuração global. Afetará todas as instâncias da integração. Use com cautela.\r\n{notice_net_dup}",
|
||||
"data": {
|
||||
"net_interfaces": "Selecione a placa de rede a ser usada",
|
||||
"enable_subscribe": "Habilitar assinatura LAN"
|
||||
}
|
||||
},
|
||||
"network_detect_config": {
|
||||
"title": "Configuração de Detecção de Rede",
|
||||
"description": "## Introdução ao Uso\r\n### Endereço de Detecção de Rede\r\nUsado para verificar se a rede está funcionando corretamente. Se não for definido, o endereço padrão do sistema será usado. Se a verificação do endereço padrão falhar, você pode tentar inserir um endereço personalizado.\r\n- Você pode inserir vários endereços de detecção, separados por vírgulas, como `8.8.8.8,https://www.bing.com`\r\n- Se for um endereço IP, a detecção será feita via ping. Se for um endereço HTTP(s), a detecção será feita via solicitação HTTP GET.\r\n- Se você deseja restaurar o endereço de detecção padrão do sistema, insira uma vírgula `,` e clique em 'Próximo'.\r\n- **Esta configuração é global e as alterações afetarão outras instâncias de integração. Modifique com cautela.**\r\n### Verificar Dependências de Rede\r\nVerifique uma por uma as seguintes dependências de rede para ver se são acessíveis. Se os endereços relacionados não forem acessíveis, isso causará problemas de integração.\r\n- Endereço de Autenticação OAuth2: `https://account.xiaomi.com/oauth2/authorize`.\r\n- Endereço da API HTTP da Xiaomi: `https://{http_host}/app/v2/ha/oauth/get_token`.\r\n- Endereço da API SPEC da Xiaomi: `https://miot-spec.org/miot-spec-v2/template/list/device`.\r\n- Endereço do Broker MQTT da Xiaomi: `mqtts://{broker_host}`.",
|
||||
"data": {
|
||||
"network_detect_addr": "Endereço de Detecção de Rede",
|
||||
"check_network_deps": "Verificar Dependências de Rede"
|
||||
}
|
||||
},
|
||||
"config_confirm": {
|
||||
"title": "Confirmar Configuração",
|
||||
"description": "Olá **{nick_name}**, confirme as informações da configuração mais recente e depois clique em ENVIAR.\r\nA integração será recarregada com a configuração atualizada.\r\n\r\nIdioma da Integração:\t{lang_new}\r\nApelido:\t{nick_name_new}\r\nModo de depuração para ação:\t{action_debug}\r\nOcultar entidades não padrão criadas:\t{hide_non_standard_entities}\r\nLargura da área cega da cortina:\t{cover_width_new}\r\nExibir notificações de mudança de status do dispositivo:\t{display_devices_changed_notify}\r\nAlterações de Dispositivos:\tAdicionar **{devices_add}** dispositivos, Remover **{devices_remove}** dispositivos\r\nAlteração nas Regras de Transformação:\tUm total de **{trans_rules_count}** regras, e **{trans_rules_count_success}** regras atualizadas",
|
||||
"data": {
|
||||
"confirm": "Confirmar a mudança"
|
||||
}
|
||||
}
|
||||
},
|
||||
"progress": {
|
||||
"oauth": "### {link_left}Por favor, clique aqui para relogar{link_right}"
|
||||
},
|
||||
"error": {
|
||||
"not_auth": "Não autenticado. Por favor, clique no link de autenticação para autenticar sua identidade.",
|
||||
"get_token_error": "Falha ao obter as informações de autorização de login (token OAuth).",
|
||||
"get_homeinfo_error": "Falha ao obter as informações da casa.",
|
||||
"get_cert_error": "Falha ao obter o certificado do gateway central.",
|
||||
"no_devices": "Não há dispositivos na casa selecionada. Por favor, selecione uma casa com dispositivos e continue.",
|
||||
"no_filter_devices": "Os dispositivos filtrados estão vazios. Por favor, selecione critérios de filtro válidos e continue.",
|
||||
"no_family_selected": "Nenhuma casa selecionada.",
|
||||
"no_central_device": "[Modo Gateway Central] requer um gateway central Xiaomi disponível na rede local onde o Home Assistant está. Verifique se a casa selecionada atende a esse requisito.",
|
||||
"mdns_discovery_error": "Exceção no serviço de descoberta de dispositivos locais.",
|
||||
"update_config_error": "Falha ao atualizar as informações de configuração.",
|
||||
"not_confirm": "As alterações não foram confirmadas. Por favor, confirme a mudança antes de enviar.",
|
||||
"invalid_network_addr": "Endereço IP ou HTTP inválido detectado, por favor insira um endereço válido.",
|
||||
"invalid_ip_addr": "Endereço IP inacessível detectado, por favor insira um endereço IP válido.",
|
||||
"invalid_http_addr": "Endereço HTTP inacessível detectado, por favor insira um endereço HTTP válido.",
|
||||
"invalid_default_addr": "O endereço de detecção de rede padrão está inacessível, por favor verifique a configuração da rede ou use um endereço de detecção de rede personalizado.",
|
||||
"unreachable_oauth2_host": "Não é possível acessar o endereço de autenticação OAuth2, verifique a configuração da rede.",
|
||||
"unreachable_http_host": "Não é possível acessar o endereço da API HTTP da Xiaomi, verifique a configuração da rede.",
|
||||
"unreachable_spec_host": "Não é possível acessar o endereço da API SPEC da Xiaomi, verifique a configuração da rede.",
|
||||
"unreachable_mqtt_broker": "Não é possível acessar o endereço do Broker MQTT da Xiaomi, verifique a configuração da rede."
|
||||
},
|
||||
"abort": {
|
||||
"network_connect_error": "Configuração falhou. A conexão de rede está anormal. Verifique a configuração da rede do equipamento.",
|
||||
"options_flow_error": "Erro na reconfiguração da integração: {error}",
|
||||
"re_add": "Por favor, adicione novamente a integração. Mensagem de erro: {error}",
|
||||
"storage_error": "Exceção no módulo de armazenamento da integração. Tente novamente ou readicione a integração: {error}",
|
||||
"inconsistent_account": "As informações da conta são inconsistentes. Por favor, faça login com a conta correta."
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,225 @@
|
||||
{
|
||||
"config": {
|
||||
"flow_title": "Integração Xiaomi Home",
|
||||
"step": {
|
||||
"eula": {
|
||||
"title": "Aviso de Risco",
|
||||
"description": "1. As informações da sua conta Xiaomi e dos seus dispositivos serão armazenadas no sistema do Home Assistant. **A Xiaomi não pode garantir a segurança do mecanismo de armazenamento do Home Assistant**. É da sua responsabilidade impedir que a sua informação seja roubada.\r\n2. Esta integração é mantida pela comunidade open-source. Podem ocorrer problemas de estabilidade ou outros. Ao encontrar problemas ou falhas nesta integração, **deverá procurar ajuda junto da comunidade open-source, em vez de contactar o apoio ao cliente da Xiaomi**.\r\n3. Necessitará de algumas competências técnicas para manter o seu ambiente de operação local. Esta integração não é intuitiva para utilizadores iniciantes.\r\n4. Leia o ficheiro README antes de começar.\n\n5. Para garantir uma utilização estável da integração e prevenir uso indevido, **esta integração só pode ser utilizada no Home Assistant. Para mais detalhes, consulte a LICENSE**.",
|
||||
"data": {
|
||||
"eula": "Estou ciente dos riscos acima e disposto(a) a assumi-los voluntariamente ao utilizar a integração."
|
||||
}
|
||||
},
|
||||
"auth_config": {
|
||||
"title": "Configuração Básica",
|
||||
"description": "### Região de Login\r\nSelecione a região da sua conta Xiaomi. Pode encontrá-la na aplicação Xiaomi Home > Perfil (menu inferior) > Configurações adicionais > Sobre o Xiaomi Home.\r\n### Idioma\r\nSelecione o idioma para os nomes de dispositivos e entidades. Algumas frases sem tradução serão apresentadas em inglês.\r\n### URL de Redirecionamento OAuth2\r\nO endereço de redirecionamento para a autenticação OAuth2 é **[http://homeassistant.local:8123](http://homeassistant.local:8123)**. O Home Assistant deve estar na mesma rede local que o terminal atual (por exemplo, o computador pessoal) e esse terminal deve conseguir aceder à página inicial do Home Assistant através deste endereço. Caso contrário, a autenticação de login pode falhar.\r\n### Configuração de Rede Integrada\r\nVerifique se a rede local está funcionando corretamente e se os recursos de rede relacionados estão acessíveis. **Recomenda-se selecionar isso ao adicionar pela primeira vez.**\r\n### Notas\r\n- Para utilizadores com centenas (ou mais) de dispositivos Mi Home, a adição inicial da integração demorará algum tempo. Seja paciente.\r\n- Se o Home Assistant estiver a ser executado num ambiente Docker, assegure-se de que o modo de rede do Docker está configurado como host; caso contrário, a funcionalidade de controlo local pode não funcionar corretamente.\r\n- A funcionalidade de controlo local da integração tem algumas dependências. Leia cuidadosamente o README.",
|
||||
"data": {
|
||||
"cloud_server": "Região de Login",
|
||||
"integration_language": "Idioma",
|
||||
"oauth_redirect_url": "URL de Redirecionamento OAuth2",
|
||||
"network_detect_config": "Configuração de Rede Integrada"
|
||||
}
|
||||
},
|
||||
"network_detect_config": {
|
||||
"title": "Configuração de Rede Integrada",
|
||||
"description": "## Introdução ao Uso\r\n### Endereço de Detecção de Rede\r\nUsado para verificar se a rede está funcionando corretamente. Se não for definido, o endereço padrão do sistema será usado. Se a verificação do endereço padrão falhar, você pode tentar inserir um endereço personalizado.\r\n- Você pode inserir vários endereços de detecção, separados por vírgulas, como `8.8.8.8,https://www.bing.com`\r\n- Se for um endereço IP, a detecção será feita via ping. Se for um endereço HTTP(s), a detecção será feita via solicitação HTTP GET.\r\n- Se você deseja restaurar o endereço de detecção padrão do sistema, insira uma vírgula `,` e clique em 'Próximo'.\r\n- **Esta configuração é global e as alterações afetarão outras instâncias de integração. Modifique com cautela.**\r\n### Verificar Dependências de Rede\r\nVerifique uma por uma as seguintes dependências de rede para ver se são acessíveis. Se os endereços relacionados não forem acessíveis, isso causará problemas de integração.\r\n- Endereço de Autenticação OAuth2: `https://account.xiaomi.com/oauth2/authorize`.\r\n- Endereço da API HTTP da Xiaomi: `https://{http_host}/app/v2/ha/oauth/get_token`.\r\n- Endereço da API SPEC da Xiaomi: `https://miot-spec.org/miot-spec-v2/template/list/device`.\r\n- Endereço do Broker MQTT da Xiaomi: `mqtts://{broker_host}`.",
|
||||
"data": {
|
||||
"network_detect_addr": "Endereço de Detecção de Rede",
|
||||
"check_network_deps": "Verificar Dependências de Rede"
|
||||
}
|
||||
},
|
||||
"oauth_error": {
|
||||
"title": "Erro de Login",
|
||||
"description": "Clique em SEGUINTE para tentar novamente."
|
||||
},
|
||||
"homes_select": {
|
||||
"title": "Selecionar Família e Dispositivo",
|
||||
"description": "## Introdução\r\n### Importar a Família do Dispositivo\r\nA integração adicionará dispositivos da família selecionada.\r\n### Modo de Sincronização do Nome da Sala\r\nAo sincronizar dispositivos do APP Mi Home para o Home Assistant, a nomeação da área no Home Assistant seguirá as regras abaixo. Observe que o processo de sincronização não alterará as configurações de família e sala no APP Mi Home.\r\n- Não sincronizar: O dispositivo não será adicionado a nenhuma área.\r\n- Outras opções: A área à qual o dispositivo é adicionado será nomeada de acordo com o nome da família ou da sala no APP Mi Home.\r\n### Configurações Avançadas\r\nMostrar configurações avançadas para modificar as opções de configuração profissional da integração.\r\n\r\n \r\n### {nick_name} Olá! Por favor, selecione a família à qual você deseja adicionar o dispositivo.",
|
||||
"data": {
|
||||
"home_infos": "Importar a Família do Dispositivo",
|
||||
"area_name_rule": "Modo de Sincronização do Nome da Sala",
|
||||
"advanced_options": "Configurações Avançadas"
|
||||
}
|
||||
},
|
||||
"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### 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"
|
||||
}
|
||||
},
|
||||
"devices_filter": {
|
||||
"title": "Filtrar Dispositivos",
|
||||
"description": "## Instruções de Utilização\r\nSuporta a filtragem de dispositivos por nome da sala, tipo de acesso do dispositivo e modelo do dispositivo, e também suporta a filtragem por dimensão do dispositivo. A lógica de filtragem é a seguinte:\r\n- Primeiro, de acordo com a lógica estatística, obtenha a união ou interseção de todos os itens incluídos, depois obtenha a interseção ou união dos itens excluídos, e finalmente subtraia o [resultado do resumo incluído] do [resultado do resumo excluído] para obter o [resultado do filtro].\r\n- Se nenhum item incluído for selecionado, significa que todos estão incluídos.\r\n### Modo de Filtragem\r\n- Excluir: Remover itens indesejados.\r\n- Incluir: Incluir itens desejados.\r\n### Lógica Estatística\r\n- Lógica E: Pegue a interseção de todos os itens no mesmo modo.\r\n- Lógica OU: Pegue a união de todos os itens no mesmo modo.\r\n\r\nVocê também pode ir para a página [Configuração > Atualizar Lista de Dispositivos] do item de integração, marcar [Filtrar Dispositivos] para refiltrar.",
|
||||
"data": {
|
||||
"room_filter_mode": "Filtrar por Sala",
|
||||
"room_list": "Salas",
|
||||
"type_filter_mode": "Filtrar por Tipo de Dispositivo",
|
||||
"type_list": "Tipos de Dispositivo",
|
||||
"model_filter_mode": "Filtrar por Modelo de Dispositivo",
|
||||
"model_list": "Modelos de Dispositivo",
|
||||
"devices_filter_mode": "Filtrar Dispositivos",
|
||||
"device_list": "Lista de Dispositivos",
|
||||
"statistics_logic": "Lógica de Estatísticas"
|
||||
}
|
||||
}
|
||||
},
|
||||
"progress": {
|
||||
"oauth": "### {link_left}Clique aqui para iniciar sessão{link_right}\r\n(Será automaticamente redirecionado após um login bem-sucedido)"
|
||||
},
|
||||
"error": {
|
||||
"eula_not_agree": "Por favor, leia o aviso de risco.",
|
||||
"get_token_error": "Não foi possível obter a informação de autorização de login (token OAuth).",
|
||||
"get_homeinfo_error": "Não foi possível obter a informação da casa.",
|
||||
"mdns_discovery_error": "Exceção no serviço de descoberta de dispositivos locais.",
|
||||
"get_cert_error": "Não foi possível obter o certificado do gateway central.",
|
||||
"no_family_selected": "Nenhuma casa selecionada.",
|
||||
"no_devices": "Não há dispositivos na casa selecionada. Por favor, selecione uma casa com dispositivos e continue.",
|
||||
"no_filter_devices": "Os dispositivos filtrados estão vazios. Por favor, selecione critérios de filtro válidos e continue.",
|
||||
"no_central_device": "O [Modo Gateway Central] requer um gateway central Xiaomi disponível na rede local onde o Home Assistant está. Verifique se a casa selecionada cumpre este requisito.",
|
||||
"invalid_network_addr": "Endereço IP ou HTTP inválido detectado, por favor insira um endereço válido.",
|
||||
"invalid_ip_addr": "Endereço IP inacessível detectado, por favor insira um endereço IP válido.",
|
||||
"invalid_http_addr": "Endereço HTTP inacessível detectado, por favor insira um endereço HTTP válido.",
|
||||
"invalid_default_addr": "O endereço de detecção de rede padrão está inacessível, por favor verifique a configuração da rede ou use um endereço de detecção de rede personalizado.",
|
||||
"unreachable_oauth2_host": "Não é possível acessar o endereço de autenticação OAuth2, verifique a configuração da rede.",
|
||||
"unreachable_http_host": "Não é possível acessar o endereço da API HTTP da Xiaomi, verifique a configuração da rede.",
|
||||
"unreachable_spec_host": "Não é possível acessar o endereço da API SPEC da Xiaomi, verifique a configuração da rede.",
|
||||
"unreachable_mqtt_broker": "Não é possível acessar o endereço do Broker MQTT da Xiaomi, verifique a configuração da rede."
|
||||
},
|
||||
"abort": {
|
||||
"ha_uuid_get_failed": "Não foi possível obter o UUID do Home Assistant.",
|
||||
"network_connect_error": "A configuração falhou. A ligação de rede é anormal. Verifique a configuração de rede do equipamento.",
|
||||
"already_configured": "A configuração para este utilizador já foi concluída. Vá à página de integrações e clique em CONFIGURAR para efetuar alterações.",
|
||||
"invalid_auth_info": "A informação de autenticação expirou. Vá à página de integrações e clique em CONFIGURAR para reautenticar.",
|
||||
"config_flow_error": "Erro na configuração da integração: {error}."
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"step": {
|
||||
"auth_config": {
|
||||
"title": "Configuração de Autenticação",
|
||||
"description": "A informação de autenticação local expirou. Por favor, reinicie o processo de autenticação.\r\n### Região de Login Atual: {cloud_server}\r\n### URL de Redirecionamento OAuth2\r\nO endereço de redirecionamento para a autenticação OAuth2 é **[http://homeassistant.local:8123](http://homeassistant.local:8123)**. O Home Assistant deve estar na mesma rede local que o terminal atual (por exemplo, o computador) e esse terminal deve conseguir aceder à página inicial do Home Assistant através deste endereço. Caso contrário, a autenticação poderá falhar.",
|
||||
"data": {
|
||||
"oauth_redirect_url": "URL de Redirecionamento OAuth2"
|
||||
}
|
||||
},
|
||||
"oauth_error": {
|
||||
"title": "Ocorreu um erro durante o login.",
|
||||
"description": "Clique em SEGUINTE para tentar novamente."
|
||||
},
|
||||
"config_options": {
|
||||
"title": "Opções de Configuração",
|
||||
"description": "### Olá, {nick_name}\r\n\r\nID Xiaomi: {uid}\r\nRegião de Login Atual: {cloud_server}\r\nID da Instância de Integração: {instance_id}\r\n\r\nSelecione as opções que pretende configurar e depois clique em SEGUINTE.",
|
||||
"data": {
|
||||
"integration_language": "Idioma da Integração",
|
||||
"update_user_info": "Atualizar informação do utilizador",
|
||||
"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",
|
||||
"network_detect_config": "Configuração de Rede Integrada",
|
||||
"cover_dead_zone_width": "Largura da zona cega da cortina"
|
||||
}
|
||||
},
|
||||
"update_user_info": {
|
||||
"title": "Atualizar Alcunha do Utilizador",
|
||||
"description": "Olá {nick_name}, pode modificar a sua alcunha personalizada abaixo.",
|
||||
"data": {
|
||||
"nick_name": "Alcunha"
|
||||
}
|
||||
},
|
||||
"homes_select": {
|
||||
"title": "Selecionar novamente a Casa e os Dispositivos",
|
||||
"description": "## Instruções de Utilização\r\n### Importar dispositivos da casa\r\nA integração adicionará dispositivos das casas selecionadas.\r\n### Filtrar Dispositivos\r\nSuporta a filtragem de dispositivos por nome da sala, tipo de acesso do dispositivo e modelo do dispositivo, e também suporta a filtragem por dimensão do dispositivo. **{local_count}** dispositivos foram filtrados.\r\n### Modo de Controlo\r\n- Automático: Quando houver um gateway central Xiaomi disponível na rede local, o Home Assistant priorizará o envio de comandos através dele para obter controlo local. Se não existir um gateway central, tentará enviar comandos através da função de controlo LAN da Xiaomi. Apenas se estas condições não forem satisfeitas, os comandos serão enviados pela nuvem.\r\n- Nuvem: Todos os comandos de controlo são enviados através da nuvem.",
|
||||
"data": {
|
||||
"home_infos": "Importar dispositivos da casa",
|
||||
"devices_filter": "Filtrar Dispositivos",
|
||||
"ctrl_mode": "Modo de Controlo"
|
||||
}
|
||||
},
|
||||
"devices_filter": {
|
||||
"title": "Filtrar Dispositivos",
|
||||
"description": "## Instruções de Utilização\r\nSuporta a filtragem de dispositivos por nome da sala, tipo de acesso do dispositivo e modelo do dispositivo, e também suporta a filtragem por dimensão do dispositivo. A lógica de filtragem é a seguinte:\r\n- Primeiro, de acordo com a lógica estatística, obtenha a união ou interseção de todos os itens incluídos, depois obtenha a interseção ou união dos itens excluídos, e finalmente subtraia o [resultado do resumo incluído] do [resultado do resumo excluído] para obter o [resultado do filtro].\r\n- Se nenhum item incluído for selecionado, significa que todos estão incluídos.\r\n### Modo de Filtragem\r\n- Excluir: Remover itens indesejados.\r\n- Incluir: Incluir itens desejados.\r\n### Lógica Estatística\r\n- Lógica E: Pegue a interseção de todos os itens no mesmo modo.\r\n- Lógica OU: Pegue a união de todos os itens no mesmo modo.\r\n\r\nVocê também pode ir para a página [Configuração > Atualizar Lista de Dispositivos] do item de integração, marcar [Filtrar Dispositivos] para refiltrar.",
|
||||
"data": {
|
||||
"room_filter_mode": "Filtrar por Sala",
|
||||
"room_list": "Salas",
|
||||
"type_filter_mode": "Filtrar por Tipo de Dispositivo",
|
||||
"type_list": "Tipos de Dispositivo",
|
||||
"model_filter_mode": "Filtrar por Modelo de Dispositivo",
|
||||
"model_list": "Modelos de Dispositivo",
|
||||
"devices_filter_mode": "Filtrar Dispositivos",
|
||||
"device_list": "Lista de Dispositivos",
|
||||
"statistics_logic": "Lógica de Estatísticas"
|
||||
}
|
||||
},
|
||||
"update_trans_rules": {
|
||||
"title": "Atualizar Regras de Transformação de Entidades",
|
||||
"description": "## Instruções de Utilização\r\n- Atualiza a informação das entidades dos dispositivos na instância atual da integração, incluindo configuração multilingue MIoT-Spec-V2, tradução de booleanos e filtragem de modelos.\r\n- **Aviso**: Esta é uma configuração global e atualizará a cache local, afetando todas as instâncias da integração.\r\n- Esta operação levará algum tempo, seja paciente. Selecione \"Confirmar a atualização\" e clique em \"SEGUINTE\" para iniciar a atualização de **{urn_count}** regras, caso contrário, ignore esta etapa.\r\n",
|
||||
"data": {
|
||||
"confirm": "Confirmar a atualização"
|
||||
}
|
||||
},
|
||||
"update_lan_ctrl_config": {
|
||||
"title": "Atualizar Configuração de Controlo LAN",
|
||||
"description": "## Instruções de Utilização\r\nAtualize as configurações para a funcionalidade de controlo LAN da Xiaomi. Quando a nuvem e o gateway central não puderem controlar os dispositivos, a integração tentará controlá-los através da LAN. Se não selecionar nenhuma interface de rede, o controlo LAN não terá efeito.\r\n- Apenas dispositivos compatíveis com MIoT-Spec-V2 ligados via IP na LAN são suportados. Alguns dispositivos produzidos antes de 2020 podem não suportar controlo LAN ou subscrição LAN.\r\n- Selecione a(s) placa(s) de rede que estejam na mesma rede que os dispositivos a controlar. Pode selecionar várias placas. Se o Home Assistant tiver duas ou mais ligações à rede local devido à seleção de várias placas, é recomendado selecionar a que tiver melhor ligação, caso contrário poderá afetar negativamente o desempenho dos dispositivos.\r\n- Se houver dispositivos terminais (colunas Xiaomi com ecrã, telemóveis, etc.) na LAN que suportem controlo local, a ativação da subscrição LAN pode causar anomalias em automações e dispositivos locais.\r\n- **Aviso**: Esta é uma configuração global, afetando todas as instâncias da integração. Utilize com cautela.\r\n{notice_net_dup}",
|
||||
"data": {
|
||||
"net_interfaces": "Selecione a(s) interface(s) de rede a utilizar",
|
||||
"enable_subscribe": "Ativar subscrição LAN"
|
||||
}
|
||||
},
|
||||
"network_detect_config": {
|
||||
"title": "Configuração de Rede Integrada",
|
||||
"description": "## Introdução ao Uso\r\n### Endereço de Detecção de Rede\r\nUsado para verificar se a rede está funcionando corretamente. Se não for definido, o endereço padrão do sistema será usado. Se a verificação do endereço padrão falhar, você pode tentar inserir um endereço personalizado.\r\n- Você pode inserir vários endereços de detecção, separados por vírgulas, como `8.8.8.8,https://www.bing.com`\r\n- Se for um endereço IP, a detecção será feita via ping. Se for um endereço HTTP(s), a detecção será feita via solicitação HTTP GET.\r\n- Se você deseja restaurar o endereço de detecção padrão do sistema, insira uma vírgula `,` e clique em 'Próximo'.\r\n- **Esta configuração é global e as alterações afetarão outras instâncias de integração. Modifique com cautela.**\r\n### Verificar Dependências de Rede\r\nVerifique uma por uma as seguintes dependências de rede para ver se são acessíveis. Se os endereços relacionados não forem acessíveis, isso causará problemas de integração.\r\n- Endereço de Autenticação OAuth2: `https://account.xiaomi.com/oauth2/authorize`.\r\n- Endereço da API HTTP da Xiaomi: `https://{http_host}/app/v2/ha/oauth/get_token`.\r\n- Endereço da API SPEC da Xiaomi: `https://miot-spec.org/miot-spec-v2/template/list/device`.\r\n- Endereço do Broker MQTT da Xiaomi: `mqtts://{broker_host}`.",
|
||||
"data": {
|
||||
"network_detect_addr": "Endereço de Detecção de Rede",
|
||||
"check_network_deps": "Verificar Dependências de Rede"
|
||||
}
|
||||
},
|
||||
"config_confirm": {
|
||||
"title": "Confirmar Configuração",
|
||||
"description": "Olá **{nick_name}**, confirme a informação da configuração mais recente e depois clique em SUBMETER.\r\nA integração será recarregada com a configuração atualizada.\r\n\r\nIdioma da Integração:\t{lang_new}\r\nAlcunha:\t{nick_name_new}\r\nModo de depuração de ação:\t{action_debug}\r\nOcultar entidades não padrão:\t{hide_non_standard_entities}\r\nLargura da zona cega da cortina:\t{cover_width_new}\r\nExibir notificações de mudança de status do dispositivo:\t{display_devices_changed_notify}\r\nAlterações aos Dispositivos:\tAdicionar **{devices_add}** dispositivos, Remover **{devices_remove}** dispositivos\r\nAlteração das Regras de Transformação:\tExistem **{trans_rules_count}** regras no total, com **{trans_rules_count_success}** regras atualizadas",
|
||||
"data": {
|
||||
"confirm": "Confirmar a alteração"
|
||||
}
|
||||
}
|
||||
},
|
||||
"progress": {
|
||||
"oauth": "### {link_left}Por favor, clique aqui para voltar a iniciar sessão{link_right}"
|
||||
},
|
||||
"error": {
|
||||
"not_auth": "Não autenticado. Por favor, clique no link de autenticação para confirmar a sua identidade.",
|
||||
"get_token_error": "Não foi possível obter a informação de autorização de login (token OAuth).",
|
||||
"get_homeinfo_error": "Não foi possível obter a informação da casa.",
|
||||
"get_cert_error": "Não foi possível obter o certificado do gateway central.",
|
||||
"no_devices": "Não há dispositivos na casa selecionada. Por favor, selecione uma casa com dispositivos e continue.",
|
||||
"no_filter_devices": "Os dispositivos filtrados estão vazios. Por favor, selecione critérios de filtro válidos e continue.",
|
||||
"no_family_selected": "Nenhuma casa selecionada.",
|
||||
"no_central_device": "O [Modo Gateway Central] requer um gateway central Xiaomi disponível na rede local onde o Home Assistant está. Verifique se a casa selecionada cumpre este requisito.",
|
||||
"mdns_discovery_error": "Exceção no serviço de descoberta de dispositivos locais.",
|
||||
"update_config_error": "Não foi possível atualizar a informação de configuração.",
|
||||
"not_confirm": "As alterações não foram confirmadas. Por favor, confirme a alteração antes de submeter.",
|
||||
"invalid_network_addr": "Endereço IP ou HTTP inválido detectado, por favor insira um endereço válido.",
|
||||
"invalid_ip_addr": "Endereço IP inacessível detectado, por favor insira um endereço IP válido.",
|
||||
"invalid_http_addr": "Endereço HTTP inacessível detectado, por favor insira um endereço HTTP válido.",
|
||||
"invalid_default_addr": "O endereço de detecção de rede padrão está inacessível, por favor verifique a configuração da rede ou use um endereço de detecção de rede personalizado.",
|
||||
"unreachable_oauth2_host": "Não é possível acessar o endereço de autenticação OAuth2, verifique a configuração da rede.",
|
||||
"unreachable_http_host": "Não é possível acessar o endereço da API HTTP da Xiaomi, verifique a configuração da rede.",
|
||||
"unreachable_spec_host": "Não é possível acessar o endereço da API SPEC da Xiaomi, verifique a configuração da rede.",
|
||||
"unreachable_mqtt_broker": "Não é possível acessar o endereço do Broker MQTT da Xiaomi, verifique a configuração da rede."
|
||||
},
|
||||
"abort": {
|
||||
"network_connect_error": "A configuração falhou. A ligação de rede é anormal. Verifique a configuração da rede do equipamento.",
|
||||
"options_flow_error": "Erro na reconfiguração da integração: {error}",
|
||||
"re_add": "Por favor, volte a adicionar a integração. Mensagem de erro: {error}",
|
||||
"storage_error": "Exceção no módulo de armazenamento da integração. Tente novamente ou volte a adicionar a integração: {error}",
|
||||
"inconsistent_account": "A informação da conta é inconsistente. Por favor, inicie sessão com a conta correta."
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,225 @@
|
||||
{
|
||||
"config": {
|
||||
"flow_title": "Ми Дома Интеграция",
|
||||
"step": {
|
||||
"eula": {
|
||||
"title": "Риск-информирование",
|
||||
"description": "1. Ваша **информация о пользователе Xiaomi и информация об устройстве** будет храниться в вашей системе Home Assistant. **Xiaomi не может гарантировать безопасность механизма хранения Home Assistant**. Вы несете ответственность за предотвращение кражи вашей информации.\r\n2. Эта интеграция поддерживается сообществом Open Source и может иметь проблемы с устойчивостью или другими проблемами, если вы столкнулись с проблемами при использовании этой интеграции, **вы должны обратиться за помощью к сообществу Open Source, а не к службе поддержки Xiaomi**.\r\n3. Вам нужно иметь определенные технические навыки для поддержания вашей локальной рабочей среды, эта интеграция не является дружественной для новичков.\r\n4. Перед использованием этой интеграции, **внимательно прочитайте README**.\r\n5. Чтобы обеспечить стабильное использование интеграции и предотвратить злоупотребление интерфейсом, **эта интеграция разрешена только для использования в Home Assistant. Для получения подробной информации, пожалуйста, обратитесь к LICENSE**.",
|
||||
"data": {
|
||||
"eula": "Я ознакомлен с вышеуказанными рисками и добровольно несу связанные с использованием интеграции риски."
|
||||
}
|
||||
},
|
||||
"auth_config": {
|
||||
"title": "Основные настройки",
|
||||
"description": "### Регион входа в систему\r\nВыберите регион, в котором находится ваша учетная запись Xiaomi. Вы можете узнать об этом в `Xiaomi Home> Мой (в нижнем меню)> Дополнительные настройки> О Xiaomi Home`.\r\n### Язык\r\nВыберите язык, используемый для имен устройств и сущностей. Части предложений, которые не имеют перевода, будут отображаться на английском языке.\r\n### Адрес перенаправления для аутентификации OAuth2\r\nАдрес перенаправления для аутентификации OAuth2 - ** [http: //homeassistant.local: 8123] (http: //homeassistant.local: 8123) **, Home Assistant должен находиться в одной локальной сети с текущим терминалом (например, персональный компьютер), и терминал должен иметь доступ к домашней странице Home Assistant по этому адресу, в противном случае аутентификация входа может завершиться неудачно.\r\n### Интегрированная Сетевая Конфигурация\r\nПроверьте, нормально ли функционирует локальная сеть и доступны ли связанные сетевые ресурсы. **Рекомендуется выбрать это при первом добавлении.**\r\n### Примечание\r\n- Для пользователей с сотнями или более устройств Mi Home первоначальное добавление интеграции займет некоторое время. Пожалуйста, будьте терпеливы.\r\n- Если Home Assistant работает в среде Docker, убедитесь, что сетевой режим Docker установлен на host, иначе функция локального управления может работать неправильно.\r\n- Функция локального управления интеграции имеет некоторые зависимости. Пожалуйста, внимательно прочитайте README.",
|
||||
"data": {
|
||||
"cloud_server": "Регион входа в систему",
|
||||
"integration_language": "Язык",
|
||||
"oauth_redirect_url": "Адрес перенаправления для аутентификации OAuth2",
|
||||
"network_detect_config": "Интегрированная Сетевая Конфигурация"
|
||||
}
|
||||
},
|
||||
"network_detect_config": {
|
||||
"title": "Интегрированная Сетевая Конфигурация",
|
||||
"description": "## Введение в Использование\r\n### Адрес Обнаружения Сети\r\nИспользуется для проверки работоспособности сети. Если не задано, будет использоваться адрес по умолчанию. Если проверка адреса по умолчанию не удалась, вы можете попробовать ввести пользовательский адрес.\r\n- Вы можете ввести несколько адресов для проверки, разделенных запятыми, например `8.8.8.8,https://www.bing.com`\r\n- Если это IP-адрес, проверка будет выполняться с помощью ping. Если это HTTP(s)-адрес, проверка будет выполняться с помощью HTTP GET запроса.\r\n- Если вы хотите восстановить адрес обнаружения по умолчанию, введите запятую `,` и нажмите 'Далее'.\r\n- **Эта конфигурация является глобальной, и изменения повлияют на другие экземпляры интеграции. Пожалуйста, изменяйте с осторожностью.**\r\n### Проверка Сетевых Зависимостей\r\nПроверьте поочередно следующие сетевые зависимости, чтобы убедиться, что они доступны. Если соответствующие адреса недоступны, это приведет к проблемам с интеграцией.\r\n- Адрес аутентификации OAuth2: `https://account.xiaomi.com/oauth2/authorize`.\r\n- Адрес HTTP API Xiaomi: `https://{http_host}/app/v2/ha/oauth/get_token`.\r\n- Адрес SPEC API Xiaomi: `https://miot-spec.org/miot-spec-v2/template/list/device`.\r\n- Адрес MQTT брокера Xiaomi: `mqtts://{broker_host}`.",
|
||||
"data": {
|
||||
"network_detect_addr": "Адрес Обнаружения Сети",
|
||||
"check_network_deps": "Проверка Сетевых Зависимостей"
|
||||
}
|
||||
},
|
||||
"oauth_error": {
|
||||
"title": "Ошибка входа в систему",
|
||||
"description": "Нажмите кнопку «Далее», чтобы повторить попытку"
|
||||
},
|
||||
"homes_select": {
|
||||
"title": "Выберите семью и устройство",
|
||||
"description": "## Введение\r\n### Импорт семьи устройства\r\nИнтеграция добавит устройства из выбранной семьи.\r\n### Режим синхронизации имени комнаты\r\nПри синхронизации устройств из приложения Mi Home с Home Assistant, название области в Home Assistant будет следовать следующим правилам. Обратите внимание, что процесс синхронизации не изменит настройки семьи и комнаты в приложении Mi Home.\r\n- Не синхронизировать: Устройство не будет добавлено ни в одну область.\r\n- Другие варианты: Область, в которую добавляется устройство, будет названа в честь имени семьи или комнаты в приложении Mi Home.\r\n### Расширенные настройки\r\nПоказать расширенные настройки для изменения профессиональных параметров конфигурации интеграции.\r\n\r\n \r\n### {nick_name} Здравствуйте! Пожалуйста, выберите семью, в которую вы хотите добавить устройство.",
|
||||
"data": {
|
||||
"home_infos": "Импорт семьи устройства",
|
||||
"area_name_rule": "Режим синхронизации имени комнаты",
|
||||
"advanced_options": "Расширенные настройки"
|
||||
}
|
||||
},
|
||||
"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Отображает бинарные датчики в Xiaomi Home как сущность текстового датчика или сущность бинарного датчика。\r\n### Отображать уведомления о изменении состояния устройства\r\nОтображать подробные уведомления о изменении состояния устройства, показывая только выбранные уведомления.",
|
||||
"data": {
|
||||
"devices_filter": "Фильтрация устройств",
|
||||
"ctrl_mode": "Режим управления",
|
||||
"action_debug": "Режим отладки действий",
|
||||
"hide_non_standard_entities": "Скрыть нестандартные сущности",
|
||||
"display_binary_mode": "Режим отображения бинарного датчика",
|
||||
"display_devices_changed_notify": "Отображать уведомления о изменении состояния устройства"
|
||||
}
|
||||
},
|
||||
"devices_filter": {
|
||||
"title": "Фильтрация устройств",
|
||||
"description": "## Инструкция по использованию\r\nПоддерживает фильтрацию устройств по названию комнаты, типу доступа устройства и модели устройства, а также поддерживает фильтрацию по размеру устройства. Логика фильтрации следующая:\r\n- Сначала, согласно статистической логике, получите объединение или пересечение всех включенных элементов, затем получите пересечение или объединение исключенных элементов, и, наконец, вычтите [включенный итоговый результат] из [исключенного итогового результата], чтобы получить [результат фильтрации].\r\n- Если не выбраны включенные элементы, это означает, что все включены.\r\n### Режим фильтрации\r\n- Исключить: Удалить ненужные элементы.\r\n- Включить: Включить нужные элементы.\r\n### Статистическая логика\r\n- Логика И: Взять пересечение всех элементов в одном режиме.\r\n- Логика ИЛИ: Взять объединение всех элементов в одном режиме.\r\n\r\nВы также можете перейти на страницу [Конфигурация > Обновить список устройств] элемента интеграции, установить флажок [Фильтровать устройства], чтобы повторно отфильтровать.",
|
||||
"data": {
|
||||
"room_filter_mode": "Фильтрация по комнатам семьи",
|
||||
"room_list": "Комнаты семьи",
|
||||
"type_filter_mode": "Фильтрация по типу устройства",
|
||||
"type_list": "Типы устройств",
|
||||
"model_filter_mode": "Фильтрация по модели устройства",
|
||||
"model_list": "Модели устройств",
|
||||
"devices_filter_mode": "Фильтрация устройств",
|
||||
"device_list": "Список устройств",
|
||||
"statistics_logic": "Логика статистики"
|
||||
}
|
||||
}
|
||||
},
|
||||
"progress": {
|
||||
"oauth": "### {link_left}Пожалуйста, нажмите здесь, чтобы войти в систему{link_right}\r\n(После успешного входа вы будете автоматически перенаправлены на следующую страницу)"
|
||||
},
|
||||
"error": {
|
||||
"eula_not_agree": "Пожалуйста, ознакомьтесь с текстом рискового информирования.",
|
||||
"get_token_error": "Не удалось получить информацию об авторизации входа в систему (OAuth token).",
|
||||
"get_homeinfo_error": "Не удалось получить информацию о домашнем устройстве.",
|
||||
"mdns_discovery_error": "Сервис обнаружения локальных устройств недоступен.",
|
||||
"get_cert_error": "Не удалось получить сертификат центрального шлюза.",
|
||||
"no_family_selected": "Не выбрана домашняя сеть.",
|
||||
"no_devices": "В выбранном доме нет устройств. Пожалуйста, выберите дом с устройствами и продолжите.",
|
||||
"no_filter_devices": "Список устройств после фильтрации пуст. Пожалуйста, выберите действительные условия фильтрации и продолжите.",
|
||||
"no_central_device": "Для режима центрального шлюза Xiaomi необходимо наличие доступного центрального шлюза Xiaomi в локальной сети Home Assistant. Проверьте, соответствует ли выбранная домашняя сеть этому требованию.",
|
||||
"invalid_network_addr": "Обнаружен недействительный IP-адрес или HTTP-адрес, пожалуйста, введите действительный адрес.",
|
||||
"invalid_ip_addr": "Обнаружен недоступный IP-адрес, пожалуйста, введите действительный IP-адрес.",
|
||||
"invalid_http_addr": "Обнаружен недоступный HTTP-адрес, пожалуйста, введите действительный HTTP-адрес.",
|
||||
"invalid_default_addr": "Адрес обнаружения сети по умолчанию недоступен, пожалуйста, проверьте конфигурацию сети или используйте пользовательский адрес обнаружения сети.",
|
||||
"unreachable_oauth2_host": "Не удается подключиться к адресу аутентификации OAuth2, проверьте настройки сети.",
|
||||
"unreachable_http_host": "Не удается подключиться к адресу HTTP API Xiaomi, проверьте настройки сети.",
|
||||
"unreachable_spec_host": "Не удается подключиться к адресу SPEC API Xiaomi, проверьте настройки сети.",
|
||||
"unreachable_mqtt_broker": "Не удается подключиться к адресу MQTT брокера Xiaomi, проверьте настройки сети."
|
||||
},
|
||||
"abort": {
|
||||
"ha_uuid_get_failed": "Не удалось получить UUID Home Assistant.",
|
||||
"network_connect_error": "Ошибка настройки. Сетевое подключение недоступно. Проверьте настройки сети устройства.",
|
||||
"already_configured": "Этот пользователь уже настроен. Перейдите на страницу интеграции и нажмите кнопку «Настроить», чтобы изменить настройки.",
|
||||
"invalid_auth_info": "Информация об авторизации истекла. Перейдите на страницу интеграции и нажмите кнопку «Настроить», чтобы переавторизоваться.",
|
||||
"config_flow_error": "Ошибка настройки интеграции: {error}"
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"step": {
|
||||
"auth_config": {
|
||||
"title": "Настройка аутентификации",
|
||||
"description": "Обнаружено, что информация об аутентификации локальной сети устарела, повторите аутентификацию.\r\n### Текущий регион входа в систему: {cloud_server}\r\n### Адрес перенаправления для аутентификации OAuth2\r\nАдрес перенаправления для аутентификации OAuth2 - ** [http: //homeassistant.local: 8123] (http: //homeassistant.local: 8123) **, Home Assistant должен находиться в одной локальной сети с текущим терминалом (например, персональный компьютер), и терминал должен иметь доступ к домашней странице Home Assistant по этому адресу, в противном случае аутентификация входа может завершиться неудачно.",
|
||||
"data": {
|
||||
"oauth_redirect_url": "Адрес перенаправления для аутентификации OAuth2"
|
||||
}
|
||||
},
|
||||
"oauth_error": {
|
||||
"title": "Ошибка входа в систему",
|
||||
"description": "Нажмите кнопку «Далее», чтобы повторить попытку"
|
||||
},
|
||||
"config_options": {
|
||||
"title": "Параметры настройки",
|
||||
"description": "### {nick_name} Здравствуйте!\r\n\r\nID учетной записи Xiaomi: {uid}\r\nТекущий регион входа в систему: {cloud_server}\r\nID экземпляра интеграции: {instance_id}\r\n\r\nВыберите параметры, которые нужно настроить заново, а затем нажмите «Далее».",
|
||||
"data": {
|
||||
"integration_language": "Язык интеграции",
|
||||
"update_user_info": "Обновить информацию о пользователе",
|
||||
"update_devices": "Обновить список устройств",
|
||||
"action_debug": "Режим отладки Action",
|
||||
"hide_non_standard_entities": "Скрыть нестандартные сущности",
|
||||
"display_binary_mode": "Режим отображения бинарного датчика",
|
||||
"display_devices_changed_notify": "Отображать уведомления о изменении состояния устройства",
|
||||
"update_trans_rules": "Обновить правила преобразования сущностей",
|
||||
"update_lan_ctrl_config": "Обновить конфигурацию управления LAN",
|
||||
"network_detect_config": "Интегрированная Сетевая Конфигурация",
|
||||
"cover_dead_zone_width": "Ширина «мертвой зоны» шторы"
|
||||
}
|
||||
},
|
||||
"update_user_info": {
|
||||
"title": "Обновить имя пользователя",
|
||||
"description": "{nick_name} Здравствуйте! Пожалуйста, введите свое имя пользователя ниже.",
|
||||
"data": {
|
||||
"nick_name": "Имя пользователя"
|
||||
}
|
||||
},
|
||||
"homes_select": {
|
||||
"title": "Выберите дом и устройства",
|
||||
"description": "## Инструкция по использованию\r\n### Импорт домашнего устройства\r\nИнтеграция добавит устройства из выбранных домов.\r\n### Фильтрация устройств\r\nПоддерживает фильтрацию устройств по названию комнаты, типу доступа устройства и модели устройства, а также поддерживает фильтрацию по размеру устройства. Отфильтровано **{local_count}** устройств.\r\n### Режим управления\r\n- Авто: Когда в локальной сети доступен центральный шлюз Xiaomi, Home Assistant будет в первую очередь отправлять команды управления устройствами через центральный шлюз для достижения локализованного управления. Если в локальной сети нет центрального шлюза, он попытается отправить команды управления через протокол Xiaomi OT для достижения локализованного управления. Только если вышеуказанные условия локализованного управления не выполняются, команды управления устройствами будут отправляться через облако.\r\n- Облако: Команды управления отправляются только через облако.",
|
||||
"data": {
|
||||
"home_infos": "Импорт домашнего устройства",
|
||||
"devices_filter": "Фильтрация устройств",
|
||||
"ctrl_mode": "Режим управления"
|
||||
}
|
||||
},
|
||||
"devices_filter": {
|
||||
"title": "Фильтрация устройств",
|
||||
"description": "## Инструкция по использованию\r\nПоддерживает фильтрацию устройств по названию комнаты, типу доступа устройства и модели устройства, а также поддерживает фильтрацию по размеру устройства. Логика фильтрации следующая:\r\n- Сначала, согласно статистической логике, получите объединение или пересечение всех включенных элементов, затем получите пересечение или объединение исключенных элементов, и, наконец, вычтите [включенный итоговый результат] из [исключенного итогового результата], чтобы получить [результат фильтрации].\r\n- Если не выбраны включенные элементы, это означает, что все включены.\r\n### Режим фильтрации\r\n- Исключить: Удалить ненужные элементы.\r\n- Включить: Включить нужные элементы.\r\n### Статистическая логика\r\n- Логика И: Взять пересечение всех элементов в одном режиме.\r\n- Логика ИЛИ: Взять объединение всех элементов в одном режиме.\r\n\r\nВы также можете перейти на страницу [Конфигурация > Обновить список устройств] элемента интеграции, установить флажок [Фильтровать устройства], чтобы повторно отфильтровать.",
|
||||
"data": {
|
||||
"room_filter_mode": "Фильтрация по комнатам семьи",
|
||||
"room_list": "Комнаты семьи",
|
||||
"type_filter_mode": "Фильтрация по типу устройства",
|
||||
"type_list": "Типы устройств",
|
||||
"model_filter_mode": "Фильтрация по модели устройства",
|
||||
"model_list": "Модели устройств",
|
||||
"devices_filter_mode": "Фильтрация устройств",
|
||||
"device_list": "Список устройств",
|
||||
"statistics_logic": "Логика статистики"
|
||||
}
|
||||
},
|
||||
"update_trans_rules": {
|
||||
"title": "Обновить правила преобразования сущностей",
|
||||
"description": "## Инструкция по использованию\r\n- Обновите информацию об объектах устройств в текущем экземпляре интеграции, включая многоязычную конфигурацию SPEC, булевый перевод SPEC и фильтрацию моделей SPEC.\r\n- **Предупреждение: Эта конфигурация является глобальной конфигурацией** и напрямую обновит локальный кэш. Если в других экземплярах интеграции есть устройства той же модели, соответствующие экземпляры также будут обновлены после перезагрузки.\r\n- Эта операция займет некоторое время, пожалуйста, будьте терпеливы. Установите флажок \"Подтвердить обновление\" и нажмите \"Далее\", чтобы начать обновление **{urn_count}** правил, иначе пропустите обновление.",
|
||||
"data": {
|
||||
"confirm": "Подтвердить обновление"
|
||||
}
|
||||
},
|
||||
"update_lan_ctrl_config": {
|
||||
"title": "Обновить конфигурацию управления LAN",
|
||||
"description": "## Инструкция по использованию\r\nОбновите информацию о конфигурации для **LAN-управления устройствами Xiaomi Home**. Когда облако и центральный шлюз не могут управлять устройствами, интеграция попытается управлять устройствами через LAN; если сетевая карта не выбрана, управление через LAN не будет включено.\r\n- В настоящее время поддерживаются только устройства WiFi **SPEC v2** в локальной сети. Некоторые старые устройства могут не поддерживать управление или синхронизацию свойств.\r\n- Пожалуйста, выберите сетевую карту(и) в той же сети, что и устройства (поддерживается множественный выбор). Если выбранная сетевая карта имеет два или более соединений в одной сети, рекомендуется выбрать ту, которая имеет наилучшее сетевое соединение, иначе это может **повлиять на нормальное использование устройств**.\r\n- **Если в локальной сети есть терминальные устройства (шлюзы, мобильные телефоны и т. д.), поддерживающие локальное управление, включение подписки на LAN может вызвать локальную автоматизацию или аномалии устройств. Пожалуйста, используйте с осторожностью**.\r\n- **Предупреждение: Эта конфигурация является глобальной, и изменения повлияют на другие экземпляры интеграции. Пожалуйста, изменяйте с осторожностью**.\r\n{notice_net_dup}",
|
||||
"data": {
|
||||
"net_interfaces": "Пожалуйста, выберите сетевую карту для использования",
|
||||
"enable_subscribe": "Включить подписку LAN"
|
||||
}
|
||||
},
|
||||
"network_detect_config": {
|
||||
"title": "Интегрированная Сетевая Конфигурация",
|
||||
"description": "## Введение в Использование\r\n### Адрес Обнаружения Сети\r\nИспользуется для проверки работоспособности сети. Если не задано, будет использоваться адрес по умолчанию. Если проверка адреса по умолчанию не удалась, вы можете попробовать ввести пользовательский адрес.\r\n- Вы можете ввести несколько адресов для проверки, разделенных запятыми, например `8.8.8.8,https://www.bing.com`\r\n- Если это IP-адрес, проверка будет выполняться с помощью ping. Если это HTTP(s)-адрес, проверка будет выполняться с помощью HTTP GET запроса.\r\n- Если вы хотите восстановить адрес обнаружения по умолчанию, введите запятую `,` и нажмите 'Далее'.\r\n- **Эта конфигурация является глобальной, и изменения повлияют на другие экземпляры интеграции. Пожалуйста, изменяйте с осторожностью.**\r\n### Проверка Сетевых Зависимостей\r\nПроверьте поочередно следующие сетевые зависимости, чтобы убедиться, что они доступны. Если соответствующие адреса недоступны, это приведет к проблемам с интеграцией.\r\n- Адрес аутентификации OAuth2: `https://account.xiaomi.com/oauth2/authorize`.\r\n- Адрес HTTP API Xiaomi: `https://{http_host}/app/v2/ha/oauth/get_token`.\r\n- Адрес SPEC API Xiaomi: `https://miot-spec.org/miot-spec-v2/template/list/device`.\r\n- Адрес MQTT брокера Xiaomi: `mqtts://{broker_host}`.",
|
||||
"data": {
|
||||
"network_detect_addr": "Адрес Обнаружения Сети",
|
||||
"check_network_deps": "Проверка Сетевых Зависимостей"
|
||||
}
|
||||
},
|
||||
"config_confirm": {
|
||||
"title": "Подтверждение настройки",
|
||||
"description": "**{nick_name}** Здравствуйте! Подтвердите последнюю информацию о настройке и нажмите «Отправить». Интеграция будет перезагружена с использованием обновленных настроек.\r\n\r\nЯзык интеграции:\t{lang_new}\r\nИмя пользователя:\t{nick_name_new}\r\nРежим отладки Action:\t{action_debug}\r\nСкрыть непроизводственные сущности:\t{hide_non_standard_entities}\r\nШирина «мертвой зоны» шторы:\t{cover_width_new}\r\nОтображать уведомления о изменении состояния устройства:\t{display_devices_changed_notify}\r\nИзменение устройства:\tДобавлено **{devices_add}** устройство, удалено **{devices_remove}** устройства\r\nИзменение правил преобразования:\tВсего **{trans_rules_count}** правил, обновлено **{trans_rules_count_success}** правил",
|
||||
"data": {
|
||||
"confirm": "Подтвердить изменения"
|
||||
}
|
||||
}
|
||||
},
|
||||
"progress": {
|
||||
"oauth": "### {link_left}Пожалуйста, нажмите здесь, чтобы повторно войти в систему{link_right}"
|
||||
},
|
||||
"error": {
|
||||
"not_auth": "Пользователь не аутентифицирован. Нажмите ссылку для аутентификации пользователя.",
|
||||
"get_token_error": "Не удалось получить информацию об авторизации входа (OAuth token).",
|
||||
"get_homeinfo_error": "Не удалось получить информацию о домашней сети.",
|
||||
"get_cert_error": "Не удалось получить центральный сертификат.",
|
||||
"no_family_selected": "Не выбрана семья.",
|
||||
"no_devices": "В выбранном доме нет устройств. Пожалуйста, выберите дом с устройствами и продолжите.",
|
||||
"no_filter_devices": "Список устройств после фильтрации пуст. Пожалуйста, выберите действительные условия фильтрации и продолжите.",
|
||||
"no_central_device": "Для режима центрального шлюза необходим существующий в локальной сети Home Assistant с доступным Xiaomi-шлюзом. Пожалуйста, проверьте, соответствует ли выбранная семья этому требованию.",
|
||||
"mdns_discovery_error": "Ошибка сервиса поиска локальных устройств.",
|
||||
"update_config_error": "Не удалось обновить информацию о конфигурации.",
|
||||
"not_confirm": "Изменение не подтверждено. Пожалуйста, отметьте для подтверждения и отправки.",
|
||||
"invalid_network_addr": "Обнаружен недействительный IP-адрес или HTTP-адрес, пожалуйста, введите действительный адрес.",
|
||||
"invalid_ip_addr": "Обнаружен недоступный IP-адрес, пожалуйста, введите действительный IP-адрес.",
|
||||
"invalid_http_addr": "Обнаружен недоступный HTTP-адрес, пожалуйста, введите действительный HTTP-адрес.",
|
||||
"invalid_default_addr": "Адрес обнаружения сети по умолчанию недоступен, пожалуйста, проверьте конфигурацию сети или используйте пользовательский адрес обнаружения сети.",
|
||||
"unreachable_oauth2_host": "Не удается подключиться к адресу аутентификации OAuth2, проверьте настройки сети.",
|
||||
"unreachable_http_host": "Не удается подключиться к адресу HTTP API Xiaomi, проверьте настройки сети.",
|
||||
"unreachable_spec_host": "Не удается подключиться к адресу SPEC API Xiaomi, проверьте настройки сети.",
|
||||
"unreachable_mqtt_broker": "Не удается подключиться к адресу MQTT брокера Xiaomi, проверьте настройки сети."
|
||||
},
|
||||
"abort": {
|
||||
"network_connect_error": "Ошибка конфигурации. Сбой сетевого подключения. Проверьте настройки сети устройства.",
|
||||
"options_flow_error": "Ошибка повторной настройки интеграции: {error}",
|
||||
"re_add": "Пожалуйста, добавьте интеграцию снова. Информация об ошибке: {error}",
|
||||
"storage_error": "Ошибка хранения интеграции. Пожалуйста, повторите попытку или добавьте интеграцию снова: {error}",
|
||||
"inconsistent_account": "Информация об аккаунте не соответствует. Пожалуйста, используйте правильный аккаунт для входа."
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,225 @@
|
||||
{
|
||||
"config": {
|
||||
"flow_title": "Xiaomi Home Entegrasyonu",
|
||||
"step": {
|
||||
"eula": {
|
||||
"title": "Risk Bildirimi",
|
||||
"description": "1. Xiaomi kullanıcı bilgileriniz ve cihaz bilgileriniz Home Assistant sisteminde saklanacaktır. **Xiaomi, Home Assistant depolama mekanizmasının güvenliğini garanti edemez**. Bilgilerinizin çalınmasını önlemekten siz sorumlusunuz.\r\n2. Bu entegrasyon açık kaynak topluluğu tarafından sürdürülmektedir. Kararlılık sorunları veya diğer sorunlar olabilir. Bu entegrasyonla ilgili sorunlar veya hatalarla karşılaştığınızda, **Xiaomi müşteri hizmetleriyle iletişime geçmek yerine açık kaynak topluluğundan yardım istemelisiniz**.\r\n3. Yerel işletim ortamınızı sürdürmek için teknik beceriye ihtiyacınız vardır. Entegrasyon yeni başlayanlar için kullanıcı dostu değildir.\r\n4. Lütfen başlamadan önce README dosyasını okuyun.\n\n5. Entegrasyonun kararlı kullanımını sağlamak ve arayüz kötüye kullanımını önlemek için, **bu entegrasyonun yalnızca Home Assistant'ta kullanılmasına izin verilir. Ayrıntılar için lütfen LICENSE'a bakın**.",
|
||||
"data": {
|
||||
"eula": "Yukarıdaki risklerin farkındayım ve entegrasyonun kullanımıyla ilişkili tüm riskleri gönüllü olarak üstlenmeye razıyım."
|
||||
}
|
||||
},
|
||||
"auth_config": {
|
||||
"title": "Temel yapılandırma",
|
||||
"description": "### Giriş Bölgesi\r\nXiaomi hesabınızın bölgesini seçin. Bunu Xiaomi Home UYGULAMASI > Profil (alttaki menüde bulunur) > Ek ayarlar > Xiaomi Home Hakkında bölümünde bulabilirsiniz.\r\n### Dil\r\nCihaz ve varlık adlarının dilini seçin. Çevirisi olmayan bazı cümleler İngilizce olarak görüntülenecektir.\r\n### OAuth2 Yönlendirme URL'si\r\nOAuth2 kimlik doğrulama yönlendirme adresi **[http://homeassistant.local:8123](http://homeassistant.local:8123)** şeklindedir. Home Assistant'ın mevcut işletim terminali (örn. kişisel bilgisayar) ile aynı yerel ağda olması ve işletim terminalinin bu adres üzerinden Home Assistant ana sayfasına erişebilmesi gerekir. Aksi takdirde giriş kimlik doğrulaması başarısız olabilir.\r\n### Entegre Ağ Yapılandırması\r\nYerel ağın düzgün çalışıp çalışmadığını ve ilgili ağ kaynaklarının erişilebilir olup olmadığını kontrol edin. **İlk kez eklerken bunu seçmeniz önerilir.**\r\n### Not\r\n- Yüzlerce veya daha fazla Mi Home cihazına sahip kullanıcılar için, entegrasyonun ilk eklenmesi biraz zaman alacaktır. Lütfen sabırlı olun.\r\n- Home Assistant bir Docker ortamında çalışıyorsa, lütfen Docker ağ modunun host olarak ayarlandığından emin olun, aksi takdirde yerel kontrol işlevi düzgün çalışmayabilir.\r\n- Entegrasyonun yerel kontrol işlevinin bazı bağımlılıkları vardır. Lütfen README'yi dikkatlice okuyun.",
|
||||
"data": {
|
||||
"cloud_server": "Giriş Bölgesi",
|
||||
"integration_language": "Dil",
|
||||
"oauth_redirect_url": "OAuth2 Yönlendirme URL'si",
|
||||
"network_detect_config": "Entegre Ağ Yapılandırması"
|
||||
}
|
||||
},
|
||||
"network_detect_config": {
|
||||
"title": "Entegre Ağ Yapılandırması",
|
||||
"description": "## Kullanım Tanıtımı\r\n### Ağ Algılama Adresi\r\nAğın düzgün çalışıp çalışmadığını kontrol etmek için kullanılır. Ayarlanmazsa, sistem varsayılan adresi kullanılacaktır. Varsayılan adres kontrolü başarısız olursa, özel bir adres girmeyi deneyebilirsiniz.\r\n- Virgülle ayrılmış birden fazla algılama adresi girebilirsiniz, örneğin `8.8.8.8,https://www.bing.com`\r\n- Bir IP adresi ise, algılama ping üzerinden yapılacaktır. Bir HTTP(s) adresi ise, algılama HTTP GET isteği üzerinden yapılacaktır.\r\n- Sistem varsayılan algılama adresini geri yüklemek istiyorsanız, lütfen bir virgül `,` girin ve 'İleri'ye tıklayın.\r\n- **Bu yapılandırma geneldir ve değişiklikler diğer entegrasyon örneklerini etkileyecektir. Lütfen dikkatli değiştirin.**\r\n### Ağ Bağımlılıklarını Kontrol Et\r\nAşağıdaki ağ bağımlılıklarının erişilebilir olup olmadığını tek tek kontrol edin. İlgili adresler erişilebilir değilse, entegrasyon sorunlarına neden olacaktır.\r\n- OAuth2 Kimlik Doğrulama Adresi: `https://account.xiaomi.com/oauth2/authorize`.\r\n- Xiaomi HTTP API Adresi: `https://{http_host}/app/v2/ha/oauth/get_token`.\r\n- Xiaomi SPEC API Adresi: `https://miot-spec.org/miot-spec-v2/template/list/device`.\r\n- Xiaomi MQTT Broker Adresi: `mqtts://{broker_host}`.",
|
||||
"data": {
|
||||
"network_detect_addr": "Ağ Algılama Adresi",
|
||||
"check_network_deps": "Ağ Bağımlılıklarını Kontrol Et"
|
||||
}
|
||||
},
|
||||
"oauth_error": {
|
||||
"title": "Giriş Hatası",
|
||||
"description": "Tekrar denemek için İLERİ'ye tıklayın."
|
||||
},
|
||||
"homes_select": {
|
||||
"title": "Ev ve Cihaz Seçimi",
|
||||
"description": "## Tanıtım\r\n### Cihazın Evini İçe Aktar\r\nEntegrasyon, seçilen evden cihazları ekleyecektir.\r\n### Oda Adı Senkronizasyon Modu\r\nMi Home UYGULAMASINDAN Home Assistant'a cihazlar senkronize edilirken, Home Assistant'taki alanın adlandırılması aşağıdaki kurallara uyacaktır. Senkronizasyon işleminin Mi Home UYGULAMASINDAKI ev ve oda ayarlarını değiştirmeyeceğini unutmayın.\r\n- Senkronize etme: Cihaz herhangi bir alana eklenmeyecektir.\r\n- Diğer seçenekler: Cihazın eklendiği alan, Mi Home UYGULAMASINDAKI ev veya oda adına göre adlandırılacaktır.\r\n### Gelişmiş Ayarlar\r\nEntegrasyonun profesyonel yapılandırma seçeneklerini değiştirmek için gelişmiş ayarları gösterin.\r\n\r\n \r\n### {nick_name} Merhaba! Lütfen cihaz eklemek istediğiniz evi seçin.",
|
||||
"data": {
|
||||
"home_infos": "Cihazın Evini İçe Aktar",
|
||||
"area_name_rule": "Oda Adı Senkronizasyon Modu",
|
||||
"advanced_options": "Gelişmiş Ayarlar"
|
||||
}
|
||||
},
|
||||
"advanced_options": {
|
||||
"title": "Gelişmiş Ayarlar",
|
||||
"description": "## Tanıtım\r\n### Aşağıdaki seçeneklerin anlamını çok net bir şekilde bilmiyorsanız, lütfen varsayılan ayarları koruyun.\r\n### Cihazları Filtrele\r\nCihazları oda adı ve cihaz türüne göre filtrelemeyi destekler, ayrıca cihaz boyutu filtrelemesini de destekler.\r\n### Kontrol Modu\r\n- Otomatik: Yerel ağda kullanılabilir bir Xiaomi merkezi hub ağ geçidi olduğunda, Home Assistant cihaz kontrol komutlarını öncelikle merkezi hub ağ geçidi üzerinden göndererek yerel kontrolü sağlar. Yerel ağda merkezi hub ağ geçidi yoksa, Xiaomi OT protokolü üzerinden kontrol komutları göndermeye çalışır. Yalnızca yukarıdaki yerel kontrol koşulları karşılanmadığında, cihaz kontrol komutları bulut üzerinden gönderilir.\r\n- Bulut: Tüm kontrol komutları bulut üzerinden gönderilir.\r\n### Eylem Hata Ayıklama Modu\r\nCihaz MIoT-Spec-V2 tarafından tanımlanan yöntemler için, bildirim varlıkları oluşturmaya ek olarak, bir metin girişi kutusu varlığı da oluşturulacaktır. Hata ayıklama sırasında cihaza kontrol komutları göndermek için bunu kullanabilirsiniz.\r\n### Standart Olmayan Oluşturulan Varlıkları Gizle\r\nAdı \"*\" ile başlayan standart olmayan MIoT-Spec-V2 örnekleri tarafından oluşturulan varlıkları gizle.\r\n### İkili Sensör Görüntüleme Modu\r\nXiaomi Home'daki ikili sensörleri metin sensör varlığı veya ikili sensör varlığı olarak görüntüleyin.\r\n### Cihaz Durum Değişikliği Bildirimlerini Göster\r\nDetaylı cihaz durum değişikliği bildirimlerini görüntüleyin, yalnızca seçilen bildirimleri gösterin.",
|
||||
"data": {
|
||||
"devices_filter": "Cihazları Filtrele",
|
||||
"ctrl_mode": "Kontrol Modu",
|
||||
"action_debug": "Eylem Hata Ayıklama Modu",
|
||||
"hide_non_standard_entities": "Standart Olmayan Oluşturulan Varlıkları Gizle",
|
||||
"display_binary_mode": "İkili Sensör Görüntüleme Modu",
|
||||
"display_devices_changed_notify": "Cihaz Durum Değişikliği Bildirimlerini Göster"
|
||||
}
|
||||
},
|
||||
"devices_filter": {
|
||||
"title": "Cihazları Filtrele",
|
||||
"description": "## Kullanım Talimatları\r\nCihazları ev oda adı, cihaz erişim türü ve cihaz modeline göre filtrelemeyi destekler, ayrıca cihaz boyutu filtrelemesini de destekler. Filtreleme mantığı aşağıdaki gibidir:\r\n- İlk olarak, istatistik mantığına göre, dahil edilen tüm öğelerin birleşimini veya kesişimini alın, ardından hariç tutulan öğelerin kesişimini veya birleşimini alın ve son olarak [hariç tutulan özet sonucu]ndan [dahil edilen özet sonucu]nu çıkararak [filtre sonucu]nu elde edin.\r\n- Dahil edilen öğe seçilmemişse, tümünün dahil edildiği anlamına gelir.\r\n### Filtre Modu\r\n- Hariç tut: İstenmeyen öğeleri kaldırın.\r\n- Dahil et: İstenen öğeleri dahil edin.\r\n### İstatistik Mantığı\r\n- VE mantığı: Aynı moddaki tüm öğelerin kesişimini alın.\r\n- VEYA mantığı: Aynı moddaki tüm öğelerin birleşimini alın.\r\n\r\nAyrıca entegrasyon öğesinin [Yapılandırma > Cihaz Listesini Güncelle] sayfasına gidip, yeniden filtrelemek için [Cihazları Filtrele]'yi işaretleyebilirsiniz.",
|
||||
"data": {
|
||||
"room_filter_mode": "Ev Odalarını Filtrele",
|
||||
"room_list": "Ev Odaları",
|
||||
"type_filter_mode": "Cihaz Bağlantı Türünü Filtrele",
|
||||
"type_list": "Cihaz Bağlantı Türü",
|
||||
"model_filter_mode": "Cihaz Modelini Filtrele",
|
||||
"model_list": "Cihaz Modeli",
|
||||
"devices_filter_mode": "Cihazları Filtrele",
|
||||
"device_list": "Cihaz Listesi",
|
||||
"statistics_logic": "İstatistik Mantığı"
|
||||
}
|
||||
}
|
||||
},
|
||||
"progress": {
|
||||
"oauth": "### {link_left}Giriş yapmak için buraya tıklayın{link_right}\r\n(Başarılı girişten sonra otomatik olarak bir sonraki sayfaya yönlendirileceksiniz)"
|
||||
},
|
||||
"error": {
|
||||
"eula_not_agree": "Lütfen risk bildirimini okuyun.",
|
||||
"get_token_error": "Giriş yetkilendirme bilgileri (OAuth token) alınamadı.",
|
||||
"get_homeinfo_error": "Ev bilgileri alınamadı.",
|
||||
"mdns_discovery_error": "Yerel cihaz keşif hizmeti istisnası.",
|
||||
"get_cert_error": "Merkezi hub ağ geçidi sertifikası alınamadı.",
|
||||
"no_family_selected": "Ev seçilmedi.",
|
||||
"no_devices": "Seçilen evde cihaz yok. Lütfen cihazı olan bir ev seçin ve devam edin.",
|
||||
"no_filter_devices": "Filtrelenmiş cihazlar boş. Lütfen geçerli filtre kriterleri seçin ve devam edin.",
|
||||
"no_central_device": "[Merkezi Hub Ağ Geçidi Modu], Home Assistant'ın bulunduğu yerel ağda kullanılabilir bir Xiaomi merkezi hub ağ geçidi gerektirir. Lütfen seçilen evin gereksinimi karşılayıp karşılamadığını kontrol edin.",
|
||||
"invalid_network_addr": "Geçersiz IP adresi veya HTTP adresi algılandı, lütfen geçerli bir adres girin.",
|
||||
"invalid_ip_addr": "Ulaşılamayan IP adresi algılandı, lütfen geçerli bir IP adresi girin.",
|
||||
"invalid_http_addr": "Ulaşılamayan HTTP adresi algılandı, lütfen geçerli bir HTTP adresi girin.",
|
||||
"invalid_default_addr": "Varsayılan ağ algılama adresi ulaşılamıyor, lütfen ağ yapılandırmasını kontrol edin veya özel bir ağ algılama adresi kullanın.",
|
||||
"unreachable_oauth2_host": "OAuth2 kimlik doğrulama adresine ulaşılamıyor, lütfen ağ yapılandırmasını kontrol edin.",
|
||||
"unreachable_http_host": "Xiaomi HTTP API adresine ulaşılamıyor, lütfen ağ yapılandırmasını kontrol edin.",
|
||||
"unreachable_spec_host": "Xiaomi SPEC API adresine ulaşılamıyor, lütfen ağ yapılandırmasını kontrol edin.",
|
||||
"unreachable_mqtt_broker": "Xiaomi MQTT Broker adresine ulaşılamıyor, lütfen ağ yapılandırmasını kontrol edin."
|
||||
},
|
||||
"abort": {
|
||||
"ha_uuid_get_failed": "Home Assistant UUID alınamadı.",
|
||||
"network_connect_error": "Yapılandırma başarısız oldu. Ağ bağlantısı anormal. Lütfen ekipman ağ yapılandırmasını kontrol edin.",
|
||||
"already_configured": "Bu kullanıcı için yapılandırma zaten tamamlandı. Lütfen entegrasyon sayfasına gidin ve değişiklikler için YAPILANDIRMA düğmesine tıklayın.",
|
||||
"invalid_auth_info": "Kimlik doğrulama bilgileri süresi doldu. Lütfen entegrasyon sayfasına gidin ve yeniden kimlik doğrulaması yapmak için YAPILANDIRMA düğmesine tıklayın.",
|
||||
"config_flow_error": "Entegrasyon yapılandırma hatası: {error}."
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"step": {
|
||||
"auth_config": {
|
||||
"title": "Kimlik Doğrulama Yapılandırması",
|
||||
"description": "Yerel kimlik doğrulama bilgileri süresi doldu. Lütfen kimlik doğrulama işlemini yeniden başlatın.\r\n### Geçerli Giriş Bölgesi: {cloud_server}\r\n### OAuth2 Yönlendirme URL'si\r\nOAuth2 kimlik doğrulama yönlendirme adresi **[http://homeassistant.local:8123](http://homeassistant.local:8123)** şeklindedir. Home Assistant'ın mevcut işletim terminali (örn. kişisel bilgisayar) ile aynı yerel ağda olması ve işletim terminalinin bu adres üzerinden Home Assistant ana sayfasına erişebilmesi gerekir. Aksi takdirde giriş kimlik doğrulaması başarısız olabilir.",
|
||||
"data": {
|
||||
"oauth_redirect_url": "OAuth2 Yönlendirme URL'si"
|
||||
}
|
||||
},
|
||||
"oauth_error": {
|
||||
"title": "Giriş sırasında bir hata oluştu.",
|
||||
"description": "Tekrar denemek için İLERİ'ye tıklayın."
|
||||
},
|
||||
"config_options": {
|
||||
"title": "Yapılandırma Seçenekleri",
|
||||
"description": "### Merhaba, {nick_name}\r\n\r\nXiaomi ID: {uid}\r\nGeçerli Giriş Bölgesi: {cloud_server}\r\nEntegrasyon Örnek Kimliği: {instance_id}\r\n\r\nLütfen yapılandırmak istediğiniz seçenekleri seçin, ardından İLERİ'ye tıklayın.",
|
||||
"data": {
|
||||
"integration_language": "Entegrasyon Dili",
|
||||
"update_user_info": "Kullanıcı bilgilerini güncelle",
|
||||
"update_devices": "Cihaz listesini güncelle",
|
||||
"action_debug": "Eylem için hata ayıklama modu",
|
||||
"hide_non_standard_entities": "Standart olmayan oluşturulan varlıkları gizle",
|
||||
"display_binary_mode": "İkili Sensör Görüntüleme Modu",
|
||||
"display_devices_changed_notify": "Cihaz durum değişikliği bildirimlerini göster",
|
||||
"update_trans_rules": "Varlık dönüştürme kurallarını güncelle",
|
||||
"update_lan_ctrl_config": "LAN kontrol yapılandırmasını güncelle",
|
||||
"network_detect_config": "Entegre ağ yapılandırması",
|
||||
"cover_dead_zone_width": "Perde ölü bölge genişliği"
|
||||
}
|
||||
},
|
||||
"update_user_info": {
|
||||
"title": "Kullanıcı Takma Adını Güncelle",
|
||||
"description": "Merhaba {nick_name}, aşağıda özel takma adınızı değiştirebilirsiniz.",
|
||||
"data": {
|
||||
"nick_name": "Takma Ad"
|
||||
}
|
||||
},
|
||||
"homes_select": {
|
||||
"title": "Evi ve Cihazları Yeniden Seç",
|
||||
"description": "## Kullanım Talimatları\r\n### Evden cihazları içe aktar\r\nEntegrasyon, seçilen evlerden cihazları ekleyecektir.\r\n### Cihazları Filtrele\r\nCihazları ev oda adı, cihaz erişim türü ve cihaz modeline göre filtrelemeyi destekler, ayrıca cihaz boyutu filtrelemesini de destekler. **{local_count}** cihaz filtrelendi.\r\n### Kontrol modu\r\n- Otomatik: Yerel ağda kullanılabilir bir Xiaomi merkezi hub ağ geçidi olduğunda, Home Assistant cihaz kontrol komutlarını öncelikle merkezi hub ağ geçidi üzerinden göndererek yerel kontrolü sağlar. Yerel ağda merkezi hub ağ geçidi yoksa, Xiaomi LAN kontrol işlevi aracılığıyla kontrol komutları göndermeye çalışır. Yalnızca yukarıdaki yerel kontrol koşulları karşılanmadığında, cihaz kontrol komutları bulut üzerinden gönderilir.\r\n- Bulut: Tüm kontrol komutları bulut üzerinden gönderilir.",
|
||||
"data": {
|
||||
"home_infos": "Evden cihazları içe aktar",
|
||||
"devices_filter": "Cihazları filtrele",
|
||||
"ctrl_mode": "Kontrol modu"
|
||||
}
|
||||
},
|
||||
"devices_filter": {
|
||||
"title": "Cihazları Filtrele",
|
||||
"description": "## Kullanım Talimatları\r\nCihazları ev oda adı, cihaz erişim türü ve cihaz modeline göre filtrelemeyi destekler, ayrıca cihaz boyutu filtrelemesini de destekler. Filtreleme mantığı aşağıdaki gibidir:\r\n- İlk olarak, istatistik mantığına göre, dahil edilen tüm öğelerin birleşimini veya kesişimini alın, ardından hariç tutulan öğelerin kesişimini veya birleşimini alın ve son olarak [hariç tutulan özet sonucu]ndan [dahil edilen özet sonucu]nu çıkararak [filtre sonucu]nu elde edin.\r\n- Dahil edilen öğe seçilmemişse, tümünün dahil edildiği anlamına gelir.\r\n### Filtre Modu\r\n- Hariç tut: İstenmeyen öğeleri kaldırın.\r\n- Dahil et: İstenen öğeleri dahil edin.\r\n### İstatistik Mantığı\r\n- VE mantığı: Aynı moddaki tüm öğelerin kesişimini alın.\r\n- VEYA mantığı: Aynı moddaki tüm öğelerin birleşimini alın.\r\n\r\nAyrıca entegrasyon öğesinin [Yapılandırma > Cihaz Listesini Güncelle] sayfasına gidip, yeniden filtrelemek için [Cihazları Filtrele]'yi işaretleyebilirsiniz.",
|
||||
"data": {
|
||||
"room_filter_mode": "Ev Odalarını Filtrele",
|
||||
"room_list": "Ev Odaları",
|
||||
"type_filter_mode": "Cihaz Bağlantı Türünü Filtrele",
|
||||
"type_list": "Cihaz Bağlantı Türü",
|
||||
"model_filter_mode": "Cihaz Modelini Filtrele",
|
||||
"model_list": "Cihaz Modeli",
|
||||
"devices_filter_mode": "Cihazları Filtrele",
|
||||
"device_list": "Cihaz Listesi",
|
||||
"statistics_logic": "İstatistik Mantığı"
|
||||
}
|
||||
},
|
||||
"update_trans_rules": {
|
||||
"title": "Varlık Dönüştürme Kurallarını Güncelle",
|
||||
"description": "## Kullanım Talimatları\r\n- Mevcut entegrasyon örneğindeki cihazların varlık bilgilerini güncelleyin, MIoT-Spec-V2 çok dilli yapılandırma, boolean çeviri ve model filtreleme dahil.\r\n- **Uyarı**: Bu genel bir yapılandırmadır ve yerel önbelleği güncelleyecektir. Tüm entegrasyon örneklerini etkileyecektir.\r\n- Bu işlem biraz zaman alacaktır, lütfen sabırlı olun. \"Güncellemeyi Onayla\"yı işaretleyin ve **{urn_count}** kuralı güncellemeye başlamak için \"İleri\"ye tıklayın, aksi takdirde güncellemeyi atlayın.",
|
||||
"data": {
|
||||
"confirm": "Güncellemeyi onayla"
|
||||
}
|
||||
},
|
||||
"update_lan_ctrl_config": {
|
||||
"title": "LAN kontrol yapılandırmasını güncelle",
|
||||
"description": "## Kullanım Talimatları\r\nXiaomi LAN kontrol işlevi için yapılandırmaları güncelleyin. Bulut ve merkezi hub ağ geçidi cihazları kontrol edemediğinde, entegrasyon LAN üzerinden cihazları kontrol etmeye çalışacaktır. Hiçbir ağ kartı seçilmezse, LAN kontrol işlevi etkin olmayacaktır.\r\n- Yalnızca LAN'daki MIoT-Spec-V2 uyumlu IP cihazları desteklenir. 2020'den önce üretilen bazı cihazlar LAN kontrolünü veya LAN aboneliğini desteklemeyebilir.\r\n- Lütfen kontrol edilecek cihazlarla aynı ağdaki ağ kartlarını seçin. Birden fazla ağ kartı seçilebilir. Home Assistant'ın birden fazla ağ kartı seçimi nedeniyle yerel ağa iki veya daha fazla bağlantısı varsa, en iyi ağ bağlantısına sahip olanı seçmeniz önerilir, aksi takdirde cihazlar üzerinde kötü etkisi olabilir.\r\n- LAN'da yerel kontrolü destekleyen terminal cihazlar (ekranlı Xiaomi hoparlör, cep telefonu, vb.) varsa, LAN aboneliğini etkinleştirmek yerel otomasyon ve cihaz anormalliklerine neden olabilir.\r\n- **Uyarı**: Bu genel bir yapılandırmadır. Tüm entegrasyon örneklerini etkileyecektir. Lütfen dikkatli kullanın.\r\n{notice_net_dup}",
|
||||
"data": {
|
||||
"net_interfaces": "Lütfen kullanılacak ağ kartını seçin",
|
||||
"enable_subscribe": "LAN aboneliğini etkinleştir"
|
||||
}
|
||||
},
|
||||
"network_detect_config": {
|
||||
"title": "Entegre Ağ Yapılandırması",
|
||||
"description": "## Kullanım Tanıtımı\r\n### Ağ Algılama Adresi\r\nAğın düzgün çalışıp çalışmadığını kontrol etmek için kullanılır. Ayarlanmazsa, sistem varsayılan adresi kullanılacaktır. Varsayılan adres kontrolü başarısız olursa, özel bir adres girmeyi deneyebilirsiniz.\r\n- Virgülle ayrılmış birden fazla algılama adresi girebilirsiniz, örneğin `8.8.8.8,https://www.bing.com`\r\n- Bir IP adresi ise, algılama ping üzerinden yapılacaktır. Bir HTTP(s) adresi ise, algılama HTTP GET isteği üzerinden yapılacaktır.\r\n- Sistem varsayılan algılama adresini geri yüklemek istiyorsanız, lütfen bir virgül `,` girin ve 'İleri'ye tıklayın.\r\n- **Bu yapılandırma geneldir ve değişiklikler diğer entegrasyon örneklerini etkileyecektir. Lütfen dikkatli değiştirin.**\r\n### Ağ Bağımlılıklarını Kontrol Et\r\nAşağıdaki ağ bağımlılıklarının erişilebilir olup olmadığını tek tek kontrol edin. İlgili adresler erişilebilir değilse, entegrasyon sorunlarına neden olacaktır.\r\n- OAuth2 Kimlik Doğrulama Adresi: `https://account.xiaomi.com/oauth2/authorize`.\r\n- Xiaomi HTTP API Adresi: `https://{http_host}/app/v2/ha/oauth/get_token`.\r\n- Xiaomi SPEC API Adresi: `https://miot-spec.org/miot-spec-v2/template/list/device`.\r\n- Xiaomi MQTT Broker Adresi: `mqtts://{broker_host}`.",
|
||||
"data": {
|
||||
"network_detect_addr": "Ağ Algılama Adresi",
|
||||
"check_network_deps": "Ağ Bağımlılıklarını Kontrol Et"
|
||||
}
|
||||
},
|
||||
"config_confirm": {
|
||||
"title": "Yapılandırmayı Onayla",
|
||||
"description": "Merhaba **{nick_name}**, lütfen en son yapılandırma bilgilerini onaylayın ve ardından GÖNDER'e tıklayın.\r\nEntegrasyon güncellenmiş yapılandırmayla yeniden yüklenecektir.\r\n\r\nEntegrasyon Dili:\t{lang_new}\r\nTakma Ad:\t{nick_name_new}\r\nEylem için hata ayıklama modu:\t{action_debug}\r\nStandart olmayan oluşturulan varlıkları gizle:\t{hide_non_standard_entities}\r\nPerde ölü bölge genişliği:\t{cover_width_new}\r\nCihaz durum değişikliği bildirimlerini göster:\t{display_devices_changed_notify}\r\nCihaz Değişiklikleri:\t**{devices_add}** cihaz ekle, **{devices_remove}** cihaz kaldır\r\nDönüştürme kuralları değişikliği:\tToplam **{trans_rules_count}** kural var ve **{trans_rules_count_success}** kural güncellendi",
|
||||
"data": {
|
||||
"confirm": "Değişikliği onayla"
|
||||
}
|
||||
}
|
||||
},
|
||||
"progress": {
|
||||
"oauth": "### {link_left}Yeniden giriş yapmak için lütfen buraya tıklayın{link_right}"
|
||||
},
|
||||
"error": {
|
||||
"not_auth": "Kimlik doğrulanmadı. Lütfen kullanıcı kimliğini doğrulamak için kimlik doğrulama bağlantısına tıklayın.",
|
||||
"get_token_error": "Giriş yetkilendirme bilgileri (OAuth token) alınamadı.",
|
||||
"get_homeinfo_error": "Ev bilgileri alınamadı.",
|
||||
"get_cert_error": "Merkezi hub ağ geçidi sertifikası alınamadı.",
|
||||
"no_devices": "Seçilen evde cihaz yok. Lütfen cihazı olan bir ev seçin ve devam edin.",
|
||||
"no_filter_devices": "Filtrelenmiş cihazlar boş. Lütfen geçerli filtre kriterleri seçin ve devam edin.",
|
||||
"no_family_selected": "Ev seçilmedi.",
|
||||
"no_central_device": "[Merkezi Hub Ağ Geçidi Modu], Home Assistant'ın bulunduğu yerel ağda kullanılabilir bir Xiaomi merkezi hub ağ geçidi gerektirir. Lütfen seçilen evin gereksinimi karşılayıp karşılamadığını kontrol edin.",
|
||||
"mdns_discovery_error": "Yerel cihaz keşif hizmeti istisnası.",
|
||||
"update_config_error": "Yapılandırma bilgileri güncellenemedi.",
|
||||
"not_confirm": "Değişiklikler onaylanmadı. Lütfen göndermeden önce değişikliği onaylayın.",
|
||||
"invalid_network_addr": "Geçersiz IP adresi veya HTTP adresi algılandı, lütfen geçerli bir adres girin.",
|
||||
"invalid_ip_addr": "Ulaşılamayan IP adresi algılandı, lütfen geçerli bir IP adresi girin.",
|
||||
"invalid_http_addr": "Ulaşılamayan HTTP adresi algılandı, lütfen geçerli bir HTTP adresi girin.",
|
||||
"invalid_default_addr": "Varsayılan ağ algılama adresi ulaşılamıyor, lütfen ağ yapılandırmasını kontrol edin veya özel bir ağ algılama adresi kullanın.",
|
||||
"unreachable_oauth2_host": "OAuth2 kimlik doğrulama adresine ulaşılamıyor, lütfen ağ yapılandırmasını kontrol edin.",
|
||||
"unreachable_http_host": "Xiaomi HTTP API adresine ulaşılamıyor, lütfen ağ yapılandırmasını kontrol edin.",
|
||||
"unreachable_spec_host": "Xiaomi SPEC API adresine ulaşılamıyor, lütfen ağ yapılandırmasını kontrol edin.",
|
||||
"unreachable_mqtt_broker": "Xiaomi MQTT Broker adresine ulaşılamıyor, lütfen ağ yapılandırmasını kontrol edin."
|
||||
},
|
||||
"abort": {
|
||||
"network_connect_error": "Yapılandırma başarısız oldu. Ağ bağlantısı anormal. Lütfen ekipman ağ yapılandırmasını kontrol edin.",
|
||||
"options_flow_error": "Entegrasyon yeniden yapılandırma hatası: {error}",
|
||||
"re_add": "Lütfen entegrasyonu yeniden ekleyin. Hata mesajı: {error}",
|
||||
"storage_error": "Entegrasyon depolama modülü istisnası. Lütfen tekrar deneyin veya entegrasyonu yeniden ekleyin: {error}",
|
||||
"inconsistent_account": "Hesap bilgileri tutarsız. Lütfen doğru hesapla giriş yapın."
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user