From 3472ac3dcc06f37b398c5b72109f1f38ba5ec021 Mon Sep 17 00:00:00 2001 From: BugHaver <43462320+bughaver@users.noreply.github.com> Date: Mon, 12 Oct 2026 20:44:01 +1100 Subject: [PATCH] [heatpumpir] Add Eco and Boost presets and fix fan speeds on Mitsubishi Heavy ZJ and ZMP (#16877) Co-authored-by: J. Nick Koston --- esphome/components/heatpumpir/heatpumpir.cpp | 25 ++++++++++++++++++-- esphome/components/heatpumpir/heatpumpir.h | 11 +++++---- tests/components/heatpumpir/common.yaml | 8 +++++++ 3 files changed, 38 insertions(+), 6 deletions(-) diff --git a/esphome/components/heatpumpir/heatpumpir.cpp b/esphome/components/heatpumpir/heatpumpir.cpp index ca0ffb37c18..b4597fe4abf 100644 --- a/esphome/components/heatpumpir/heatpumpir.cpp +++ b/esphome/components/heatpumpir/heatpumpir.cpp @@ -127,6 +127,13 @@ void HeatpumpIRClimate::setup() { } } +void HeatpumpIRClimate::control(const climate::ClimateCall &call) { + // Picking a fan speed ends HiPower or Econo, as it does on the remote + if (this->has_fan_byte_presets_() && call.get_fan_mode().has_value() && !call.get_preset().has_value()) + this->preset = climate::CLIMATE_PRESET_NONE; + climate_ir::ClimateIR::control(call); +} + void HeatpumpIRClimate::transmit_state() { uint8_t power_mode_cmd; uint8_t operating_mode_cmd; @@ -190,8 +197,9 @@ void HeatpumpIRClimate::transmit_state() { } // MitsubishiMSCHeatpumpIR only knows FAN_1..FAN_3 and sends anything else as auto, - // so low/medium/high have to start at FAN_1 there instead of FAN_2. - const bool three_speed_fan = this->protocol_ == PROTOCOL_MITSUBISHI_MSC; + // so low/medium/high have to start at FAN_1 there instead of FAN_2. Mitsubishi Heavy + // ZJ and ZMP also stop at FAN_3 and use FAN_4 and FAN_5 for HiPower and Econo. + const bool three_speed_fan = this->protocol_ == PROTOCOL_MITSUBISHI_MSC || this->has_fan_byte_presets_(); switch (this->fan_mode.value_or(climate::CLIMATE_FAN_AUTO)) { case climate::CLIMATE_FAN_LOW: fan_speed_cmd = three_speed_fan ? FAN_1 : FAN_2; @@ -208,6 +216,19 @@ void HeatpumpIRClimate::transmit_state() { break; } + if (this->has_fan_byte_presets_()) { + switch (this->preset.value_or(climate::CLIMATE_PRESET_NONE)) { + case climate::CLIMATE_PRESET_BOOST: + fan_speed_cmd = FAN_4; // HiPower + break; + case climate::CLIMATE_PRESET_ECO: + fan_speed_cmd = FAN_5; // Econo + break; + default: + break; + } + } + switch (this->mode) { case climate::CLIMATE_MODE_COOL: power_mode_cmd = POWER_ON; diff --git a/esphome/components/heatpumpir/heatpumpir.h b/esphome/components/heatpumpir/heatpumpir.h index 2c119c75504..d00fa91d05a 100644 --- a/esphome/components/heatpumpir/heatpumpir.h +++ b/esphome/components/heatpumpir/heatpumpir.h @@ -104,10 +104,8 @@ class HeatpumpIRClimate final : public climate_ir::ClimateIR { void setup() override; void set_protocol(Protocol protocol) { this->protocol_ = protocol; - if (protocol == PROTOCOL_MITSUBISHI_HEAVY_ZMP) { - this->presets_.insert(climate::CLIMATE_PRESET_NONE); - this->presets_.insert(climate::CLIMATE_PRESET_ECO); - this->presets_.insert(climate::CLIMATE_PRESET_BOOST); + if (this->has_fan_byte_presets_()) { + this->presets_ = {climate::CLIMATE_PRESET_NONE, climate::CLIMATE_PRESET_ECO, climate::CLIMATE_PRESET_BOOST}; } } void set_horizontal_default(HorizontalDirection horizontal_direction) { @@ -122,8 +120,13 @@ class HeatpumpIRClimate final : public climate_ir::ClimateIR { protected: HeatpumpIR *heatpump_ir_; + void control(const climate::ClimateCall &call) override; /// Transmit via IR the state of this climate controller. void transmit_state() override; + /// Mitsubishi Heavy ZJ and ZMP carry HiPower and Econo in the fan byte as FAN_4 and FAN_5 + bool has_fan_byte_presets_() const { + return this->protocol_ == PROTOCOL_MITSUBISHI_HEAVY_ZJ || this->protocol_ == PROTOCOL_MITSUBISHI_HEAVY_ZMP; + } /// Handle received IR data from the remote control. bool on_receive(remote_base::RemoteReceiveData data) override; Protocol protocol_; diff --git a/tests/components/heatpumpir/common.yaml b/tests/components/heatpumpir/common.yaml index 24cc22f06f2..de45f91ec96 100644 --- a/tests/components/heatpumpir/common.yaml +++ b/tests/components/heatpumpir/common.yaml @@ -7,6 +7,14 @@ climate: min_temperature: 18 max_temperature: 30 transmitter_id: xmitr + - platform: heatpumpir + protocol: mitsubishi_heavy_zj + horizontal_default: left + vertical_default: mup + name: HeatpumpIR Climate Mitsubishi ZJ + min_temperature: 18 + max_temperature: 30 + transmitter_id: xmitr - platform: heatpumpir protocol: mitsubishi_heavy_zmp horizontal_default: left