Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Samsung AC IR climate component #444

Closed
kvvoff opened this issue Oct 24, 2019 · 39 comments
Closed

Add Samsung AC IR climate component #444

kvvoff opened this issue Oct 24, 2019 · 39 comments

Comments

@kvvoff
Copy link

kvvoff commented Oct 24, 2019

Describe the problem you have/What new integration you would like

I would like to use ESPHome to control Samsung AC.

Please describe your use case for this integration and alternatives you've tried:

Learning through an IR receiver does not give a result, the code is always different and the air conditioner does not respond to it

Additional context

Samsung AC is mentioned here, I do not know how much this will help integration:
https://github.com/crankyoldgit/IRremoteESP8266/blob/master/examples/IRMQTTServer/IRMQTTServer.ino

@glmnet
Copy link
Member

glmnet commented Oct 25, 2019

the code is always different and the air conditioner

The codes should be the same, however the codes are not tied to a button but to the full state of the remote, e.g. there is a code for cool at 24 with fan high speed, other for 23 deg, etc.

Your AC should respond to the code otherwise you might have a hw issue.

Samsung AC is mentioned here, I do not know how much this will help integration

Ideally you will try another library to see if the code works with your AC, if it does then we can move forward on migrating a working code onto ESPHome.

If it doesn't you can try other remote protocols there.

@kvvoff
Copy link
Author

kvvoff commented Oct 25, 2019

@glmnet

The codes should be the same, however the codes are not tied to a button but to the full state of the remote, e.g. there is a code for cool at 24 with fan high speed, other for 23 deg, etc.

Yes, I know that, I even added my other Erisson AC to the SmartIR project, adding each button separately. It was tiring.

I meant that even the code from the same button is always different (for example 24, cooling, low fan speed - the code is always different and if you write them all down, nothing happens to the AC anyway)

Ideally you will try another library to see if the code works with your AC, if it does then we can move forward on migrating a working code onto ESPHome.

In the same project, IRremoteESP8266, already has codes for many air conditioner manufacturers. Including those already added in ESPHome Coolix and Tcl112
https://github.com/crankyoldgit/IRremoteESP8266/blob/master/SupportedProtocols.md

How about adding samsung for testing? I have no way to use this project (IRremoteESP8266), I would like to test it in ESPHome

@Nathareth
Copy link

Hello! Unfortunately, I have the same problem. I cannot get Samsung AC to work with existing components for ESPHome. I am always ready to conduct testing or any experiments to solve this problem.

@computingwithinfinitedata
Copy link

computingwithinfinitedata commented Oct 31, 2019

Not sure if this helps, but I just managed to get everything setup with my Daikin and my Panasonic AC. Everything is via IR, so there's no feedback from the AC. There's a Samsung AC library within the IRremote project, so you should be able to adapt my code.

This is what I did:

  1. The yaml file is:
esphome:
  name: irdaikin
  platform: ESP8266
  board: d1_mini
  includes: 
    - irdaikin/daikin_ir.h
  libraries:
    - IRremoteESP8266

wifi:
  ssid: "your_ssid"
  password: "your_wifi"

# Enable logging
logger:

ota:

api:

climate:
- platform: custom
  lambda: |-
    auto my_daikinac = new DaikinAC();
    App.register_component(my_daikinac);
    return {my_daikinac};

  climates:
    - name: "Living Room AC"
  1. And the irdaikin.h file is (save in the same directory as your config file)
#include "esphome.h"
#include "IRremoteESP8266.h"
#include "IRsend.h"
#include "ir_Daikin.h"


const uint16_t kIrLed = 0;  // ESP8266 GPIO pin to use. Recommended: 0 (D3).
IRDaikinESP ac(kIrLed);

class DaikinAC : public Component, public Climate {
 public:
  void setup() override {
    ac.begin();
    ac.on();
    ac.setTemp(21);
    ac.setFan(kDaikinFanAuto);
    ac.setMode(kDaikinHeat);
    ac.setSwingVertical(false);
    ac.setSwingHorizontal(false);
  }

  climate::ClimateTraits traits() {
    auto traits = climate::ClimateTraits();
    traits.set_supports_current_temperature(true);
    traits.set_supports_auto_mode(true);
    traits.set_supports_cool_mode(true);
    traits.set_supports_heat_mode(true);
    traits.set_supports_two_point_target_temperature(false);
    traits.set_supports_away(false);
    traits.set_visual_min_temperature(16);
    traits.set_visual_max_temperature(30);
    traits.set_visual_temperature_step(1.f);
    return traits;
  }
  void control(const ClimateCall &call) override {
    if (call.get_mode().has_value()) {
      // User requested mode change
      ClimateMode mode = *call.get_mode();
      // Send mode to hardware
      if (mode == CLIMATE_MODE_HEAT) {
        ac.on();
        ac.setMode(kDaikinHeat);
      }
      else if (mode == CLIMATE_MODE_COOL) {
        ac.on();
        ac.setMode(kDaikinCool);
      }
      else if (mode == CLIMATE_MODE_AUTO) {
        ac.on();
        ac.setMode(kDaikinAuto);
      }
      else if (mode == CLIMATE_MODE_OFF) {
        ac.off();
        }

      // Publish updated state
    this->mode = mode;
    this->publish_state();
    }
    if (call.get_target_temperature().has_value()) {
      // User requested target temperature change
      float temp = *call.get_target_temperature();
      // Send target temp to climate
      ac.setTemp(temp);
      this->target_temperature = temp;
     this->publish_state();
    }

    ac.send();
  }
};

@kvvoff
Copy link
Author

kvvoff commented Oct 31, 2019

@computingwithinfinitedata It looks really cool, I'll try it. Thanks friend

@OttoWinter
Copy link
Member

@computingwithinfinitedata Great! FYI, you can use libraries instead of lib_deps. I updated your comment to reflect that.

@kvvoff
Copy link
Author

kvvoff commented Oct 31, 2019

@OttoWinter Is it possible to somehow create a component for esphome with all codes of all air conditioners from project IRremoteESP8266? I am ready to test it
Or each AC needs to be created separately?

@OttoWinter
Copy link
Member

@kvvoff Each one needs to be done separately. Though the base part has been greatly simplified thanks to @glmnet 's climate_ir base.

@kvvoff
Copy link
Author

kvvoff commented Oct 31, 2019

@computingwithinfinitedata

I tried now your code for your ac. The compilation was successful, a new climate was added, but without a choice of temperature.

image

I did not change the code, I inserted the one that you wrote. How could I be wrong?

Here's the log:

[19:08:41][D][climate:175]:   Mode: COOL
[19:08:41][D][climate:177]:   Current Temperature: nan°C
[19:08:41][D][climate:183]:   Target Temperature: 0.00°C
[19:08:44][D][climate:010]: 'Living Room AC' - Setting
[19:08:44][D][climate:014]:   Mode: OFF
[19:08:44][D][climate:172]: 'Living Room AC' - Sending state:
[19:08:44][D][climate:175]:   Mode: OFF
[19:08:44][D][climate:177]:   Current Temperature: nan°C
[19:08:44][D][climate:183]:   Target Temperature: 0.00°C
[19:08:46][D][remote.raw:041]: Received Raw: 306
[19:08:48][D][remote.raw:041]: Received Raw: 389
[19:08:53][D][climate:010]: 'Living Room AC' - Setting
[19:08:53][D][climate:014]:   Mode: AUTO
[19:08:53][D][climate:172]: 'Living Room AC' - Sending state:
[19:08:53][D][climate:175]:   Mode: AUTO
[19:08:53][D][climate:177]:   Current Temperature: nan°C
[19:08:53][D][climate:183]:   Target Temperature: 0.00°C
[19:08:54][D][climate:010]: 'Living Room AC' - Setting
[19:08:54][D][climate:014]:   Mode: HEAT
[19:08:54][D][climate:172]: 'Living Room AC' - Sending state:
[19:08:54][D][climate:175]:   Mode: HEAT
[19:08:54][D][climate:177]:   Current Temperature: nan°C
[19:08:54][D][climate:183]:   Target Temperature: 0.00°C
[19:09:22][D][climate:010]: 'Living Room AC' - Setting
[19:09:22][D][climate:014]:   Mode: COOL
[19:09:22][D][climate:172]: 'Living Room AC' - Sending state:
[19:09:22][D][climate:175]:   Mode: COOL
[19:09:22][D][climate:177]:   Current Temperature: nan°C
[19:09:22][D][climate:183]:   Target Temperature: 0.00°C

@computingwithinfinitedata

@kvvoff add a thermostat component in the UI and you will be able to select the (target) temperature. The temperature showing in the component above is the "current" temperature, which isn't measured. (Since the IR only works one-way. You could add a temperature probe to your ESP that reports the room's temperature...)

@kvvoff
Copy link
Author

kvvoff commented Nov 1, 2019

add a thermostat component in the UI and you will be able to select the (target) temperature.

The problem is that there is no choice of temperature ... I therefore showed a screenshot in the previous comment.. strangely

@OttoWinter
Copy link
Member

@computingwithinfinitedata If the device does not support sending current temperature, you should set traits.set_supports_current_temperature(true); to false.

@selfhoster
Copy link

For anyone interested, using computingwithinfinitedata's template I put together code to control a Panasonic AC:

NOTE: This requires you to have the dev branch of esphome installed, as it contains extra climate traits

  1. esphome yaml:
esphome:
  name: upstairsac
  platform: ESP8266
  board: d1_mini
  includes: 
    - panasonic_ir.h
  libraries:
    - IRremoteESP8266

wifi:
  ssid: ""
  password: ""

# Enable logging
logger:

ota:

api:

climate:
- platform: custom
  lambda: |-
    auto my_panasonic = new PanasonicAC();
    App.register_component(my_panasonic);
    return {my_panasonic};

  climates:
    - name: "Upstairs AC"
  1. panasonic_ir.h
#include "esphome.h"
#include "IRremoteESP8266.h"
#include "IRsend.h"
#include "ir_Panasonic.h"


const uint16_t kIrLed = 0;  // ESP8266 GPIO pin to use. Recommended: 0 (D3).
IRPanasonicAc ac(kIrLed);

class PanasonicAC : public Component, public Climate {
 public:
  void setup() override {
    ac.begin();
    ac.on();
    ac.setTemp(21);
    ac.setFan(kPanasonicAcFanAuto);  //Min,Med,Max,Auto
    ac.setMode(kPanasonicAcHeat);
    ac.setSwingVertical(false);
    ac.setSwingHorizontal(false);
  }

  climate::ClimateTraits traits() {
    auto traits = climate::ClimateTraits();
    traits.set_supports_current_temperature(true);
    traits.set_supports_two_point_target_temperature(false);
    traits.set_visual_min_temperature(16);
    traits.set_visual_max_temperature(30);
    traits.set_visual_temperature_step(1.f);

    traits.set_supports_auto_mode(true);
    traits.set_supports_cool_mode(true);
    traits.set_supports_heat_mode(true);
    traits.set_supports_fan_only_mode(true);    //fan only mode is really just thermostat at 27
    traits.set_supports_dry_mode(true);
    //traits.set_supports_away(true);   //economy

    traits.set_supports_fan_mode_auto(true);
    traits.set_supports_fan_mode_low(true);
    traits.set_supports_fan_mode_medium(true);
    traits.set_supports_fan_mode_high(true);

    traits.set_supports_swing_mode_off(true);   //auto?
    traits.set_supports_swing_mode_both(true);
    traits.set_supports_swing_mode_vertical(true);
    traits.set_supports_swing_mode_horizontal(true);

    return traits;
  }
  void control(const ClimateCall &call) override {
    if (call.get_mode().has_value()) {
      // User requested mode change
      ClimateMode mode = *call.get_mode();
      // Send mode to hardware
      switch(mode) {
        case CLIMATE_MODE_HEAT:
          ac.on();
          ac.setMode(kPanasonicAcHeat);
          break;
        case CLIMATE_MODE_COOL:
          ac.on();
          ac.setMode(kPanasonicAcCool);
          break;
        case CLIMATE_MODE_AUTO:
          ac.on();
          ac.setMode(kPanasonicAcAuto);
          break;
        case CLIMATE_MODE_FAN_ONLY:  //fan only
          ac.on();
          //this->target_temperature = kPanasonicAcFanModeTemp;
          ac.setMode(kPanasonicAcFan);
          break;
        case CLIMATE_MODE_DRY:
          ac.on();
          ac.setMode(kPanasonicAcDry);
          break;
        case CLIMATE_MODE_OFF:
          ac.off();
          break;
      }
    // Publish updated state
    this->mode = mode;
    this->publish_state();
    }
    if (call.get_target_temperature().has_value()) {
      // User requested target temperature change
      float temp = *call.get_target_temperature();
      // Send target temp to climate
      ac.setTemp(temp);
      this->target_temperature = temp;
      this->publish_state();
    }
    /*if (call.get_away().has_value()) {
      bool awayMode = *call.get_away();
      // Send target temp to climate
      ac.setTemp(awayMode);
      this->away = awayMode;
      this->publish_state();
    }*/
    if (call.get_fan_mode().has_value()) {
      ClimateFanMode fanMode = *call.get_fan_mode();
      switch(fanMode) {
        case CLIMATE_FAN_AUTO:
          ac.setFan(kPanasonicAcFanAuto);
          break;
        case CLIMATE_FAN_LOW:
          ac.setFan(kPanasonicAcFanMin);
          break;
        case CLIMATE_FAN_MEDIUM:
          ac.setFan(kPanasonicAcFanMed);
          break;
        case CLIMATE_FAN_HIGH:
          ac.setFan(kPanasonicAcFanMax);
          break;
      }
      this->fan_mode = fanMode;
      this->publish_state();
    }
    if (call.get_swing_mode().has_value()) {
      ClimateSwingMode swingMode = *call.get_swing_mode();
      switch(swingMode) {
        case CLIMATE_SWING_OFF:
          ac.setSwingVertical(kPanasonicAcSwingVMiddle);
          ac.setSwingHorizontal(kPanasonicAcSwingHMiddle);
          break;
        case CLIMATE_SWING_BOTH:
          ac.setSwingVertical(kPanasonicAcSwingVAuto);
          ac.setSwingHorizontal(kPanasonicAcSwingHAuto);
          break;
        case CLIMATE_SWING_VERTICAL:
          ac.setSwingVertical(kPanasonicAcSwingVAuto);
          ac.setSwingHorizontal(kPanasonicAcSwingHMiddle);
          break;
        case CLIMATE_SWING_HORIZONTAL:
          ac.setSwingVertical(kPanasonicAcSwingVMiddle);
          ac.setSwingHorizontal(kPanasonicAcSwingHAuto);
          break;
      }
      this->swing_mode = swingMode;
      this->publish_state();
    }

    ac.send();
  }
};

