Initial commit - hard fork

This commit is contained in:
Sagi Dayan 2024-07-02 13:40:00 +03:00
commit d022753ade
Signed by: sagi
GPG key ID: FAB96BFC63B46458
7 changed files with 298 additions and 0 deletions

22
LICENSE Normal file
View file

@ -0,0 +1,22 @@
MIT License
Copyright (c) 2023 Roman Klassen
Copyright (c) 2024 Sagi Dayan
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

43
README.md Normal file
View file

@ -0,0 +1,43 @@
# ESPHome Electra AC IR remote control component
This implementation of the ESPHome component to control HVAC with IR channel.
Base implementation of the protocol can be found here: [https://github.com/crankyoldgit/IRremoteESP8266](https://github.com/crankyoldgit/IRremoteESP8266)
This repo was originally forked from [https://github.com/rozh1/esphome-haier-ac-ir](https://github.com/rozh1/esphome-haier-ac-ir)
## Supported AC
- Brand: AUX, Model: KFR-35GW/BpNFW=3 A/C
- Brand: AUX, Model: YKR-T/011 remote
- Brand: Electra, Model: Classic INV 17 / AXW12DCS A/C
- Brand: Electra, Model: YKR-M/003E remote
- Brand: Frigidaire, Model: FGPC102AB1 A/C
- Brand: Subtropic, Model: SUB-07HN1_18Y A/C
- Brand: Subtropic, Model: YKR-H/102E remote
- Brand: Centek, Model: SCT-65Q09 A/C
- Brand: Centek, Model: YKR-P/002E remote
- Brand: AEG, Model: Chillflex Pro AXP26U338CW A/C
- Brand: Electrolux, Model: YKR-H/531E A/C
- Brand: Delonghi, Modell: PAC EM90
## How to use
1. Add sensor configuration. It can be a connected temperature sensor or home assistant provided sensor. For example:
```
sensor:
# External temperature sensor from Home Assistant
- platform: homeassistant
id: current_temperature
entity_id: ${temperature_sensor}
```
2. Add climate component, set platform as `electra_ac`, set `sensor_id` and `pin` number for IR LED.
```
climate:
- platform: electra_ac
sensor_id: current_temperature # Sensor ID with the current temperature
pin: 3 # Pin with IR led
name: "Electra A/C"
```

View file

View file

@ -0,0 +1,29 @@
import esphome.codegen as cg
import esphome.config_validation as cv
from esphome.components import climate, sensor
from esphome.const import CONF_ID, CONF_PIN, CONF_SENSOR_ID
from esphome.core import CORE
AUTO_LOAD = ["climate"]
electra_ac_ns = cg.esphome_ns.namespace("electra_ac")
ElectraClimate = electra_ac_ns.class_("ElectraClimate", climate.Climate)
CONFIG_SCHEMA = climate.CLIMATE_SCHEMA.extend(
{
cv.GenerateID(): cv.declare_id(ElectraClimate),
cv.Required(CONF_SENSOR_ID): cv.use_id(sensor.Sensor),
cv.Required(CONF_PIN): cv.int_,
}
)
async def to_code(config):
if CORE.is_esp8266 or CORE.is_esp32:
cg.add_library("crankyoldgit/IRremoteESP8266", "2.8.4")
var = cg.new_Pvariable(config[CONF_ID])
await climate.register_climate(var, config)
sens = await cg.get_variable(config[CONF_SENSOR_ID])
cg.add(var.init(sens, config[CONF_PIN]))

View file

@ -0,0 +1,130 @@
#include "electra_ac.h"
namespace esphome {
namespace electra_ac {
static const char *const TAG = "climate.electra_ac";
void ElectraClimate::init(sensor::Sensor *sensor, uint16_t pin) {
this->set_sensor(sensor);
ac_ = new IRElecrtaAC(pin);
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 = 24;
this->fan_mode = climate::CLIMATE_FAN_AUTO;
this->swing_mode = climate::CLIMATE_SWING_OFF;
this->preset = climate::CLIMATE_PRESET_NONE;
}
if (isnan(this->target_temperature)) {
this->target_temperature = 25;
}
ac_->begin();
this->setup_ir_cmd();
ESP_LOGD("DEBUG", "Electra A/C remote is in the following state:");
ESP_LOGD("DEBUG", " %s\n", ac_->toString().c_str());
}
void ElectraClimate::set_sensor(sensor::Sensor *sensor) { this->sensor_ = sensor; }
void ElectraClimate::setup_ir_cmd() {
if (this->mode == climate::CLIMATE_MODE_OFF) {
ac_->off();
} else {
ac_->on();
if (this->mode == climate::CLIMATE_MODE_AUTO) {
ac_->setMode(kElectraAcAuto);
} else if (this->mode == climate::CLIMATE_MODE_COOL) {
ac_->setMode(kElectraAcCool);
} else if (this->mode == climate::CLIMATE_MODE_HEAT) {
ac_->setMode(kElectraAcHeat);
} else if (this->mode == climate::CLIMATE_MODE_DRY) {
ac_->setMode(kElectraAcDry);
} else if (this->mode == climate::CLIMATE_MODE_FAN_ONLY) {
ac_->setMode(kElectraAcFan);
}
ac_->setTemp((uint8_t)this->target_temperature);
if (this->fan_mode == climate::CLIMATE_FAN_AUTO) {
ac_->setFan(kElectraAcFanAuto);
} else if (this->fan_mode == climate::CLIMATE_FAN_LOW) {
ac_->setFan(kElectraAcFanLow);
} else if (this->fan_mode == climate::CLIMATE_FAN_MEDIUM) {
ac_->setFan(kElectraAcFanMed);
} else if (this->fan_mode == climate::CLIMATE_FAN_HIGH) {
ac_->setFan(kElectraAcFanHigh);
}
if (this->swing_mode == climate::CLIMATE_SWING_OFF) {
ac_->setSwing(kElectraAcSwingOff);
} else if (this->swing_mode == climate::CLIMATE_SWING_ON) {
ac_->setSwing(kElectraAcSwingOn);
}
ac_->setSleep(this->preset == climate::CLIMATE_PRESET_SLEEP);
ac_->setHealth(this->preset == climate::CLIMATE_PRESET_COMFORT);
ac_->setTurbo(this->preset == climate::CLIMATE_PRESET_BOOST);
}
}
climate::ClimateTraits ElectraClimate::traits() {
auto traits = climate::ClimateTraits();
traits.set_supported_modes({climate::CLIMATE_MODE_OFF, climate::CLIMATE_MODE_COOL, climate::CLIMATE_MODE_HEAT,
climate::CLIMATE_MODE_FAN_ONLY, climate::CLIMATE_MODE_DRY, climate::CLIMATE_MODE_AUTO});
traits.set_supported_fan_modes(
{climate::CLIMATE_FAN_LOW, climate::CLIMATE_FAN_MEDIUM, climate::CLIMATE_FAN_HIGH, climate::CLIMATE_FAN_AUTO});
traits.set_supported_swing_modes({climate::CLIMATE_SWING_OFF, climate::CLIMATE_SWING_ON});
traits.set_supported_presets({climate::CLIMATE_PRESET_NONE, climate::CLIMATE_PRESET_SLEEP,
climate::CLIMATE_PRESET_COMFORT, climate::CLIMATE_PRESET_BOOST});
traits.set_visual_max_temperature(ELECTRA_AC_TEMP_MAX);
traits.set_visual_min_temperature(ELECTRA_AC_TEMP_MIN);
traits.set_visual_temperature_step(1);
traits.set_supports_current_temperature(true);
return traits;
}
void ElectraClimate::control(const climate::ClimateCall &call) {
if (call.get_mode().has_value())
this->mode = *call.get_mode();
if (call.get_target_temperature().has_value())
this->target_temperature = *call.get_target_temperature();
if (call.get_fan_mode().has_value())
this->fan_mode = *call.get_fan_mode();
if (call.get_swing_mode().has_value())
this->swing_mode = *call.get_swing_mode();
if (call.get_preset().has_value())
this->preset = *call.get_preset();
this->setup_ir_cmd();
ac_->send();
this->publish_state();
ESP_LOGD("DEBUG", "Electra A/C remote is in the following state:");
ESP_LOGD("DEBUG", " %s\n", ac_->toString().c_str());
}
} // namespace electra_ac
} // namespace esphome

View file

@ -0,0 +1,37 @@
#pragma once
#include "esphome/core/log.h"
#include "esphome/components/climate/climate.h"
#include "esphome/components/sensor/sensor.h"
#include "IRremoteESP8266.h"
#include "IRsend.h"
#include "ir_Electra.h"
namespace esphome {
namespace electra_ac {
const uint8_t ELECTRA_AC_TEMP_MIN = 16; // 16C
const uint8_t ELECTRA_AC_TEMP_MAX = 30; // 32C
class ElectraClimate : public climate::Climate {
public:
ElectraClimate() : climate::Climate() {}
public:
void set_sensor(sensor::Sensor *sensor);
void init(sensor::Sensor *sensor, uint16_t pin);
protected:
IRElecrtaAC *ac_{nullptr};
sensor::Sensor *sensor_{nullptr};
void setup_ir_cmd();
climate::ClimateTraits traits() override;
void control(const climate::ClimateCall &call) override;
};
} // namespace haier_acyrw02
} // namespace esphome

37
example.yaml Normal file
View file

@ -0,0 +1,37 @@
esphome:
name: electra-ac-ir-remote
esp8266:
board: esp01_1m
logger:
baud_rate: 0
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "electra-ac-ir-remote Fallback Hotspot"
password: "0000"
web_server:
port: 80
external_components:
- source:
type: git
url: https://git.dayanhub.com/sagi/esphome-electra-ac-ir
sensor:
# External temperature sensor from Home Assistant
- platform: homeassistant
id: current_temperature
entity_id: ${temperature_sensor}
climate:
- platform: electra_ac
sensor_id: current_temperature
pin: 3 # Pin with IR led
name: "Electra A/C"