From 704aee72f93576fd67e194abd1b9b47e74c36ba4 Mon Sep 17 00:00:00 2001 From: staritbusfans Date: Mon, 6 May 2024 16:01:11 +0800 Subject: [PATCH 1/4] =?UTF-8?q?water=5Fheater=E5=AE=9E=E4=BD=93=C2=B7?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=94=AF=E6=8C=81=E7=A9=BA=E6=B0=94=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- custom_components/haier/core/attribute.py | 23 ++++++++ custom_components/haier/water_heater.py | 64 ++++++++++++++++++----- 2 files changed, 75 insertions(+), 12 deletions(-) diff --git a/custom_components/haier/core/attribute.py b/custom_components/haier/core/attribute.py index 6ba2955..2d945da 100644 --- a/custom_components/haier/core/attribute.py +++ b/custom_components/haier/core/attribute.py @@ -88,6 +88,10 @@ def parse_global(self, attributes: List[dict]): if 'outWaterTemp' in all_attribute_keys and 'targetTemp' in all_attribute_keys and 'totalUseGasL' in all_attribute_keys: yield self._parse_as_gas_water_heater(attributes) + # 空气能热水器 + if 'targetTemperature' in all_attribute_keys and 'dualHeaterMode' in all_attribute_keys: + yield self._parse_as_water_heater(attributes) + @staticmethod def _parse_as_sensor(attribute): if V1SpecAttributeParser._is_binary_attribute(attribute): @@ -199,6 +203,25 @@ def _parse_as_gas_water_heater(attributes: List[dict]): return HaierAttribute('gas_water_heater', 'GasWaterHeater', Platform.WATER_HEATER, options, ext) @staticmethod + def _parse_as_water_heater(attributes: List[dict]): + for attr in attributes: + if attr['name'] == 'targetTemperature': + target_temperature_attr = attr + break + else: + raise RuntimeError('targetTemp attr not found') + + options = { + 'min_temp': target_temperature_attr['valueRange']['dataStep']['minValue'], + 'max_temp': target_temperature_attr['valueRange']['dataStep']['maxValue'], + 'target_temperature_step': target_temperature_attr['valueRange']['dataStep']['step'] + } + ext = { + 'customize': True, + } + + return HaierAttribute('water_heater', 'Water Heater', Platform.WATER_HEATER, ext=ext) + @staticmethod def _is_binary_attribute(attribute): valueRange = attribute['valueRange'] diff --git a/custom_components/haier/water_heater.py b/custom_components/haier/water_heater.py index 7e5400f..f323cfa 100644 --- a/custom_components/haier/water_heater.py +++ b/custom_components/haier/water_heater.py @@ -4,6 +4,8 @@ from homeassistant.components.water_heater import ( WaterHeaterEntity, STATE_GAS, + STATE_PERFORMANCE, + STATE_HEAT_PUMP, SUPPORT_AWAY_MODE, SUPPORT_TARGET_TEMPERATURE, SUPPORT_OPERATION_MODE, @@ -43,28 +45,49 @@ def __init__(self, device: HaierDevice, attribute: HaierAttribute): self._attr_supported_features = SUPPORT_FLAGS # 默认的0-70温度范围太宽,homekit不支持 self._attr_min_temp = 35 - self._attr_max_temp = 50 + self._attr_max_temp = 65 @property def operation_list(self): """List of available operation modes.""" - return [STATE_OFF, STATE_GAS] + if 'dualHeaterMode' in self._attributes_data: + return [STATE_OFF, STATE_PERFORMANCE,STATE_HEAT_PUMP] + else: + return [STATE_OFF, STATE_GAS] def set_temperature(self, **kwargs) -> None: - self._send_command({ - 'targetTemp': kwargs['temperature'] - }) + if 'targetTemp' in self._attributes_data: + self._send_command({ + 'targetTemp': kwargs['temperature'] + }) + elif 'targetTemperature' in self._attributes_data: + self._send_command({ + 'targetTemperature': kwargs['temperature'] + }) def _update_value(self): if 'outWaterTemp' in self._attributes_data: self._attr_current_temperature = float(self._attributes_data['outWaterTemp']) + elif 'currentTemperature' in self._attributes_data: + self._attr_current_temperature = float(self._attributes_data['currentTemperature']) - self._attr_target_temperature = float(self._attributes_data['targetTemp']) + if 'targetTemp' in self._attributes_data: + self._attr_target_temperature = float(self._attributes_data['targetTemp']) + elif 'targetTemperature' in self._attributes_data: + self._attr_target_temperature = float(self._attributes_data['targetTemperature']) if not try_read_as_bool(self._attributes_data['onOffStatus']): # 关机状态 self._attr_current_operation = STATE_OFF self._attr_is_away_mode_on = True + elif 'dualHeaterMode' in self._attributes_data and try_read_as_bool(self._attributes_data['dualHeaterMode']): + # 空气能双源速热 + self._attr_current_operation = STATE_PERFORMANCE + self._attr_is_away_mode_on = False + elif 'dualHeaterMode' in self._attributes_data and not try_read_as_bool(self._attributes_data['dualHeaterMode']): + # 空气能节能模式 + self._attr_current_operation = STATE_HEAT_PUMP + self._attr_is_away_mode_on = False else: # 开机状态 self._attr_current_operation = STATE_GAS @@ -84,10 +107,27 @@ def turn_away_mode_off(self): def set_operation_mode(self, operation_mode): """Set operation mode""" - if operation_mode == STATE_GAS: - power_state = True + if 'dualHeaterMode' in self._attributes_data: + if operation_mode == STATE_HEAT_PUMP: + self._send_command({ + 'onOffStatus': True, + 'dualHeaterMode': False + }) + elif operation_mode == STATE_PERFORMANCE: + self._send_command({ + 'onOffStatus': True, + 'dualHeaterMode': True + }) + else: + self._send_command({ + 'onOffStatus': False + }) + else: - power_state = False - self._send_command({ - 'onOffStatus': power_state - }) + if operation_mode == STATE_GAS: + power_state = True + else: + power_state = False + self._send_command({ + 'onOffStatus': power_state + }) From 8746b4e823bde0a0301a221ea511d506aa94b5a9 Mon Sep 17 00:00:00 2001 From: staritbusfans Date: Tue, 7 May 2024 09:40:37 +0800 Subject: [PATCH 2/4] =?UTF-8?q?Revert=20"water=5Fheater=E5=AE=9E=E4=BD=93?= =?UTF-8?q?=C2=B7=E5=A2=9E=E5=8A=A0=E6=94=AF=E6=8C=81=E7=A9=BA=E6=B0=94?= =?UTF-8?q?=E8=83=BD"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 704aee72f93576fd67e194abd1b9b47e74c36ba4. --- custom_components/haier/core/attribute.py | 23 -------- custom_components/haier/water_heater.py | 64 +++++------------------ 2 files changed, 12 insertions(+), 75 deletions(-) diff --git a/custom_components/haier/core/attribute.py b/custom_components/haier/core/attribute.py index 2d945da..6ba2955 100644 --- a/custom_components/haier/core/attribute.py +++ b/custom_components/haier/core/attribute.py @@ -88,10 +88,6 @@ def parse_global(self, attributes: List[dict]): if 'outWaterTemp' in all_attribute_keys and 'targetTemp' in all_attribute_keys and 'totalUseGasL' in all_attribute_keys: yield self._parse_as_gas_water_heater(attributes) - # 空气能热水器 - if 'targetTemperature' in all_attribute_keys and 'dualHeaterMode' in all_attribute_keys: - yield self._parse_as_water_heater(attributes) - @staticmethod def _parse_as_sensor(attribute): if V1SpecAttributeParser._is_binary_attribute(attribute): @@ -203,25 +199,6 @@ def _parse_as_gas_water_heater(attributes: List[dict]): return HaierAttribute('gas_water_heater', 'GasWaterHeater', Platform.WATER_HEATER, options, ext) @staticmethod - def _parse_as_water_heater(attributes: List[dict]): - for attr in attributes: - if attr['name'] == 'targetTemperature': - target_temperature_attr = attr - break - else: - raise RuntimeError('targetTemp attr not found') - - options = { - 'min_temp': target_temperature_attr['valueRange']['dataStep']['minValue'], - 'max_temp': target_temperature_attr['valueRange']['dataStep']['maxValue'], - 'target_temperature_step': target_temperature_attr['valueRange']['dataStep']['step'] - } - ext = { - 'customize': True, - } - - return HaierAttribute('water_heater', 'Water Heater', Platform.WATER_HEATER, ext=ext) - @staticmethod def _is_binary_attribute(attribute): valueRange = attribute['valueRange'] diff --git a/custom_components/haier/water_heater.py b/custom_components/haier/water_heater.py index f323cfa..7e5400f 100644 --- a/custom_components/haier/water_heater.py +++ b/custom_components/haier/water_heater.py @@ -4,8 +4,6 @@ from homeassistant.components.water_heater import ( WaterHeaterEntity, STATE_GAS, - STATE_PERFORMANCE, - STATE_HEAT_PUMP, SUPPORT_AWAY_MODE, SUPPORT_TARGET_TEMPERATURE, SUPPORT_OPERATION_MODE, @@ -45,49 +43,28 @@ def __init__(self, device: HaierDevice, attribute: HaierAttribute): self._attr_supported_features = SUPPORT_FLAGS # 默认的0-70温度范围太宽,homekit不支持 self._attr_min_temp = 35 - self._attr_max_temp = 65 + self._attr_max_temp = 50 @property def operation_list(self): """List of available operation modes.""" - if 'dualHeaterMode' in self._attributes_data: - return [STATE_OFF, STATE_PERFORMANCE,STATE_HEAT_PUMP] - else: - return [STATE_OFF, STATE_GAS] + return [STATE_OFF, STATE_GAS] def set_temperature(self, **kwargs) -> None: - if 'targetTemp' in self._attributes_data: - self._send_command({ - 'targetTemp': kwargs['temperature'] - }) - elif 'targetTemperature' in self._attributes_data: - self._send_command({ - 'targetTemperature': kwargs['temperature'] - }) + self._send_command({ + 'targetTemp': kwargs['temperature'] + }) def _update_value(self): if 'outWaterTemp' in self._attributes_data: self._attr_current_temperature = float(self._attributes_data['outWaterTemp']) - elif 'currentTemperature' in self._attributes_data: - self._attr_current_temperature = float(self._attributes_data['currentTemperature']) - if 'targetTemp' in self._attributes_data: - self._attr_target_temperature = float(self._attributes_data['targetTemp']) - elif 'targetTemperature' in self._attributes_data: - self._attr_target_temperature = float(self._attributes_data['targetTemperature']) + self._attr_target_temperature = float(self._attributes_data['targetTemp']) if not try_read_as_bool(self._attributes_data['onOffStatus']): # 关机状态 self._attr_current_operation = STATE_OFF self._attr_is_away_mode_on = True - elif 'dualHeaterMode' in self._attributes_data and try_read_as_bool(self._attributes_data['dualHeaterMode']): - # 空气能双源速热 - self._attr_current_operation = STATE_PERFORMANCE - self._attr_is_away_mode_on = False - elif 'dualHeaterMode' in self._attributes_data and not try_read_as_bool(self._attributes_data['dualHeaterMode']): - # 空气能节能模式 - self._attr_current_operation = STATE_HEAT_PUMP - self._attr_is_away_mode_on = False else: # 开机状态 self._attr_current_operation = STATE_GAS @@ -107,27 +84,10 @@ def turn_away_mode_off(self): def set_operation_mode(self, operation_mode): """Set operation mode""" - if 'dualHeaterMode' in self._attributes_data: - if operation_mode == STATE_HEAT_PUMP: - self._send_command({ - 'onOffStatus': True, - 'dualHeaterMode': False - }) - elif operation_mode == STATE_PERFORMANCE: - self._send_command({ - 'onOffStatus': True, - 'dualHeaterMode': True - }) - else: - self._send_command({ - 'onOffStatus': False - }) - + if operation_mode == STATE_GAS: + power_state = True else: - if operation_mode == STATE_GAS: - power_state = True - else: - power_state = False - self._send_command({ - 'onOffStatus': power_state - }) + power_state = False + self._send_command({ + 'onOffStatus': power_state + }) From ee0008b7a5cf3738fb770d6960c2626e337d7517 Mon Sep 17 00:00:00 2001 From: staritbusfans Date: Tue, 7 May 2024 12:12:44 +0800 Subject: [PATCH 3/4] =?UTF-8?q?water=5Fheater=E8=AE=BE=E5=A4=87=E7=B1=BB?= =?UTF-8?q?=E5=9E=8B=E4=B8=AD=E5=8D=95=E5=88=97=E4=BA=86HaierGasWaterHeate?= =?UTF-8?q?r=E5=8F=8AHaierWaterHeater=EF=BC=8C=E5=90=8C=E6=97=B6=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E4=BA=86=E7=94=B5=E7=83=AD=E6=B0=B4=E5=99=A8=E6=94=AF?= =?UTF-8?q?=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- custom_components/haier/core/attribute.py | 32 ++++++-- custom_components/haier/water_heater.py | 97 ++++++++++++++++++++++- 2 files changed, 121 insertions(+), 8 deletions(-) diff --git a/custom_components/haier/core/attribute.py b/custom_components/haier/core/attribute.py index 6ba2955..ebde6f3 100644 --- a/custom_components/haier/core/attribute.py +++ b/custom_components/haier/core/attribute.py @@ -86,7 +86,14 @@ def parse_global(self, attributes: List[dict]): # 燃气热水器 if 'outWaterTemp' in all_attribute_keys and 'targetTemp' in all_attribute_keys and 'totalUseGasL' in all_attribute_keys: - yield self._parse_as_gas_water_heater(attributes) + yield self._parse_as_water_heater(attributes,True,False) + elif 'targetTemperature' in all_attribute_keys and 'currentTemperature' in all_attribute_keys: + # 空气能 + if 'dualHeaterMode' in all_attribute_keys: + yield self._parse_as_water_heater(attributes,False,True) + # 电热水器 + else: + yield self._parse_as_water_heater(attributes,False,False) @staticmethod def _parse_as_sensor(attribute): @@ -178,11 +185,16 @@ def _parse_as_climate(attributes: List[dict], feature_fields: List[str]): return HaierAttribute('climate', 'Climate', Platform.CLIMATE, options, ext) @staticmethod - def _parse_as_gas_water_heater(attributes: List[dict]): + def _parse_as_water_heater(attributes: List[dict], is_gas, is_heat_pump): for attr in attributes: - if attr['name'] == 'targetTemp': - target_temperature_attr = attr - break + if is_gas: + if attr['name'] == 'targetTemp': + target_temperature_attr = attr + break + else: + if attr['name'] == 'targetTemperature': + target_temperature_attr = attr + break else: raise RuntimeError('targetTemp attr not found') @@ -194,9 +206,17 @@ def _parse_as_gas_water_heater(attributes: List[dict]): ext = { 'customize': True, + 'is_gas': is_gas, + 'is_heat_pump': is_heat_pump, } - return HaierAttribute('gas_water_heater', 'GasWaterHeater', Platform.WATER_HEATER, options, ext) + return HaierAttribute( + 'gas_water_heater' if is_gas else 'water_heater', + 'GasWaterHeater' if is_gas else 'WaterHeater', + Platform.WATER_HEATER, + options, + ext + ) @staticmethod def _is_binary_attribute(attribute): diff --git a/custom_components/haier/water_heater.py b/custom_components/haier/water_heater.py index 7e5400f..0c2c674 100644 --- a/custom_components/haier/water_heater.py +++ b/custom_components/haier/water_heater.py @@ -5,6 +5,9 @@ WaterHeaterEntity, STATE_GAS, SUPPORT_AWAY_MODE, + STATE_PERFORMANCE, + STATE_ELECTRIC, + STATE_HEAT_PUMP, SUPPORT_TARGET_TEMPERATURE, SUPPORT_OPERATION_MODE, ) @@ -31,11 +34,11 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry, async_add_e entry, async_add_entities, Platform.WATER_HEATER, - lambda device, attribute: HaierWaterHeater(device, attribute) + lambda device, attribute: HaierGasWaterHeater(device, attribute) if attribute.ext['is_gas'] else HaierWaterHeater(device, attribute) ) -class HaierWaterHeater(HaierAbstractEntity, WaterHeaterEntity): +class HaierGasWaterHeater(HaierAbstractEntity, WaterHeaterEntity): def __init__(self, device: HaierDevice, attribute: HaierAttribute): super().__init__(device, attribute) @@ -91,3 +94,93 @@ def set_operation_mode(self, operation_mode): self._send_command({ 'onOffStatus': power_state }) + +class HaierWaterHeater(HaierAbstractEntity, WaterHeaterEntity): + + def __init__(self, device: HaierDevice, attribute: HaierAttribute): + super().__init__(device, attribute) + self._attr_temperature_unit = TEMP_CELSIUS + self._attr_supported_features = SUPPORT_FLAGS + self._attr_is_heat_pump = self._attribute.ext['is_heat_pump'] + # 默认的0-70温度范围太宽,homekit不支持 + self._attr_min_temp = 35 + self._attr_max_temp = 65 + + @property + def operation_list(self): + """List of available operation modes.""" + if self._attr_is_heat_pump: + return [STATE_OFF, STATE_HEAT_PUMP, STATE_PERFORMANCE] + else: + return [STATE_OFF, STATE_ELECTRIC] + + def set_temperature(self, **kwargs) -> None: + self._send_command({ + 'targetTemperature': kwargs['temperature'] + }) + + def _update_value(self): + if 'currentTemperature' in self._attributes_data: + self._attr_current_temperature = float(self._attributes_data['currentTemperature']) + + self._attr_target_temperature = float(self._attributes_data['targetTemperature']) + + if not try_read_as_bool(self._attributes_data['onOffStatus']): + # 关机状态 + self._attr_current_operation = STATE_OFF + self._attr_is_away_mode_on = True + elif self._attr_is_heat_pump and try_read_as_bool(self._attributes_data['dualHeaterMode']): + # 空气能双源速热 + self._attr_current_operation = STATE_PERFORMANCE + self._attr_is_away_mode_on = False + elif self._attr_is_heat_pump and not try_read_as_bool(self._attributes_data['dualHeaterMode']): + # 空气能节能模式 + self._attr_current_operation = STATE_HEAT_PUMP + self._attr_is_away_mode_on = False + else: + # 电热水器开机状态 + self._attr_current_operation = STATE_ELECTRIC + self._attr_is_away_mode_on = False + + def turn_away_mode_on(self): + """Turn away mode on.""" + self._send_command({ + 'onOffStatus': False + }) + + def turn_away_mode_off(self): + """Turn away mode off.""" + self._send_command({ + 'onOffStatus': True + }) + + def set_operation_mode(self, operation_mode): + """Set operation mode""" + if self._attr_is_heat_pump: + if operation_mode == STATE_HEAT_PUMP: + self._send_command({ + 'onOffStatus': True + }) + self._send_command({ + 'dualHeaterMode': False + }) + elif operation_mode == STATE_PERFORMANCE: + self._send_command({ + 'onOffStatus': True + }) + self._send_command({ + 'dualHeaterMode': True + }) + else: + self._send_command({ + 'onOffStatus': False + }) + + else: + if operation_mode == STATE_ELECTRIC: + power_state = True + else: + power_state = False + self._send_command({ + 'onOffStatus': power_state + }) \ No newline at end of file From 8999b58407934a6b173eab2a2c7d5b126c4742bf Mon Sep 17 00:00:00 2001 From: staritbusfans Date: Wed, 8 May 2024 16:07:01 +0800 Subject: [PATCH 4/4] =?UTF-8?q?water=5Fheater=E5=AE=9E=E4=BD=93=E5=AF=B9?= =?UTF-8?q?=E4=BA=8E=E6=97=A0=E5=AE=9E=E6=97=B6=E5=87=BA=E6=B0=B4=E6=B8=A9?= =?UTF-8?q?=E5=BA=A6=E7=9A=84=E7=87=83=E6=B0=94=E7=83=AD=E6=B0=B4=E5=99=A8?= =?UTF-8?q?=EF=BC=8C=E9=99=8D=E7=BA=A7=E4=B8=BA=E8=AF=BB=E5=8F=96=E8=AE=BE?= =?UTF-8?q?=E7=BD=AE=E6=B8=A9=E5=BA=A6=E4=BD=9C=E4=B8=BA=E5=AE=9E=E6=97=B6?= =?UTF-8?q?=E6=B8=A9=E5=BA=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- custom_components/haier/core/attribute.py | 2 +- custom_components/haier/water_heater.py | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/custom_components/haier/core/attribute.py b/custom_components/haier/core/attribute.py index ebde6f3..f88717d 100644 --- a/custom_components/haier/core/attribute.py +++ b/custom_components/haier/core/attribute.py @@ -85,7 +85,7 @@ def parse_global(self, attributes: List[dict]): break # 燃气热水器 - if 'outWaterTemp' in all_attribute_keys and 'targetTemp' in all_attribute_keys and 'totalUseGasL' in all_attribute_keys: + if 'targetTemp' in all_attribute_keys and 'totalUseGasL' in all_attribute_keys: yield self._parse_as_water_heater(attributes,True,False) elif 'targetTemperature' in all_attribute_keys and 'currentTemperature' in all_attribute_keys: # 空气能 diff --git a/custom_components/haier/water_heater.py b/custom_components/haier/water_heater.py index 0c2c674..cb0dc90 100644 --- a/custom_components/haier/water_heater.py +++ b/custom_components/haier/water_heater.py @@ -61,6 +61,8 @@ def set_temperature(self, **kwargs) -> None: def _update_value(self): if 'outWaterTemp' in self._attributes_data: self._attr_current_temperature = float(self._attributes_data['outWaterTemp']) + else: + self._attr_current_temperature = float(self._attributes_data['targetTemp']) self._attr_target_temperature = float(self._attributes_data['targetTemp'])