@11protos11
Copy link

Can somebody make a file as panasonic_ir.h and irdaikin.h but for ir_Gree.h. I have an air conditioner with a remote control YAW1F.

@Fusseldieb
Copy link

Also would love to see this implemented!

Searching around the internet, I found this other repo in which they succeeded adding the Samsung AC:

https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Samsung.cpp
https://github.com/crankyoldgit/IRremoteESP8266/blob/master/src/ir_Samsung.h

Maybe that helps.

From the issues of that same repo, it seems that almost everything (or even everything) is working alright.

@saifulkoh
Copy link

@kvvoff add a thermostat component in the UI and you will be able to select the (target) temperature. The temperature showing in the component above is the "current" temperature, which isn't measured. (Since the IR only works one-way. You could add a temperature probe to your ESP that reports the room's temperature...)

Hi, I have setup a custom climate for my AC which dont support getting current temperature..i also have sensor component for temperature displayed on different card...is it possible to display this temperature in thermostat card?

@iglu-sebastian
Copy link

iglu-sebastian commented Jan 22, 2021

In case someone is interested in a Samsung climate integration file via IRremoteESP8266 this works fine with me. Please take note that on init/state restore it sends out those commands to the AC and the IR pin is hardcoded in there but it has sensor support for current temperature.

include/irsamsung.h

#include "esphome.h"
#include "IRremoteESP8266.h"
#include "IRsend.h"
#include "ir_Samsung.h"

const uint16_t kIrLed = 14; // LED PIN
IRSamsungAc ac(kIrLed);

class SamsungAC : public Component, public Climate {
  public:
    sensor::Sensor *sensor_{nullptr};

    void set_sensor(sensor::Sensor *sensor) { this->sensor_ = sensor; }

    void setup() override
    {
      if (this->sensor_) {
        this->sensor_->add_on_state_callback([this](float state) {
          this->current_temperature = state;
          this->publish_state();
        });
        this->current_temperature = this->sensor_->state;
      } else {
        this->current_temperature = NAN;
      }

      auto restore = this->restore_state_();
      if (restore.has_value()) {
        restore->apply(this);
      } else {
        this->mode = climate::CLIMATE_MODE_OFF;
        this->target_temperature = roundf(clamp(this->current_temperature, 16, 30));
        this->fan_mode = climate::CLIMATE_FAN_AUTO;
        this->swing_mode = climate::CLIMATE_SWING_OFF;
      }

      if (isnan(this->target_temperature)) {
        this->target_temperature = 25;
      }

      ac.begin();
      ac.on();
      if (this->mode == CLIMATE_MODE_OFF) {
        ac.off();
      } else if (this->mode == CLIMATE_MODE_COOL) {
        ac.setMode(kSamsungAcCool);
      } else if (this->mode == CLIMATE_MODE_DRY) {
        ac.setMode(kSamsungAcDry);
      } else if (this->mode == CLIMATE_MODE_FAN_ONLY) {
        ac.setMode(kSamsungAcFan);
      }
      ac.setTemp(this->target_temperature);
      if (this->fan_mode == CLIMATE_FAN_AUTO) {
        ac.setFan(kSamsungAcFanAuto);
      } else if (this->fan_mode == CLIMATE_FAN_LOW) {
        ac.setFan(kSamsungAcFanLow);
      } else if (this->fan_mode == CLIMATE_FAN_MEDIUM) {
        ac.setFan(kSamsungAcFanMed);
      } else if (this->fan_mode == CLIMATE_FAN_HIGH) {
        ac.setFan(kSamsungAcFanHigh);
      }
      if (this->swing_mode == CLIMATE_SWING_OFF) {
        ac.setSwing(false);
      } else if (this->swing_mode == CLIMATE_SWING_VERTICAL) {
        ac.setSwing(true);
      }
      if (this->mode == CLIMATE_MODE_OFF) {
        ac.sendOff();
      } else {
        ac.send();
      }

      ESP_LOGD("DEBUG", "Samsung A/C remote is in the following state:");
      ESP_LOGD("DEBUG", "  %s\n", ac.toString().c_str());
    }

    climate::ClimateTraits traits() {
      auto traits = climate::ClimateTraits();
      traits.set_supports_cool_mode(true);
      traits.set_supports_current_temperature(this->sensor_ != nullptr);
      traits.set_supports_dry_mode(true);
      traits.set_supports_fan_mode_auto(true);
      traits.set_supports_fan_mode_high(true);
      traits.set_supports_fan_mode_low(true);
      traits.set_supports_fan_mode_medium(true);
      traits.set_supports_fan_only_mode(true);
      traits.set_supports_swing_mode_off(true);
      traits.set_supports_swing_mode_vertical(true);
      traits.set_supports_two_point_target_temperature(false);
      traits.set_visual_max_temperature(30);
      traits.set_visual_min_temperature(16);
      traits.set_visual_temperature_step(1);

      return traits;
    }

  void control(const ClimateCall &call) override {
    if (call.get_mode().has_value()) {
      ClimateMode mode = *call.get_mode();
      if (mode == CLIMATE_MODE_OFF) {
        ac.off();
      } else if (mode == CLIMATE_MODE_COOL) {
        ac.on();
        ac.setMode(kSamsungAcCool);
      } else if (mode == CLIMATE_MODE_DRY) {
        ac.on();
        ac.setMode(kSamsungAcDry);
      } else if (mode == CLIMATE_MODE_FAN_ONLY) {
        ac.on();
        ac.setMode(kSamsungAcFan);
      }
      this->mode = mode;
    }

    if (call.get_target_temperature().has_value()) {
      float temp = *call.get_target_temperature();
      ac.setTemp(temp);
      this->target_temperature = temp;
    }

    if (call.get_fan_mode().has_value()) {
      ClimateFanMode fan_mode = *call.get_fan_mode();
      if (fan_mode == CLIMATE_FAN_AUTO) {
        ac.setFan(kSamsungAcFanAuto);
      } else if (fan_mode == CLIMATE_FAN_LOW) {
        ac.setFan(kSamsungAcFanLow);
      } else if (fan_mode == CLIMATE_FAN_MEDIUM) {
        ac.setFan(kSamsungAcFanMed);
      } else if (fan_mode == CLIMATE_FAN_HIGH) {
        ac.setFan(kSamsungAcFanHigh);
      }
      this->fan_mode = fan_mode;
    }

    if (call.get_swing_mode().has_value()) {
      ClimateSwingMode swing_mode = *call.get_swing_mode();
      if (swing_mode == CLIMATE_SWING_OFF) {
        ac.setSwing(false);
      } else if (swing_mode == CLIMATE_SWING_VERTICAL) {
        ac.setSwing(true);
      }
      this->swing_mode = swing_mode;
    }

    if (this->mode == CLIMATE_MODE_OFF) {
      ac.sendOff();
    } else {
      ac.send();
    }

    this->publish_state();

    ESP_LOGD("DEBUG", "Samsung A/C remote is in the following state:");
    ESP_LOGD("DEBUG", "  %s\n", ac.toString().c_str());
  }
};

includes:

  includes: 
    - include/irsamsung.h
  libraries:
    - IRremoteESP8266

climate:

- platform: custom
  lambda: |-
    auto samsungac = new SamsungAC();
    samsungac->set_sensor(id(YOUR_SENSOR_HERE));
    App.register_component(samsungac);
    return {samsungac};
  climates:
    - name: "AC"

@ICuddlesI
Copy link

This works perfectly. Thank you

@Fusseldieb
Copy link

@iglu-sebastian It didn't work here:

INFO Reading configuration /config/esphome/valentino_ar.yaml...
INFO Generating C++ source...
INFO Compiling app...
INFO Running:  platformio run -d /config/esphome/valentino_ar
Processing valentino_ar (board: nodemcuv2; framework: arduino; platform: espressif8266@2.6.2)
--------------------------------------------------------------------------------
HARDWARE: ESP8266 80MHz, 80KB RAM, 4MB Flash
PACKAGES: 
 - framework-arduinoespressif8266 3.20704.0 (2.7.4) 
 - tool-esptool 1.413.0 (4.13) 
 - tool-esptoolpy 1.20800.0 (2.8.0) 
 - toolchain-xtensa 2.40802.200502 (4.8.2)
Library Manager: Installing Update
Library Manager: Already installed, built-in library
Dependency Graph
|-- <ESPAsyncTCP-esphome> 1.2.3
|   |-- <ESP8266WiFi> 1.0
|-- <ESP8266WiFi> 1.0
|-- <ESP8266mDNS> 1.2
|   |-- <ESP8266WiFi> 1.0
|-- <IRremoteESP8266> 2.7.14
Compiling /data/valentino_ar/.pioenvs/valentino_ar/src/main.cpp.o
Compiling /data/valentino_ar/.pioenvs/valentino_ar/lib344/ESPAsyncTCP-esphome/SyncClient.cpp.o
Compiling /data/valentino_ar/.pioenvs/valentino_ar/lib344/ESPAsyncTCP-esphome/tcp_axtls.c.o
Compiling /data/valentino_ar/.pioenvs/valentino_ar/lib0d3/ESP8266mDNS/ESP8266mDNS.cpp.o
Compiling /data/valentino_ar/.pioenvs/valentino_ar/lib0d3/ESP8266mDNS/ESP8266mDNS_Legacy.cpp.o
In file included from src/main.cpp:16:0:
src/irsamsung.h:11:5: error: 'sensor' does not name a type
     sensor::Sensor *sensor_{nullptr};
     ^
src/irsamsung.h:13:21: error: 'sensor' has not been declared
     void set_sensor(sensor::Sensor *sensor) { this->sensor_ = sensor; }
                     ^
src/irsamsung.h:13:36: error: expected ',' or '...' before '*' token
     void set_sensor(sensor::Sensor *sensor) { this->sensor_ = sensor; }
                                    ^
src/irsamsung.h: In member function 'void SamsungAC::set_sensor(int)':
src/irsamsung.h:13:53: error: 'class SamsungAC' has no member named 'sensor_'
     void set_sensor(sensor::Sensor *sensor) { this->sensor_ = sensor; }
                                                     ^
src/irsamsung.h:13:63: error: 'sensor' was not declared in this scope
     void set_sensor(sensor::Sensor *sensor) { this->sensor_ = sensor; }
                                                               ^
