From bff5b3bf4455de3260642dded4655a41fa19d093 Mon Sep 17 00:00:00 2001 From: LiShuzhen Date: Tue, 17 Dec 2024 16:31:08 +0800 Subject: [PATCH 01/19] fix: air-conditioner switch on --- custom_components/xiaomi_home/climate.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/custom_components/xiaomi_home/climate.py b/custom_components/xiaomi_home/climate.py index 860afac..baedf61 100644 --- a/custom_components/xiaomi_home/climate.py +++ b/custom_components/xiaomi_home/climate.py @@ -254,6 +254,7 @@ class AirConditioner(MIoTServiceEntity, ClimateEntity): async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None: """Set new target hvac mode.""" + # set air-conditioner off if hvac_mode == HVACMode.OFF and self._prop_on: if not await self.set_property_async( prop=self._prop_on, value=False): @@ -261,6 +262,11 @@ class AirConditioner(MIoTServiceEntity, ClimateEntity): f'set climate prop.on failed, {hvac_mode}, ' f'{self.entity_id}') return + # set air-conditioner on + if hvac_mode != HVACMode.OFF and not self.get_prop_value( + prop=self._prop_on): + await self.async_turn_on() + # set mode mode_value = self.get_map_value( map_=self._hvac_mode_map, description=hvac_mode) if ( From dbf943386ef5f2ec643c1d404b85deafd4e7650c Mon Sep 17 00:00:00 2001 From: LiShuzhen Date: Tue, 17 Dec 2024 17:33:28 +0800 Subject: [PATCH 02/19] fix: set prop --- custom_components/xiaomi_home/climate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom_components/xiaomi_home/climate.py b/custom_components/xiaomi_home/climate.py index baedf61..0b1ffd7 100644 --- a/custom_components/xiaomi_home/climate.py +++ b/custom_components/xiaomi_home/climate.py @@ -265,7 +265,7 @@ class AirConditioner(MIoTServiceEntity, ClimateEntity): # set air-conditioner on if hvac_mode != HVACMode.OFF and not self.get_prop_value( prop=self._prop_on): - await self.async_turn_on() + await self.set_property_async(prop=self._prop_on, value=True) # set mode mode_value = self.get_map_value( map_=self._hvac_mode_map, description=hvac_mode) From da58d4c0a59aa52e8ff52cc334b9b4f3d1a0c8e5 Mon Sep 17 00:00:00 2001 From: LiShuzhen Date: Tue, 17 Dec 2024 17:50:08 +0800 Subject: [PATCH 03/19] perf: remove permanent true statement --- custom_components/xiaomi_home/climate.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/custom_components/xiaomi_home/climate.py b/custom_components/xiaomi_home/climate.py index 0b1ffd7..a1d2ad4 100644 --- a/custom_components/xiaomi_home/climate.py +++ b/custom_components/xiaomi_home/climate.py @@ -255,7 +255,7 @@ class AirConditioner(MIoTServiceEntity, ClimateEntity): async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None: """Set new target hvac mode.""" # set air-conditioner off - if hvac_mode == HVACMode.OFF and self._prop_on: + if hvac_mode == HVACMode.OFF: if not await self.set_property_async( prop=self._prop_on, value=False): raise RuntimeError( @@ -263,7 +263,7 @@ class AirConditioner(MIoTServiceEntity, ClimateEntity): f'{self.entity_id}') return # set air-conditioner on - if hvac_mode != HVACMode.OFF and not self.get_prop_value( + elif not self.get_prop_value( prop=self._prop_on): await self.set_property_async(prop=self._prop_on, value=True) # set mode @@ -372,7 +372,7 @@ class AirConditioner(MIoTServiceEntity, ClimateEntity): @ property def hvac_mode(self) -> Optional[HVACMode]: """Return the hvac mode. e.g., heat, cool mode.""" - if self._prop_on and self.get_prop_value(prop=self._prop_on) is False: + if not self.get_prop_value(prop=self._prop_on): return HVACMode.OFF return self.get_map_description( map_=self._hvac_mode_map, From b7fc534a34e518a3f05ee1a0049342b21335cfb6 Mon Sep 17 00:00:00 2001 From: LiShuzhen Date: Tue, 17 Dec 2024 17:57:02 +0800 Subject: [PATCH 04/19] fix: bool value false --- custom_components/xiaomi_home/climate.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/custom_components/xiaomi_home/climate.py b/custom_components/xiaomi_home/climate.py index a1d2ad4..cc12373 100644 --- a/custom_components/xiaomi_home/climate.py +++ b/custom_components/xiaomi_home/climate.py @@ -263,8 +263,7 @@ class AirConditioner(MIoTServiceEntity, ClimateEntity): f'{self.entity_id}') return # set air-conditioner on - elif not self.get_prop_value( - prop=self._prop_on): + elif self.get_prop_value(prop=self._prop_on) is False: await self.set_property_async(prop=self._prop_on, value=True) # set mode mode_value = self.get_map_value( @@ -372,7 +371,7 @@ class AirConditioner(MIoTServiceEntity, ClimateEntity): @ property def hvac_mode(self) -> Optional[HVACMode]: """Return the hvac mode. e.g., heat, cool mode.""" - if not self.get_prop_value(prop=self._prop_on): + if self.get_prop_value(prop=self._prop_on) is False: return HVACMode.OFF return self.get_map_description( map_=self._hvac_mode_map, From 99e654f0c7285ab959980a1c36a272192afe2604 Mon Sep 17 00:00:00 2001 From: topsworld Date: Wed, 18 Dec 2024 10:34:07 +0800 Subject: [PATCH 05/19] style: remove invalid space --- custom_components/xiaomi_home/climate.py | 14 +++++++------- custom_components/xiaomi_home/config_flow.py | 4 ++-- custom_components/xiaomi_home/light.py | 4 ++-- custom_components/xiaomi_home/miot/miot_client.py | 2 +- custom_components/xiaomi_home/miot/miot_lan.py | 4 ++-- 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/custom_components/xiaomi_home/climate.py b/custom_components/xiaomi_home/climate.py index cc12373..909fee4 100644 --- a/custom_components/xiaomi_home/climate.py +++ b/custom_components/xiaomi_home/climate.py @@ -344,31 +344,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 +377,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 +387,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. diff --git a/custom_components/xiaomi_home/config_flow.py b/custom_components/xiaomi_home/config_flow.py index ccc91f9..c1e4e67 100644 --- a/custom_components/xiaomi_home/config_flow.py +++ b/custom_components/xiaomi_home/config_flow.py @@ -564,8 +564,8 @@ class XiaomiMihomeConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): last_step=False, ) - @ staticmethod - @ callback + @staticmethod + @callback def async_get_options_flow( config_entry: config_entries.ConfigEntry, ) -> config_entries.OptionsFlow: diff --git a/custom_components/xiaomi_home/light.py b/custom_components/xiaomi_home/light.py index 610882e..49229f5 100644 --- a/custom_components/xiaomi_home/light.py +++ b/custom_components/xiaomi_home/light.py @@ -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( diff --git a/custom_components/xiaomi_home/miot/miot_client.py b/custom_components/xiaomi_home/miot/miot_client.py index 771de41..31c87f0 100644 --- a/custom_components/xiaomi_home/miot/miot_client.py +++ b/custom_components/xiaomi_home/miot/miot_client.py @@ -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 diff --git a/custom_components/xiaomi_home/miot/miot_lan.py b/custom_components/xiaomi_home/miot/miot_lan.py index 4635572..525be2f 100644 --- a/custom_components/xiaomi_home/miot/miot_lan.py +++ b/custom_components/xiaomi_home/miot/miot_lan.py @@ -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 From b5f9e931b70cf4013eebc1aa83923d7ef92d7cdd Mon Sep 17 00:00:00 2001 From: topsworld Date: Wed, 18 Dec 2024 10:35:59 +0800 Subject: [PATCH 06/19] feat: support xiaomi heater devices --- custom_components/xiaomi_home/climate.py | 112 +++++++++++++++++- .../xiaomi_home/miot/specs/specv2entity.py | 27 ++++- 2 files changed, 135 insertions(+), 4 deletions(-) diff --git a/custom_components/xiaomi_home/climate.py b/custom_components/xiaomi_home/climate.py index 909fee4..ccda2b6 100644 --- a/custom_components/xiaomi_home/climate.py +++ b/custom_components/xiaomi_home/climate.py @@ -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) @@ -473,3 +476,108 @@ 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] + # service: environment + _prop_env_temp: Optional[MIoTSpecProperty] + _prop_env_humi: Optional[MIoTSpecProperty] + + 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._prop_on = None + self._prop_mode = None + self._prop_target_temp = None + self._prop_env_temp = None + self._prop_env_humi = 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 == '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) + + @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) diff --git a/custom_components/xiaomi_home/miot/specs/specv2entity.py b/custom_components/xiaomi_home/miot/specs/specv2entity.py index 5c64083..084cb1a 100644 --- a/custom_components/xiaomi_home/miot/specs/specv2entity.py +++ b/custom_components/xiaomi_home/miot/specs/specv2entity.py @@ -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'} + }, + } + }, + 'optional': { + 'environment': { + 'required': {}, + 'optional': { + 'properties': {'temperature', 'relative-humidity'} + } + }, + }, + 'entity': 'heater' + } } """SPEC_SERVICE_TRANS_MAP From 6bb4bf32d76f0f97a1a8ea4d97a1b3809393742a Mon Sep 17 00:00:00 2001 From: KNOOP Date: Tue, 17 Dec 2024 16:20:02 +0800 Subject: [PATCH 07/19] fix: handle UnitOfConductivity import Move unit imports inside function and add fallback for older versions. Resolves #123 --- .../xiaomi_home/miot/miot_device.py | 51 +++++++++++-------- 1 file changed, 31 insertions(+), 20 deletions(-) diff --git a/custom_components/xiaomi_home/miot/miot_device.py b/custom_components/xiaomi_home/miot/miot_device.py index 56637d6..3531ebf 100644 --- a/custom_components/xiaomi_home/miot/miot_device.py +++ b/custom_components/xiaomi_home/miot/miot_device.py @@ -59,20 +59,6 @@ from homeassistant.const import ( LIGHT_LUX, PERCENTAGE, SIGNAL_STRENGTH_DECIBELS, - UnitOfEnergy, - UnitOfElectricCurrent, - UnitOfElectricPotential, - UnitOfInformation, - UnitOfLength, - UnitOfMass, - UnitOfSpeed, - UnitOfTime, - UnitOfTemperature, - UnitOfPressure, - UnitOfPower, - UnitOfVolume, - UnitOfVolumeFlowRate, - UnitOfConductivity ) from homeassistant.helpers.entity import DeviceInfo from homeassistant.components.switch import SwitchDeviceClass @@ -505,7 +491,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 +571,24 @@ class MIoTDevice: self.append_action(action=action) def unit_convert(self, spec_unit: str) -> Optional[str]: - return { + """Convert MIoT unit to Home Assistant unit.""" + from homeassistant.const import ( + UnitOfEnergy, + UnitOfElectricCurrent, + UnitOfElectricPotential, + UnitOfInformation, + UnitOfLength, + UnitOfMass, + UnitOfSpeed, + UnitOfTime, + UnitOfTemperature, + UnitOfPressure, + UnitOfPower, + UnitOfVolume, + UnitOfVolumeFlowRate, + ) + + unit_map = { 'percentage': PERCENTAGE, 'weeks': UnitOfTime.WEEKS, 'days': UnitOfTime.DAYS, @@ -616,11 +620,18 @@ 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) + } + + try: + 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( From c744919032ca7ae81311ebae91b1d920db7752c6 Mon Sep 17 00:00:00 2001 From: KNOOP Date: Tue, 17 Dec 2024 18:21:03 +0800 Subject: [PATCH 08/19] fix: handle UnitOfConductivity import #54 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move unit imports inside function 和 add fallback for older versions. Resolves --- .../xiaomi_home/miot/miot_device.py | 32 +++++++++---------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/custom_components/xiaomi_home/miot/miot_device.py b/custom_components/xiaomi_home/miot/miot_device.py index 3531ebf..8de4c1c 100644 --- a/custom_components/xiaomi_home/miot/miot_device.py +++ b/custom_components/xiaomi_home/miot/miot_device.py @@ -54,11 +54,24 @@ 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, + UnitOfEnergy, + UnitOfElectricCurrent, + UnitOfElectricPotential, + UnitOfInformation, + UnitOfLength, + UnitOfMass, + UnitOfSpeed, + UnitOfTime, + UnitOfTemperature, + UnitOfPressure, + UnitOfPower, + UnitOfVolume, + UnitOfVolumeFlowRate, ) from homeassistant.helpers.entity import DeviceInfo from homeassistant.components.switch import SwitchDeviceClass @@ -572,22 +585,6 @@ class MIoTDevice: def unit_convert(self, spec_unit: str) -> Optional[str]: """Convert MIoT unit to Home Assistant unit.""" - from homeassistant.const import ( - UnitOfEnergy, - UnitOfElectricCurrent, - UnitOfElectricPotential, - UnitOfInformation, - UnitOfLength, - UnitOfMass, - UnitOfSpeed, - UnitOfTime, - UnitOfTemperature, - UnitOfPressure, - UnitOfPower, - UnitOfVolume, - UnitOfVolumeFlowRate, - ) - unit_map = { 'percentage': PERCENTAGE, 'weeks': UnitOfTime.WEEKS, @@ -625,6 +622,7 @@ class MIoTDevice: 'kB': UnitOfInformation.KILOBYTES, } + # Handle UnitOfConductivity separately since it might not be available in all HA versions try: from homeassistant.const import UnitOfConductivity unit_map['μS/cm'] = UnitOfConductivity.MICROSIEMENS_PER_CM From b498a708acf860f0a3be0f0794318aa055d8027a Mon Sep 17 00:00:00 2001 From: Guoliang Li Date: Wed, 18 Dec 2024 15:44:04 +0800 Subject: [PATCH 09/19] style: ignore pylint warning --- custom_components/xiaomi_home/miot/miot_device.py | 1 + 1 file changed, 1 insertion(+) diff --git a/custom_components/xiaomi_home/miot/miot_device.py b/custom_components/xiaomi_home/miot/miot_device.py index 8de4c1c..8fdc597 100644 --- a/custom_components/xiaomi_home/miot/miot_device.py +++ b/custom_components/xiaomi_home/miot/miot_device.py @@ -624,6 +624,7 @@ class MIoTDevice: # 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: From e70acd8421a5105e7cf12b2ead6bfb8269a0ff9c Mon Sep 17 00:00:00 2001 From: Guoliang Li Date: Wed, 18 Dec 2024 15:48:51 +0800 Subject: [PATCH 10/19] style: update comments to meet coding standards --- custom_components/xiaomi_home/miot/miot_device.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/custom_components/xiaomi_home/miot/miot_device.py b/custom_components/xiaomi_home/miot/miot_device.py index 8fdc597..3cda670 100644 --- a/custom_components/xiaomi_home/miot/miot_device.py +++ b/custom_components/xiaomi_home/miot/miot_device.py @@ -622,7 +622,8 @@ class MIoTDevice: 'kB': UnitOfInformation.KILOBYTES, } - # Handle UnitOfConductivity separately since it might not be available in all HA versions + # Handle UnitOfConductivity separately since + # it might not be available in all HA versions try: # pylint: disable=import-outside-toplevel from homeassistant.const import UnitOfConductivity From ce4f23b1bd0a695d8b212d494e4313fe6744f2bf Mon Sep 17 00:00:00 2001 From: Guoliang Li Date: Wed, 18 Dec 2024 15:54:37 +0800 Subject: [PATCH 11/19] style: fix the trailing space problem reported by pylint --- custom_components/xiaomi_home/miot/miot_device.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom_components/xiaomi_home/miot/miot_device.py b/custom_components/xiaomi_home/miot/miot_device.py index 3cda670..fa48345 100644 --- a/custom_components/xiaomi_home/miot/miot_device.py +++ b/custom_components/xiaomi_home/miot/miot_device.py @@ -622,7 +622,7 @@ class MIoTDevice: 'kB': UnitOfInformation.KILOBYTES, } - # Handle UnitOfConductivity separately since + # Handle UnitOfConductivity separately since # it might not be available in all HA versions try: # pylint: disable=import-outside-toplevel From 6e2de896c39731844a9cc04847ff949a62cb70d0 Mon Sep 17 00:00:00 2001 From: topsworld Date: Wed, 18 Dec 2024 17:42:40 +0800 Subject: [PATCH 12/19] feat: update xiaomi heater ctrl logic --- custom_components/xiaomi_home/climate.py | 36 +++++++++++++++++++ .../xiaomi_home/miot/specs/specv2entity.py | 2 +- 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/custom_components/xiaomi_home/climate.py b/custom_components/xiaomi_home/climate.py index ccda2b6..106abb9 100644 --- a/custom_components/xiaomi_home/climate.py +++ b/custom_components/xiaomi_home/climate.py @@ -484,10 +484,13 @@ class Heater(MIoTServiceEntity, ClimateEntity): _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: @@ -495,12 +498,15 @@ class Heater(MIoTServiceEntity, ClimateEntity): 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: @@ -523,6 +529,21 @@ class Heater(MIoTServiceEntity, ClimateEntity): 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': @@ -557,6 +578,13 @@ class Heater(MIoTServiceEntity, ClimateEntity): 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.""" @@ -581,3 +609,11 @@ class Heater(MIoTServiceEntity, ClimateEntity): 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) diff --git a/custom_components/xiaomi_home/miot/specs/specv2entity.py b/custom_components/xiaomi_home/miot/specs/specv2entity.py index 084cb1a..4a57867 100644 --- a/custom_components/xiaomi_home/miot/specs/specv2entity.py +++ b/custom_components/xiaomi_home/miot/specs/specv2entity.py @@ -220,7 +220,7 @@ SPEC_DEVICE_TRANS_MAP: dict[str, dict | str] = { } }, 'optional': { - 'properties': {'target-temperature'} + 'properties': {'target-temperature', 'heat-level'} }, } }, From fec5d10f42c200c20dd427bafa49aa5a46c54f55 Mon Sep 17 00:00:00 2001 From: fanjinyu Date: Wed, 18 Dec 2024 19:32:00 +0800 Subject: [PATCH 13/19] add pt and pt-BR language support in i18n --- .../xiaomi_home/miot/i18n/pt-BR.json | 95 +++++++++++++++++++ .../xiaomi_home/miot/i18n/pt.json | 95 +++++++++++++++++++ 2 files changed, 190 insertions(+) create mode 100644 custom_components/xiaomi_home/miot/i18n/pt-BR.json create mode 100644 custom_components/xiaomi_home/miot/i18n/pt.json diff --git a/custom_components/xiaomi_home/miot/i18n/pt-BR.json b/custom_components/xiaomi_home/miot/i18n/pt-BR.json new file mode 100644 index 0000000..8df352b --- /dev/null +++ b/custom_components/xiaomi_home/miot/i18n/pt-BR.json @@ -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" + } + } +} \ No newline at end of file diff --git a/custom_components/xiaomi_home/miot/i18n/pt.json b/custom_components/xiaomi_home/miot/i18n/pt.json new file mode 100644 index 0000000..dd30774 --- /dev/null +++ b/custom_components/xiaomi_home/miot/i18n/pt.json @@ -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" + } + } +} \ No newline at end of file From 2c37fb63ca94909602e9c7634f626f0a5f2452c6 Mon Sep 17 00:00:00 2001 From: topsworld Date: Wed, 18 Dec 2024 20:39:48 +0800 Subject: [PATCH 14/19] doc: update change log and version --- custom_components/xiaomi_home/manifest.json | 2 +- doc/CHANGELOG.md | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/custom_components/xiaomi_home/manifest.json b/custom_components/xiaomi_home/manifest.json index 67ff027..406fe9d 100644 --- a/custom_components/xiaomi_home/manifest.json +++ b/custom_components/xiaomi_home/manifest.json @@ -25,7 +25,7 @@ "cryptography", "psutil" ], - "version": "v0.1.0", + "version": "v0.1.2", "zeroconf": [ "_miot-central._tcp.local." ] diff --git a/doc/CHANGELOG.md b/doc/CHANGELOG.md index 4fc27b4..a05915e 100644 --- a/doc/CHANGELOG.md +++ b/doc/CHANGELOG.md @@ -1,5 +1,23 @@ # CHANGELOG +## 0.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 + +## 0.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 + ## 0.1.0 ### Added - first version From fce67ba2da8058c5364a2bfcfe579f1ca5e1773a Mon Sep 17 00:00:00 2001 From: topsworld Date: Wed, 18 Dec 2024 20:45:07 +0800 Subject: [PATCH 15/19] doc: move CONTRIBUTING.md, CHANGELOG.md to root path --- doc/CHANGELOG.md => CHANGELOG.md | 6 +++--- doc/CONTRIBUTING.md => CONTRIBUTING.md | 2 +- README.md | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) rename doc/CHANGELOG.md => CHANGELOG.md (96%) rename doc/CONTRIBUTING.md => CONTRIBUTING.md (98%) diff --git a/doc/CHANGELOG.md b/CHANGELOG.md similarity index 96% rename from doc/CHANGELOG.md rename to CHANGELOG.md index a05915e..ed98f74 100644 --- a/doc/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # CHANGELOG -## 0.1.2 +## 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. @@ -8,7 +8,7 @@ - Adjust the minimum version of HASS core to 2024.4.4 and above versions. ### Fixed -## 0.1.1 +## v0.1.1 ### Added ### Changed ### Fixed @@ -18,7 +18,7 @@ - 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 -## 0.1.0 +## v0.1.0 ### Added - first version ### Changed diff --git a/doc/CONTRIBUTING.md b/CONTRIBUTING.md similarity index 98% rename from doc/CONTRIBUTING.md rename to CONTRIBUTING.md index ff13ba1..dfcdb65 100644 --- a/doc/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -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. diff --git a/README.md b/README.md index 6f97f2a..c140586 100644 --- a/README.md +++ b/README.md @@ -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 From 7618f6b366857a81d63d48a1f1e2074458e32834 Mon Sep 17 00:00:00 2001 From: topsworld Date: Wed, 18 Dec 2024 20:46:32 +0800 Subject: [PATCH 16/19] doc: update change log --- CHANGELOG.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ed98f74..a14aec7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,14 +12,14 @@ ### 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 +- 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 +- First version ### Changed ### Fixed From 1e0ddc1f0cbab5c849068a1c3bc30e4d82351613 Mon Sep 17 00:00:00 2001 From: topsworld Date: Wed, 18 Dec 2024 21:20:51 +0800 Subject: [PATCH 17/19] feat: const.INTEGRATION_LANGUAGES add pt, pt-BR --- custom_components/xiaomi_home/miot/const.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/custom_components/xiaomi_home/miot/const.py b/custom_components/xiaomi_home/miot/const.py index 7aec73d..7518ca2 100644 --- a/custom_components/xiaomi_home/miot/const.py +++ b/custom_components/xiaomi_home/miot/const.py @@ -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' From be627afe54ce6c680e5bec4500a247c05198936f Mon Sep 17 00:00:00 2001 From: LiShuzhen Date: Wed, 18 Dec 2024 21:34:04 +0800 Subject: [PATCH 18/19] docs: add i18n in README --- README.md | 2 +- doc/README_zh.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c140586..fe3b75c 100644 --- a/README.md +++ b/README.md @@ -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. diff --git a/doc/README_zh.md b/doc/README_zh.md index cee5c67..742c0ea 100644 --- a/doc/README_zh.md +++ b/doc/README_zh.md @@ -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` 是本地维护的多语言配置字典,其优先级高于从云端获取的多语言文件,可用于补充或修改设备的多语言翻译。 From 6fae26a378cbcb3bd507b150529b27b7c9e056c6 Mon Sep 17 00:00:00 2001 From: yejinze Date: Wed, 18 Dec 2024 22:01:10 +0800 Subject: [PATCH 19/19] fix: directory copy issue --- install.sh | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/install.sh b/install.sh index f625e34..5873f13 100755 --- a/install.sh +++ b/install.sh @@ -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."