mirror of
				https://github.com/XiaoMi/ha_xiaomi_home.git
				synced 2025-10-31 17:32:20 +08:00 
			
		
		
		
	Merge branch 'XiaoMi:main' into main
This commit is contained in:
		| @@ -1,4 +1,12 @@ | |||||||
| # CHANGELOG | # CHANGELOG | ||||||
|  | ## v0.2.3 | ||||||
|  | ### Changed | ||||||
|  | - Specify the service name and the property name during the climate entity's on/off feature initialization. [#899](https://github.com/XiaoMi/ha_xiaomi_home/pull/899) | ||||||
|  | - Remove the useless total-battery property from `SPEC_PROP_TRANS_MAP`. | ||||||
|  | ### Fixed | ||||||
|  | - Fix the hvac mode setting error when changing the preset mode of the ptc-bath-heater. | ||||||
|  | - Fix the ambiguous descriptions of yeelink.bhf_light.v10 ptc-bath-heater mode value-list. | ||||||
|  | - Fix the power consumption value of chuangmi.plug.212a01. [#910](https://github.com/XiaoMi/ha_xiaomi_home/pull/910) | ||||||
|  |  | ||||||
| ## v0.2.2 | ## v0.2.2 | ||||||
| This version has modified the conversion rules of the climate entity, which will have effect on the devices with the ptc-bath-heater, the air-conditioner and the air-fresh service. After updating, you need to restart Home Assistant and check `xiaomi_home > CONFIGURE > | This version has modified the conversion rules of the climate entity, which will have effect on the devices with the ptc-bath-heater, the air-conditioner and the air-fresh service. After updating, you need to restart Home Assistant and check `xiaomi_home > CONFIGURE > | ||||||
|   | |||||||
| @@ -51,6 +51,7 @@ from typing import Any, Optional | |||||||
|  |  | ||||||
| from homeassistant.config_entries import ConfigEntry | from homeassistant.config_entries import ConfigEntry | ||||||
| from homeassistant.core import HomeAssistant | from homeassistant.core import HomeAssistant | ||||||
|  | from homeassistant.const import UnitOfTemperature | ||||||
| from homeassistant.helpers.entity_platform import AddEntitiesCallback | from homeassistant.helpers.entity_platform import AddEntitiesCallback | ||||||
| from homeassistant.components.climate import ( | from homeassistant.components.climate import ( | ||||||
|     FAN_ON, FAN_OFF, SWING_OFF, SWING_BOTH, SWING_VERTICAL, SWING_HORIZONTAL, |     FAN_ON, FAN_OFF, SWING_OFF, SWING_BOTH, SWING_VERTICAL, SWING_HORIZONTAL, | ||||||
| @@ -101,21 +102,19 @@ class FeatureOnOff(MIoTServiceEntity, ClimateEntity): | |||||||
|         self._prop_on = None |         self._prop_on = None | ||||||
|  |  | ||||||
|         super().__init__(miot_device=miot_device, entity_data=entity_data) |         super().__init__(miot_device=miot_device, entity_data=entity_data) | ||||||
|         # properties |  | ||||||
|         for prop in entity_data.props: |     def _init_on_off(self, service_name: str, prop_name: str) -> None: | ||||||
|             if prop.name == 'on': |         """Initialize the on_off feature.""" | ||||||
|                 if ( |         for prop in self.entity_data.props: | ||||||
|                         # The "on" property of the "fan-control" service is not |             if prop.name == prop_name and prop.service.name == service_name: | ||||||
|                         # the on/off feature of the entity. |                 if prop.format_ != bool: | ||||||
|                         prop.service.name == 'air-conditioner' or |                     _LOGGER.error('wrong format %s %s, %s', service_name, | ||||||
|                         prop.service.name == 'heater' or |                                   prop_name, self.entity_id) | ||||||
|                         prop.service.name == 'thermostat' or |                     continue | ||||||
|                         prop.service.name == 'electric-blanket'): |                 self._attr_supported_features |= ClimateEntityFeature.TURN_ON | ||||||
|                     self._attr_supported_features |= ( |                 self._attr_supported_features |= ClimateEntityFeature.TURN_OFF | ||||||
|                         ClimateEntityFeature.TURN_ON) |                 self._prop_on = prop | ||||||
|                     self._attr_supported_features |= ( |                 break | ||||||
|                         ClimateEntityFeature.TURN_OFF) |  | ||||||
|                     self._prop_on = prop |  | ||||||
|  |  | ||||||
|     async def async_turn_on(self) -> None: |     async def async_turn_on(self) -> None: | ||||||
|         """Turn on.""" |         """Turn on.""" | ||||||
| @@ -134,6 +133,7 @@ class FeatureTargetTemperature(MIoTServiceEntity, ClimateEntity): | |||||||
|                  entity_data: MIoTEntityData) -> None: |                  entity_data: MIoTEntityData) -> None: | ||||||
|         """Initialize the feature class.""" |         """Initialize the feature class.""" | ||||||
|         self._prop_target_temp = None |         self._prop_target_temp = None | ||||||
|  |         self._attr_temperature_unit = None | ||||||
|  |  | ||||||
|         super().__init__(miot_device=miot_device, entity_data=entity_data) |         super().__init__(miot_device=miot_device, entity_data=entity_data) | ||||||
|         # properties |         # properties | ||||||
| @@ -151,6 +151,10 @@ class FeatureTargetTemperature(MIoTServiceEntity, ClimateEntity): | |||||||
|                 self._attr_supported_features |= ( |                 self._attr_supported_features |= ( | ||||||
|                     ClimateEntityFeature.TARGET_TEMPERATURE) |                     ClimateEntityFeature.TARGET_TEMPERATURE) | ||||||
|                 self._prop_target_temp = prop |                 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): |     async def async_set_temperature(self, **kwargs): | ||||||
|         """Set the target temperature.""" |         """Set the target temperature.""" | ||||||
| @@ -197,6 +201,7 @@ class FeaturePresetMode(MIoTServiceEntity, ClimateEntity): | |||||||
|                 self._attr_supported_features |= ( |                 self._attr_supported_features |= ( | ||||||
|                     ClimateEntityFeature.PRESET_MODE) |                     ClimateEntityFeature.PRESET_MODE) | ||||||
|                 self._prop_mode = prop |                 self._prop_mode = prop | ||||||
|  |                 break | ||||||
|  |  | ||||||
|     async def async_set_preset_mode(self, preset_mode: str) -> None: |     async def async_set_preset_mode(self, preset_mode: str) -> None: | ||||||
|         """Set the preset mode.""" |         """Set the preset mode.""" | ||||||
| @@ -365,6 +370,7 @@ class FeatureTemperature(MIoTServiceEntity, ClimateEntity): | |||||||
|         for prop in entity_data.props: |         for prop in entity_data.props: | ||||||
|             if prop.name == 'temperature': |             if prop.name == 'temperature': | ||||||
|                 self._prop_env_temperature = prop |                 self._prop_env_temperature = prop | ||||||
|  |                 break | ||||||
|  |  | ||||||
|     @property |     @property | ||||||
|     def current_temperature(self) -> Optional[float]: |     def current_temperature(self) -> Optional[float]: | ||||||
| @@ -387,6 +393,7 @@ class FeatureHumidity(MIoTServiceEntity, ClimateEntity): | |||||||
|         for prop in entity_data.props: |         for prop in entity_data.props: | ||||||
|             if prop.name == 'relative-humidity': |             if prop.name == 'relative-humidity': | ||||||
|                 self._prop_env_humidity = prop |                 self._prop_env_humidity = prop | ||||||
|  |                 break | ||||||
|  |  | ||||||
|     @property |     @property | ||||||
|     def current_humidity(self) -> Optional[float]: |     def current_humidity(self) -> Optional[float]: | ||||||
| @@ -418,6 +425,7 @@ class FeatureTargetHumidity(MIoTServiceEntity, ClimateEntity): | |||||||
|                 self._attr_supported_features |= ( |                 self._attr_supported_features |= ( | ||||||
|                     ClimateEntityFeature.TARGET_HUMIDITY) |                     ClimateEntityFeature.TARGET_HUMIDITY) | ||||||
|                 self._prop_target_humidity = prop |                 self._prop_target_humidity = prop | ||||||
|  |                 break | ||||||
|  |  | ||||||
|     async def async_set_humidity(self, humidity): |     async def async_set_humidity(self, humidity): | ||||||
|         """Set the target humidity.""" |         """Set the target humidity.""" | ||||||
| @@ -447,6 +455,8 @@ class Heater(FeatureOnOff, FeatureTargetTemperature, FeatureTemperature, | |||||||
|         self._attr_icon = 'mdi:radiator' |         self._attr_icon = 'mdi:radiator' | ||||||
|         # hvac modes |         # hvac modes | ||||||
|         self._attr_hvac_modes = [HVACMode.HEAT, HVACMode.OFF] |         self._attr_hvac_modes = [HVACMode.HEAT, HVACMode.OFF] | ||||||
|  |         # on/off | ||||||
|  |         self._init_on_off('heater', 'on') | ||||||
|         # preset modes |         # preset modes | ||||||
|         self._init_preset_modes('heater', 'heat-level') |         self._init_preset_modes('heater', 'heat-level') | ||||||
|  |  | ||||||
| @@ -482,10 +492,12 @@ class AirConditioner(FeatureOnOff, FeatureTargetTemperature, | |||||||
|  |  | ||||||
|         super().__init__(miot_device=miot_device, entity_data=entity_data) |         super().__init__(miot_device=miot_device, entity_data=entity_data) | ||||||
|         self._attr_icon = 'mdi:air-conditioner' |         self._attr_icon = 'mdi:air-conditioner' | ||||||
|  |         # on/off | ||||||
|  |         self._init_on_off('air-conditioner', 'on') | ||||||
|         # hvac modes |         # hvac modes | ||||||
|         self._attr_hvac_modes = None |         self._attr_hvac_modes = None | ||||||
|         for prop in entity_data.props: |         for prop in entity_data.props: | ||||||
|             if prop.name == 'mode': |             if prop.name == 'mode' and prop.service.name == 'air-conditioner': | ||||||
|                 if not prop.value_list: |                 if not prop.value_list: | ||||||
|                     _LOGGER.error('invalid mode value_list, %s', self.entity_id) |                     _LOGGER.error('invalid mode value_list, %s', self.entity_id) | ||||||
|                     continue |                     continue | ||||||
| @@ -620,22 +632,17 @@ class PtcBathHeater(FeatureTargetTemperature, FeatureTemperature, | |||||||
|         self._attr_icon = 'mdi:hvac' |         self._attr_icon = 'mdi:hvac' | ||||||
|         # hvac modes |         # hvac modes | ||||||
|         for prop in entity_data.props: |         for prop in entity_data.props: | ||||||
|             if prop.name == 'mode': |             if prop.name == 'mode' and prop.service.name == 'ptc-bath-heater': | ||||||
|                 if not prop.value_list: |                 if not prop.value_list: | ||||||
|                     _LOGGER.error('invalid mode value_list, %s', self.entity_id) |                     _LOGGER.error('invalid mode value_list, %s', self.entity_id) | ||||||
|                     continue |                     continue | ||||||
|                 self._hvac_mode_map = {} |                 self._hvac_mode_map = {} | ||||||
|                 for item in prop.value_list.items: |                 for item in prop.value_list.items: | ||||||
|                     if item.name in {'off', 'idle'}: |                     if item.name in {'off', 'idle'}: | ||||||
|                         if (HVACMode.OFF |                         self._hvac_mode_map[item.value] = HVACMode.OFF | ||||||
|                                 not in list(self._hvac_mode_map.values())): |                         break | ||||||
|                             self._hvac_mode_map[item.value] = HVACMode.OFF |                 if self._hvac_mode_map: | ||||||
|                     elif (HVACMode.AUTO |                     self._attr_hvac_modes = [HVACMode.AUTO, HVACMode.OFF] | ||||||
|                           not in list(self._hvac_mode_map.values())): |  | ||||||
|                         self._hvac_mode_map[item.value] = HVACMode.AUTO |  | ||||||
|                 self._attr_hvac_modes = list(self._hvac_mode_map.values()) |  | ||||||
|                 if HVACMode.OFF in self._attr_hvac_modes: |  | ||||||
|                     self._prop_mode = prop |  | ||||||
|                 else: |                 else: | ||||||
|                     _LOGGER.error('no idle mode, %s', self.entity_id) |                     _LOGGER.error('no idle mode, %s', self.entity_id) | ||||||
|         # preset modes |         # preset modes | ||||||
| @@ -643,7 +650,7 @@ class PtcBathHeater(FeatureTargetTemperature, FeatureTemperature, | |||||||
|  |  | ||||||
|     async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None: |     async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None: | ||||||
|         """Set the target hvac mode.""" |         """Set the target hvac mode.""" | ||||||
|         if self._prop_mode is None: |         if self._prop_mode is None or hvac_mode != HVACMode.OFF: | ||||||
|             return |             return | ||||||
|         mode_value = self.get_map_key(map_=self._hvac_mode_map, value=hvac_mode) |         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( |         if mode_value is None or not await self.set_property_async( | ||||||
| @@ -656,13 +663,12 @@ class PtcBathHeater(FeatureTargetTemperature, FeatureTemperature, | |||||||
|         """The current hvac mode.""" |         """The current hvac mode.""" | ||||||
|         if self._prop_mode is None: |         if self._prop_mode is None: | ||||||
|             return None |             return None | ||||||
|         mode_value = self.get_map_value( |         current_mode = self.get_prop_value(prop=self._prop_mode) | ||||||
|             map_=self._hvac_mode_map, |         if current_mode is None: | ||||||
|             key=self.get_prop_value(prop=self._prop_mode)) |             return None | ||||||
|         if mode_value == HVACMode.OFF or mode_value is None: |         mode_value = self.get_map_value(map_=self._hvac_mode_map, | ||||||
|             return mode_value |                                         key=current_mode) | ||||||
|         return HVACMode.AUTO if (HVACMode.AUTO |         return HVACMode.OFF if mode_value == HVACMode.OFF else HVACMode.AUTO | ||||||
|                                  in self._attr_hvac_modes) else None |  | ||||||
|  |  | ||||||
|  |  | ||||||
| class Thermostat(FeatureOnOff, FeatureTargetTemperature, FeatureTemperature, | class Thermostat(FeatureOnOff, FeatureTargetTemperature, FeatureTemperature, | ||||||
| @@ -677,6 +683,8 @@ class Thermostat(FeatureOnOff, FeatureTargetTemperature, FeatureTemperature, | |||||||
|         self._attr_icon = 'mdi:thermostat' |         self._attr_icon = 'mdi:thermostat' | ||||||
|         # hvac modes |         # hvac modes | ||||||
|         self._attr_hvac_modes = [HVACMode.AUTO, HVACMode.OFF] |         self._attr_hvac_modes = [HVACMode.AUTO, HVACMode.OFF] | ||||||
|  |         # on/off | ||||||
|  |         self._init_on_off('thermostat', 'on') | ||||||
|         # preset modes |         # preset modes | ||||||
|         self._init_preset_modes('thermostat', 'mode') |         self._init_preset_modes('thermostat', 'mode') | ||||||
|  |  | ||||||
| @@ -705,6 +713,8 @@ class ElectricBlanket(FeatureOnOff, FeatureTargetTemperature, | |||||||
|         self._attr_icon = 'mdi:rug' |         self._attr_icon = 'mdi:rug' | ||||||
|         # hvac modes |         # hvac modes | ||||||
|         self._attr_hvac_modes = [HVACMode.HEAT, HVACMode.OFF] |         self._attr_hvac_modes = [HVACMode.HEAT, HVACMode.OFF] | ||||||
|  |         # on/off | ||||||
|  |         self._init_on_off('electric-blanket', 'on') | ||||||
|         # preset modes |         # preset modes | ||||||
|         self._init_preset_modes('electric-blanket', 'mode') |         self._init_preset_modes('electric-blanket', 'mode') | ||||||
|  |  | ||||||
|   | |||||||
| @@ -25,7 +25,7 @@ | |||||||
|         "cryptography", |         "cryptography", | ||||||
|         "psutil" |         "psutil" | ||||||
|     ], |     ], | ||||||
|     "version": "v0.2.2", |     "version": "v0.2.3", | ||||||
|     "zeroconf": [ |     "zeroconf": [ | ||||||
|         "_miot-central._tcp.local." |         "_miot-central._tcp.local." | ||||||
|     ] |     ] | ||||||
|   | |||||||
| @@ -168,5 +168,20 @@ | |||||||
|             "service:016:action:001": "中键确认", |             "service:016:action:001": "中键确认", | ||||||
|             "service:017:action:001": "右键确认" |             "service:017:action:001": "右键确认" | ||||||
|         } |         } | ||||||
|  |     }, | ||||||
|  |     "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" | ||||||
|  |         } | ||||||
|  |     }, | ||||||
|  |     "urn:miot-spec-v2:device:plant-monitor:0000A030:hhcc-v1": { | ||||||
|  |         "en": { | ||||||
|  |             "service:002:property:001": "Soil Moisture" | ||||||
|  |         }, | ||||||
|  |         "zh-Hans": { | ||||||
|  |             "service:002:property:001": "土壤湿度", | ||||||
|  |             "service:002:property:003": "光照强度" | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @@ -76,3 +76,56 @@ urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-m9:2: urn:miot-spec-v2:d | |||||||
| 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: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: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:5: urn:miot-spec-v2:device:air-conditioner:0000A004:xiaomi-m9:6 | ||||||
|  | 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: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:outlet:0000A002:chuangmi-212a01:3: | ||||||
|  |   prop.5.1: | ||||||
|  |     expr: round(src_value*6/1000000, 3) | ||||||
|  | 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: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 | ||||||
|   | |||||||
| @@ -560,12 +560,6 @@ SPEC_PROP_TRANS_MAP: dict = { | |||||||
|             'entity': 'sensor', |             'entity': 'sensor', | ||||||
|             'state_class': SensorStateClass.MEASUREMENT, |             'state_class': SensorStateClass.MEASUREMENT, | ||||||
|             'unit_of_measurement': UnitOfPower.WATT |             'unit_of_measurement': UnitOfPower.WATT | ||||||
|         }, |  | ||||||
|         'total-battery': { |  | ||||||
|             'device_class': SensorDeviceClass.ENERGY, |  | ||||||
|             'entity': 'sensor', |  | ||||||
|             'state_class': SensorStateClass.TOTAL_INCREASING, |  | ||||||
|             'unit_of_measurement': UnitOfEnergy.KILO_WATT_HOUR |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user