mirror of
https://github.com/XiaoMi/ha_xiaomi_home.git
synced 2026-01-14 13:20:42 +08:00
Merge branch 'main' into advanced-options
# Conflicts: # custom_components/xiaomi_home/config_flow.py
This commit is contained in:
commit
b37a249c11
25
CHANGELOG.md
Normal file
25
CHANGELOG.md
Normal file
@ -0,0 +1,25 @@
|
||||
# CHANGELOG
|
||||
|
||||
## v0.1.2
|
||||
### Added
|
||||
- Support Xiaomi Heater devices. https://github.com/XiaoMi/ha_xiaomi_home/issues/124 https://github.com/XiaoMi/ha_xiaomi_home/issues/117
|
||||
- Language supports pt, pt-BR.
|
||||
### Changed
|
||||
- Adjust the minimum version of HASS core to 2024.4.4 and above versions.
|
||||
### Fixed
|
||||
|
||||
## v0.1.1
|
||||
### Added
|
||||
### Changed
|
||||
### Fixed
|
||||
- Fix humidifier trans rule. https://github.com/XiaoMi/ha_xiaomi_home/issues/59
|
||||
- Fix get homeinfo error. https://github.com/XiaoMi/ha_xiaomi_home/issues/22
|
||||
- Fix air-conditioner switch on. https://github.com/XiaoMi/ha_xiaomi_home/issues/37 https://github.com/XiaoMi/ha_xiaomi_home/issues/16
|
||||
- Fix invalid cover status. https://github.com/XiaoMi/ha_xiaomi_home/issues/11 https://github.com/XiaoMi/ha_xiaomi_home/issues/85
|
||||
- Water heater entity add STATE_OFF. https://github.com/XiaoMi/ha_xiaomi_home/issues/105 https://github.com/XiaoMi/ha_xiaomi_home/issues/17
|
||||
|
||||
## v0.1.0
|
||||
### Added
|
||||
- First version
|
||||
### Changed
|
||||
### Fixed
|
||||
@ -1,6 +1,6 @@
|
||||
# Contribution Guidelines
|
||||
|
||||
[English](./CONTRIBUTING.md) | [简体中文](./CONTRIBUTING_zh.md)
|
||||
[English](./CONTRIBUTING.md) | [简体中文](./doc/CONTRIBUTING_zh.md)
|
||||
|
||||
Thank you for considering contributing to our project! We appreciate your efforts to make our project better.
|
||||
|
||||
@ -323,7 +323,7 @@ Device information service (urn:miot-spec-v2:service:device-information:00007801
|
||||
|
||||
## Multiple Language Support
|
||||
|
||||
There are 8 languages available for selection in the config flow language option of Xiaomi Home, including Simplified Chinese, Traditional Chinese, English, Spanish, Russian, French, German, and Japanese. The config flow page in Simplified Chinese and English has been manually reviewed by the developer. Other languages are translated by machine translation. If you want to modify the words and sentences in the config flow page, you need to modify the json file of the certain language in `custom_components/xiaomi_home/translations/` directory.
|
||||
There are 8 languages available for selection in the config flow language option of Xiaomi Home, including Simplified Chinese, Traditional Chinese, English, Spanish, Russian, French, German, and Japanese. The config flow page in Simplified Chinese and English has been manually reviewed by the developer. Other languages are translated by machine translation. If you want to modify the words and sentences in the config flow page, you need to modify the json file of the certain language in `custom_components/xiaomi_home/translations/` and `custom_components/xiaomi_home/miot/i18n/` directory.
|
||||
|
||||
When displaying Home Assistant entity name, Xiaomi Home downloads the multiple language file configured by the device vendor from MIoT Cloud, which contains translations for MIoT-Spec-V2 instances of the device. `multi_lang.json` is a locally maintained multiple language dictionary, which has a higher priority than the multiple language file obtained from the cloud and can be used to supplement or modify the multiple language translation of devices.
|
||||
|
||||
@ -376,8 +376,8 @@ Example:
|
||||
## Documents
|
||||
|
||||
- [License](./LICENSE.md)
|
||||
- Contribution Guidelines: [English](./doc/CONTRIBUTING.md) | [简体中文](./doc/CONTRIBUTING_zh.md)
|
||||
- [ChangeLog](./doc/CHANGELOG.md)
|
||||
- Contribution Guidelines: [English](./CONTRIBUTING.md) | [简体中文](./doc/CONTRIBUTING_zh.md)
|
||||
- [ChangeLog](./CHANGELOG.md)
|
||||
- Development Documents: https://developers.home-assistant.io/docs/creating_component_index
|
||||
|
||||
## Directory Structure
|
||||
|
||||
@ -82,9 +82,12 @@ async def async_setup_entry(
|
||||
|
||||
new_entities = []
|
||||
for miot_device in device_list:
|
||||
for data in miot_device.entity_list.get('climate', []):
|
||||
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))
|
||||
|
||||
if new_entities:
|
||||
async_add_entities(new_entities)
|
||||
@ -115,7 +118,7 @@ class AirConditioner(MIoTServiceEntity, ClimateEntity):
|
||||
def __init__(
|
||||
self, miot_device: MIoTDevice, entity_data: MIoTEntityData
|
||||
) -> None:
|
||||
"""Initialize the Climate."""
|
||||
"""Initialize the Air conditioner."""
|
||||
super().__init__(miot_device=miot_device, entity_data=entity_data)
|
||||
self._attr_icon = 'mdi:air-conditioner'
|
||||
self._attr_supported_features = ClimateEntityFeature(0)
|
||||
@ -344,31 +347,31 @@ class AirConditioner(MIoTServiceEntity, ClimateEntity):
|
||||
f'set climate prop.fan_mode failed, {fan_mode}, '
|
||||
f'{self.entity_id}')
|
||||
|
||||
@ property
|
||||
@property
|
||||
def target_temperature(self) -> Optional[float]:
|
||||
"""Return the target temperature."""
|
||||
return self.get_prop_value(
|
||||
prop=self._prop_target_temp) if self._prop_target_temp else None
|
||||
|
||||
@ property
|
||||
@property
|
||||
def target_humidity(self) -> Optional[int]:
|
||||
"""Return the target humidity."""
|
||||
return self.get_prop_value(
|
||||
prop=self._prop_target_humi) if self._prop_target_humi else None
|
||||
|
||||
@ property
|
||||
@property
|
||||
def current_temperature(self) -> Optional[float]:
|
||||
"""Return the current temperature."""
|
||||
return self.get_prop_value(
|
||||
prop=self._prop_env_temp) if self._prop_env_temp else None
|
||||
|
||||
@ property
|
||||
@property
|
||||
def current_humidity(self) -> Optional[int]:
|
||||
"""Return the current humidity."""
|
||||
return self.get_prop_value(
|
||||
prop=self._prop_env_humi) if self._prop_env_humi else None
|
||||
|
||||
@ property
|
||||
@property
|
||||
def hvac_mode(self) -> Optional[HVACMode]:
|
||||
"""Return the hvac mode. e.g., heat, cool mode."""
|
||||
if self.get_prop_value(prop=self._prop_on) is False:
|
||||
@ -377,7 +380,7 @@ class AirConditioner(MIoTServiceEntity, ClimateEntity):
|
||||
map_=self._hvac_mode_map,
|
||||
key=self.get_prop_value(prop=self._prop_mode))
|
||||
|
||||
@ property
|
||||
@property
|
||||
def fan_mode(self) -> Optional[str]:
|
||||
"""Return the fan mode.
|
||||
|
||||
@ -387,7 +390,7 @@ class AirConditioner(MIoTServiceEntity, ClimateEntity):
|
||||
map_=self._fan_mode_map,
|
||||
key=self.get_prop_value(prop=self._prop_fan_level))
|
||||
|
||||
@ property
|
||||
@property
|
||||
def swing_mode(self) -> Optional[str]:
|
||||
"""Return the swing mode.
|
||||
|
||||
@ -473,3 +476,144 @@ class AirConditioner(MIoTServiceEntity, ClimateEntity):
|
||||
self._value_ac_state.update(v_ac_state)
|
||||
_LOGGER.debug(
|
||||
'ac_state update, %s', self._value_ac_state)
|
||||
|
||||
|
||||
class Heater(MIoTServiceEntity, ClimateEntity):
|
||||
"""Heater entities for Xiaomi Home."""
|
||||
# service: heater
|
||||
_prop_on: Optional[MIoTSpecProperty]
|
||||
_prop_mode: Optional[MIoTSpecProperty]
|
||||
_prop_target_temp: Optional[MIoTSpecProperty]
|
||||
_prop_heat_level: Optional[MIoTSpecProperty]
|
||||
# service: environment
|
||||
_prop_env_temp: Optional[MIoTSpecProperty]
|
||||
_prop_env_humi: Optional[MIoTSpecProperty]
|
||||
|
||||
_heat_level_map: Optional[dict[int, str]]
|
||||
|
||||
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:air-conditioner'
|
||||
self._attr_supported_features = ClimateEntityFeature(0)
|
||||
self._attr_preset_modes = []
|
||||
|
||||
self._prop_on = None
|
||||
self._prop_mode = None
|
||||
self._prop_target_temp = None
|
||||
self._prop_heat_level = None
|
||||
self._prop_env_temp = None
|
||||
self._prop_env_humi = None
|
||||
self._heat_level_map = None
|
||||
|
||||
# properties
|
||||
for prop in entity_data.props:
|
||||
if prop.name == 'on':
|
||||
self._attr_supported_features |= (
|
||||
ClimateEntityFeature.TURN_ON)
|
||||
self._attr_supported_features |= (
|
||||
ClimateEntityFeature.TURN_OFF)
|
||||
self._prop_on = prop
|
||||
elif prop.name == 'target-temperature':
|
||||
if not isinstance(prop.value_range, dict):
|
||||
_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
|
||||
elif prop.name == 'heat-level':
|
||||
if (
|
||||
not isinstance(prop.value_list, list)
|
||||
or not prop.value_list
|
||||
):
|
||||
_LOGGER.error(
|
||||
'invalid heat-level value_list, %s', self.entity_id)
|
||||
continue
|
||||
self._heat_level_map = {
|
||||
item['value']: item['description']
|
||||
for item in prop.value_list}
|
||||
self._attr_preset_modes = list(self._heat_level_map.values())
|
||||
self._attr_supported_features |= (
|
||||
ClimateEntityFeature.PRESET_MODE)
|
||||
self._prop_heat_level = prop
|
||||
elif prop.name == 'temperature':
|
||||
self._prop_env_temp = prop
|
||||
elif prop.name == 'relative-humidity':
|
||||
self._prop_env_humi = prop
|
||||
|
||||
# hvac modes
|
||||
self._attr_hvac_modes = [HVACMode.HEAT, HVACMode.OFF]
|
||||
|
||||
async def async_turn_on(self) -> None:
|
||||
"""Turn the entity on."""
|
||||
await self.set_property_async(prop=self._prop_on, value=True)
|
||||
|
||||
async def async_turn_off(self) -> None:
|
||||
"""Turn the entity off."""
|
||||
await self.set_property_async(prop=self._prop_on, value=False)
|
||||
|
||||
async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None:
|
||||
"""Set new target hvac mode."""
|
||||
await self.set_property_async(
|
||||
prop=self._prop_on, value=False
|
||||
if hvac_mode == HVACMode.OFF else True)
|
||||
|
||||
async def async_set_temperature(self, **kwargs):
|
||||
"""Set new target temperature."""
|
||||
if ATTR_TEMPERATURE in kwargs:
|
||||
temp = kwargs[ATTR_TEMPERATURE]
|
||||
if temp > self.max_temp:
|
||||
temp = self.max_temp
|
||||
elif temp < self.min_temp:
|
||||
temp = self.min_temp
|
||||
|
||||
await self.set_property_async(
|
||||
prop=self._prop_target_temp, value=temp)
|
||||
|
||||
async def async_set_preset_mode(self, preset_mode: str) -> None:
|
||||
"""Set the preset mode."""
|
||||
await self.set_property_async(
|
||||
self._prop_heat_level,
|
||||
value=self.get_map_value(
|
||||
map_=self._heat_level_map, description=preset_mode))
|
||||
|
||||
@property
|
||||
def target_temperature(self) -> Optional[float]:
|
||||
"""Return the target temperature."""
|
||||
return self.get_prop_value(
|
||||
prop=self._prop_target_temp) if self._prop_target_temp else None
|
||||
|
||||
@property
|
||||
def current_temperature(self) -> Optional[float]:
|
||||
"""Return the current temperature."""
|
||||
return self.get_prop_value(
|
||||
prop=self._prop_env_temp) if self._prop_env_temp else None
|
||||
|
||||
@property
|
||||
def current_humidity(self) -> Optional[int]:
|
||||
"""Return the current humidity."""
|
||||
return self.get_prop_value(
|
||||
prop=self._prop_env_humi) if self._prop_env_humi else None
|
||||
|
||||
@property
|
||||
def hvac_mode(self) -> Optional[HVACMode]:
|
||||
"""Return the hvac mode."""
|
||||
return (
|
||||
HVACMode.HEAT if self.get_prop_value(prop=self._prop_on)
|
||||
else HVACMode.OFF)
|
||||
|
||||
@property
|
||||
def preset_mode(self) -> Optional[str]:
|
||||
return (
|
||||
self.get_map_description(
|
||||
map_=self._heat_level_map,
|
||||
key=self.get_prop_value(prop=self._prop_heat_level))
|
||||
if self._prop_heat_level else None)
|
||||
|
||||
@ -602,8 +602,8 @@ class XiaomiMihomeConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
||||
last_step=True,
|
||||
)
|
||||
|
||||
@ staticmethod
|
||||
@ callback
|
||||
@staticmethod
|
||||
@callback
|
||||
def async_get_options_flow(
|
||||
config_entry: config_entries.ConfigEntry,
|
||||
) -> config_entries.OptionsFlow:
|
||||
|
||||
@ -236,7 +236,7 @@ class Light(MIoTServiceEntity, LightEntity):
|
||||
"""Return the color temperature."""
|
||||
return self.get_prop_value(prop=self._prop_color_temp)
|
||||
|
||||
@ property
|
||||
@property
|
||||
def rgb_color(self) -> Optional[tuple[int, int, int]]:
|
||||
"""Return the rgb color value."""
|
||||
rgb = self.get_prop_value(prop=self._prop_color)
|
||||
@ -247,7 +247,7 @@ class Light(MIoTServiceEntity, LightEntity):
|
||||
b = rgb & 0xFF
|
||||
return r, g, b
|
||||
|
||||
@ property
|
||||
@property
|
||||
def effect(self) -> Optional[str]:
|
||||
"""Return the current mode."""
|
||||
return self.__get_mode_description(
|
||||
|
||||
@ -25,7 +25,7 @@
|
||||
"cryptography",
|
||||
"psutil"
|
||||
],
|
||||
"version": "v0.1.0",
|
||||
"version": "v0.1.2",
|
||||
"zeroconf": [
|
||||
"_miot-central._tcp.local."
|
||||
]
|
||||
|
||||
@ -110,11 +110,13 @@ INTEGRATION_LANGUAGES = {
|
||||
'zh-Hans': '简体中文',
|
||||
'zh-Hant': '繁體中文',
|
||||
'en': 'English',
|
||||
'es': 'Español',
|
||||
'ru': 'Русский',
|
||||
'fr': 'Français',
|
||||
'de': 'Deutsch',
|
||||
'ja': '日本語'
|
||||
'es': 'Español',
|
||||
'fr': 'Français',
|
||||
'ja': '日本語',
|
||||
'pt': 'Português',
|
||||
'pt-BR': 'Português (Brasil)',
|
||||
'ru': 'Русский',
|
||||
}
|
||||
|
||||
DEFAULT_CTRL_MODE: str = 'auto'
|
||||
|
||||
95
custom_components/xiaomi_home/miot/i18n/pt-BR.json
Normal file
95
custom_components/xiaomi_home/miot/i18n/pt-BR.json
Normal file
@ -0,0 +1,95 @@
|
||||
{
|
||||
"config": {
|
||||
"other": {
|
||||
"devices": "dispositivos",
|
||||
"found_central_gateway": "encontrado o gateway central local"
|
||||
},
|
||||
"control_mode": {
|
||||
"auto": "automático",
|
||||
"cloud": "nuvem"
|
||||
},
|
||||
"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"
|
||||
},
|
||||
"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"
|
||||
}
|
||||
},
|
||||
"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",
|
||||
"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"
|
||||
}
|
||||
}
|
||||
}
|
||||
95
custom_components/xiaomi_home/miot/i18n/pt.json
Normal file
95
custom_components/xiaomi_home/miot/i18n/pt.json
Normal file
@ -0,0 +1,95 @@
|
||||
{
|
||||
"config": {
|
||||
"other": {
|
||||
"devices": "dispositivos",
|
||||
"found_central_gateway": ", encontrou a central de gateway local"
|
||||
},
|
||||
"control_mode": {
|
||||
"auto": "Automático",
|
||||
"cloud": "Nuvem"
|
||||
},
|
||||
"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"
|
||||
},
|
||||
"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"
|
||||
}
|
||||
},
|
||||
"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",
|
||||
"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"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1760,7 +1760,7 @@ class MIoTClient:
|
||||
delay_sec, self.__show_devices_changed_notify)
|
||||
|
||||
|
||||
@ staticmethod
|
||||
@staticmethod
|
||||
async def get_miot_instance_async(
|
||||
hass: HomeAssistant, entry_id: str, entry_data: Optional[dict] = None,
|
||||
persistent_notify: Optional[Callable[[str, str, str], None]] = None
|
||||
|
||||
@ -54,8 +54,8 @@ from homeassistant.helpers.entity import Entity
|
||||
from homeassistant.const import (
|
||||
CONCENTRATION_MICROGRAMS_PER_CUBIC_METER,
|
||||
CONCENTRATION_MILLIGRAMS_PER_CUBIC_METER,
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
CONCENTRATION_PARTS_PER_BILLION,
|
||||
CONCENTRATION_PARTS_PER_MILLION,
|
||||
LIGHT_LUX,
|
||||
PERCENTAGE,
|
||||
SIGNAL_STRENGTH_DECIBELS,
|
||||
@ -72,7 +72,6 @@ from homeassistant.const import (
|
||||
UnitOfPower,
|
||||
UnitOfVolume,
|
||||
UnitOfVolumeFlowRate,
|
||||
UnitOfConductivity
|
||||
)
|
||||
from homeassistant.helpers.entity import DeviceInfo
|
||||
from homeassistant.components.switch import SwitchDeviceClass
|
||||
@ -505,7 +504,8 @@ class MIoTDevice:
|
||||
prop_access.add('read')
|
||||
if prop.writable:
|
||||
prop_access.add('write')
|
||||
if prop_access != (SPEC_PROP_TRANS_MAP['entities'][platform]['access']):
|
||||
if prop_access != (SPEC_PROP_TRANS_MAP[
|
||||
'entities'][platform]['access']):
|
||||
return None
|
||||
if prop.format_ not in SPEC_PROP_TRANS_MAP[
|
||||
'entities'][platform]['format']:
|
||||
@ -584,7 +584,8 @@ class MIoTDevice:
|
||||
self.append_action(action=action)
|
||||
|
||||
def unit_convert(self, spec_unit: str) -> Optional[str]:
|
||||
return {
|
||||
"""Convert MIoT unit to Home Assistant unit."""
|
||||
unit_map = {
|
||||
'percentage': PERCENTAGE,
|
||||
'weeks': UnitOfTime.WEEKS,
|
||||
'days': UnitOfTime.DAYS,
|
||||
@ -616,11 +617,21 @@ class MIoTDevice:
|
||||
'm': UnitOfLength.METERS,
|
||||
'km': UnitOfLength.KILOMETERS,
|
||||
'm3/h': UnitOfVolumeFlowRate.CUBIC_METERS_PER_HOUR,
|
||||
'μS/cm': UnitOfConductivity.MICROSIEMENS_PER_CM,
|
||||
'gram': UnitOfMass.GRAMS,
|
||||
'dB': SIGNAL_STRENGTH_DECIBELS,
|
||||
'kB': UnitOfInformation.KILOBYTES,
|
||||
}.get(spec_unit, None)
|
||||
}
|
||||
|
||||
# Handle UnitOfConductivity separately since
|
||||
# it might not be available in all HA versions
|
||||
try:
|
||||
# pylint: disable=import-outside-toplevel
|
||||
from homeassistant.const import UnitOfConductivity
|
||||
unit_map['μS/cm'] = UnitOfConductivity.MICROSIEMENS_PER_CM
|
||||
except ImportError:
|
||||
unit_map['μS/cm'] = 'μS/cm'
|
||||
|
||||
return unit_map.get(spec_unit, None)
|
||||
|
||||
def icon_convert(self, spec_unit: str) -> Optional[str]:
|
||||
if spec_unit in ['percentage']:
|
||||
@ -1170,8 +1181,8 @@ class MIoTEventEntity(Entity):
|
||||
handler=self.__on_device_state_changed)
|
||||
# Sub value changed
|
||||
self.miot_device.sub_event(
|
||||
handler=self.__on_event_occurred, siid=self.service.iid,
|
||||
eiid=self.spec.iid)
|
||||
handler=self.__on_event_occurred,
|
||||
siid=self.service.iid, eiid=self.spec.iid)
|
||||
|
||||
async def async_will_remove_from_hass(self) -> None:
|
||||
self.miot_device.unsub_device_state(
|
||||
|
||||
@ -564,11 +564,11 @@ class MIoTLan:
|
||||
0, lambda: self._main_loop.create_task(
|
||||
self.init_async()))
|
||||
|
||||
@ property
|
||||
@property
|
||||
def virtual_did(self) -> str:
|
||||
return self._virtual_did
|
||||
|
||||
@ property
|
||||
@property
|
||||
def mev(self) -> MIoTEventLoop:
|
||||
return self._mev
|
||||
|
||||
|
||||
@ -208,9 +208,32 @@ SPEC_DEVICE_TRANS_MAP: dict[str, dict | str] = {
|
||||
}
|
||||
}
|
||||
},
|
||||
'entity': 'climate'
|
||||
'entity': 'air-conditioner'
|
||||
},
|
||||
'air-condition-outlet': 'air-conditioner'
|
||||
'air-condition-outlet': 'air-conditioner',
|
||||
'heater': {
|
||||
'required': {
|
||||
'heater': {
|
||||
'required': {
|
||||
'properties': {
|
||||
'on': {'read', 'write'}
|
||||
}
|
||||
},
|
||||
'optional': {
|
||||
'properties': {'target-temperature', 'heat-level'}
|
||||
},
|
||||
}
|
||||
},
|
||||
'optional': {
|
||||
'environment': {
|
||||
'required': {},
|
||||
'optional': {
|
||||
'properties': {'temperature', 'relative-humidity'}
|
||||
}
|
||||
},
|
||||
},
|
||||
'entity': 'heater'
|
||||
}
|
||||
}
|
||||
|
||||
"""SPEC_SERVICE_TRANS_MAP
|
||||
|
||||
@ -1,7 +0,0 @@
|
||||
# CHANGELOG
|
||||
|
||||
## 0.1.0
|
||||
### Added
|
||||
- first version
|
||||
### Changed
|
||||
### Fixed
|
||||
@ -325,7 +325,7 @@ event instance name 下的值表示转换后实体所用的 `_attr_device_class`
|
||||
|
||||
## 多语言支持
|
||||
|
||||
米家集成配置选项中可选择的集成使用的语言有简体中文、繁体中文、英文、西班牙语、俄语、法语、德语、日语这八种语言。目前,米家集成配置页面的简体中文和英文已经过人工校审,其他语言由机器翻译。如果您希望修改配置页面的词句,则需要修改 `custom_components/xiaomi_home/translations/` 目录下相应语言的 json 文件。
|
||||
米家集成配置选项中可选择的集成使用的语言有简体中文、繁体中文、英文、西班牙语、俄语、法语、德语、日语这八种语言。目前,米家集成配置页面的简体中文和英文已经过人工校审,其他语言由机器翻译。如果您希望修改配置页面的词句,则需要修改 `custom_components/xiaomi_home/translations/` 以及 `custom_components/xiaomi_home/miot/i18n/` 目录下相应语言的 json 文件。
|
||||
|
||||
在显示 Home Assistant 实体名称时,米家集成会从小米云下载设备厂商为设备配置的多语言文件,该文件包含设备 MIoT-Spec-V2 实例的多语言翻译。 `multi_lang.json` 是本地维护的多语言配置字典,其优先级高于从云端获取的多语言文件,可用于补充或修改设备的多语言翻译。
|
||||
|
||||
|
||||
@ -20,8 +20,13 @@ rm -rf "$config_path/custom_components/xiaomi_home"
|
||||
script_path=$(dirname "$0")
|
||||
# Change to the script path.
|
||||
cd "$script_path"
|
||||
|
||||
# Copy the new version.
|
||||
cp -r custom_components/xiaomi_home/ "$config_path/custom_components/"
|
||||
if [ -d "$config_path/custom_components" ]; then
|
||||
cp -r custom_components/xiaomi_home/ "$config_path/custom_components/"
|
||||
else
|
||||
cp -r custom_components/ "$config_path/custom_components/"
|
||||
fi
|
||||
|
||||
# Done.
|
||||
echo "Xiaomi Home installation is completed. Please restart Home Assistant."
|
||||
|
||||
Loading…
Reference in New Issue
Block a user