src/irsamsung.h: In member function 'virtual void SamsungAC::setup()':
src/irsamsung.h:17:17: error: 'class SamsungAC' has no member named 'sensor_'
       if (this->sensor_) {
                 ^
src/irsamsung.h:18:15: error: 'class SamsungAC' has no member named 'sensor_'
         this->sensor_->add_on_state_callback([this](float state) {
               ^
src/irsamsung.h:22:43: error: 'class SamsungAC' has no member named 'sensor_'
         this->current_temperature = this->sensor_->state;
                                           ^
src/irsamsung.h: In member function 'virtual esphome::climate::ClimateTraits SamsungAC::traits()':
src/irsamsung.h:80:53: error: 'class SamsungAC' has no member named 'sensor_'
       traits.set_supports_current_temperature(this->sensor_ != nullptr);
                                                     ^
src/main.cpp: In lambda function:
src/main.cpp:162:36: error: no matching function for call to 'SamsungAC::set_sensor(std::nullptr_t)'
       samsungac->set_sensor(nullptr);
                                    ^
src/main.cpp:162:36: note: candidate is:
In file included from src/main.cpp:16:0:
src/irsamsung.h:13:10: note: void SamsungAC::set_sensor(int)
     void set_sensor(sensor::Sensor *sensor) { this->sensor_ = sensor; }
          ^
src/irsamsung.h:13:10: note:   no known conversion for argument 1 from 'std::nullptr_t' to 'int'
Compiling /data/valentino_ar/.pioenvs/valentino_ar/lib0d3/ESP8266mDNS/LEAmDNS.cpp.o
Archiving /data/valentino_ar/.pioenvs/valentino_ar/lib344/libESPAsyncTCP-esphome.a
Compiling /data/valentino_ar/.pioenvs/valentino_ar/lib0d3/ESP8266mDNS/LEAmDNS_Control.cpp.o
*** [/data/valentino_ar/.pioenvs/valentino_ar/src/main.cpp.o] Error 1
========================== [FAILED] Took 6.62 seconds ==========================

Am I doing something wrong?

Thanks in advance

@ICuddlesI
Copy link

sensor isn't just supported, it's required 😄
so just add one, even if there is no physical sensor connected it will still work, you just wont get actual temp in thermostat card.

esphome:
  name: samsung_ac_remote_control
  platform: ESP8266
  board: d1_mini
  includes: 
    - include/irsamsung.h
  libraries:
    - IRremoteESP8266

wifi:
  ssid: "ssid"
  password: "password"
  
  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Samsung Ac Remote Control"
    password: "password"

captive_portal:

# Enable logging
logger:

# Enable Home Assistant API
api:
  password: "password"

ota:
  password: "password"
  
status_led:
  pin:
    number: 2
    inverted: False

dallas:
  - pin: 12
    update_interval: 10s
sensor:
  - platform: dallas
    address: 0x22XXXXXXXXXXF28
    name: "My Room Temperature"
    accuracy_decimals: 1
    id: my_room_temp

climate:
- platform: custom
  lambda: |-
    auto samsungac = new SamsungAC();
    samsungac->set_sensor(id(my_room_temp));
    App.register_component(samsungac);
    return {samsungac};
  climates:
    - name: "My Room AC"

I used a dallas (ds18b20) sensor but you might want to use dht instead incase it hassles you about the address.

sensor:
  - platform: dht
    pin: 12
    temperature:
      name: "Living Room Temperature"
      id: my_room_temp
    humidity:
      name: "Living Room Humidity"
    update_interval: 60s

I also added some lines for auto and heat mode since my ac has such modes

#include "esphome.h"
#include "IRremoteESP8266.h"
#include "IRsend.h"
#include "ir_Samsung.h"

const uint16_t kIrLed = 14; // LED PIN
IRSamsungAc ac(kIrLed);

class SamsungAC : public Component, public Climate {
  public:
    sensor::Sensor *sensor_{nullptr};

    void set_sensor(sensor::Sensor *sensor) { this->sensor_ = sensor; }

    void setup() override
    {
      if (this->sensor_) {
        this->sensor_->add_on_state_callback([this](float state) {
          this->current_temperature = state;
          this->publish_state();
        });
        this->current_temperature = this->sensor_->state;
      } else {
        this->current_temperature = NAN;
      }

      auto restore = this->restore_state_();
      if (restore.has_value()) {
        restore->apply(this);
      } else {
        this->mode = climate::CLIMATE_MODE_OFF;
        this->target_temperature = roundf(clamp(this->current_temperature, 16, 30));
        this->fan_mode = climate::CLIMATE_FAN_AUTO;
        this->swing_mode = climate::CLIMATE_SWING_OFF;
      }

      if (isnan(this->target_temperature)) {
        this->target_temperature = 25;
      }

      ac.begin();
      ac.on();
      if (this->mode == CLIMATE_MODE_OFF) {
        ac.off();
      } else if (this->mode == CLIMATE_MODE_COOL) {
        ac.setMode(kSamsungAcCool);
      } else if (this->mode == CLIMATE_MODE_DRY) {
        ac.setMode(kSamsungAcDry);
      } else if (this->mode == CLIMATE_MODE_FAN_ONLY) {
        ac.setMode(kSamsungAcFan);
      } else if (this->mode == CLIMATE_MODE_HEAT) {
        ac.setMode(kSamsungAcFan);
      } else if (this->mode == CLIMATE_MODE_AUTO) {
        ac.setMode(kSamsungAcFan);
      } 
      ac.setTemp(this->target_temperature);
      if (this->fan_mode == CLIMATE_FAN_AUTO) {
        ac.setFan(kSamsungAcFanAuto);
      } else if (this->fan_mode == CLIMATE_FAN_LOW) {
        ac.setFan(kSamsungAcFanLow);
      } else if (this->fan_mode == CLIMATE_FAN_MEDIUM) {
        ac.setFan(kSamsungAcFanMed);
      } else if (this->fan_mode == CLIMATE_FAN_HIGH) {
        ac.setFan(kSamsungAcFanHigh);
      }
      if (this->swing_mode == CLIMATE_SWING_OFF) {
        ac.setSwing(false);
      } else if (this->swing_mode == CLIMATE_SWING_VERTICAL) {
        ac.setSwing(true);
      }
      if (this->mode == CLIMATE_MODE_OFF) {
        ac.sendOff();
      } else {
        ac.send();
      }

      ESP_LOGD("DEBUG", "Samsung A/C remote is in the following state:");
      ESP_LOGD("DEBUG", "  %s\n", ac.toString().c_str());
    }

    climate::ClimateTraits traits() {
      auto traits = climate::ClimateTraits();
      traits.set_supports_cool_mode(true);
      traits.set_supports_current_temperature(this->sensor_ != nullptr);
      traits.set_supports_dry_mode(true);
      traits.set_supports_auto_mode(true);
      traits.set_supports_heat_mode(true);
      traits.set_supports_fan_mode_auto(true);
      traits.set_supports_fan_mode_high(true);
      traits.set_supports_fan_mode_low(true);
      traits.set_supports_fan_mode_medium(true);
      traits.set_supports_fan_only_mode(true);
      traits.set_supports_swing_mode_off(true);
      traits.set_supports_swing_mode_vertical(true);
      traits.set_supports_two_point_target_temperature(false);
      traits.set_visual_max_temperature(30);
      traits.set_visual_min_temperature(16);
      traits.set_visual_temperature_step(1);

      return traits;
    }

  void control(const ClimateCall &call) override {
    if (call.get_mode().has_value()) {
      ClimateMode mode = *call.get_mode();
      if (mode == CLIMATE_MODE_OFF) {
        ac.off();
      } else if (mode == CLIMATE_MODE_COOL) {
        ac.on();
        ac.setMode(kSamsungAcCool);
      } else if (mode == CLIMATE_MODE_DRY) {
        ac.on();
        ac.setMode(kSamsungAcDry);
      } else if (mode == CLIMATE_MODE_FAN_ONLY) {
        ac.on();
        ac.setMode(kSamsungAcFan);
      } else if (mode == CLIMATE_MODE_HEAT) {
        ac.on();
        ac.setMode(kSamsungAcFan);
      } else if (mode == CLIMATE_MODE_AUTO) {
        ac.on();
        ac.setMode(kSamsungAcFan);
      }
      this->mode = mode;
    }

    if (call.get_target_temperature().has_value()) {
      float temp = *call.get_target_temperature();
      ac.setTemp(temp);
      this->target_temperature = temp;
    }

    if (call.get_fan_mode().has_value()) {
      ClimateFanMode fan_mode = *call.get_fan_mode();
      if (fan_mode == CLIMATE_FAN_AUTO) {
        ac.setFan(kSamsungAcFanAuto);
      } else if (fan_mode == CLIMATE_FAN_LOW) {
        ac.setFan(kSamsungAcFanLow);
      } else if (fan_mode == CLIMATE_FAN_MEDIUM) {
        ac.setFan(kSamsungAcFanMed);
      } else if (fan_mode == CLIMATE_FAN_HIGH) {
        ac.setFan(kSamsungAcFanHigh);
      }
      this->fan_mode = fan_mode;
    }

    if (call.get_swing_mode().has_value()) {
      ClimateSwingMode swing_mode = *call.get_swing_mode();
      if (swing_mode == CLIMATE_SWING_OFF) {
        ac.setSwing(false);
      } else if (swing_mode == CLIMATE_SWING_VERTICAL) {
        ac.setSwing(true);
      }
      this->swing_mode = swing_mode;
    }

    if (this->mode == CLIMATE_MODE_OFF) {
      ac.sendOff();
    } else {
      ac.send();
    }

    this->publish_state();

    ESP_LOGD("DEBUG", "Samsung A/C remote is in the following state:");
    ESP_LOGD("DEBUG", "  %s\n", ac.toString().c_str());
  }
};

@Fusseldieb
Copy link

Fusseldieb commented Feb 3, 2021

@ICuddlesI Thanks for solving my issue and also for providing the additional code, since my A/C has heat too :)

Worked perfectly! Awesomeee!

Finally I have full HVAC control!!!

Just one more question: Does the library support Fast cool and quiet mode?

EDIT: For those interested, I just made a variant of the irsamsung.h file which accepts an INPUT PIN from the HVAC "On" LED in order to sync the actual state in HA. That means even if someone turns on your HVAC with its intended remote, it should still reflect the change in Home Assistant just fine :)
File here: https://gist.github.com/Fusseldieb/a141581eaccff2b1ff9917c43e750f6a

@iglu-sebastian
Copy link

Thanks @ICuddlesI @Fusseldieb for extending this current approach. I'm aware that this is "plugging holes" in regards to ESPHome, since this looks pretty much feature complete how do we move this into esphome core?

@mletenay
Copy link

mletenay commented Feb 22, 2021

@ICuddlesI @Fusseldieb there's a copy/paste mistake in your code at lines 61 and 63, kSamsungAcFan should be kSamsungAcHeat res. kSamsungAcFanAuto.
Otherwise a great job, works like a charm on my AC052RNNDKGEU !

@Tozapid
Copy link

Tozapid commented Feb 25, 2021

@ICuddlesI @Fusseldieb there's a copy/paste mistake in your code at lines 61 and 63, kSamsungAcFan should be kSamsungAcHeat res. kSamsungAcFanAuto.
Otherwise a great job, works like a charm on my AC052RNNDKGEU !

not just 61, 63, Also 119 and 122

#include "esphome.h"
#include "IRremoteESP8266.h"
#include "IRsend.h"
#include "ir_Samsung.h"

const uint16_t kIrLed = 14; // LED PIN
IRSamsungAc ac(kIrLed);

class SamsungAC : public Component, public Climate {
  public:
    sensor::Sensor *sensor_{nullptr};

    void set_sensor(sensor::Sensor *sensor) { this->sensor_ = sensor; }

    void setup() override
    {
      if (this->sensor_) {
        this->sensor_->add_on_state_callback([this](float state) {
          this->current_temperature = state;
          this->publish_state();
        });
        this->current_temperature = this->sensor_->state;
      } else {
        this->current_temperature = NAN;
      }

      auto restore = this->restore_state_();
      if (restore.has_value()) {
        restore->apply(this);
      } else {
        this->mode = climate::CLIMATE_MODE_OFF;
        this->target_temperature = roundf(clamp(this->current_temperature, 16, 30));
        this->fan_mode = climate::CLIMATE_FAN_AUTO;
        this->swing_mode = climate::CLIMATE_SWING_OFF;
      }

      if (isnan(this->target_temperature)) {
        this->target_temperature = 25;
      }

      ac.begin();
      ac.on();
      if (this->mode == CLIMATE_MODE_OFF) {
        ac.off();
      } else if (this->mode == CLIMATE_MODE_COOL) {
        ac.setMode(kSamsungAcCool);
      } else if (this->mode == CLIMATE_MODE_DRY) {
        ac.setMode(kSamsungAcDry);
      } else if (this->mode == CLIMATE_MODE_FAN_ONLY) {
        ac.setMode(kSamsungAcFan);
      } else if (this->mode == CLIMATE_MODE_HEAT) {
        ac.setMode(kSamsungAcHeat);
      } else if (this->mode == CLIMATE_MODE_AUTO) {
        ac.setMode(kSamsungAcFanAuto);
      } 
      ac.setTemp(this->target_temperature);
      if (this->fan_mode == CLIMATE_FAN_AUTO) {
        ac.setFan(kSamsungAcFanAuto);
      } else if (this->fan_mode == CLIMATE_FAN_LOW) {
        ac.setFan(kSamsungAcFanLow);
      } else if (this->fan_mode == CLIMATE_FAN_MEDIUM) {
        ac.setFan(kSamsungAcFanMed);
      } else if (this->fan_mode == CLIMATE_FAN_HIGH) {
        ac.setFan(kSamsungAcFanHigh);
      }
      if (this->swing_mode == CLIMATE_SWING_OFF) {
        ac.setSwing(false);
      } else if (this->swing_mode == CLIMATE_SWING_VERTICAL) {
        ac.setSwing(true);
      }
      if (this->mode == CLIMATE_MODE_OFF) {
        ac.sendOff();
      } else {
        ac.send();
      }

      ESP_LOGD("DEBUG", "Samsung A/C remote is in the following state:");
      ESP_LOGD("DEBUG", "  %s\n", ac.toString().c_str());
    }

    climate::ClimateTraits traits() {
      auto traits = climate::ClimateTraits();
      traits.set_supports_cool_mode(true);
      traits.set_supports_current_temperature(this->sensor_ != nullptr);
      traits.set_supports_dry_mode(true);
      traits.set_supports_auto_mode(true);
      traits.set_supports_heat_mode(true);
      traits.set_supports_fan_mode_auto(true);
      traits.set_supports_fan_mode_high(true);
      traits.set_supports_fan_mode_low(true);
      traits.set_supports_fan_mode_medium(true);
      traits.set_supports_fan_only_mode(true);
      traits.set_supports_swing_mode_off(true);
      traits.set_supports_swing_mode_vertical(true);
      traits.set_supports_two_point_target_temperature(false);
      traits.set_visual_max_temperature(30);
      traits.set_visual_min_temperature(16);
      traits.set_visual_temperature_step(1);

      return traits;
    }

  void control(const ClimateCall &call) override {
    if (call.get_mode().has_value()) {
      ClimateMode mode = *call.get_mode();
      if (mode == CLIMATE_MODE_OFF) {
        ac.off();
      } else if (mode == CLIMATE_MODE_COOL) {
        ac.on();
        ac.setMode(kSamsungAcCool);
      } else if (mode == CLIMATE_MODE_DRY) {
        ac.on();
        ac.setMode(kSamsungAcDry);
      } else if (mode == CLIMATE_MODE_FAN_ONLY) {
        ac.on();
        ac.setMode(kSamsungAcFan);
      } else if (mode == CLIMATE_MODE_HEAT) {
        ac.on();
        ac.setMode(kSamsungAcHeat);
      } else if (mode == CLIMATE_MODE_AUTO) {
        ac.on();
        ac.setMode(kSamsungAcFanAuto);
      }
      this->mode = mode;
    }

    if (call.get_target_temperature().has_value()) {
      float temp = *call.get_target_temperature();
      ac.setTemp(temp);
      this->target_temperature = temp;
    }

    if (call.get_fan_mode().has_value()) {
      ClimateFanMode fan_mode = *call.get_fan_mode();
      if (fan_mode == CLIMATE_FAN_AUTO) {
        ac.setFan(kSamsungAcFanAuto);
      } else if (fan_mode == CLIMATE_FAN_LOW) {
        ac.setFan(kSamsungAcFanLow);
      } else if (fan_mode == CLIMATE_FAN_MEDIUM) {
        ac.setFan(kSamsungAcFanMed);
      } else if (fan_mode == CLIMATE_FAN_HIGH) {
        ac.setFan(kSamsungAcFanHigh);
      }
      this->fan_mode = fan_mode;
    }

    if (call.get_swing_mode().has_value()) {
      ClimateSwingMode swing_mode = *call.get_swing_mode();
      if (swing_mode == CLIMATE_SWING_OFF) {
        ac.setSwing(false);
      } else if (swing_mode == CLIMATE_SWING_VERTICAL) {
        ac.setSwing(true);
      }
      this->swing_mode = swing_mode;
    }

    if (this->mode == CLIMATE_MODE_OFF) {
      ac.sendOff();
    } else {
      ac.send();
    }

    this->publish_state();

    ESP_LOGD("DEBUG", "Samsung A/C remote is in the following state:");
    ESP_LOGD("DEBUG", "  %s\n", ac.toString().c_str());
  }
};

@Fusseldieb
Copy link

Fusseldieb commented Apr 6, 2021

Hi, it's me again ahaha

This works wonderfully, again, thanks for the hard work.

However, I put a DS18B20 sensor in my HVAC today to display the current temperature, as it's supported, so I thought "why not".

It also works, but it rounds it to an integer in Lovelace (eliminates the decimal place). Can I display it with one decimal place?

Thanks in advance :)

