mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 07:03:55 +00:00 
			
		
		
		
	Add support for new modes in Tuya Climate (#5159)
* Add support support for new modes Added support for Fan Only Mode, Dry Mode, Swing Mode and Fan Speed Control. Also added/fixed support for entity states syncing with current operation mode. * Add support for more climate modes in climate.tuya Added support for Fan Only Mode, Dry Mode, Swing Mode and Fan Speed Control. Also added/fixed support for entity states syncing with current operation mode. This commit fixes the namespace, because I uploaded the test files to start with. * Code Formatting Changes per Clang format. * More clang formatting fixes. * Breaking Change: Group YAML entries by type Add grouping to Preset, Swing Mode, Fan Speed and Active State. This is a breaking change. * Formatting Changes for validation Formatting changes to be compliant with black and flake8. Also changed constants to match expected format. * More constant value fixes * Final black formatting check? * Changes to init.py according to reviewer requests Make changes to _init_.py according to649b923804 (r1278620976),649b923804 (r1278621039),649b923804 (r1278620904), and649b923804 (r1278620549)Also put Sleep preset in its own config block to be consistent with other presets and fix logic for validate_cooling_values function to better align with existing documentation. * Commit reviewed change Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> * update deprecated config option wording * add "this->" to member variables that were missed adding "this->" to some member variables in the swing_mode function. * Update _init_.py to use Python 3.8 Walrus operator Adding Walrus Operator in the to_code function for _init_.py similar to https://github.com/esphome/esphome/pull/5181 * Fix Temperature_Multiplier config entry for code generation --------- Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Co-authored-by: Keith Burzinski <kbx81x@gmail.com>
This commit is contained in:
		| @@ -7,15 +7,22 @@ from esphome.const import ( | |||||||
|     CONF_SWITCH_DATAPOINT, |     CONF_SWITCH_DATAPOINT, | ||||||
|     CONF_SUPPORTS_COOL, |     CONF_SUPPORTS_COOL, | ||||||
|     CONF_SUPPORTS_HEAT, |     CONF_SUPPORTS_HEAT, | ||||||
|  |     CONF_PRESET, | ||||||
|  |     CONF_SWING_MODE, | ||||||
|  |     CONF_FAN_MODE, | ||||||
|  |     CONF_TEMPERATURE, | ||||||
| ) | ) | ||||||
| from .. import tuya_ns, CONF_TUYA_ID, Tuya | from .. import tuya_ns, CONF_TUYA_ID, Tuya | ||||||
|  |  | ||||||
| DEPENDENCIES = ["tuya"] | DEPENDENCIES = ["tuya"] | ||||||
| CODEOWNERS = ["@jesserockz"] | CODEOWNERS = ["@jesserockz"] | ||||||
|  |  | ||||||
| CONF_ACTIVE_STATE_DATAPOINT = "active_state_datapoint" | CONF_ACTIVE_STATE = "active_state" | ||||||
| CONF_ACTIVE_STATE_HEATING_VALUE = "active_state_heating_value" | CONF_DATAPOINT = "datapoint" | ||||||
| CONF_ACTIVE_STATE_COOLING_VALUE = "active_state_cooling_value" | CONF_HEATING_VALUE = "heating_value" | ||||||
|  | CONF_COOLING_VALUE = "cooling_value" | ||||||
|  | CONF_DRYING_VALUE = "drying_value" | ||||||
|  | CONF_FANONLY_VALUE = "fanonly_value" | ||||||
| CONF_HEATING_STATE_PIN = "heating_state_pin" | CONF_HEATING_STATE_PIN = "heating_state_pin" | ||||||
| CONF_COOLING_STATE_PIN = "cooling_state_pin" | CONF_COOLING_STATE_PIN = "cooling_state_pin" | ||||||
| CONF_TARGET_TEMPERATURE_DATAPOINT = "target_temperature_datapoint" | CONF_TARGET_TEMPERATURE_DATAPOINT = "target_temperature_datapoint" | ||||||
| @@ -23,9 +30,17 @@ CONF_CURRENT_TEMPERATURE_DATAPOINT = "current_temperature_datapoint" | |||||||
| CONF_TEMPERATURE_MULTIPLIER = "temperature_multiplier" | CONF_TEMPERATURE_MULTIPLIER = "temperature_multiplier" | ||||||
| CONF_CURRENT_TEMPERATURE_MULTIPLIER = "current_temperature_multiplier" | CONF_CURRENT_TEMPERATURE_MULTIPLIER = "current_temperature_multiplier" | ||||||
| CONF_TARGET_TEMPERATURE_MULTIPLIER = "target_temperature_multiplier" | CONF_TARGET_TEMPERATURE_MULTIPLIER = "target_temperature_multiplier" | ||||||
| CONF_ECO_DATAPOINT = "eco_datapoint" | CONF_ECO = "eco" | ||||||
| CONF_ECO_TEMPERATURE = "eco_temperature" | CONF_SLEEP = "sleep" | ||||||
|  | CONF_SLEEP_DATAPOINT = "sleep_datapoint" | ||||||
| CONF_REPORTS_FAHRENHEIT = "reports_fahrenheit" | CONF_REPORTS_FAHRENHEIT = "reports_fahrenheit" | ||||||
|  | CONF_VERTICAL_DATAPOINT = "vertical_datapoint" | ||||||
|  | CONF_HORIZONTAL_DATAPOINT = "horizontal_datapoint" | ||||||
|  | CONF_LOW_VALUE = "low_value" | ||||||
|  | CONF_MEDIUM_VALUE = "medium_value" | ||||||
|  | CONF_MIDDLE_VALUE = "middle_value" | ||||||
|  | CONF_HIGH_VALUE = "high_value" | ||||||
|  | CONF_AUTO_VALUE = "auto_value" | ||||||
|  |  | ||||||
| TuyaClimate = tuya_ns.class_("TuyaClimate", climate.Climate, cg.Component) | TuyaClimate = tuya_ns.class_("TuyaClimate", climate.Climate, cg.Component) | ||||||
|  |  | ||||||
| @@ -67,30 +82,73 @@ def validate_temperature_multipliers(value): | |||||||
|     return value |     return value | ||||||
|  |  | ||||||
|  |  | ||||||
| def validate_active_state_values(value): | def validate_cooling_values(value): | ||||||
|     if CONF_ACTIVE_STATE_DATAPOINT not in value: |     if CONF_SUPPORTS_COOL in value: | ||||||
|         if CONF_ACTIVE_STATE_COOLING_VALUE in value: |         cooling_supported = value[CONF_SUPPORTS_COOL] | ||||||
|  |         if not cooling_supported and CONF_ACTIVE_STATE in value: | ||||||
|  |             active_state_config = value[CONF_ACTIVE_STATE] | ||||||
|  |             if ( | ||||||
|  |                 CONF_COOLING_VALUE in active_state_config | ||||||
|  |                 or CONF_COOLING_STATE_PIN in value | ||||||
|  |             ): | ||||||
|                 raise cv.Invalid( |                 raise cv.Invalid( | ||||||
|                 f"{CONF_ACTIVE_STATE_DATAPOINT} required if using " |                     f"Device does not support cooling, but {CONF_COOLING_VALUE} or {CONF_COOLING_STATE_PIN} specified." | ||||||
|                 f"{CONF_ACTIVE_STATE_COOLING_VALUE}" |                     f" Please add '{CONF_SUPPORTS_COOL}: true' to your configuration." | ||||||
|                 ) |                 ) | ||||||
|     else: |         elif cooling_supported and CONF_ACTIVE_STATE in value: | ||||||
|         if value[CONF_SUPPORTS_COOL] and CONF_ACTIVE_STATE_COOLING_VALUE not in value: |             active_state_config = value[CONF_ACTIVE_STATE] | ||||||
|  |             if ( | ||||||
|  |                 CONF_COOLING_VALUE not in active_state_config | ||||||
|  |                 and CONF_COOLING_STATE_PIN not in value | ||||||
|  |             ): | ||||||
|                 raise cv.Invalid( |                 raise cv.Invalid( | ||||||
|                 f"{CONF_ACTIVE_STATE_COOLING_VALUE} required if using " |                     f"Either {CONF_ACTIVE_STATE} {CONF_COOLING_VALUE} or {CONF_COOLING_STATE_PIN} is required if" | ||||||
|                 f"{CONF_ACTIVE_STATE_DATAPOINT} and device supports cooling" |                     f" {CONF_SUPPORTS_COOL}: true' is in your configuration." | ||||||
|                 ) |                 ) | ||||||
|     return value |     return value | ||||||
|  |  | ||||||
|  |  | ||||||
| def validate_eco_values(value): | ACTIVE_STATES = cv.Schema( | ||||||
|     if CONF_ECO_TEMPERATURE in value and CONF_ECO_DATAPOINT not in value: |     { | ||||||
|         raise cv.Invalid( |         cv.Required(CONF_DATAPOINT): cv.uint8_t, | ||||||
|             f"{CONF_ECO_DATAPOINT} required if using {CONF_ECO_TEMPERATURE}" |         cv.Optional(CONF_HEATING_VALUE, default=1): cv.uint8_t, | ||||||
|  |         cv.Optional(CONF_COOLING_VALUE): cv.uint8_t, | ||||||
|  |         cv.Optional(CONF_DRYING_VALUE): cv.uint8_t, | ||||||
|  |         cv.Optional(CONF_FANONLY_VALUE): cv.uint8_t, | ||||||
|  |     }, | ||||||
| ) | ) | ||||||
|     return value |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | PRESETS = cv.Schema( | ||||||
|  |     { | ||||||
|  |         cv.Optional(CONF_ECO): { | ||||||
|  |             cv.Required(CONF_DATAPOINT): cv.uint8_t, | ||||||
|  |             cv.Optional(CONF_TEMPERATURE): cv.temperature, | ||||||
|  |         }, | ||||||
|  |         cv.Optional(CONF_SLEEP): { | ||||||
|  |             cv.Required(CONF_DATAPOINT): cv.uint8_t, | ||||||
|  |         }, | ||||||
|  |     }, | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | FAN_MODES = cv.Schema( | ||||||
|  |     { | ||||||
|  |         cv.Required(CONF_DATAPOINT): cv.uint8_t, | ||||||
|  |         cv.Optional(CONF_AUTO_VALUE): cv.uint8_t, | ||||||
|  |         cv.Optional(CONF_LOW_VALUE): cv.uint8_t, | ||||||
|  |         cv.Optional(CONF_MEDIUM_VALUE): cv.uint8_t, | ||||||
|  |         cv.Optional(CONF_MIDDLE_VALUE): cv.uint8_t, | ||||||
|  |         cv.Optional(CONF_HIGH_VALUE): cv.uint8_t, | ||||||
|  |     } | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | SWING_MODES = cv.Schema( | ||||||
|  |     { | ||||||
|  |         cv.Optional(CONF_VERTICAL_DATAPOINT): cv.uint8_t, | ||||||
|  |         cv.Optional(CONF_HORIZONTAL_DATAPOINT): cv.uint8_t, | ||||||
|  |     }, | ||||||
|  | ) | ||||||
|  |  | ||||||
| CONFIG_SCHEMA = cv.All( | CONFIG_SCHEMA = cv.All( | ||||||
|     climate.CLIMATE_SCHEMA.extend( |     climate.CLIMATE_SCHEMA.extend( | ||||||
|         { |         { | ||||||
| @@ -99,9 +157,7 @@ CONFIG_SCHEMA = cv.All( | |||||||
|             cv.Optional(CONF_SUPPORTS_HEAT, default=True): cv.boolean, |             cv.Optional(CONF_SUPPORTS_HEAT, default=True): cv.boolean, | ||||||
|             cv.Optional(CONF_SUPPORTS_COOL, default=False): cv.boolean, |             cv.Optional(CONF_SUPPORTS_COOL, default=False): cv.boolean, | ||||||
|             cv.Optional(CONF_SWITCH_DATAPOINT): cv.uint8_t, |             cv.Optional(CONF_SWITCH_DATAPOINT): cv.uint8_t, | ||||||
|             cv.Optional(CONF_ACTIVE_STATE_DATAPOINT): cv.uint8_t, |             cv.Optional(CONF_ACTIVE_STATE): ACTIVE_STATES, | ||||||
|             cv.Optional(CONF_ACTIVE_STATE_HEATING_VALUE, default=1): cv.uint8_t, |  | ||||||
|             cv.Optional(CONF_ACTIVE_STATE_COOLING_VALUE): cv.uint8_t, |  | ||||||
|             cv.Optional(CONF_HEATING_STATE_PIN): pins.gpio_input_pin_schema, |             cv.Optional(CONF_HEATING_STATE_PIN): pins.gpio_input_pin_schema, | ||||||
|             cv.Optional(CONF_COOLING_STATE_PIN): pins.gpio_input_pin_schema, |             cv.Optional(CONF_COOLING_STATE_PIN): pins.gpio_input_pin_schema, | ||||||
|             cv.Optional(CONF_TARGET_TEMPERATURE_DATAPOINT): cv.uint8_t, |             cv.Optional(CONF_TARGET_TEMPERATURE_DATAPOINT): cv.uint8_t, | ||||||
| @@ -109,17 +165,32 @@ CONFIG_SCHEMA = cv.All( | |||||||
|             cv.Optional(CONF_TEMPERATURE_MULTIPLIER): cv.positive_float, |             cv.Optional(CONF_TEMPERATURE_MULTIPLIER): cv.positive_float, | ||||||
|             cv.Optional(CONF_CURRENT_TEMPERATURE_MULTIPLIER): cv.positive_float, |             cv.Optional(CONF_CURRENT_TEMPERATURE_MULTIPLIER): cv.positive_float, | ||||||
|             cv.Optional(CONF_TARGET_TEMPERATURE_MULTIPLIER): cv.positive_float, |             cv.Optional(CONF_TARGET_TEMPERATURE_MULTIPLIER): cv.positive_float, | ||||||
|             cv.Optional(CONF_ECO_DATAPOINT): cv.uint8_t, |  | ||||||
|             cv.Optional(CONF_ECO_TEMPERATURE): cv.temperature, |  | ||||||
|             cv.Optional(CONF_REPORTS_FAHRENHEIT, default=False): cv.boolean, |             cv.Optional(CONF_REPORTS_FAHRENHEIT, default=False): cv.boolean, | ||||||
|  |             cv.Optional(CONF_PRESET): PRESETS, | ||||||
|  |             cv.Optional(CONF_FAN_MODE): FAN_MODES, | ||||||
|  |             cv.Optional(CONF_SWING_MODE): SWING_MODES, | ||||||
|  |             cv.Optional("active_state_datapoint"): cv.invalid( | ||||||
|  |                 "'active_state_datapoint' has been moved inside of the 'active_state' config block as 'datapoint'" | ||||||
|  |             ), | ||||||
|  |             cv.Optional("active_state_heating_value"): cv.invalid( | ||||||
|  |                 "'active_state_heating_value' has been moved inside of the 'active_state' config block as 'heating_value'" | ||||||
|  |             ), | ||||||
|  |             cv.Optional("active_state_cooling_value"): cv.invalid( | ||||||
|  |                 "'active_state_cooling_value' has been moved inside of the 'active_state' config block as 'cooling_value'" | ||||||
|  |             ), | ||||||
|  |             cv.Optional("eco_datapoint"): cv.invalid( | ||||||
|  |                 "'eco_datapoint' has been moved inside of the 'eco' config block under 'preset' as 'datapoint'" | ||||||
|  |             ), | ||||||
|  |             cv.Optional("eco_temperature"): cv.invalid( | ||||||
|  |                 "'eco_temperature' has been moved inside of the 'eco' config block under 'preset' as 'temperature'" | ||||||
|  |             ), | ||||||
|         } |         } | ||||||
|     ).extend(cv.COMPONENT_SCHEMA), |     ).extend(cv.COMPONENT_SCHEMA), | ||||||
|     cv.has_at_least_one_key(CONF_TARGET_TEMPERATURE_DATAPOINT, CONF_SWITCH_DATAPOINT), |     cv.has_at_least_one_key(CONF_TARGET_TEMPERATURE_DATAPOINT, CONF_SWITCH_DATAPOINT), | ||||||
|     validate_temperature_multipliers, |     validate_temperature_multipliers, | ||||||
|     validate_active_state_values, |     validate_cooling_values, | ||||||
|     cv.has_at_most_one_key(CONF_ACTIVE_STATE_DATAPOINT, CONF_HEATING_STATE_PIN), |     cv.has_at_most_one_key(CONF_ACTIVE_STATE, CONF_HEATING_STATE_PIN), | ||||||
|     cv.has_at_most_one_key(CONF_ACTIVE_STATE_DATAPOINT, CONF_COOLING_STATE_PIN), |     cv.has_at_most_one_key(CONF_ACTIVE_STATE, CONF_COOLING_STATE_PIN), | ||||||
|     validate_eco_values, |  | ||||||
| ) | ) | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -133,61 +204,78 @@ async def to_code(config): | |||||||
|  |  | ||||||
|     cg.add(var.set_supports_heat(config[CONF_SUPPORTS_HEAT])) |     cg.add(var.set_supports_heat(config[CONF_SUPPORTS_HEAT])) | ||||||
|     cg.add(var.set_supports_cool(config[CONF_SUPPORTS_COOL])) |     cg.add(var.set_supports_cool(config[CONF_SUPPORTS_COOL])) | ||||||
|     if CONF_SWITCH_DATAPOINT in config: |     if switch_datapoint := config.get(CONF_SWITCH_DATAPOINT): | ||||||
|         cg.add(var.set_switch_id(config[CONF_SWITCH_DATAPOINT])) |         cg.add(var.set_switch_id(switch_datapoint)) | ||||||
|     if CONF_ACTIVE_STATE_DATAPOINT in config: |  | ||||||
|         cg.add(var.set_active_state_id(config[CONF_ACTIVE_STATE_DATAPOINT])) |     if active_state_config := config.get(CONF_ACTIVE_STATE): | ||||||
|         if CONF_ACTIVE_STATE_HEATING_VALUE in config: |         cg.add(var.set_active_state_id(CONF_DATAPOINT)) | ||||||
|             cg.add( |         if (heating_value := active_state_config.get(CONF_HEATING_VALUE)) is not None: | ||||||
|                 var.set_active_state_heating_value( |             cg.add(var.set_active_state_heating_value(heating_value)) | ||||||
|                     config[CONF_ACTIVE_STATE_HEATING_VALUE] |         if (cooling_value := active_state_config.get(CONF_COOLING_VALUE)) is not None: | ||||||
|                 ) |             cg.add(var.set_active_state_cooling_value(cooling_value)) | ||||||
|             ) |         if (drying_value := active_state_config.get(CONF_DRYING_VALUE)) is not None: | ||||||
|         if CONF_ACTIVE_STATE_COOLING_VALUE in config: |             cg.add(var.set_active_state_drying_value(drying_value)) | ||||||
|             cg.add( |         if (fanonly_value := active_state_config.get(CONF_FANONLY_VALUE)) is not None: | ||||||
|                 var.set_active_state_cooling_value( |             cg.add(var.set_active_state_fanonly_value(fanonly_value)) | ||||||
|                     config[CONF_ACTIVE_STATE_COOLING_VALUE] |  | ||||||
|                 ) |  | ||||||
|             ) |  | ||||||
|     else: |     else: | ||||||
|         if CONF_HEATING_STATE_PIN in config: |         if heating_state_pin_config := config.get(CONF_HEATING_STATE_PIN): | ||||||
|             heating_state_pin = await cg.gpio_pin_expression( |             heating_state_pin = await cg.gpio_pin_expression( | ||||||
|                 config[CONF_HEATING_STATE_PIN] |                 config(heating_state_pin_config) | ||||||
|             ) |             ) | ||||||
|             cg.add(var.set_heating_state_pin(heating_state_pin)) |             cg.add(var.set_heating_state_pin(heating_state_pin)) | ||||||
|         if CONF_COOLING_STATE_PIN in config: |         if cooling_state_pin_config := config.get(CONF_COOLING_STATE_PIN): | ||||||
|             cooling_state_pin = await cg.gpio_pin_expression( |             cooling_state_pin = await cg.gpio_pin_expression( | ||||||
|                 config[CONF_COOLING_STATE_PIN] |                 config(cooling_state_pin_config) | ||||||
|             ) |             ) | ||||||
|             cg.add(var.set_cooling_state_pin(cooling_state_pin)) |             cg.add(var.set_cooling_state_pin(cooling_state_pin)) | ||||||
|     if CONF_TARGET_TEMPERATURE_DATAPOINT in config: |  | ||||||
|         cg.add(var.set_target_temperature_id(config[CONF_TARGET_TEMPERATURE_DATAPOINT])) |     if target_temperature_datapoint := config.get(CONF_TARGET_TEMPERATURE_DATAPOINT): | ||||||
|     if CONF_CURRENT_TEMPERATURE_DATAPOINT in config: |         cg.add(var.set_target_temperature_id(target_temperature_datapoint)) | ||||||
|         cg.add( |     if current_temperature_datapoint := config.get(CONF_CURRENT_TEMPERATURE_DATAPOINT): | ||||||
|             var.set_current_temperature_id(config[CONF_CURRENT_TEMPERATURE_DATAPOINT]) |         cg.add(var.set_current_temperature_id(current_temperature_datapoint)) | ||||||
|         ) |  | ||||||
|     if CONF_TEMPERATURE_MULTIPLIER in config: |     if temperature_multiplier := config.get(CONF_TEMPERATURE_MULTIPLIER): | ||||||
|         cg.add( |         cg.add(var.set_target_temperature_multiplier(temperature_multiplier)) | ||||||
|             var.set_target_temperature_multiplier(config[CONF_TEMPERATURE_MULTIPLIER]) |         cg.add(var.set_current_temperature_multiplier(temperature_multiplier)) | ||||||
|         ) |  | ||||||
|         cg.add( |  | ||||||
|             var.set_current_temperature_multiplier(config[CONF_TEMPERATURE_MULTIPLIER]) |  | ||||||
|         ) |  | ||||||
|     else: |     else: | ||||||
|  |         if current_temperature_multiplier := config.get( | ||||||
|  |             CONF_CURRENT_TEMPERATURE_MULTIPLIER | ||||||
|  |         ): | ||||||
|             cg.add( |             cg.add( | ||||||
|             var.set_current_temperature_multiplier( |                 var.set_current_temperature_multiplier(current_temperature_multiplier) | ||||||
|                 config[CONF_CURRENT_TEMPERATURE_MULTIPLIER] |  | ||||||
|             ) |             ) | ||||||
|         ) |         if target_temperature_multiplier := config.get( | ||||||
|         cg.add( |             CONF_TARGET_TEMPERATURE_MULTIPLIER | ||||||
|             var.set_target_temperature_multiplier( |         ): | ||||||
|                 config[CONF_TARGET_TEMPERATURE_MULTIPLIER] |             cg.add(var.set_target_temperature_multiplier(target_temperature_multiplier)) | ||||||
|             ) |  | ||||||
|         ) |  | ||||||
|     if CONF_ECO_DATAPOINT in config: |  | ||||||
|         cg.add(var.set_eco_id(config[CONF_ECO_DATAPOINT])) |  | ||||||
|         if CONF_ECO_TEMPERATURE in config: |  | ||||||
|             cg.add(var.set_eco_temperature(config[CONF_ECO_TEMPERATURE])) |  | ||||||
|  |  | ||||||
|     if config[CONF_REPORTS_FAHRENHEIT]: |     if config[CONF_REPORTS_FAHRENHEIT]: | ||||||
|         cg.add(var.set_reports_fahrenheit()) |         cg.add(var.set_reports_fahrenheit()) | ||||||
|  |  | ||||||
|  |     if preset_config := config.get(CONF_PRESET, {}): | ||||||
|  |         if eco_config := preset_config.get(CONF_ECO, {}): | ||||||
|  |             cg.add(var.set_eco_id(CONF_DATAPOINT)) | ||||||
|  |             if eco_temperature := eco_config.get(CONF_TEMPERATURE): | ||||||
|  |                 cg.add(var.set_eco_temperature(eco_temperature)) | ||||||
|  |         if CONF_SLEEP in preset_config: | ||||||
|  |             cg.add(var.set_sleep_id(CONF_DATAPOINT)) | ||||||
|  |  | ||||||
|  |     if swing_mode_config := config.get(CONF_SWING_MODE): | ||||||
|  |         if swing_vertical_datapoint := swing_mode_config.get(CONF_VERTICAL_DATAPOINT): | ||||||
|  |             cg.add(var.set_swing_vertical_id(swing_vertical_datapoint)) | ||||||
|  |         if swing_horizontal_datapoint := swing_mode_config.get( | ||||||
|  |             CONF_HORIZONTAL_DATAPOINT | ||||||
|  |         ): | ||||||
|  |             cg.add(var.set_swing_horizontal_id(swing_horizontal_datapoint)) | ||||||
|  |     if fan_mode_config := config.get(CONF_FAN_MODE): | ||||||
|  |         cg.add(var.set_fan_speed_id(CONF_DATAPOINT)) | ||||||
|  |         if (fan_auto_value := fan_mode_config.get(CONF_AUTO_VALUE)) is not None: | ||||||
|  |             cg.add(var.set_fan_speed_auto_value(fan_auto_value)) | ||||||
|  |         if (fan_low_value := fan_mode_config.get(CONF_LOW_VALUE)) is not None: | ||||||
|  |             cg.add(var.set_fan_speed_low_value(fan_low_value)) | ||||||
|  |         if (fan_medium_value := fan_mode_config.get(CONF_MEDIUM_VALUE)) is not None: | ||||||
|  |             cg.add(var.set_fan_speed_medium_value(fan_medium_value)) | ||||||
|  |         if (fan_middle_value := fan_mode_config.get(CONF_MIDDLE_VALUE)) is not None: | ||||||
|  |             cg.add(var.set_fan_speed_middle_value(fan_middle_value)) | ||||||
|  |         if (fan_high_value := fan_mode_config.get(CONF_HIGH_VALUE)) is not None: | ||||||
|  |             cg.add(var.set_fan_speed_high_value(fan_high_value)) | ||||||
|   | |||||||
| @@ -75,6 +75,41 @@ void TuyaClimate::setup() { | |||||||
|       this->publish_state(); |       this->publish_state(); | ||||||
|     }); |     }); | ||||||
|   } |   } | ||||||
|  |   if (this->sleep_id_.has_value()) { | ||||||
|  |     this->parent_->register_listener(*this->sleep_id_, [this](const TuyaDatapoint &datapoint) { | ||||||
|  |       this->sleep_ = datapoint.value_bool; | ||||||
|  |       ESP_LOGV(TAG, "MCU reported sleep is: %s", ONOFF(this->sleep_)); | ||||||
|  |       this->compute_preset_(); | ||||||
|  |       this->compute_target_temperature_(); | ||||||
|  |       this->publish_state(); | ||||||
|  |     }); | ||||||
|  |   } | ||||||
|  |   if (this->swing_vertical_id_.has_value()) { | ||||||
|  |     this->parent_->register_listener(*this->swing_vertical_id_, [this](const TuyaDatapoint &datapoint) { | ||||||
|  |       this->swing_vertical_ = datapoint.value_bool; | ||||||
|  |       ESP_LOGV(TAG, "MCU reported vertical swing is: %s", ONOFF(datapoint.value_bool)); | ||||||
|  |       this->compute_swingmode_(); | ||||||
|  |       this->publish_state(); | ||||||
|  |     }); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if (this->swing_horizontal_id_.has_value()) { | ||||||
|  |     this->parent_->register_listener(*this->swing_horizontal_id_, [this](const TuyaDatapoint &datapoint) { | ||||||
|  |       this->swing_horizontal_ = datapoint.value_bool; | ||||||
|  |       ESP_LOGV(TAG, "MCU reported horizontal swing is: %s", ONOFF(datapoint.value_bool)); | ||||||
|  |       this->compute_swingmode_(); | ||||||
|  |       this->publish_state(); | ||||||
|  |     }); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if (this->fan_speed_id_.has_value()) { | ||||||
|  |     this->parent_->register_listener(*this->fan_speed_id_, [this](const TuyaDatapoint &datapoint) { | ||||||
|  |       ESP_LOGV(TAG, "MCU reported Fan Speed Mode is: %u", datapoint.value_enum); | ||||||
|  |       this->fan_state_ = datapoint.value_enum; | ||||||
|  |       this->compute_fanmode_(); | ||||||
|  |       this->publish_state(); | ||||||
|  |     }); | ||||||
|  |   } | ||||||
| } | } | ||||||
|  |  | ||||||
| void TuyaClimate::loop() { | void TuyaClimate::loop() { | ||||||
| @@ -110,7 +145,21 @@ void TuyaClimate::control(const climate::ClimateCall &call) { | |||||||
|     const bool switch_state = *call.get_mode() != climate::CLIMATE_MODE_OFF; |     const bool switch_state = *call.get_mode() != climate::CLIMATE_MODE_OFF; | ||||||
|     ESP_LOGV(TAG, "Setting switch: %s", ONOFF(switch_state)); |     ESP_LOGV(TAG, "Setting switch: %s", ONOFF(switch_state)); | ||||||
|     this->parent_->set_boolean_datapoint_value(*this->switch_id_, switch_state); |     this->parent_->set_boolean_datapoint_value(*this->switch_id_, switch_state); | ||||||
|  |     const climate::ClimateMode new_mode = *call.get_mode(); | ||||||
|  |  | ||||||
|  |     if (new_mode == climate::CLIMATE_MODE_HEAT && this->supports_heat_) { | ||||||
|  |       this->parent_->set_enum_datapoint_value(*this->active_state_id_, *this->active_state_heating_value_); | ||||||
|  |     } else if (new_mode == climate::CLIMATE_MODE_COOL && this->supports_cool_) { | ||||||
|  |       this->parent_->set_enum_datapoint_value(*this->active_state_id_, *this->active_state_cooling_value_); | ||||||
|  |     } else if (new_mode == climate::CLIMATE_MODE_DRY && this->active_state_drying_value_.has_value()) { | ||||||
|  |       this->parent_->set_enum_datapoint_value(*this->active_state_id_, *this->active_state_drying_value_); | ||||||
|  |     } else if (new_mode == climate::CLIMATE_MODE_FAN_ONLY && this->active_state_fanonly_value_.has_value()) { | ||||||
|  |       this->parent_->set_enum_datapoint_value(*this->active_state_id_, *this->active_state_fanonly_value_); | ||||||
|     } |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   control_swing_mode_(call); | ||||||
|  |   control_fan_mode_(call); | ||||||
|  |  | ||||||
|   if (call.get_target_temperature().has_value()) { |   if (call.get_target_temperature().has_value()) { | ||||||
|     float target_temperature = *call.get_target_temperature(); |     float target_temperature = *call.get_target_temperature(); | ||||||
| @@ -129,6 +178,106 @@ void TuyaClimate::control(const climate::ClimateCall &call) { | |||||||
|       ESP_LOGV(TAG, "Setting eco: %s", ONOFF(eco)); |       ESP_LOGV(TAG, "Setting eco: %s", ONOFF(eco)); | ||||||
|       this->parent_->set_boolean_datapoint_value(*this->eco_id_, eco); |       this->parent_->set_boolean_datapoint_value(*this->eco_id_, eco); | ||||||
|     } |     } | ||||||
|  |     if (this->sleep_id_.has_value()) { | ||||||
|  |       const bool sleep = preset == climate::CLIMATE_PRESET_SLEEP; | ||||||
|  |       ESP_LOGV(TAG, "Setting sleep: %s", ONOFF(sleep)); | ||||||
|  |       this->parent_->set_boolean_datapoint_value(*this->sleep_id_, sleep); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void TuyaClimate::control_swing_mode_(const climate::ClimateCall &call) { | ||||||
|  |   bool vertical_swing_changed = false; | ||||||
|  |   bool horizontal_swing_changed = false; | ||||||
|  |  | ||||||
|  |   if (call.get_swing_mode().has_value()) { | ||||||
|  |     const auto swing_mode = *call.get_swing_mode(); | ||||||
|  |  | ||||||
|  |     switch (swing_mode) { | ||||||
|  |       case climate::CLIMATE_SWING_OFF: | ||||||
|  |         if (swing_vertical_ || swing_horizontal_) { | ||||||
|  |           this->swing_vertical_ = false; | ||||||
|  |           this->swing_horizontal_ = false; | ||||||
|  |           vertical_swing_changed = true; | ||||||
|  |           horizontal_swing_changed = true; | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |  | ||||||
|  |       case climate::CLIMATE_SWING_BOTH: | ||||||
|  |         if (!swing_vertical_ || !swing_horizontal_) { | ||||||
|  |           this->swing_vertical_ = true; | ||||||
|  |           this->swing_horizontal_ = true; | ||||||
|  |           vertical_swing_changed = true; | ||||||
|  |           horizontal_swing_changed = true; | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |  | ||||||
|  |       case climate::CLIMATE_SWING_VERTICAL: | ||||||
|  |         if (!swing_vertical_ || swing_horizontal_) { | ||||||
|  |           this->swing_vertical_ = true; | ||||||
|  |           this->swing_horizontal_ = false; | ||||||
|  |           vertical_swing_changed = true; | ||||||
|  |           horizontal_swing_changed = true; | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |  | ||||||
|  |       case climate::CLIMATE_SWING_HORIZONTAL: | ||||||
|  |         if (swing_vertical_ || !swing_horizontal_) { | ||||||
|  |           this->swing_vertical_ = false; | ||||||
|  |           this->swing_horizontal_ = true; | ||||||
|  |           vertical_swing_changed = true; | ||||||
|  |           horizontal_swing_changed = true; | ||||||
|  |         } | ||||||
|  |         break; | ||||||
|  |  | ||||||
|  |       default: | ||||||
|  |         break; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if (vertical_swing_changed && this->swing_vertical_id_.has_value()) { | ||||||
|  |     ESP_LOGV(TAG, "Setting vertical swing: %s", ONOFF(swing_vertical_)); | ||||||
|  |     this->parent_->set_boolean_datapoint_value(*this->swing_vertical_id_, swing_vertical_); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if (horizontal_swing_changed && this->swing_horizontal_id_.has_value()) { | ||||||
|  |     ESP_LOGV(TAG, "Setting horizontal swing: %s", ONOFF(swing_horizontal_)); | ||||||
|  |     this->parent_->set_boolean_datapoint_value(*this->swing_horizontal_id_, swing_horizontal_); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // Publish the state after updating the swing mode | ||||||
|  |   this->publish_state(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void TuyaClimate::control_fan_mode_(const climate::ClimateCall &call) { | ||||||
|  |   if (call.get_fan_mode().has_value()) { | ||||||
|  |     climate::ClimateFanMode fan_mode = *call.get_fan_mode(); | ||||||
|  |  | ||||||
|  |     uint8_t tuya_fan_speed; | ||||||
|  |     switch (fan_mode) { | ||||||
|  |       case climate::CLIMATE_FAN_LOW: | ||||||
|  |         tuya_fan_speed = *fan_speed_low_value_; | ||||||
|  |         break; | ||||||
|  |       case climate::CLIMATE_FAN_MEDIUM: | ||||||
|  |         tuya_fan_speed = *fan_speed_medium_value_; | ||||||
|  |         break; | ||||||
|  |       case climate::CLIMATE_FAN_MIDDLE: | ||||||
|  |         tuya_fan_speed = *fan_speed_middle_value_; | ||||||
|  |         break; | ||||||
|  |       case climate::CLIMATE_FAN_HIGH: | ||||||
|  |         tuya_fan_speed = *fan_speed_high_value_; | ||||||
|  |         break; | ||||||
|  |       case climate::CLIMATE_FAN_AUTO: | ||||||
|  |         tuya_fan_speed = *fan_speed_auto_value_; | ||||||
|  |         break; | ||||||
|  |       default: | ||||||
|  |         tuya_fan_speed = 0; | ||||||
|  |         break; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (this->fan_speed_id_.has_value()) { | ||||||
|  |       this->parent_->set_enum_datapoint_value(*this->fan_speed_id_, tuya_fan_speed); | ||||||
|  |     } | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -140,10 +289,46 @@ climate::ClimateTraits TuyaClimate::traits() { | |||||||
|     traits.add_supported_mode(climate::CLIMATE_MODE_HEAT); |     traits.add_supported_mode(climate::CLIMATE_MODE_HEAT); | ||||||
|   if (supports_cool_) |   if (supports_cool_) | ||||||
|     traits.add_supported_mode(climate::CLIMATE_MODE_COOL); |     traits.add_supported_mode(climate::CLIMATE_MODE_COOL); | ||||||
|  |   if (this->active_state_drying_value_.has_value()) | ||||||
|  |     traits.add_supported_mode(climate::CLIMATE_MODE_DRY); | ||||||
|  |   if (this->active_state_fanonly_value_.has_value()) | ||||||
|  |     traits.add_supported_mode(climate::CLIMATE_MODE_FAN_ONLY); | ||||||
|   if (this->eco_id_.has_value()) { |   if (this->eco_id_.has_value()) { | ||||||
|     traits.add_supported_preset(climate::CLIMATE_PRESET_NONE); |  | ||||||
|     traits.add_supported_preset(climate::CLIMATE_PRESET_ECO); |     traits.add_supported_preset(climate::CLIMATE_PRESET_ECO); | ||||||
|   } |   } | ||||||
|  |   if (this->sleep_id_.has_value()) { | ||||||
|  |     traits.add_supported_preset(climate::CLIMATE_PRESET_SLEEP); | ||||||
|  |   } | ||||||
|  |   if (this->sleep_id_.has_value() || this->eco_id_.has_value()) { | ||||||
|  |     traits.add_supported_preset(climate::CLIMATE_PRESET_NONE); | ||||||
|  |   } | ||||||
|  |   if (this->swing_vertical_id_.has_value() && this->swing_horizontal_id_.has_value()) { | ||||||
|  |     std::set<climate::ClimateSwingMode> supported_swing_modes = { | ||||||
|  |         climate::CLIMATE_SWING_OFF, climate::CLIMATE_SWING_BOTH, climate::CLIMATE_SWING_VERTICAL, | ||||||
|  |         climate::CLIMATE_SWING_HORIZONTAL}; | ||||||
|  |     traits.set_supported_swing_modes(std::move(supported_swing_modes)); | ||||||
|  |   } else if (this->swing_vertical_id_.has_value()) { | ||||||
|  |     std::set<climate::ClimateSwingMode> supported_swing_modes = {climate::CLIMATE_SWING_OFF, | ||||||
|  |                                                                  climate::CLIMATE_SWING_VERTICAL}; | ||||||
|  |     traits.set_supported_swing_modes(std::move(supported_swing_modes)); | ||||||
|  |   } else if (this->swing_horizontal_id_.has_value()) { | ||||||
|  |     std::set<climate::ClimateSwingMode> supported_swing_modes = {climate::CLIMATE_SWING_OFF, | ||||||
|  |                                                                  climate::CLIMATE_SWING_HORIZONTAL}; | ||||||
|  |     traits.set_supported_swing_modes(std::move(supported_swing_modes)); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if (fan_speed_id_) { | ||||||
|  |     if (fan_speed_low_value_) | ||||||
|  |       traits.add_supported_fan_mode(climate::CLIMATE_FAN_LOW); | ||||||
|  |     if (fan_speed_medium_value_) | ||||||
|  |       traits.add_supported_fan_mode(climate::CLIMATE_FAN_MEDIUM); | ||||||
|  |     if (fan_speed_middle_value_) | ||||||
|  |       traits.add_supported_fan_mode(climate::CLIMATE_FAN_MIDDLE); | ||||||
|  |     if (fan_speed_high_value_) | ||||||
|  |       traits.add_supported_fan_mode(climate::CLIMATE_FAN_HIGH); | ||||||
|  |     if (fan_speed_auto_value_) | ||||||
|  |       traits.add_supported_fan_mode(climate::CLIMATE_FAN_AUTO); | ||||||
|  |   } | ||||||
|   return traits; |   return traits; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -166,16 +351,56 @@ void TuyaClimate::dump_config() { | |||||||
|   if (this->eco_id_.has_value()) { |   if (this->eco_id_.has_value()) { | ||||||
|     ESP_LOGCONFIG(TAG, "  Eco has datapoint ID %u", *this->eco_id_); |     ESP_LOGCONFIG(TAG, "  Eco has datapoint ID %u", *this->eco_id_); | ||||||
|   } |   } | ||||||
|  |   if (this->sleep_id_.has_value()) { | ||||||
|  |     ESP_LOGCONFIG(TAG, "  Sleep has datapoint ID %u", *this->sleep_id_); | ||||||
|  |   } | ||||||
|  |   if (this->swing_vertical_id_.has_value()) { | ||||||
|  |     ESP_LOGCONFIG(TAG, "  Swing Vertical has datapoint ID %u", *this->swing_vertical_id_); | ||||||
|  |   } | ||||||
|  |   if (this->swing_horizontal_id_.has_value()) { | ||||||
|  |     ESP_LOGCONFIG(TAG, "  Swing Horizontal has datapoint ID %u", *this->swing_horizontal_id_); | ||||||
|  |   } | ||||||
| } | } | ||||||
|  |  | ||||||
| void TuyaClimate::compute_preset_() { | void TuyaClimate::compute_preset_() { | ||||||
|   if (this->eco_) { |   if (this->eco_) { | ||||||
|     this->preset = climate::CLIMATE_PRESET_ECO; |     this->preset = climate::CLIMATE_PRESET_ECO; | ||||||
|  |   } else if (this->sleep_) { | ||||||
|  |     this->preset = climate::CLIMATE_PRESET_SLEEP; | ||||||
|   } else { |   } else { | ||||||
|     this->preset = climate::CLIMATE_PRESET_NONE; |     this->preset = climate::CLIMATE_PRESET_NONE; | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | void TuyaClimate::compute_swingmode_() { | ||||||
|  |   if (this->swing_vertical_ && this->swing_horizontal_) { | ||||||
|  |     this->swing_mode = climate::CLIMATE_SWING_BOTH; | ||||||
|  |   } else if (this->swing_vertical_) { | ||||||
|  |     this->swing_mode = climate::CLIMATE_SWING_VERTICAL; | ||||||
|  |   } else if (this->swing_horizontal_) { | ||||||
|  |     this->swing_mode = climate::CLIMATE_SWING_HORIZONTAL; | ||||||
|  |   } else { | ||||||
|  |     this->swing_mode = climate::CLIMATE_SWING_OFF; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void TuyaClimate::compute_fanmode_() { | ||||||
|  |   if (this->fan_speed_id_.has_value()) { | ||||||
|  |     // Use state from MCU datapoint | ||||||
|  |     if (this->fan_speed_auto_value_.has_value() && this->fan_state_ == this->fan_speed_auto_value_) { | ||||||
|  |       this->fan_mode = climate::CLIMATE_FAN_AUTO; | ||||||
|  |     } else if (this->fan_speed_high_value_.has_value() && this->fan_state_ == this->fan_speed_high_value_) { | ||||||
|  |       this->fan_mode = climate::CLIMATE_FAN_HIGH; | ||||||
|  |     } else if (this->fan_speed_medium_value_.has_value() && this->fan_state_ == this->fan_speed_medium_value_) { | ||||||
|  |       this->fan_mode = climate::CLIMATE_FAN_MEDIUM; | ||||||
|  |     } else if (this->fan_speed_middle_value_.has_value() && this->fan_state_ == this->fan_speed_middle_value_) { | ||||||
|  |       this->fan_mode = climate::CLIMATE_FAN_MIDDLE; | ||||||
|  |     } else if (this->fan_speed_low_value_.has_value() && this->fan_state_ == this->fan_speed_low_value_) { | ||||||
|  |       this->fan_mode = climate::CLIMATE_FAN_LOW; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
| void TuyaClimate::compute_target_temperature_() { | void TuyaClimate::compute_target_temperature_() { | ||||||
|   if (this->eco_ && this->eco_temperature_.has_value()) { |   if (this->eco_ && this->eco_temperature_.has_value()) { | ||||||
|     this->target_temperature = *this->eco_temperature_; |     this->target_temperature = *this->eco_temperature_; | ||||||
| @@ -202,16 +427,28 @@ void TuyaClimate::compute_state_() { | |||||||
|     if (this->supports_heat_ && this->active_state_heating_value_.has_value() && |     if (this->supports_heat_ && this->active_state_heating_value_.has_value() && | ||||||
|         this->active_state_ == this->active_state_heating_value_) { |         this->active_state_ == this->active_state_heating_value_) { | ||||||
|       target_action = climate::CLIMATE_ACTION_HEATING; |       target_action = climate::CLIMATE_ACTION_HEATING; | ||||||
|  |       this->mode = climate::CLIMATE_MODE_HEAT; | ||||||
|     } else if (this->supports_cool_ && this->active_state_cooling_value_.has_value() && |     } else if (this->supports_cool_ && this->active_state_cooling_value_.has_value() && | ||||||
|                this->active_state_ == this->active_state_cooling_value_) { |                this->active_state_ == this->active_state_cooling_value_) { | ||||||
|       target_action = climate::CLIMATE_ACTION_COOLING; |       target_action = climate::CLIMATE_ACTION_COOLING; | ||||||
|  |       this->mode = climate::CLIMATE_MODE_COOL; | ||||||
|  |     } else if (this->active_state_drying_value_.has_value() && | ||||||
|  |                this->active_state_ == this->active_state_drying_value_) { | ||||||
|  |       target_action = climate::CLIMATE_ACTION_DRYING; | ||||||
|  |       this->mode = climate::CLIMATE_MODE_DRY; | ||||||
|  |     } else if (this->active_state_fanonly_value_.has_value() && | ||||||
|  |                this->active_state_ == this->active_state_fanonly_value_) { | ||||||
|  |       target_action = climate::CLIMATE_ACTION_FAN; | ||||||
|  |       this->mode = climate::CLIMATE_MODE_FAN_ONLY; | ||||||
|     } |     } | ||||||
|   } else if (this->heating_state_pin_ != nullptr || this->cooling_state_pin_ != nullptr) { |   } else if (this->heating_state_pin_ != nullptr || this->cooling_state_pin_ != nullptr) { | ||||||
|     // Use state from input pins |     // Use state from input pins | ||||||
|     if (this->heating_state_) { |     if (this->heating_state_) { | ||||||
|       target_action = climate::CLIMATE_ACTION_HEATING; |       target_action = climate::CLIMATE_ACTION_HEATING; | ||||||
|  |       this->mode = climate::CLIMATE_MODE_HEAT; | ||||||
|     } else if (this->cooling_state_) { |     } else if (this->cooling_state_) { | ||||||
|       target_action = climate::CLIMATE_ACTION_COOLING; |       target_action = climate::CLIMATE_ACTION_COOLING; | ||||||
|  |       this->mode = climate::CLIMATE_MODE_COOL; | ||||||
|     } |     } | ||||||
|   } else { |   } else { | ||||||
|     // Fallback to active state calc based on temp and hysteresis |     // Fallback to active state calc based on temp and hysteresis | ||||||
| @@ -219,8 +456,10 @@ void TuyaClimate::compute_state_() { | |||||||
|     if (std::abs(temp_diff) > this->hysteresis_) { |     if (std::abs(temp_diff) > this->hysteresis_) { | ||||||
|       if (this->supports_heat_ && temp_diff > 0) { |       if (this->supports_heat_ && temp_diff > 0) { | ||||||
|         target_action = climate::CLIMATE_ACTION_HEATING; |         target_action = climate::CLIMATE_ACTION_HEATING; | ||||||
|  |         this->mode = climate::CLIMATE_MODE_HEAT; | ||||||
|       } else if (this->supports_cool_ && temp_diff < 0) { |       } else if (this->supports_cool_ && temp_diff < 0) { | ||||||
|         target_action = climate::CLIMATE_ACTION_COOLING; |         target_action = climate::CLIMATE_ACTION_COOLING; | ||||||
|  |         this->mode = climate::CLIMATE_MODE_COOL; | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|   | |||||||
| @@ -18,8 +18,22 @@ class TuyaClimate : public climate::Climate, public Component { | |||||||
|   void set_active_state_id(uint8_t state_id) { this->active_state_id_ = state_id; } |   void set_active_state_id(uint8_t state_id) { this->active_state_id_ = state_id; } | ||||||
|   void set_active_state_heating_value(uint8_t value) { this->active_state_heating_value_ = value; } |   void set_active_state_heating_value(uint8_t value) { this->active_state_heating_value_ = value; } | ||||||
|   void set_active_state_cooling_value(uint8_t value) { this->active_state_cooling_value_ = value; } |   void set_active_state_cooling_value(uint8_t value) { this->active_state_cooling_value_ = value; } | ||||||
|  |   void set_active_state_drying_value(uint8_t value) { this->active_state_drying_value_ = value; } | ||||||
|  |   void set_active_state_fanonly_value(uint8_t value) { this->active_state_fanonly_value_ = value; } | ||||||
|   void set_heating_state_pin(GPIOPin *pin) { this->heating_state_pin_ = pin; } |   void set_heating_state_pin(GPIOPin *pin) { this->heating_state_pin_ = pin; } | ||||||
|   void set_cooling_state_pin(GPIOPin *pin) { this->cooling_state_pin_ = pin; } |   void set_cooling_state_pin(GPIOPin *pin) { this->cooling_state_pin_ = pin; } | ||||||
|  |   void set_swing_vertical_id(uint8_t swing_vertical_id) { this->swing_vertical_id_ = swing_vertical_id; } | ||||||
|  |   void set_swing_horizontal_id(uint8_t swing_horizontal_id) { this->swing_horizontal_id_ = swing_horizontal_id; } | ||||||
|  |   void set_fan_speed_id(uint8_t fan_speed_id) { this->fan_speed_id_ = fan_speed_id; } | ||||||
|  |   void set_fan_speed_low_value(uint8_t fan_speed_low_value) { this->fan_speed_low_value_ = fan_speed_low_value; } | ||||||
|  |   void set_fan_speed_medium_value(uint8_t fan_speed_medium_value) { | ||||||
|  |     this->fan_speed_medium_value_ = fan_speed_medium_value; | ||||||
|  |   } | ||||||
|  |   void set_fan_speed_middle_value(uint8_t fan_speed_middle_value) { | ||||||
|  |     this->fan_speed_middle_value_ = fan_speed_middle_value; | ||||||
|  |   } | ||||||
|  |   void set_fan_speed_high_value(uint8_t fan_speed_high_value) { this->fan_speed_high_value_ = fan_speed_high_value; } | ||||||
|  |   void set_fan_speed_auto_value(uint8_t fan_speed_auto_value) { this->fan_speed_auto_value_ = fan_speed_auto_value; } | ||||||
|   void set_target_temperature_id(uint8_t target_temperature_id) { |   void set_target_temperature_id(uint8_t target_temperature_id) { | ||||||
|     this->target_temperature_id_ = target_temperature_id; |     this->target_temperature_id_ = target_temperature_id; | ||||||
|   } |   } | ||||||
| @@ -34,6 +48,7 @@ class TuyaClimate : public climate::Climate, public Component { | |||||||
|   } |   } | ||||||
|   void set_eco_id(uint8_t eco_id) { this->eco_id_ = eco_id; } |   void set_eco_id(uint8_t eco_id) { this->eco_id_ = eco_id; } | ||||||
|   void set_eco_temperature(float eco_temperature) { this->eco_temperature_ = eco_temperature; } |   void set_eco_temperature(float eco_temperature) { this->eco_temperature_ = eco_temperature; } | ||||||
|  |   void set_sleep_id(uint8_t sleep_id) { this->sleep_id_ = sleep_id; } | ||||||
|  |  | ||||||
|   void set_reports_fahrenheit() { this->reports_fahrenheit_ = true; } |   void set_reports_fahrenheit() { this->reports_fahrenheit_ = true; } | ||||||
|  |  | ||||||
| @@ -43,6 +58,12 @@ class TuyaClimate : public climate::Climate, public Component { | |||||||
|   /// Override control to change settings of the climate device. |   /// Override control to change settings of the climate device. | ||||||
|   void control(const climate::ClimateCall &call) override; |   void control(const climate::ClimateCall &call) override; | ||||||
|  |  | ||||||
|  |   /// Override control to change settings of swing mode. | ||||||
|  |   void control_swing_mode_(const climate::ClimateCall &call); | ||||||
|  |  | ||||||
|  |   /// Override control to change settings of fan mode. | ||||||
|  |   void control_fan_mode_(const climate::ClimateCall &call); | ||||||
|  |  | ||||||
|   /// Return the traits of this controller. |   /// Return the traits of this controller. | ||||||
|   climate::ClimateTraits traits() override; |   climate::ClimateTraits traits() override; | ||||||
|  |  | ||||||
| @@ -55,6 +76,12 @@ class TuyaClimate : public climate::Climate, public Component { | |||||||
|   /// Re-compute the state of this climate controller. |   /// Re-compute the state of this climate controller. | ||||||
|   void compute_state_(); |   void compute_state_(); | ||||||
|  |  | ||||||
|  |   /// Re-Compute the swing mode of this climate controller. | ||||||
|  |   void compute_swingmode_(); | ||||||
|  |  | ||||||
|  |   /// Re-Compute the fan mode of this climate controller. | ||||||
|  |   void compute_fanmode_(); | ||||||
|  |  | ||||||
|   /// Switch the climate device to the given climate mode. |   /// Switch the climate device to the given climate mode. | ||||||
|   void switch_to_action_(climate::ClimateAction action); |   void switch_to_action_(climate::ClimateAction action); | ||||||
|  |  | ||||||
| @@ -65,6 +92,8 @@ class TuyaClimate : public climate::Climate, public Component { | |||||||
|   optional<uint8_t> active_state_id_{}; |   optional<uint8_t> active_state_id_{}; | ||||||
|   optional<uint8_t> active_state_heating_value_{}; |   optional<uint8_t> active_state_heating_value_{}; | ||||||
|   optional<uint8_t> active_state_cooling_value_{}; |   optional<uint8_t> active_state_cooling_value_{}; | ||||||
|  |   optional<uint8_t> active_state_drying_value_{}; | ||||||
|  |   optional<uint8_t> active_state_fanonly_value_{}; | ||||||
|   GPIOPin *heating_state_pin_{nullptr}; |   GPIOPin *heating_state_pin_{nullptr}; | ||||||
|   GPIOPin *cooling_state_pin_{nullptr}; |   GPIOPin *cooling_state_pin_{nullptr}; | ||||||
|   optional<uint8_t> target_temperature_id_{}; |   optional<uint8_t> target_temperature_id_{}; | ||||||
| @@ -73,12 +102,25 @@ class TuyaClimate : public climate::Climate, public Component { | |||||||
|   float target_temperature_multiplier_{1.0f}; |   float target_temperature_multiplier_{1.0f}; | ||||||
|   float hysteresis_{1.0f}; |   float hysteresis_{1.0f}; | ||||||
|   optional<uint8_t> eco_id_{}; |   optional<uint8_t> eco_id_{}; | ||||||
|  |   optional<uint8_t> sleep_id_{}; | ||||||
|   optional<float> eco_temperature_{}; |   optional<float> eco_temperature_{}; | ||||||
|   uint8_t active_state_; |   uint8_t active_state_; | ||||||
|  |   uint8_t fan_state_; | ||||||
|  |   optional<uint8_t> swing_vertical_id_{}; | ||||||
|  |   optional<uint8_t> swing_horizontal_id_{}; | ||||||
|  |   optional<uint8_t> fan_speed_id_{}; | ||||||
|  |   optional<uint8_t> fan_speed_low_value_{}; | ||||||
|  |   optional<uint8_t> fan_speed_medium_value_{}; | ||||||
|  |   optional<uint8_t> fan_speed_middle_value_{}; | ||||||
|  |   optional<uint8_t> fan_speed_high_value_{}; | ||||||
|  |   optional<uint8_t> fan_speed_auto_value_{}; | ||||||
|  |   bool swing_vertical_{false}; | ||||||
|  |   bool swing_horizontal_{false}; | ||||||
|   bool heating_state_{false}; |   bool heating_state_{false}; | ||||||
|   bool cooling_state_{false}; |   bool cooling_state_{false}; | ||||||
|   float manual_temperature_; |   float manual_temperature_; | ||||||
|   bool eco_; |   bool eco_; | ||||||
|  |   bool sleep_; | ||||||
|   bool reports_fahrenheit_{false}; |   bool reports_fahrenheit_{false}; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user