Skip to content

Instantly share code, notes, and snippets.

@Fusseldieb
Last active February 4, 2021 03:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Fusseldieb/a141581eaccff2b1ff9917c43e750f6a to your computer and use it in GitHub Desktop.
Save Fusseldieb/a141581eaccff2b1ff9917c43e750f6a to your computer and use it in GitHub Desktop.
IRremoteESP8266 for ESPHome with LED "sync" pin
// This version of the code allows you to use an INPUT pin to sync the state of your HVAC with ESPHome
// This is particularly useful if you have integrated an ESP8266 inside your HVAC and hooked up the ON-LED from it to the ESP8266
// That way even if someone turns the HVAC on with the remote control, Home Assistant should show the ACTUAL state of it (ON/OFF).
#include "esphome.h"
#include "IRremoteESP8266.h"
#include "IRsend.h"
#include "ir_Samsung.h"
const uint16_t kIrLed = D8; // IR LED (OUTPUT) PIN
IRSamsungAc ac(kIrLed);
const uint16_t kOnLed = D7; // "ON" LED (INPUT) PIN
class SamsungAC : public Component, public Climate {
public:
sensor::Sensor *sensor_{nullptr};
void set_sensor(sensor::Sensor *sensor) { this->sensor_ = sensor; }
void setup() override
{
pinMode(kOnLed, INPUT);
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 = 22;
}
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());
}
void loop() override
{
if (this->mode == CLIMATE_MODE_OFF && digitalRead(kOnLed) == 1) {
this->mode = climate::CLIMATE_MODE_AUTO;
ESP_LOGD("DEBUG", "Sync'd HA with LED");
ESP_LOGD("DEBUG", "LED was turned on by itself. Assuming AUTO mode (Actual state unknown). This is not an error.");
this->publish_state();
} else if (this->mode != CLIMATE_MODE_OFF && digitalRead(kOnLed) == 0) {
this->mode = climate::CLIMATE_MODE_OFF;
ESP_LOGD("DEBUG", "Sync'd HA with LED.");
this->publish_state();
}
}
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());
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment