Closed kvvoff closed 2 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.
@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
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.
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:
esphome:
name: irdaikin
platform: ESP8266
board: d1_mini
includes:
- irdaikin/daikin_ir.h
libraries:
- IRremoteESP8266
wifi: ssid: "your_ssid" password: "your_wifi"
logger:
ota:
api:
climate:
platform: custom lambda: |- auto my_daikinac = new DaikinAC(); App.register_component(my_daikinac); return {my_daikinac};
climates:
#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();
} };
@computingwithinfinitedata It looks really cool, I'll try it. Thanks friend
@computingwithinfinitedata Great! FYI, you can use libraries
instead of lib_deps
. I updated your comment to reflect that.
@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?
@kvvoff Each one needs to be done separately. Though the base part has been greatly simplified thanks to @glmnet 's climate_ir base.
@computingwithinfinitedata
I tried now your code for your ac. The compilation was successful, a new climate was added, but without a choice of temperature.
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
@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...)
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
@computingwithinfinitedata If the device does not support sending current temperature, you should set traits.set_supports_current_temperature(true);
to false.
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
esphome:
name: upstairsac
platform: ESP8266
board: d1_mini
includes:
- panasonic_ir.h
libraries:
- IRremoteESP8266
wifi: ssid: "" password: ""
logger:
ota:
api:
climate:
platform: custom lambda: |- auto my_panasonic = new PanasonicAC(); App.register_component(my_panasonic); return {my_panasonic};
climates:
#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();
} };
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.
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.
@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?
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"
This works perfectly. Thank you
@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
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());
}
};
@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
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?
@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 !
@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());
}
};
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
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);
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!
@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());
}
};
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
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.
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....
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());
}
};
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
So, my
irsamsung.h
looks like this for now it is working fine on ESPHome 1.20.4Hi @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
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:
Using the latest 2022.3.0 version of ESPHome.
@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
can I hookup IR receiver to IRremoteESP8266
using esphome
so that if I change anything from remote it reflects on my esphome
@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..
@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.
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
}
};
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