Initial commit - hard fork
This commit is contained in:
commit
7bf9657e24
7 changed files with 298 additions and 0 deletions
22
LICENSE
Normal file
22
LICENSE
Normal 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
43
README.md
Normal 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"
|
||||||
|
```
|
0
components/electra_ac/__init__.py
Normal file
0
components/electra_ac/__init__.py
Normal file
29
components/electra_ac/climate.py
Normal file
29
components/electra_ac/climate.py
Normal 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]))
|
130
components/electra_ac/electra_ac.cpp
Normal file
130
components/electra_ac/electra_ac.cpp
Normal 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 IRElectraAc(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
|
37
components/electra_ac/electra_ac.h
Normal file
37
components/electra_ac/electra_ac.h
Normal 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:
|
||||||
|
IRElectraAc *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
37
example.yaml
Normal 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"
|
Loading…
Reference in a new issue