EDIT:

I just did something, but I don't know if this will work or mess something up. I put traits.set_visual_temperature_step(0.1); and now it displays it with one decimal, however, the arrows are now also setting 0.1 steps (obviously). Since the HVAC doesn't have this precision/option, does it just get rounded? (It should, as seen in this->target_temperature = roundf(clamp(this->current_temperature, 16, 30));)

Still would be better to have 1.0 steps and 0.1 sensor steps

@mletenay
Copy link

There seem to be some breaking changes done in esphome 1.19, so if you have upgraded and wondering why AC stopped working, you have to at least replace set_supports_auto_mode with set_supports_heat_cool_mode and CLIMATE_MODE_AUTO with CLIMATE_MODE_HEAT_COOL, after that it works again.

Would probably be wise to replace these deprecated calls as well:

src/irsamsung.h: In member function 'virtual esphome::climate::ClimateTraits SamsungAC::traits()':
src/irsamsung.h:83:41: warning: 'void esphome::climate::ClimateTraits::set_supports_cool_mode(bool)' is deprecated (declared at src/esphome/components/climate/climate_traits.h:56): This method is deprecated, use set_supported_modes() instead [-Wdeprecated-declarations]
       traits.set_supports_cool_mode(true);
                                         ^
src/irsamsung.h:85:40: warning: 'void esphome::climate::ClimateTraits::set_supports_dry_mode(bool)' is deprecated (declared at src/esphome/components/climate/climate_traits.h:66): This method is deprecated, use set_supported_modes() instead [-Wdeprecated-declarations]
       traits.set_supports_dry_mode(true);
                                        ^
src/irsamsung.h:86:46: warning: 'void esphome::climate::ClimateTraits::set_supports_heat_cool_mode(bool)' is deprecated (declared at src/esphome/components/climate/climate_traits.h:60): This method is deprecated, use set_supported_modes() instead [-Wdeprecated-declarations]
       traits.set_supports_heat_cool_mode(true);
                                              ^
src/irsamsung.h:87:41: warning: 'void esphome::climate::ClimateTraits::set_supports_heat_mode(bool)' is deprecated (declared at src/esphome/components/climate/climate_traits.h:58): This method is deprecated, use set_supported_modes() instead [-Wdeprecated-declarations]
       traits.set_supports_heat_mode(true);
                                         ^
src/irsamsung.h:88:45: warning: 'void esphome::climate::ClimateTraits::set_supports_fan_mode_auto(bool)' is deprecated (declared at src/esphome/components/climate/climate_traits.h:80): This method is deprecated, use set_supported_fan_modes() instead [-Wdeprecated-declarations]
       traits.set_supports_fan_mode_auto(true);
                                             ^
src/irsamsung.h:89:45: warning: 'void esphome::climate::ClimateTraits::set_supports_fan_mode_high(bool)' is deprecated (declared at src/esphome/components/climate/climate_traits.h:86): This method is deprecated, use set_supported_fan_modes() instead [-Wdeprecated-declarations]
       traits.set_supports_fan_mode_high(true);
                                             ^
src/irsamsung.h:90:44: warning: 'void esphome::climate::ClimateTraits::set_supports_fan_mode_low(bool)' is deprecated (declared at src/esphome/components/climate/climate_traits.h:82): This method is deprecated, use set_supported_fan_modes() instead [-Wdeprecated-declarations]
       traits.set_supports_fan_mode_low(true);
                                            ^
src/irsamsung.h:91:47: warning: 'void esphome::climate::ClimateTraits::set_supports_fan_mode_medium(bool)' is deprecated (declared at src/esphome/components/climate/climate_traits.h:84): This method is deprecated, use set_supported_fan_modes() instead [-Wdeprecated-declarations]
       traits.set_supports_fan_mode_medium(true);
                                               ^
src/irsamsung.h:92:45: warning: 'void esphome::climate::ClimateTraits::set_supports_fan_only_mode(bool)' is deprecated (declared at src/esphome/components/climate/climate_traits.h:62): This method is deprecated, use set_supported_modes() instead [-Wdeprecated-declarations]
       traits.set_supports_fan_only_mode(true);
                                             ^
src/irsamsung.h:93:46: warning: 'void esphome::climate::ClimateTraits::set_supports_swing_mode_off(bool)' is deprecated (declared at src/esphome/components/climate/climate_traits.h:131): This method is deprecated, use set_supported_fan_modes() instead [-Wdeprecated-declarations]
       traits.set_supports_swing_mode_off(true);
                                              ^
src/irsamsung.h:94:51: warning: 'void esphome::climate::ClimateTraits::set_supports_swing_mode_vertical(bool)' is deprecated (declared at src/esphome/components/climate/climate_traits.h:135): This method is deprecated, use set_supported_fan_modes() instead [-Wdeprecated-declarations]
       traits.set_supports_swing_mode_vertical(true);

@rafaelnfernandes
Copy link

There seem to be some breaking changes done in esphome 1.19, so if you have upgraded and wondering why AC stopped working, you have to at least replace set_supports_auto_mode with set_supports_heat_cool_mode and CLIMATE_MODE_AUTO with CLIMATE_MODE_HEAT_COOL, after that it works again.

Would probably be wise to replace these deprecated calls as well:

src/irsamsung.h: In member function 'virtual esphome::climate::ClimateTraits SamsungAC::traits()':
src/irsamsung.h:83:41: warning: 'void esphome::climate::ClimateTraits::set_supports_cool_mode(bool)' is deprecated (declared at src/esphome/components/climate/climate_traits.h:56): This method is deprecated, use set_supported_modes() instead [-Wdeprecated-declarations]
       traits.set_supports_cool_mode(true);
                                         ^
src/irsamsung.h:85:40: warning: 'void esphome::climate::ClimateTraits::set_supports_dry_mode(bool)' is deprecated (declared at src/esphome/components/climate/climate_traits.h:66): This method is deprecated, use set_supported_modes() instead [-Wdeprecated-declarations]
       traits.set_supports_dry_mode(true);
                                        ^
src/irsamsung.h:86:46: warning: 'void esphome::climate::ClimateTraits::set_supports_heat_cool_mode(bool)' is deprecated (declared at src/esphome/components/climate/climate_traits.h:60): This method is deprecated, use set_supported_modes() instead [-Wdeprecated-declarations]
       traits.set_supports_heat_cool_mode(true);
                                              ^
src/irsamsung.h:87:41: warning: 'void esphome::climate::ClimateTraits::set_supports_heat_mode(bool)' is deprecated (declared at src/esphome/components/climate/climate_traits.h:58): This method is deprecated, use set_supported_modes() instead [-Wdeprecated-declarations]
       traits.set_supports_heat_mode(true);
                                         ^
src/irsamsung.h:88:45: warning: 'void esphome::climate::ClimateTraits::set_supports_fan_mode_auto(bool)' is deprecated (declared at src/esphome/components/climate/climate_traits.h:80): This method is deprecated, use set_supported_fan_modes() instead [-Wdeprecated-declarations]
       traits.set_supports_fan_mode_auto(true);
                                             ^
src/irsamsung.h:89:45: warning: 'void esphome::climate::ClimateTraits::set_supports_fan_mode_high(bool)' is deprecated (declared at src/esphome/components/climate/climate_traits.h:86): This method is deprecated, use set_supported_fan_modes() instead [-Wdeprecated-declarations]
       traits.set_supports_fan_mode_high(true);
                                             ^
src/irsamsung.h:90:44: warning: 'void esphome::climate::ClimateTraits::set_supports_fan_mode_low(bool)' is deprecated (declared at src/esphome/components/climate/climate_traits.h:82): This method is deprecated, use set_supported_fan_modes() instead [-Wdeprecated-declarations]
       traits.set_supports_fan_mode_low(true);
                                            ^
src/irsamsung.h:91:47: warning: 'void esphome::climate::ClimateTraits::set_supports_fan_mode_medium(bool)' is deprecated (declared at src/esphome/components/climate/climate_traits.h:84): This method is deprecated, use set_supported_fan_modes() instead [-Wdeprecated-declarations]
       traits.set_supports_fan_mode_medium(true);
                                               ^
src/irsamsung.h:92:45: warning: 'void esphome::climate::ClimateTraits::set_supports_fan_only_mode(bool)' is deprecated (declared at src/esphome/components/climate/climate_traits.h:62): This method is deprecated, use set_supported_modes() instead [-Wdeprecated-declarations]
       traits.set_supports_fan_only_mode(true);
                                             ^
src/irsamsung.h:93:46: warning: 'void esphome::climate::ClimateTraits::set_supports_swing_mode_off(bool)' is deprecated (declared at src/esphome/components/climate/climate_traits.h:131): This method is deprecated, use set_supported_fan_modes() instead [-Wdeprecated-declarations]
       traits.set_supports_swing_mode_off(true);
                                              ^
src/irsamsung.h:94:51: warning: 'void esphome::climate::ClimateTraits::set_supports_swing_mode_vertical(bool)' is deprecated (declared at src/esphome/components/climate/climate_traits.h:135): This method is deprecated, use set_supported_fan_modes() instead [-Wdeprecated-declarations]
       traits.set_supports_swing_mode_vertical(true);

@mletenay , I'm very new to this, but I followed @ICuddlesI posted and got it "working" (unfortunately I'm far from the AC unit I want to control, so I can not actually test for a couple of weeks), it complies, and I'm able to load it into the ESP32. (using the cellphone camera I see that the IR LED is blinking when I send a command).

BUT I'm getting a lot of warning msgs during the compiling. would you guys be kind enough to correct/repost @ICuddlesI code with @mletenay corrections (for deprecated / copy and past mistakes).

Thank you very much!

@Tozapid
Copy link

Tozapid commented Jul 19, 2021

@rafaelnfernandes Now my irsamsung.h looks like this

#include "IRremoteESP8266.h"
#include "IRsend.h"
#include "ir_Samsung.h"

const uint16_t kIrLed = 14; // LED PIN
IRSamsungAc ac(kIrLed);

class SamsungAC : public Component, public Climate {
  public:
    sensor::Sensor *sensor_{nullptr};

    void set_sensor(sensor::Sensor *sensor) { this->sensor_ = sensor; }

    void setup() override
    {
      if (this->sensor_) {
        this->sensor_->add_on_state_callback([this](float state) {
          this->current_temperature = state;
          this->publish_state();
        });
        this->current_temperature = this->sensor_->state;
      } else {
        this->current_temperature = NAN;
      }

      auto restore = this->restore_state_();
      if (restore.has_value()) {
        restore->apply(this);
      } else {
        this->mode = climate::CLIMATE_MODE_OFF;
        this->target_temperature = roundf(clamp(this->current_temperature, 16, 30));
        this->fan_mode = climate::CLIMATE_FAN_AUTO;
        this->swing_mode = climate::CLIMATE_SWING_OFF;
      }

      if (isnan(this->target_temperature)) {
        this->target_temperature = 25;
      }

      ac.begin();
      ac.on();
      if (this->mode == CLIMATE_MODE_OFF) {
        ac.off();
      } else if (this->mode == CLIMATE_MODE_COOL) {
        ac.setMode(kSamsungAcCool);
      } else if (this->mode == CLIMATE_MODE_DRY) {
        ac.setMode(kSamsungAcDry);
      } else if (this->mode == CLIMATE_MODE_FAN_ONLY) {
        ac.setMode(kSamsungAcFan);
      } else if (this->mode == CLIMATE_MODE_HEAT) {
        ac.setMode(kSamsungAcHeat);
      } else if (this->mode == CLIMATE_MODE_HEAT_COOL) {
        ac.setMode(kSamsungAcFanAuto);
      } 
      ac.setTemp(this->target_temperature);
      if (this->fan_mode == CLIMATE_FAN_AUTO) {
        ac.setFan(kSamsungAcFanAuto);
      } else if (this->fan_mode == CLIMATE_FAN_LOW) {
        ac.setFan(kSamsungAcFanLow);
      } else if (this->fan_mode == CLIMATE_FAN_MEDIUM) {
        ac.setFan(kSamsungAcFanMed);
      } else if (this->fan_mode == CLIMATE_FAN_HIGH) {
        ac.setFan(kSamsungAcFanHigh);
      }
      if (this->swing_mode == CLIMATE_SWING_OFF) {
        ac.setSwing(false);
      } else if (this->swing_mode == CLIMATE_SWING_VERTICAL) {
        ac.setSwing(true);
      }
      if (this->mode == CLIMATE_MODE_OFF) {
        ac.sendOff();
      } else {
        ac.send();
      }

      ESP_LOGD("DEBUG", "Samsung A/C remote is in the following state:");
      ESP_LOGD("DEBUG", "  %s\n", ac.toString().c_str());
    }

