esphome / feature-requests

ESPHome Feature Request Tracker
https://esphome.io/
411 stars 26 forks source link

Add Samsung AC IR climate component #444

Closed kvvoff closed 2 years ago

kvvoff commented 4 years ago

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 commented 4 years ago

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 commented 4 years ago

@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 commented 4 years ago

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 commented 4 years ago

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:

  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 commented 4 years ago

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

OttoWinter commented 4 years ago

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

kvvoff commented 4 years ago

@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 commented 4 years ago

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

kvvoff commented 4 years ago

@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 commented 4 years ago

@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 commented 4 years ago

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 commented 4 years ago

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

selfhoster commented 4 years ago

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:

  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 commented 4 years ago

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 commented 3 years ago

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 commented 3 years ago

@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 commented 3 years ago

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 commented 3 years ago

This works perfectly. Thank you

Fusseldieb commented 3 years ago

@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 commented 3 years ago

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 commented 3 years ago

@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 commented 3 years ago

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 commented 3 years ago

@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 commented 3 years ago

@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 commented 3 years ago

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 commented 3 years ago

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_automode with _set_supports_heat_coolmode and _CLIMATE_MODEAUTO with _CLIMATE_MODE_HEATCOOL, 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 commented 3 years ago

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_automode with _set_supports_heat_coolmode and _CLIMATE_MODEAUTO with _CLIMATE_MODE_HEATCOOL, 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 commented 3 years ago

@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 commented 3 years ago

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_modesupport(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_modesupport(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_modesupport(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_modesupport(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_modesupport(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_modesupport(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_modesupport(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_modesupport(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 commented 3 years ago

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_modesupport(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_modesupport(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_modesupport(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_modesupport(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_modesupport(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_modesupport(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_modesupport(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_modesupport(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 commented 3 years ago

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 commented 2 years ago

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 commented 2 years ago

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 commented 2 years ago

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 commented 2 years ago

@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 commented 2 years ago

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

mr2c12 commented 2 years ago

@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 commented 2 years ago

@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 commented 2 years ago

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
  }
};