mirror of
				https://github.com/XiaoMi/ha_xiaomi_home.git
				synced 2025-10-31 09:22:08 +08:00 
			
		
		
		
	Merge branch 'XiaoMi:main' into main
This commit is contained in:
		| @@ -1,4 +1,12 @@ | ||||
| # 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 | ||||
| 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.core import HomeAssistant | ||||
| from homeassistant.const import UnitOfTemperature | ||||
| from homeassistant.helpers.entity_platform import AddEntitiesCallback | ||||
| from homeassistant.components.climate import ( | ||||
|     FAN_ON, FAN_OFF, SWING_OFF, SWING_BOTH, SWING_VERTICAL, SWING_HORIZONTAL, | ||||
| @@ -101,21 +102,19 @@ class FeatureOnOff(MIoTServiceEntity, ClimateEntity): | ||||
|         self._prop_on = None | ||||
|  | ||||
|         super().__init__(miot_device=miot_device, entity_data=entity_data) | ||||
|         # properties | ||||
|         for prop in entity_data.props: | ||||
|             if prop.name == 'on': | ||||
|                 if ( | ||||
|                         # The "on" property of the "fan-control" service is not | ||||
|                         # the on/off feature of the entity. | ||||
|                         prop.service.name == 'air-conditioner' or | ||||
|                         prop.service.name == 'heater' or | ||||
|                         prop.service.name == 'thermostat' or | ||||
|                         prop.service.name == 'electric-blanket'): | ||||
|                     self._attr_supported_features |= ( | ||||
|                         ClimateEntityFeature.TURN_ON) | ||||
|                     self._attr_supported_features |= ( | ||||
|                         ClimateEntityFeature.TURN_OFF) | ||||
|                     self._prop_on = prop | ||||
|  | ||||
|     def _init_on_off(self, service_name: str, prop_name: str) -> None: | ||||
|         """Initialize the on_off feature.""" | ||||
|         for prop in self.entity_data.props: | ||||
|             if prop.name == prop_name and prop.service.name == service_name: | ||||
|                 if prop.format_ != bool: | ||||
|                     _LOGGER.error('wrong format %s %s, %s', service_name, | ||||
|                                   prop_name, self.entity_id) | ||||
|                     continue | ||||
|                 self._attr_supported_features |= ClimateEntityFeature.TURN_ON | ||||
|                 self._attr_supported_features |= ClimateEntityFeature.TURN_OFF | ||||
|                 self._prop_on = prop | ||||
|                 break | ||||
|  | ||||
|     async def async_turn_on(self) -> None: | ||||
|         """Turn on.""" | ||||
| @@ -134,6 +133,7 @@ class FeatureTargetTemperature(MIoTServiceEntity, ClimateEntity): | ||||
|                  entity_data: MIoTEntityData) -> None: | ||||
|         """Initialize the feature class.""" | ||||
|         self._prop_target_temp = None | ||||
|         self._attr_temperature_unit = None | ||||
|  | ||||
|         super().__init__(miot_device=miot_device, entity_data=entity_data) | ||||
|         # properties | ||||
| @@ -151,6 +151,10 @@ class FeatureTargetTemperature(MIoTServiceEntity, ClimateEntity): | ||||
|                 self._attr_supported_features |= ( | ||||
|                     ClimateEntityFeature.TARGET_TEMPERATURE) | ||||
|                 self._prop_target_temp = prop | ||||
|                 break | ||||
|         # temperature_unit is required by the climate entity | ||||
|         if not self._attr_temperature_unit: | ||||
|             self._attr_temperature_unit = UnitOfTemperature.CELSIUS | ||||
|  | ||||
|     async def async_set_temperature(self, **kwargs): | ||||
|         """Set the target temperature.""" | ||||
| @@ -197,6 +201,7 @@ class FeaturePresetMode(MIoTServiceEntity, ClimateEntity): | ||||
|                 self._attr_supported_features |= ( | ||||
|                     ClimateEntityFeature.PRESET_MODE) | ||||
|                 self._prop_mode = prop | ||||
|                 break | ||||
|  | ||||
|     async def async_set_preset_mode(self, preset_mode: str) -> None: | ||||
|         """Set the preset mode.""" | ||||
| @@ -365,6 +370,7 @@ class FeatureTemperature(MIoTServiceEntity, ClimateEntity): | ||||
|         for prop in entity_data.props: | ||||
|             if prop.name == 'temperature': | ||||
|                 self._prop_env_temperature = prop | ||||
|                 break | ||||
|  | ||||
|     @property | ||||
|     def current_temperature(self) -> Optional[float]: | ||||
| @@ -387,6 +393,7 @@ class FeatureHumidity(MIoTServiceEntity, ClimateEntity): | ||||
|         for prop in entity_data.props: | ||||
|             if prop.name == 'relative-humidity': | ||||
|                 self._prop_env_humidity = prop | ||||
|                 break | ||||
|  | ||||
|     @property | ||||
|     def current_humidity(self) -> Optional[float]: | ||||
| @@ -418,6 +425,7 @@ class FeatureTargetHumidity(MIoTServiceEntity, ClimateEntity): | ||||
|                 self._attr_supported_features |= ( | ||||
|                     ClimateEntityFeature.TARGET_HUMIDITY) | ||||
|                 self._prop_target_humidity = prop | ||||
|                 break | ||||
|  | ||||
|     async def async_set_humidity(self, humidity): | ||||
|         """Set the target humidity.""" | ||||
| @@ -447,6 +455,8 @@ class Heater(FeatureOnOff, FeatureTargetTemperature, FeatureTemperature, | ||||
|         self._attr_icon = 'mdi:radiator' | ||||
|         # hvac modes | ||||
|         self._attr_hvac_modes = [HVACMode.HEAT, HVACMode.OFF] | ||||
|         # on/off | ||||
|         self._init_on_off('heater', 'on') | ||||
|         # preset modes | ||||
|         self._init_preset_modes('heater', 'heat-level') | ||||
|  | ||||
| @@ -482,10 +492,12 @@ class AirConditioner(FeatureOnOff, FeatureTargetTemperature, | ||||
|  | ||||
|         super().__init__(miot_device=miot_device, entity_data=entity_data) | ||||
|         self._attr_icon = 'mdi:air-conditioner' | ||||
|         # on/off | ||||
|         self._init_on_off('air-conditioner', 'on') | ||||
|         # hvac modes | ||||
|         self._attr_hvac_modes = None | ||||
|         for prop in entity_data.props: | ||||
|             if prop.name == 'mode': | ||||
|             if prop.name == 'mode' and prop.service.name == 'air-conditioner': | ||||
|                 if not prop.value_list: | ||||
|                     _LOGGER.error('invalid mode value_list, %s', self.entity_id) | ||||
|                     continue | ||||
| @@ -620,22 +632,17 @@ class PtcBathHeater(FeatureTargetTemperature, FeatureTemperature, | ||||
|         self._attr_icon = 'mdi:hvac' | ||||
|         # hvac modes | ||||
|         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: | ||||
|                     _LOGGER.error('invalid mode value_list, %s', self.entity_id) | ||||
|                     continue | ||||
|                 self._hvac_mode_map = {} | ||||
|                 for item in prop.value_list.items: | ||||
|                     if item.name in {'off', 'idle'}: | ||||
|                         if (HVACMode.OFF | ||||
|                                 not in list(self._hvac_mode_map.values())): | ||||
|                             self._hvac_mode_map[item.value] = HVACMode.OFF | ||||
|                     elif (HVACMode.AUTO | ||||
|                           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 | ||||
|                         self._hvac_mode_map[item.value] = HVACMode.OFF | ||||
|                         break | ||||
|                 if self._hvac_mode_map: | ||||
|                     self._attr_hvac_modes = [HVACMode.AUTO, HVACMode.OFF] | ||||
|                 else: | ||||
|                     _LOGGER.error('no idle mode, %s', self.entity_id) | ||||
|         # preset modes | ||||
| @@ -643,7 +650,7 @@ class PtcBathHeater(FeatureTargetTemperature, FeatureTemperature, | ||||
|  | ||||
|     async def async_set_hvac_mode(self, hvac_mode: HVACMode) -> None: | ||||
|         """Set the target hvac mode.""" | ||||
|         if self._prop_mode is None: | ||||
|         if self._prop_mode is None or hvac_mode != HVACMode.OFF: | ||||
|             return | ||||
|         mode_value = self.get_map_key(map_=self._hvac_mode_map, value=hvac_mode) | ||||
|         if mode_value is None or not await self.set_property_async( | ||||
| @@ -656,13 +663,12 @@ class PtcBathHeater(FeatureTargetTemperature, FeatureTemperature, | ||||
|         """The current hvac mode.""" | ||||
|         if self._prop_mode is None: | ||||
|             return None | ||||
|         mode_value = self.get_map_value( | ||||
|             map_=self._hvac_mode_map, | ||||
|             key=self.get_prop_value(prop=self._prop_mode)) | ||||
|         if mode_value == HVACMode.OFF or mode_value is None: | ||||
|             return mode_value | ||||
|         return HVACMode.AUTO if (HVACMode.AUTO | ||||
|                                  in self._attr_hvac_modes) else None | ||||
|         current_mode = self.get_prop_value(prop=self._prop_mode) | ||||
|         if current_mode is None: | ||||
|             return None | ||||
|         mode_value = self.get_map_value(map_=self._hvac_mode_map, | ||||
|                                         key=current_mode) | ||||
|         return HVACMode.OFF if mode_value == HVACMode.OFF else HVACMode.AUTO | ||||
|  | ||||
|  | ||||
| class Thermostat(FeatureOnOff, FeatureTargetTemperature, FeatureTemperature, | ||||
| @@ -677,6 +683,8 @@ class Thermostat(FeatureOnOff, FeatureTargetTemperature, FeatureTemperature, | ||||
|         self._attr_icon = 'mdi:thermostat' | ||||
|         # hvac modes | ||||
|         self._attr_hvac_modes = [HVACMode.AUTO, HVACMode.OFF] | ||||
|         # on/off | ||||
|         self._init_on_off('thermostat', 'on') | ||||
|         # preset modes | ||||
|         self._init_preset_modes('thermostat', 'mode') | ||||
|  | ||||
| @@ -705,6 +713,8 @@ class ElectricBlanket(FeatureOnOff, FeatureTargetTemperature, | ||||
|         self._attr_icon = 'mdi:rug' | ||||
|         # hvac modes | ||||
|         self._attr_hvac_modes = [HVACMode.HEAT, HVACMode.OFF] | ||||
|         # on/off | ||||
|         self._init_on_off('electric-blanket', 'on') | ||||
|         # preset modes | ||||
|         self._init_preset_modes('electric-blanket', 'mode') | ||||
|  | ||||
|   | ||||
| @@ -25,7 +25,7 @@ | ||||
|         "cryptography", | ||||
|         "psutil" | ||||
|     ], | ||||
|     "version": "v0.2.2", | ||||
|     "version": "v0.2.3", | ||||
|     "zeroconf": [ | ||||
|         "_miot-central._tcp.local." | ||||
|     ] | ||||
|   | ||||
| @@ -168,5 +168,20 @@ | ||||
|             "service:016: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: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: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', | ||||
|             'state_class': SensorStateClass.MEASUREMENT, | ||||
|             '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