    climate::ClimateTraits traits() {
      auto traits = climate::ClimateTraits();
      traits.set_supports_cool_mode(true);
      traits.set_supports_current_temperature(this->sensor_ != nullptr);
      traits.set_supports_dry_mode(true);
      traits.set_supports_heat_cool_mode(true);
      traits.set_supports_heat_mode(true);
      traits.set_supports_fan_mode_auto(true);
      traits.set_supports_fan_mode_high(true);
      traits.set_supports_fan_mode_low(true);
      traits.set_supports_fan_mode_medium(true);
      traits.set_supports_fan_only_mode(true);
      traits.set_supports_swing_mode_off(true);
      traits.set_supports_swing_mode_vertical(true);
      traits.set_supports_two_point_target_temperature(false);
      traits.set_visual_max_temperature(30);
      traits.set_visual_min_temperature(16);
      traits.set_visual_temperature_step(1);

      return traits;
    }

  void control(const ClimateCall &call) override {
    if (call.get_mode().has_value()) {
      ClimateMode mode = *call.get_mode();
      if (mode == CLIMATE_MODE_OFF) {
        ac.off();
      } else if (mode == CLIMATE_MODE_COOL) {
        ac.on();
        ac.setMode(kSamsungAcCool);
      } else if (mode == CLIMATE_MODE_DRY) {
        ac.on();
        ac.setMode(kSamsungAcDry);
      } else if (mode == CLIMATE_MODE_FAN_ONLY) {
        ac.on();
        ac.setMode(kSamsungAcFan);
      } else if (mode == CLIMATE_MODE_HEAT) {
        ac.on();
        ac.setMode(kSamsungAcHeat);
      } else if (mode == CLIMATE_MODE_HEAT_COOL) {
        ac.on();
        ac.setMode(kSamsungAcFanAuto);
      }
      this->mode = mode;
    }

    if (call.get_target_temperature().has_value()) {
      float temp = *call.get_target_temperature();
      ac.setTemp(temp);
      this->target_temperature = temp;
    }

    if (call.get_fan_mode().has_value()) {
      ClimateFanMode fan_mode = *call.get_fan_mode();
      if (fan_mode == CLIMATE_FAN_AUTO) {
        ac.setFan(kSamsungAcFanAuto);
      } else if (fan_mode == CLIMATE_FAN_LOW) {
        ac.setFan(kSamsungAcFanLow);
      } else if (fan_mode == CLIMATE_FAN_MEDIUM) {
        ac.setFan(kSamsungAcFanMed);
      } else if (fan_mode == CLIMATE_FAN_HIGH) {
        ac.setFan(kSamsungAcFanHigh);
      }
      this->fan_mode = fan_mode;
    }

    if (call.get_swing_mode().has_value()) {
      ClimateSwingMode swing_mode = *call.get_swing_mode();
      if (swing_mode == CLIMATE_SWING_OFF) {
        ac.setSwing(false);
      } else if (swing_mode == CLIMATE_SWING_VERTICAL) {
        ac.setSwing(true);
      }
      this->swing_mode = swing_mode;
    }

    if (this->mode == CLIMATE_MODE_OFF) {
      ac.sendOff();
    } else {
      ac.send();
    }

    this->publish_state();

    ESP_LOGD("DEBUG", "Samsung A/C remote is in the following state:");
    ESP_LOGD("DEBUG", "  %s\n", ac.toString().c_str());
  }
};

@rafaelnfernandes
Copy link

rafaelnfernandes commented Aug 1, 2021

Hi guys,

Run out of knowledge, will need a little more help.

After updating HA and Esphome to the latest versions I'm not able to compile the ESPhome yaml to control the Samsung AC anymore. Have been getting this errors:

Compiling /data/arsamsung/.pioenvs/arsamsung/src/main.cpp.o
In file included from src/main.cpp:19:0:
src/irsamsung.h: In member function 'virtual void SamsungAC::setup()':
src/irsamsung.h:33:82: error: no matching function for call to 'clamp(float&, int, int)'
this->target_temperature = roundf(clamp(this->current_temperature, 16, 30));
^
In file included from src/esphome/core/application.h:8:0,
from src/esphome/components/api/api_connection.h:4,
from src/esphome.h:2,
from src/main.cpp:3:
src/esphome/core/helpers.h:83:24: note: candidate: template T esphome::clamp(T, T, T)
template T clamp(T val, T min, T max);
^
src/esphome/core/helpers.h:83:24: note: template argument deduction/substitution failed:
In file included from src/main.cpp:19:0:
src/irsamsung.h:33:82: note: deduced conflicting types for parameter 'T' ('float' and 'int')
this->target_temperature = roundf(clamp(this->current_temperature, 16, 30));
^
src/irsamsung.h: In member function 'virtual esphome::climate::ClimateTraits SamsungAC::traits()':
src/irsamsung.h:80:41: warning: 'void esphome::climate::ClimateTraits::set_supports_cool_mode(bool)' is deprecated: This method is deprecated, use set_supported_modes() instead [-Wdeprecated-declarations]
traits.set_supports_cool_mode(true);
^
In file included from src/esphome/components/climate/climate.h:8:0,
from src/esphome/core/application.h:27,
from src/esphome/components/api/api_connection.h:4,
from src/esphome.h:2,
from src/main.cpp:3:
src/esphome/components/climate/climate_traits.h:56:8: note: declared here
void set_supports_cool_mode(bool supports_cool_mode) { set_mode_support_(CLIMATE_MODE_COOL, supports_cool_mode); }
^
In file included from src/main.cpp:19:0:
src/irsamsung.h:82:40: warning: 'void esphome::climate::ClimateTraits::set_supports_dry_mode(bool)' is deprecated: This method is deprecated, use set_supported_modes() instead [-Wdeprecated-declarations]
traits.set_supports_dry_mode(true);
^
In file included from src/esphome/components/climate/climate.h:8:0,
from src/esphome/core/application.h:27,
from src/esphome/components/api/api_connection.h:4,
from src/esphome.h:2,
from src/main.cpp:3:
src/esphome/components/climate/climate_traits.h:66:8: note: declared here
void set_supports_dry_mode(bool supports_dry_mode) { set_mode_support_(CLIMATE_MODE_DRY, supports_dry_mode); }
^
In file included from src/main.cpp:19:0:
src/irsamsung.h:83:45: warning: 'void esphome::climate::ClimateTraits::set_supports_fan_mode_auto(bool)' is deprecated: This method is deprecated, use set_supported_fan_modes() instead [-Wdeprecated-declarations]
traits.set_supports_fan_mode_auto(true);
^
In file included from src/esphome/components/climate/climate.h:8:0,
from src/esphome/core/application.h:27,
from src/esphome/components/api/api_connection.h:4,
from src/esphome.h:2,
from src/main.cpp:3:
src/esphome/components/climate/climate_traits.h:80:8: note: declared here
void set_supports_fan_mode_auto(bool supported) { set_fan_mode_support_(CLIMATE_FAN_AUTO, supported); }
^
In file included from src/main.cpp:19:0:
src/irsamsung.h:84:45: warning: 'void esphome::climate::ClimateTraits::set_supports_fan_mode_high(bool)' is deprecated: This method is deprecated, use set_supported_fan_modes() instead [-Wdeprecated-declarations]
traits.set_supports_fan_mode_high(true);
^
In file included from src/esphome/components/climate/climate.h:8:0,
from src/esphome/core/application.h:27,
from src/esphome/components/api/api_connection.h:4,
from src/esphome.h:2,
from src/main.cpp:3:
src/esphome/components/climate/climate_traits.h:86:8: note: declared here
void set_supports_fan_mode_high(bool supported) { set_fan_mode_support_(CLIMATE_FAN_HIGH, supported); }
^
In file included from src/main.cpp:19:0:
src/irsamsung.h:85:44: warning: 'void esphome::climate::ClimateTraits::set_supports_fan_mode_low(bool)' is deprecated: This method is deprecated, use set_supported_fan_modes() instead [-Wdeprecated-declarations]
traits.set_supports_fan_mode_low(true);
^
In file included from src/esphome/components/climate/climate.h:8:0,
from src/esphome/core/application.h:27,
from src/esphome/components/api/api_connection.h:4,
from src/esphome.h:2,
from src/main.cpp:3:
src/esphome/components/climate/climate_traits.h:82:8: note: declared here
void set_supports_fan_mode_low(bool supported) { set_fan_mode_support_(CLIMATE_FAN_LOW, supported); }
^
In file included from src/main.cpp:19:0:
src/irsamsung.h:86:47: warning: 'void esphome::climate::ClimateTraits::set_supports_fan_mode_medium(bool)' is deprecated: This method is deprecated, use set_supported_fan_modes() instead [-Wdeprecated-declarations]
traits.set_supports_fan_mode_medium(true);
^
In file included from src/esphome/components/climate/climate.h:8:0,
from src/esphome/core/application.h:27,
from src/esphome/components/api/api_connection.h:4,
from src/esphome.h:2,
from src/main.cpp:3:
src/esphome/components/climate/climate_traits.h:84:8: note: declared here
void set_supports_fan_mode_medium(bool supported) { set_fan_mode_support_(CLIMATE_FAN_MEDIUM, supported); }
^
In file included from src/main.cpp:19:0:
src/irsamsung.h:87:45: warning: 'void esphome::climate::ClimateTraits::set_supports_fan_only_mode(bool)' is deprecated: This method is deprecated, use set_supported_modes() instead [-Wdeprecated-declarations]
traits.set_supports_fan_only_mode(true);
^
In file included from src/esphome/components/climate/climate.h:8:0,
from src/esphome/core/application.h:27,
from src/esphome/components/api/api_connection.h:4,
from src/esphome.h:2,
from src/main.cpp:3:
src/esphome/components/climate/climate_traits.h:62:8: note: declared here
void set_supports_fan_only_mode(bool supports_fan_only_mode) {
^
In file included from src/main.cpp:19:0:
src/irsamsung.h:88:46: warning: 'void esphome::climate::ClimateTraits::set_supports_swing_mode_off(bool)' is deprecated: This method is deprecated, use set_supported_swing_modes() instead [-Wdeprecated-declarations]
traits.set_supports_swing_mode_off(true);
^
In file included from src/esphome/components/climate/climate.h:8:0,
from src/esphome/core/application.h:27,
from src/esphome/components/api/api_connection.h:4,
from src/esphome.h:2,
from src/main.cpp:3:
src/esphome/components/climate/climate_traits.h:131:8: note: declared here
void set_supports_swing_mode_off(bool supported) { set_swing_mode_support_(CLIMATE_SWING_OFF, supported); }
^
In file included from src/main.cpp:19:0:
src/irsamsung.h:89:51: warning: 'void esphome::climate::ClimateTraits::set_supports_swing_mode_vertical(bool)' is deprecated: This method is deprecated, use set_supported_swing_modes() instead [-Wdeprecated-declarations]
traits.set_supports_swing_mode_vertical(true);
^
In file included from src/esphome/components/climate/climate.h:8:0,
from src/esphome/core/application.h:27,
from src/esphome/components/api/api_connection.h:4,
from src/esphome.h:2,
from src/main.cpp:3:
src/esphome/components/climate/climate_traits.h:135:8: note: declared here
void set_supports_swing_mode_vertical(bool supported) { set_swing_mode_support_(CLIMATE_SWING_VERTICAL, supported); }
^
Generating partitions /data/arsamsung/.pioenvs/arsamsung/partitions.bin
Compiling /data/arsamsung/.pioenvs/arsamsung/lib198/AsyncTCP-esphome/AsyncTCP.cpp.o
*** [/data/arsamsung/.pioenvs/arsamsung/src/main.cpp.o] Error 1
========================= [FAILED] Took 106.93 seconds =========================

Just to make it more visible, the error (in red in the compiler) is this line, at the beginning:

src/irsamsung.h:33:82: error: no matching function for call to 'clamp(float&, int, int)'

Further info: Other Esphome yamls are compiling fine.

@rafaelnfernandes
Copy link

Hi guys,

Run out of knowledge, will need a little more help.

After updating HA and Esphome to the latest versions I'm not able to compile the ESPhome yaml to control the Samsung AC anymore. Have been getting this errors:

Compiling /data/arsamsung/.pioenvs/arsamsung/src/main.cpp.o
In file included from src/main.cpp:19:0:
src/irsamsung.h: In member function 'virtual void SamsungAC::setup()':
src/irsamsung.h:33:82: error: no matching function for call to 'clamp(float&, int, int)'
this->target_temperature = roundf(clamp(this->current_temperature, 16, 30));
^
In file included from src/esphome/core/application.h:8:0,
from src/esphome/components/api/api_connection.h:4,
from src/esphome.h:2,
from src/main.cpp:3:
src/esphome/core/helpers.h:83:24: note: candidate: template T esphome::clamp(T, T, T)
template T clamp(T val, T min, T max);
^
src/esphome/core/helpers.h:83:24: note: template argument deduction/substitution failed:
In file included from src/main.cpp:19:0:
src/irsamsung.h:33:82: note: deduced conflicting types for parameter 'T' ('float' and 'int')
this->target_temperature = roundf(clamp(this->current_temperature, 16, 30));
^
src/irsamsung.h: In member function 'virtual esphome::climate::ClimateTraits SamsungAC::traits()':
src/irsamsung.h:80:41: warning: 'void esphome::climate::ClimateTraits::set_supports_cool_mode(bool)' is deprecated: This method is deprecated, use set_supported_modes() instead [-Wdeprecated-declarations]
traits.set_supports_cool_mode(true);
^
In file included from src/esphome/components/climate/climate.h:8:0,
from src/esphome/core/application.h:27,
from src/esphome/components/api/api_connection.h:4,
from src/esphome.h:2,
from src/main.cpp:3:
src/esphome/components/climate/climate_traits.h:56:8: note: declared here
void set_supports_cool_mode(bool supports_cool_mode) { set_mode_support_(CLIMATE_MODE_COOL, supports_cool_mode); }
^
In file included from src/main.cpp:19:0:
src/irsamsung.h:82:40: warning: 'void esphome::climate::ClimateTraits::set_supports_dry_mode(bool)' is deprecated: This method is deprecated, use set_supported_modes() instead [-Wdeprecated-declarations]
traits.set_supports_dry_mode(true);
^
In file included from src/esphome/components/climate/climate.h:8:0,
from src/esphome/core/application.h:27,
from src/esphome/components/api/api_connection.h:4,
from src/esphome.h:2,
from src/main.cpp:3:
src/esphome/components/climate/climate_traits.h:66:8: note: declared here
void set_supports_dry_mode(bool supports_dry_mode) { set_mode_support_(CLIMATE_MODE_DRY, supports_dry_mode); }
^
In file included from src/main.cpp:19:0:
src/irsamsung.h:83:45: warning: 'void esphome::climate::ClimateTraits::set_supports_fan_mode_auto(bool)' is deprecated: This method is deprecated, use set_supported_fan_modes() instead [-Wdeprecated-declarations]
traits.set_supports_fan_mode_auto(true);
^
In file included from src/esphome/components/climate/climate.h:8:0,
from src/esphome/core/application.h:27,
from src/esphome/components/api/api_connection.h:4,
from src/esphome.h:2,
from src/main.cpp:3:
src/esphome/components/climate/climate_traits.h:80:8: note: declared here
void set_supports_fan_mode_auto(bool supported) { set_fan_mode_support_(CLIMATE_FAN_AUTO, supported); }
^
In file included from src/main.cpp:19:0:
src/irsamsung.h:84:45: warning: 'void esphome::climate::ClimateTraits::set_supports_fan_mode_high(bool)' is deprecated: This method is deprecated, use set_supported_fan_modes() instead [-Wdeprecated-declarations]
traits.set_supports_fan_mode_high(true);
^
In file included from src/esphome/components/climate/climate.h:8:0,
from src/esphome/core/application.h:27,
from src/esphome/components/api/api_connection.h:4,
from src/esphome.h:2,
from src/main.cpp:3:
src/esphome/components/climate/climate_traits.h:86:8: note: declared here
void set_supports_fan_mode_high(bool supported) { set_fan_mode_support_(CLIMATE_FAN_HIGH, supported); }
^
In file included from src/main.cpp:19:0:
src/irsamsung.h:85:44: warning: 'void esphome::climate::ClimateTraits::set_supports_fan_mode_low(bool)' is deprecated: This method is deprecated, use set_supported_fan_modes() instead [-Wdeprecated-declarations]
traits.set_supports_fan_mode_low(true);
^
In file included from src/esphome/components/climate/climate.h:8:0,
from src/esphome/core/application.h:27,
from src/esphome/components/api/api_connection.h:4,
from src/esphome.h:2,
from src/main.cpp:3:
src/esphome/components/climate/climate_traits.h:82:8: note: declared here
void set_supports_fan_mode_low(bool supported) { set_fan_mode_support_(CLIMATE_FAN_LOW, supported); }
^
In file included from src/main.cpp:19:0:
src/irsamsung.h:86:47: warning: 'void esphome::climate::ClimateTraits::set_supports_fan_mode_medium(bool)' is deprecated: This method is deprecated, use set_supported_fan_modes() instead [-Wdeprecated-declarations]
traits.set_supports_fan_mode_medium(true);
^
In file included from src/esphome/components/climate/climate.h:8:0,
from src/esphome/core/application.h:27,
from src/esphome/components/api/api_connection.h:4,
from src/esphome.h:2,
from src/main.cpp:3:
src/esphome/components/climate/climate_traits.h:84:8: note: declared here
void set_supports_fan_mode_medium(bool supported) { set_fan_mode_support_(CLIMATE_FAN_MEDIUM, supported); }
^
In file included from src/main.cpp:19:0:
src/irsamsung.h:87:45: warning: 'void esphome::climate::ClimateTraits::set_supports_fan_only_mode(bool)' is deprecated: This method is deprecated, use set_supported_modes() instead [-Wdeprecated-declarations]
traits.set_supports_fan_only_mode(true);
^
In file included from src/esphome/components/climate/climate.h:8:0,
from src/esphome/core/application.h:27,
from src/esphome/components/api/api_connection.h:4,
from src/esphome.h:2,
from src/main.cpp:3:
src/esphome/components/climate/climate_traits.h:62:8: note: declared here
void set_supports_fan_only_mode(bool supports_fan_only_mode) {
^
In file included from src/main.cpp:19:0:
src/irsamsung.h:88:46: warning: 'void esphome::climate::ClimateTraits::set_supports_swing_mode_off(bool)' is deprecated: This method is deprecated, use set_supported_swing_modes() instead [-Wdeprecated-declarations]
traits.set_supports_swing_mode_off(true);
^
In file included from src/esphome/components/climate/climate.h:8:0,
from src/esphome/core/application.h:27,
from src/esphome/components/api/api_connection.h:4,
from src/esphome.h:2,
from src/main.cpp:3:
src/esphome/components/climate/climate_traits.h:131:8: note: declared here
void set_supports_swing_mode_off(bool supported) { set_swing_mode_support_(CLIMATE_SWING_OFF, supported); }
^
In file included from src/main.cpp:19:0:
src/irsamsung.h:89:51: warning: 'void esphome::climate::ClimateTraits::set_supports_swing_mode_vertical(bool)' is deprecated: This method is deprecated, use set_supported_swing_modes() instead [-Wdeprecated-declarations]
traits.set_supports_swing_mode_vertical(true);
^
In file included from src/esphome/components/climate/climate.h:8:0,
from src/esphome/core/application.h:27,
from src/esphome/components/api/api_connection.h:4,
from src/esphome.h:2,
from src/main.cpp:3:
src/esphome/components/climate/climate_traits.h:135:8: note: declared here
void set_supports_swing_mode_vertical(bool supported) { set_swing_mode_support_(CLIMATE_SWING_VERTICAL, supported); }
^
Generating partitions /data/arsamsung/.pioenvs/arsamsung/partitions.bin
Compiling /data/arsamsung/.pioenvs/arsamsung/lib198/AsyncTCP-esphome/AsyncTCP.cpp.o
*** [/data/arsamsung/.pioenvs/arsamsung/src/main.cpp.o] Error 1
========================= [FAILED] Took 106.93 seconds =========================

Just to make it more visible, the error (in red in the compiler) is this line, at the beginning:

src/irsamsung.h:33:82: error: no matching function for call to 'clamp(float&, int, int)'

Further info: Other Esphome yamls are compiling fine.

Just in case, someone gets the same error, I made it compile.

Fisrt, I have VERY LITTLE idea of what I`m doing, so, proceed at your own risk.

The error seam to be some complaining about data types (int versus float), so I created two constants (type: float) instead of using the numbers in the function call.... now it compiles and seem to work (cant really test is, but the IR Led is blinking as/when expected).

so, in the samsung.h file I included (after this line: "const uint16_t kIrLed = 14; // LED PIN"):

const float const_min = 16;
const float const_max = 30;

and change the line:

this->target_temperature = roundf(clamp(this->current_temperature, 16, 30));

to

this->target_temperature = roundf(clamp(this->current_temperature, const_min, const_max));

and... it worked!

I sure there are much better ways to solve this, but....

@Tozapid
Copy link

Tozapid commented Aug 14, 2021

So, my irsamsung.h looks like this for now it is working fine on ESPHome 1.20.4

#include "esphome.h"
#include "IRremoteESP8266.h"
#include "IRsend.h"
#include "ir_Samsung.h"

const uint16_t kIrLed = 14; // LED PIN

const float const_min = 16;
const float const_max = 30;

IRSamsungAc ac(kIrLed);

class SamsungAC : public Component, public Climate {
  public:
    sensor::Sensor *sensor_{nullptr};

    void set_sensor(sensor::Sensor *sensor) { this->sensor_ = sensor; }

    void setup() override
    {
      if (this->sensor_) {
        this->sensor_->add_on_state_callback([this](float state) {
          this->current_temperature = state;
          this->publish_state();
        });
        this->current_temperature = this->sensor_->state;
      } else {
        this->current_temperature = NAN;
      }

      auto restore = this->restore_state_();
      if (restore.has_value()) {
        restore->apply(this);
      } else {
        this->mode = climate::CLIMATE_MODE_OFF;
        this->target_temperature = roundf(clamp(this->current_temperature, const_min, const_max));
        this->fan_mode = climate::CLIMATE_FAN_AUTO;
        this->swing_mode = climate::CLIMATE_SWING_OFF;
      }

      if (isnan(this->target_temperature)) {
        this->target_temperature = 25;
      }

      ac.begin();
      ac.on();
      if (this->mode == CLIMATE_MODE_OFF) {
        ac.off();
      } else if (this->mode == CLIMATE_MODE_COOL) {
        ac.setMode(kSamsungAcCool);
      } else if (this->mode == CLIMATE_MODE_DRY) {
        ac.setMode(kSamsungAcDry);
      } else if (this->mode == CLIMATE_MODE_FAN_ONLY) {
        ac.setMode(kSamsungAcFan);
      } else if (this->mode == CLIMATE_MODE_HEAT) {
        ac.setMode(kSamsungAcHeat);
      } else if (this->mode == CLIMATE_MODE_HEAT_COOL) {
        ac.setMode(kSamsungAcFanAuto);
      } 
      ac.setTemp(this->target_temperature);
      if (this->fan_mode == CLIMATE_FAN_AUTO) {
        ac.setFan(kSamsungAcFanAuto);
      } else if (this->fan_mode == CLIMATE_FAN_LOW) {
        ac.setFan(kSamsungAcFanLow);
      } else if (this->fan_mode == CLIMATE_FAN_MEDIUM) {
        ac.setFan(kSamsungAcFanMed);
      } else if (this->fan_mode == CLIMATE_FAN_HIGH) {
        ac.setFan(kSamsungAcFanHigh);
      }
      if (this->swing_mode == CLIMATE_SWING_OFF) {
        ac.setSwing(false);
      } else if (this->swing_mode == CLIMATE_SWING_VERTICAL) {
        ac.setSwing(true);
      }
      if (this->mode == CLIMATE_MODE_OFF) {
        ac.sendOff();
      } else {
        ac.send();
      }

      ESP_LOGD("DEBUG", "Samsung A/C remote is in the following state:");
      ESP_LOGD("DEBUG", "  %s\n", ac.toString().c_str());
    }

    climate::ClimateTraits traits() {
      auto traits = climate::ClimateTraits();
      traits.set_visual_min_temperature(const_min);
      traits.set_visual_max_temperature(const_max);
      traits.set_visual_temperature_step(1);
      traits.set_supported_modes({
          climate::CLIMATE_MODE_OFF,
          climate::CLIMATE_MODE_HEAT_COOL,
          climate::CLIMATE_MODE_COOL,
          climate::CLIMATE_MODE_DRY,
          climate::CLIMATE_MODE_HEAT,
          climate::CLIMATE_MODE_FAN_ONLY,
      });
      traits.set_supported_fan_modes({
          climate::CLIMATE_FAN_AUTO,
          climate::CLIMATE_FAN_LOW,
          climate::CLIMATE_FAN_MEDIUM,
          climate::CLIMATE_FAN_HIGH,
      });
      traits.set_supported_swing_modes({
          climate::CLIMATE_SWING_OFF,
          climate::CLIMATE_SWING_VERTICAL,
      });
      traits.set_supports_current_temperature(true);
      return traits;
    }

  void control(const ClimateCall &call) override {
    if (call.get_mode().has_value()) {
      ClimateMode mode = *call.get_mode();
      if (mode == CLIMATE_MODE_OFF) {
        ac.off();
      } else if (mode == CLIMATE_MODE_COOL) {
        ac.on();
        ac.setMode(kSamsungAcCool);
      } else if (mode == CLIMATE_MODE_DRY) {
        ac.on();
        ac.setMode(kSamsungAcDry);
      } else if (mode == CLIMATE_MODE_FAN_ONLY) {
        ac.on();
        ac.setMode(kSamsungAcFan);
      } else if (mode == CLIMATE_MODE_HEAT) {
        ac.on();
        ac.setMode(kSamsungAcHeat);
      } else if (mode == CLIMATE_MODE_HEAT_COOL) {
        ac.on();
        ac.setMode(kSamsungAcFanAuto);
      }
      this->mode = mode;
    }

    if (call.get_target_temperature().has_value()) {
      float temp = *call.get_target_temperature();
      ac.setTemp(temp);
      this->target_temperature = temp;
    }

    if (call.get_fan_mode().has_value()) {
      ClimateFanMode fan_mode = *call.get_fan_mode();
      if (fan_mode == CLIMATE_FAN_AUTO) {
        ac.setFan(kSamsungAcFanAuto);
      } else if (fan_mode == CLIMATE_FAN_LOW) {
        ac.setFan(kSamsungAcFanLow);
      } else if (fan_mode == CLIMATE_FAN_MEDIUM) {
        ac.setFan(kSamsungAcFanMed);
      } else if (fan_mode == CLIMATE_FAN_HIGH) {
        ac.setFan(kSamsungAcFanHigh);
      }
      this->fan_mode = fan_mode;
    }

    if (call.get_swing_mode().has_value()) {
      ClimateSwingMode swing_mode = *call.get_swing_mode();
      if (swing_mode == CLIMATE_SWING_OFF) {
        ac.setSwing(false);
      } else if (swing_mode == CLIMATE_SWING_VERTICAL) {
        ac.setSwing(true);
      }
      this->swing_mode = swing_mode;
    }

    if (this->mode == CLIMATE_MODE_OFF) {
      ac.sendOff();
    } else {
      ac.send();
    }

    this->publish_state();

    ESP_LOGD("DEBUG", "Samsung A/C remote is in the following state:");
    ESP_LOGD("DEBUG", "  %s\n", ac.toString().c_str());
  }
};

@hobojoe
Copy link

hobojoe commented Jan 28, 2022

So, my irsamsung.h looks like this for now it is working fine on ESPHome 1.20.4

Hi @Tozapid tried with your config file on the latest ESPHome and I am getting compile errors:

Compiling /data/ar-lucas/.pioenvs/ar-lucas/src/main.cpp.o
In file included from src/main.cpp:24:0:
src/irsamsung.h:15:5: error: 'sensor' does not name a type
     sensor::Sensor *sensor_{nullptr};
     ^
src/irsamsung.h:17:21: error: 'sensor' has not been declared
     void set_sensor(sensor::Sensor *sensor) { this->sensor_ = sensor; }
                     ^
src/irsamsung.h:17:36: error: expected ',' or '...' before '*' token
     void set_sensor(sensor::Sensor *sensor) { this->sensor_ = sensor; }
                                    ^
src/irsamsung.h: In member function 'void SamsungAC::set_sensor(int)':
src/irsamsung.h:17:53: error: 'class SamsungAC' has no member named 'sensor_'
     void set_sensor(sensor::Sensor *sensor) { this->sensor_ = sensor; }
                                                     ^
src/irsamsung.h:17:63: error: 'sensor' was not declared in this scope
     void set_sensor(sensor::Sensor *sensor) { this->sensor_ = sensor; }
                                                               ^
src/irsamsung.h: In member function 'virtual void SamsungAC::setup()':
src/irsamsung.h:21:17: error: 'class SamsungAC' has no member named 'sensor_'
       if (this->sensor_) {
                 ^
src/irsamsung.h:22:15: error: 'class SamsungAC' has no member named 'sensor_'
         this->sensor_->add_on_state_callback([this](float state) {
               ^
src/irsamsung.h:26:43: error: 'class SamsungAC' has no member named 'sensor_'
         this->current_temperature = this->sensor_->state;
                                           ^
*** [/data/ar-lucas/.pioenvs/ar-lucas/src/main.cpp.o] Error 1
========================= [FAILED] Took 10.93 seconds =========================

Could anyone make it work?

Thanks

@Tozapid
Copy link

Tozapid commented Jan 28, 2022

So, my irsamsung.h looks like this for now it is working fine on ESPHome 1.20.4

Hi @Tozapid tried with your config file on the latest ESPHome and I am getting compile errors:

Compiling /data/ar-lucas/.pioenvs/ar-lucas/src/main.cpp.o
In file included from src/main.cpp:24:0:
src/irsamsung.h:15:5: error: 'sensor' does not name a type
     sensor::Sensor *sensor_{nullptr};
     ^
src/irsamsung.h:17:21: error: 'sensor' has not been declared
     void set_sensor(sensor::Sensor *sensor) { this->sensor_ = sensor; }
                     ^
src/irsamsung.h:17:36: error: expected ',' or '...' before '*' token
     void set_sensor(sensor::Sensor *sensor) { this->sensor_ = sensor; }
                                    ^
src/irsamsung.h: In member function 'void SamsungAC::set_sensor(int)':
src/irsamsung.h:17:53: error: 'class SamsungAC' has no member named 'sensor_'
     void set_sensor(sensor::Sensor *sensor) { this->sensor_ = sensor; }
                                                     ^
src/irsamsung.h:17:63: error: 'sensor' was not declared in this scope
     void set_sensor(sensor::Sensor *sensor) { this->sensor_ = sensor; }
                                                               ^
src/irsamsung.h: In member function 'virtual void SamsungAC::setup()':
src/irsamsung.h:21:17: error: 'class SamsungAC' has no member named 'sensor_'
       if (this->sensor_) {
                 ^
src/irsamsung.h:22:15: error: 'class SamsungAC' has no member named 'sensor_'
         this->sensor_->add_on_state_callback([this](float state) {
               ^
src/irsamsung.h:26:43: error: 'class SamsungAC' has no member named 'sensor_'
         this->current_temperature = this->sensor_->state;
                                           ^
*** [/data/ar-lucas/.pioenvs/ar-lucas/src/main.cpp.o] Error 1
========================= [FAILED] Took 10.93 seconds =========================

Could anyone make it work?

Thanks

You need to add a sensor in a ESPhome config, here is mine for example:

dallas:
  - pin: GPIO2
    update_interval: 10s
sensor:
  - platform: dallas
    address: 0x488A19025613FF28
    name: "Temperature"
    accuracy_decimals: 1
    id: avatto_ir_temp

climate:
  - platform: custom
    lambda: |-
       auto samsungac = new SamsungAC();
       samsungac->set_sensor(id(avatto_ir_temp));
       App.register_component(samsungac);
       return {samsungac};
    climates:
    - name: "AC"

If you don't have one try to use template sensor:

sensor:
  - platform: template
    id: avatto_ir_temp
    name: "Template Sensor"
    lambda: return 0.0;
    update_interval: 60s

@itkama
Copy link

itkama commented Mar 17, 2022

Hi,
I'm also trying to get his working. I'm also using your irsamsung.h and the config from your last comment @Tozapid. I'm getting an error while compiling though:

image

Using the latest 2022.3.0 version of ESPHome.

@Tozapid
Copy link

Tozapid commented Mar 18, 2022

@itkama You need to include irsamsung.h in the esphome config

Here is my part:

esphome:
  name: avatto-ir-remote
  platform: ESP8266
  board: esp01_1m
  includes: 
    - include/irsamsung.h
  libraries:
    - IRremoteESP8266

@bnap00
Copy link

bnap00 commented Apr 9, 2022

can I hookup IR receiver to IRremoteESP8266 using esphome
so that if I change anything from remote it reflects on my esphome

@mr2c12
Copy link

mr2c12 commented Sep 4, 2022

@Tozapid , do you think is possible to port your code to ESP32?

Actually I cannot compile the code for esp8266 too, but my final target is esp32..

@Tozapid
Copy link

Tozapid commented Sep 4, 2022

@mr2c12,
Unfortunately, I can't say for now and also this is not my code:(

Let's ask @iglu-sebastian or @ICuddlesI hope they can help us.

@anklav24
Copy link

anklav24 commented Sep 5, 2022

Hi guys.
I have a HITACHI RAC-09CH7 with a RAR-2P2 remote and tuya-ir.
I've tried to integrate it in a Home Assistant, but works only raw commands as a couple buttons.
How to make it work as a climate device?

tuya-ir.yaml

esphome:
  name: tuya-ir
  platform: ESP8266
  board: esp01_1m
  includes:
    - include/hitachi_ir.h
  libraries:
    - crankyoldgit/IRremoteESP8266@^2.8.2
  platformio_options:
    build_flags: 
      - -DSEND_HITACHI_AC264
      - -DDEBUG_AC

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

logger:

api:
  password: !secret esphome_api_password

ota:
  password: !secret esphome_api_password

# Use the blue LED as a status light.
#   Blink slowly = Temporary issue (WiFi/MQTT disconnected, sensor unavailable, ...)
#   Blink quickly = Error encountered
status_led:
  pin: GPIO4

# Configure the IR receiver. Handy to pickup confirmation messages
# from your AC (or capture commands from the actual remote)
remote_receiver:
  pin:
    number: GPIO5
    inverted: true
    mode:
      input: true
      pullup: true
  # high 55% tolerance is recommended for some remote control units
  tolerance: 55%
  dump: raw  # all or raw for my case

# Configure the IR LED: this one sends commands to other devices
remote_transmitter:
  pin: GPIO14
  carrier_duty_percent: 50%

# Configure the AC unit you have. Mine is a Hitachi.

switch:
  - platform: template
    name: Turn On A/C
    turn_on_action:
      - remote_transmitter.transmit_raw:
          carrier_frequency: 38kHz
          # Hitachi AC 24C FanLow SwingOff
          code: [3442, -1657, 440, -1260, 440, -410, 439, -410, 464, -386, 440, -409, 440, -412, 438, -410, 440, -409, 467, -383, 444, -406, 466, -383, 441, -409, 465, -1235, 439, -410, 464, -386, 440, -410, 463, -387, 463, -385, 465, -385, 465, -385, 443, -407, 440, -410, 439, -410, 465, -384, 465, -385, 440, -410, 440, -410, 439, -411, 439, -410, 440, -410, 440, -1259, 441, -409, 440, -1259, 441, -1258, 443, -1257, 439, -1261, 443, -1255, 441, -1259, 466, -383, 440, -1260, 440, -1259, 440, -1259, 445, -1255, 440, -1260, 438, -1260, 440, -1259, 440, -1260, 465, -1235, 444, -405, 465, -385, 440, -409, 465, -385, 439, -411, 439, -410, 440, -410, 465, -384, 465, -385, 441, -412, 437, -1262, 438, -1259, 440, -410, 439, -410, 464, -1235, 440, -1259, 440, -1260, 441, -1258, 441, -409, 463, -386, 466, -1234, 463, -1237, 440, -409, 441, -408, 440, -414, 460, -1236, 439, -410, 441, -410, 439, -1259, 442, -408, 466, -384, 466, -1233, 441, -1259, 440, -411, 463, -1235, 441, -1257, 442, -408, 465, -1235, 441, -1258, 464, -385, 441, -1259, 440, -1260, 442, -407, 441, -409, 440, -1259, 440, -410, 464, -385, 466, -384, 468, -382, 466, -383, 465, -1235, 466, -1232, 466, -385, 442, -1257, 466, -1233, 466, -1234, 439, -411, 439, -410, 464, -386, 467, -385, 463, -384, 465, -1235, 440, -1259, 439, -411, 464, -1235, 439, -1260, 440, -1260, 466, -1236, 440, -1257, 440, -409, 464, -385, 441, -1259, 441, -409, 440, -410, 439, -412, 439, -409, 440, -409, 465, -385, 466, -388, 436, -410, 439, -1259, 441, -1259, 465, -1235, 439, -1260, 441, -1258, 465, -1235, 439, -1260, 440, -1259, 442, -408, 468, -381, 441, -409, 465, -385, 439, -411, 440, -409, 440, -410, 444, -406, 441, -1262, 436, -1261, 440, -1258, 439, -1260, 441, -1258, 442, -1258, 440, -1260, 439, -1259, 440, -410, 440, -410, 440, -410, 439, -410, 466, -383, 440, -411, 441, -408, 440, -411, 439, -1259, 466, -1233, 465, -1235, 440, -1262, 438, -1258, 487, -1212, 467, -1233, 440, -1260, 440, -409, 440, -410, 440, -409, 441, -409, 465, -385, 464, -385, 442, -410, 464, -383, 442, -1258, 465, -1234, 442, -1257, 465, -1235, 440, -1259, 441, -1258, 466, -1234, 444, -1255, 465, -386, 438, -411, 464, -387, 463, -385, 464, -386, 465, -385, 440, -410, 465, -385, 439, -1259, 441, -1259, 440, -1259, 464, -1235, 440, -1260, 438, -1261, 466, -1233, 440, -1260, 439, -1260, 441, -1258, 440, -410, 464, -386, 464, -1235, 465, -384, 465, -385, 442, -408, 441, -409, 439, -411, 439, -1260, 464, -1235, 465, -384, 441, -1259, 440, -1260, 440, -1258, 466, -1238, 437, -408, 467, -383, 465, -385, 443, -1256, 465, -384, 465, -1235, 443, -1256, 465, -385, 464, -1236, 442, -1258, 438, -1261, 438, -411, 465, -1234, 466, -388, 462, -383, 466, -1234, 443, -407, 445, -1254, 465, -384, 442, -409, 438, -410, 466, -385, 441, -409, 440, -409, 464, -1235, 440, -410, 440, -1259, 440, -1260, 441, -1258, 440, -1260, 439, -1260, 469, -1230, 440, -410, 465, -385, 440, -1258, 442, -409, 440, -411, 438, -410, 440, -409, 441, -410, 440, -1258, 465, -1235, 465, -385, 440, -1258, 441, -1259, 466, -1237, 437, -1259, 465]

  - platform: template
    name: Turn On A/C Swing Toggle
    turn_on_action:
      - remote_transmitter.transmit_raw:
          carrier_frequency: 38kHz
          # Hitachi AC 24C FanLow Toggle
          code: [3440, -1656, 441, -1258, 445, -406, 440, -409, 465, -384, 466, -384, 466, -384, 440, -410, 465, -384, 442, -408, 441, -408, 467, -383, 456, -394, 464, -1235, 465, -385, 466, -384, 465, -385, 440, -409, 446, -404, 441, -409, 465, -384, 465, -388, 436, -412, 439, -409, 464, -386, 465, -384, 466, -385, 465, -384, 466, -383, 442, -408, 441, -409, 465, -1234, 464, -386, 465, -1234, 466, -1233, 441, -1259, 440, -1260, 440, -1259, 465, -1234, 440, -410, 464, -1235, 443, -1257, 440, -1259, 465, -1234, 442, -1258, 441, -1259, 439, -1260, 465, -1234, 441, -1258, 439, -411, 441, -408, 442, -408, 466, -384, 439, -411, 465, -384, 440, -410, 465, -385, 465, -385, 440, -409, 440, -1261, 463, -1235, 440, -410, 441, -408, 465, -1234, 466, -1234, 440, -1260, 440, -1259, 441, -409, 441, -408, 441, -1258, 440, -1263, 437, -410, 465, -384, 466, -383, 465, -1235, 441, -409, 469, -381, 465, -1234, 440, -410, 464, -388, 462, -1234, 466, -1234, 441, -408, 465, -1234, 442, -1259, 467, -382, 441, -1261, 441, -1256, 440, -410, 440, -1259, 444, -406, 464, -385, 466, -384, 441, -409, 440, -410, 465, -384, 440, -1260, 464, -385, 465, -1234, 441, -1259, 468, -1231, 466, -1233, 441, -1259, 464, -1235, 441, -409, 465, -384, 466, -387, 464, -384, 463, -386, 466, -383, 440, -1259, 465, -1235, 440, -409, 465, -1235, 465, -1234, 440, -1260, 441, -1258, 439, -1261, 464, -384, 441, -410, 460, -1239, 466, -384, 469, -381, 461, -388, 464, -388, 437, -410, 464, -386, 442, -408, 464, -386, 445, -1255, 465, -1233, 465, -1235, 441, -1260, 441, -1256, 441, -1259, 440, -1259, 465, -1234, 441, -409, 464, -386, 466, -384, 440, -409, 440, -411, 439, -410, 464, -385, 466, -384, 469, -1231, 440, -1259, 440, -1259, 441, -1259, 444, -1255, 442, -1258, 438, -1261, 440, -1259, 440, -410, 440, -410, 440, -410, 439, -410, 466, -384, 465, -384, 465, -385, 464, -385, 466, -1234, 465, -1234, 466, -1234, 440, -1262, 436, -1261, 439, -1260, 464, -1235, 441, -1258, 463, -387, 464, -386, 466, -383, 467, -383, 441, -409, 441, -408, 465, -386, 464, -386, 441, -1257, 441, -1258, 466, -1234, 440, -1259, 440, -1260, 465, -1234, 440, -1260, 439, -1260, 440, -409, 441, -409, 466, -384, 441, -409, 465, -384, 465, -385, 465, -385, 439, -411, 468, -1231, 440, -1259, 441, -1258, 440, -1260, 440, -1259, 466, -1233, 466, -1233, 465, -1235, 441, -1258, 466, -1235, 440, -412, 441, -405, 441, -1259, 465, -384, 465, -385, 466, -384, 465, -385, 440, -410, 465, -1236, 463, -1234, 465, -384, 441, -1259, 441, -1258, 440, -1261, 439, -1258, 443, -408, 464, -386, 464, -386, 463, -1237, 443, -405, 441, -1259, 440, -1258, 441, -410, 464, -1235, 441, -1259, 465, -1233, 442, -408, 465, -1235, 440, -409, 443, -407, 441, -1259, 442, -407, 466, -1234, 440, -409, 441, -409, 440, -410, 464, -385, 441, -408, 467, -384, 466, -1233, 440, -410, 464, -1236, 439, -1259, 440, -1260, 440, -1259, 441, -1259, 440, -1259, 440, -410, 440, -409, 440, -1260, 441, -408, 464, -388, 463, -384, 465, -385, 465, -387, 463, -1234, 440, -1260, 440, -409, 466, -1234, 439, -1260, 441, -1258, 466, -1234, 440]

  - platform: template
    name: Turn Off A/C
    turn_on_action:
      - remote_transmitter.transmit_raw:
          carrier_frequency: 38kHz
          # Hitachi AC TurnOff: 
          code: [3438, -1658, 442, -1259, 439, -410, 465, -385, 440, -409, 466, -384, 440, -410, 440, -409, 465, -384, 467, -383, 466, -384, 441, -409, 441, -409, 439, -1260, 465, -384, 466, -384, 465, -384, 441, -410, 440, -409, 440, -410, 466, -384, 441, -408, 441, -409, 465, -384, 447, -403, 441, -409, 440, -409, 454, -400, 462, -385, 465, -383, 466, -384, 439, -1261, 463, -386, 465, -1234, 441, -1259, 448, -1251, 440, -1261, 439, -1259, 440, -1260, 440, -410, 463, -1236, 439, -1260, 465, -1234, 465, -1234, 441, -1260, 439, -1259, 440, -1260, 464, -1235, 441, -1258, 465, -386, 440, -408, 466, -385, 439, -410, 466, -384, 440, -410, 439, -409, 466, -385, 464, -385, 440, -409, 441, -1259, 440, -1259, 439, -412, 465, -384, 466, -1233, 465, -1234, 465, -1235, 466, -1233, 440, -410, 466, -383, 442, -1258, 441, -1259, 464, -385, 466, -384, 464, -386, 440, -1259, 440, -410, 440, -410, 464, -1234, 467, -383, 440, -410, 465, -1234, 466, -1234, 439, -411, 464, -1235, 439, -1260, 465, -385, 443, -1256, 465, -1234, 464, -386, 439, -1261, 470, -1230, 439, -410, 440, -409, 466, -1233, 466, -384, 440, -410, 465, -385, 440, -409, 466, -389, 436, -1258, 466, -1233, 440, -410, 440, -1261, 439, -1260, 439, -1260, 440, -409, 441, -409, 464, -385, 441, -409, 440, -410, 439, -1260, 464, -1235, 465, -385, 464, -1236, 458, -1241, 441, -1259, 440, -1259, 440, -1259, 441, -409, 442, -407, 466, -1234, 439, -411, 466, -383, 466, -384, 465, -384, 442, -408, 440, -410, 464, -386, 465, -384, 442, -1258, 465, -1234, 440, -1259, 465, -1234, 440, -1260, 441, -1259, 440, -1259, 441, -1258, 440, -410, 465, -384, 441, -409, 440, -410, 467, -384, 463, -385, 441, -410, 439, -410, 440, -1259, 441, -1259, 465, -1234, 441, -1262, 440, -1255, 466, -1233, 466, -1234, 440, -1260, 440, -412, 462, -385, 440, -409, 464, -386, 442, -408, 465, -385, 464, -385, 440, -411, 439, -1259, 465, -1235, 440, -1259, 468, -1231, 440, -1261, 439, -1260, 442, -1256, 440, -1259, 441, -410, 445, -406, 464, -384, 464, -385, 466, -384, 441, -409, 440, -409, 440, -411, 463, -1235, 441, -1263, 461, -1234, 465, -1235, 440, -1260, 439, -1260, 440, -1259, 464, -1235, 466, -384, 465, -385, 441, -408, 466, -384, 440, -410, 464, -385, 441, -413, 435, -411, 440, -1259, 440, -1260, 440, -1259, 440, -1262, 436, -1261, 440, -1258, 441, -1259, 440, -1259, 464, -1235, 456, -1249, 439, -406, 465, -385, 464, -1235, 440, -410, 440, -410, 439, -411, 441, -408, 465, -384, 440, -1260, 465, -1234, 464, -386, 466, -1233, 440, -1260, 464, -1234, 442, -1258, 465, -385, 440, -410, 439, -410, 439, -411, 439, -410, 441, -1260, 467, -1231, 468, -382, 440, -1259, 440, -1260, 464, -1235, 466, -1233, 468, -1231, 442, -409, 464, -385, 465, -1234, 441, -410, 464, -1235, 440, -410, 441, -408, 466, -383, 441, -410, 465, -385, 440, -409, 464, -1235, 465, -385, 440, -1259, 440, -1259, 465, -1235, 441, -1258, 440, -1260, 440, -1259, 440, -409, 463, -388, 438, -1260, 466, -384, 469, -381, 466, -383, 467, -383, 465, -385, 453, -1246, 465, -1235, 441, -408, 440, -1259, 466, -1234, 465, -1234, 441, -1259, 440]

climate:
  - platform: custom
    lambda: |-
      auto my_hitachiac = new HitachiAC();
      App.register_component(my_hitachiac);
      return {my_hitachiac};

    climates:
      - name: "Master Bedroom AC"

hitachi_ir.h

#include "esphome.h"
#include "IRremoteESP8266.h"
#include "IRsend.h"
#include "ir_Hitachi.h"

///This code is relevant for cases where the IR control for an AC is available in IRremoteESP8266, but isn't supported yet in Esphome

const uint16_t kIrLed = 14;  // ESP8266 GPIO pin to use. Recommended: 0 (D3).
const bool inverted = false;
const bool use_modulation = true;
IRHitachiAc264 ac(kIrLed, inverted, use_modulation);


// Setup files. This is the equivalent of the code written in the setup loop of Arduino
class HitachiAC : public Component, public Climate { public: void setup() override {
    // Setup pins etc
    ac.begin();
    // AC model. This is only relevant in cases where the ir_company.h requires a model (i.e. the signals change by model)
    // ac.setModel(R_LT0541_HTA_A);
    delay(200);
    // Setting up base conditions, so that the system doesn't send garbage to begin with
    ac.setTemp(24);
    ac.setFan(kHitachiAc264FanAuto);
    // ac.setSwingV(true);
    ac.off();
    // Setting up base conditions transferred to Home Assistant, so that there's no garbage at initialization
    this->mode = mode;
    this->fan_mode = CLIMATE_FAN_AUTO;
    this->swing_mode = CLIMATE_SWING_VERTICAL;
    this->target_temperature = 24;
    this->publish_state();
  }

  // Traits: This tells home assistant what "traits" are supported by AC in terms of heating/cooling/fan speeds/swing modes. These are used by Home Assistant to customize the AC card on your dashboard
  climate::ClimateTraits traits() {
    auto traits = climate::ClimateTraits();
    traits.set_supports_current_temperature(false);
    traits.set_supports_two_point_target_temperature(false);

    traits.set_supported_modes({
      climate::CLIMATE_MODE_OFF,
      climate::CLIMATE_MODE_HEAT,
      climate::CLIMATE_MODE_DRY,
      climate::CLIMATE_MODE_COOL,
      climate::CLIMATE_MODE_FAN_ONLY,
      //Adding this leads to esphome data not showing on Home Assistant somehow, hence skipping. Others please try and let me know
    });

    traits.set_supported_fan_modes({
      climate::CLIMATE_FAN_AUTO,
      climate::CLIMATE_FAN_LOW,
      climate::CLIMATE_FAN_MEDIUM,
      climate::CLIMATE_FAN_HIGH,
      });

    traits.set_supported_swing_modes({
      climate::CLIMATE_SWING_OFF,
      climate::CLIMATE_SWING_VERTICAL,
    });

    traits.set_visual_min_temperature(16);
    traits.set_visual_max_temperature(30);
    traits.set_visual_temperature_step(1);
    return traits;
  }

  //Code for what to do when the mode of the AC is changed on the dashboard
  void control(const ClimateCall &call) override {
    if (call.get_mode().has_value()) {
      // User requested mode change
      ClimateMode mode = *call.get_mode();
      // Send mode to hardware
      //You need an condition of each of the supported modes mentioned in the traits section above
      //For each mode, you need to find the relevant mode from the list of constants. This list can be found in the relevant .h library from IRremoteESP8266 library. In this case the file is "ir_Hitachi.h". Typically the function should be the same - .setMode. However, best check the relevant .h library. 

      if (mode == CLIMATE_MODE_OFF) {
        ac.off();
      } else if (mode == CLIMATE_MODE_HEAT) {
        ac.on();
        ac.setMode(kHitachiAc264Heat);
      } else if (mode == CLIMATE_MODE_DRY) {
        ac.on();
        ac.setMode(kHitachiAc264Dry);
      } else if (mode == CLIMATE_MODE_COOL) {
        ac.on();
        ac.setMode(kHitachiAc264Cool);
      } else if (mode == CLIMATE_MODE_FAN_ONLY) {
        ac.on();
        ac.setMode(kHitachiAc264Fan);
      }

      // Publish updated state
      this->mode = mode;
      this->publish_state();
    }

    //Code for what to do when the fan speed / mode is changed on the dashboard
    if (call.get_fan_mode().has_value()) {
      // User requested fan mode change
      ClimateFanMode fan_mode = *call.get_fan_mode();
      // Send fan mode to hardware
      if (fan_mode == CLIMATE_FAN_AUTO) {
        ac.setFan(kHitachiAc264FanAuto);
      } else if (fan_mode == CLIMATE_FAN_LOW) {
        ac.setFan(kHitachiAc264FanMin);
      } else if (fan_mode == CLIMATE_FAN_MEDIUM) {
        ac.setFan(kHitachiAc264FanMedium);
      } else if (fan_mode == CLIMATE_FAN_HIGH) {
        ac.setFan(kHitachiAc264FanHigh);
      }

      this->fan_mode = fan_mode;
      this->publish_state();
    }

    //Code for what to do when the swing mode is changed on the dashboard
    //Check what function is available in the relevant .h file. For example, .setSwingV is the relevant function in ir_Hitachi.h, but it is .setSwingVertical in some others
    if (call.get_swing_mode().has_value()) {
      // User requested fan mode change
      ClimateSwingMode swing_mode = *call.get_swing_mode();
      // Send fan mode to hardware
      if (swing_mode == CLIMATE_SWING_OFF) {
        ac.setSwingVToggle(false);
      } else if (swing_mode == CLIMATE_SWING_VERTICAL) {
        ac.setSwingVToggle(true);
      }

      this->swing_mode = swing_mode;
      this->publish_state();
    }

    //Code for what to do when the temperature is changed on the dashboard
    if (call.get_target_temperature().has_value()) {
      // User requested target temperature change
      float temp = *call.get_target_temperature();
      // Send target temp to climate
      ac.setTemp(temp);

      this->target_temperature = temp;
      this->publish_state();
    }

  //Send the IR code you've built basis all the above data
  ac.send();
  #if DEBUG_AC
  ESP_LOGD("DEBUG", "Home A/C remote is in the following state:");
  ESP_LOGD("DEBUG", "%s\n", ac.toString().c_str());
  #endif // DEBUG_AC
  }
};

@github-actions github-actions bot locked and limited conversation to collaborators Jan 4, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests