[haier_tundra] New Climate IR component (#20469)

Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
Co-authored-by: J. Nick Koston <nick@koston.org>
Co-authored-by: J. Nick Koston <nick@home-assistant.io>
This commit is contained in:
Ryan
2026-10-13 08:10:36 -10:00
committed by GitHub
co-authored by pre-commit-ci-lite[bot] J. Nick Koston J. Nick Koston
parent 95766ed3ad
commit 40271fb597
14 changed files with 723 additions and 0 deletions
+3
View File
@@ -243,6 +243,9 @@ esphome/components/haier/button/* @paveldn
esphome/components/haier/sensor/* @paveldn
esphome/components/haier/switch/* @paveldn
esphome/components/haier/text_sensor/* @paveldn
esphome/components/haier_tundra/* @fauxpark
esphome/components/haier_tundra/button/* @fauxpark
esphome/components/haier_tundra/switch/* @fauxpark
esphome/components/havells_solar/* @sourabhjaiswal
esphome/components/hbridge/fan/* @WeekendWarrior
esphome/components/hbridge/light/* @DotNetDann
@@ -0,0 +1,2 @@
DOMAIN = "haier_tundra"
CODEOWNERS = ["@fauxpark"]
@@ -0,0 +1,43 @@
import esphome.codegen as cg
from esphome.components import button
import esphome.config_validation as cv
from esphome.const import CONF_LIGHT
from esphome.types import ConfigType
from ..climate import HaierTundra, haier_tundra_ns
CODEOWNERS = ["@fauxpark"]
HaierTundraButton = haier_tundra_ns.class_(
"HaierTundraButton", button.Button, cg.Component
)
ButtonKind = haier_tundra_ns.enum("ButtonKind", is_class=True)
ICON_LED_OUTLINE = "mdi:led-outline"
ICON_SPRAY_BOTTLE = "mdi:spray-bottle"
CONF_HAIER_TUNDRA_ID = "haier_tundra_id"
CONF_SELF_CLEAN = "self_clean"
CONFIG_SCHEMA = cv.Schema(
{
cv.Required(CONF_HAIER_TUNDRA_ID): cv.use_id(HaierTundra),
cv.Optional(CONF_LIGHT): button.button_schema(
HaierTundraButton, icon=ICON_LED_OUTLINE
),
cv.Optional(CONF_SELF_CLEAN): button.button_schema(
HaierTundraButton, icon=ICON_SPRAY_BOTTLE
),
}
)
async def to_code(config: ConfigType) -> None:
hub = await cg.get_variable(config[CONF_HAIER_TUNDRA_ID])
for key, kind in (
(CONF_LIGHT, ButtonKind.BUTTON_KIND_LIGHT),
(CONF_SELF_CLEAN, ButtonKind.BUTTON_KIND_SELF_CLEAN),
):
if (conf := config.get(key)) is not None:
var = await button.new_button(conf, hub, kind)
await cg.register_component(var, conf)
@@ -0,0 +1,18 @@
#include "haier_tundra_button.h"
#include "esphome/core/log.h"
namespace esphome::haier_tundra {
ESPHOME_LOG_TAG(TAG, "haier_tundra.button");
void HaierTundraButton::dump_config() { LOG_BUTTON("", "Haier Tundra Button", this); }
void HaierTundraButton::press_action() {
if (this->kind_ == ButtonKind::BUTTON_KIND_LIGHT) {
this->parent_->toggle_light();
} else {
this->parent_->start_self_clean();
}
}
} // namespace esphome::haier_tundra
@@ -0,0 +1,25 @@
#pragma once
#include "esphome/core/component.h"
#include "esphome/components/button/button.h"
#include "esphome/components/haier_tundra/haier_tundra.h"
namespace esphome::haier_tundra {
enum class ButtonKind : uint8_t {
BUTTON_KIND_LIGHT,
BUTTON_KIND_SELF_CLEAN,
};
class HaierTundraButton final : public button::Button, public Component, public Parented<HaierTundra> {
public:
HaierTundraButton(HaierTundra *parent, ButtonKind kind) : Parented(parent), kind_(kind) {}
void dump_config() override;
protected:
void press_action() override;
ButtonKind kind_;
};
} // namespace esphome::haier_tundra
@@ -0,0 +1,51 @@
import esphome.codegen as cg
from esphome.components import climate_ir, remote_base
import esphome.config_validation as cv
from esphome.const import CONF_ID, CONF_PLATFORM
import esphome.final_validate as fv
from esphome.types import ConfigType
AUTO_LOAD = ["climate_ir"]
haier_tundra_ns = cg.esphome_ns.namespace("haier_tundra")
HaierTundra = haier_tundra_ns.class_("HaierTundra", climate_ir.ClimateIR)
CONF_UNIT = "unit"
Unit = haier_tundra_ns.enum("Unit")
UNITS = {
"a": Unit.HAIER_HEADER_UNIT_A,
"b": Unit.HAIER_HEADER_UNIT_B,
}
CONFIG_SCHEMA = climate_ir.climate_ir_with_receiver_schema(HaierTundra).extend(
{
cv.Optional(CONF_UNIT, default="a"): cv.enum(UNITS, lower=True),
}
)
def _final_validate_unit(config: ConfigType) -> None:
# Each transmitter may drive at most one unit A and one unit B
climates = fv.full_config.get()["climate"]
seen = set()
for climate in climates:
if CONF_PLATFORM in climate and climate[CONF_PLATFORM] == "haier_tundra":
unit_tx_pair = (
climate[CONF_UNIT],
climate[remote_base.CONF_TRANSMITTER_ID],
)
if unit_tx_pair in seen and climate[CONF_ID] == config[CONF_ID]:
raise cv.Invalid(
"Only one of each unit is allowed per transmitter", path=[CONF_UNIT]
)
seen.add(unit_tx_pair)
FINAL_VALIDATE_SCHEMA = _final_validate_unit
async def to_code(config: ConfigType) -> None:
remote_base.request_protocol("haier")
await climate_ir.new_climate_ir(config, config[CONF_UNIT])
@@ -0,0 +1,260 @@
#include "haier_tundra.h"
namespace esphome::haier_tundra {
// Number of bytes in decoded packet sans checksum
static constexpr uint8_t HAIER_TUNDRA_FRAME_SIZE = 13;
void HaierTundra::transmit_state() {
// Button value does not seem to matter too much except
// when toggling light, as it has no bit flag of its own
// So in the default case we can simply set it to POWER
this->transmit_(HAIER_BUTTON_POWER);
}
void HaierTundra::transmit_(uint8_t button) {
// Force Quiet and Turbo off if we're not in Cool or Heat mode
if (this->mode != climate::CLIMATE_MODE_COOL && this->mode != climate::CLIMATE_MODE_HEAT) {
#ifdef USE_SWITCH
if (this->quiet_mode_switch_ != nullptr) {
this->quiet_mode_switch_->publish_state(false);
}
if (this->turbo_mode_switch_ != nullptr) {
this->turbo_mode_switch_->publish_state(false);
}
#endif
this->quiet_mode_ = false;
this->turbo_mode_ = false;
}
remote_base::HaierData remote_state{{
this->unit_,
static_cast<uint8_t>(this->temperature_() << 4 | this->vertical_swing_()),
static_cast<uint8_t>(this->horizontal_swing_() << 5),
static_cast<uint8_t>(this->health_() << 1),
static_cast<uint8_t>(this->power_() << 6),
static_cast<uint8_t>(this->fan_speed_() << 5),
static_cast<uint8_t>(this->quiet_() << 7 | this->turbo_() << 6),
static_cast<uint8_t>(this->operation_mode_() << 5),
0x00,
0x00,
static_cast<uint8_t>((button == HAIER_BUTTON_SELF_CLEAN ? 1 : 0) << 4),
0x00,
button,
}};
auto transmit = this->transmitter_->transmit();
remote_base::HaierProtocol().encode(transmit.get_data(), remote_state);
transmit.perform();
}
uint8_t HaierTundra::temperature_() {
return (uint8_t) roundf(clamp<float>(this->target_temperature, HAIER_TEMP_MIN, HAIER_TEMP_MAX)) - HAIER_TEMP_MIN;
}
uint8_t HaierTundra::vertical_swing_() {
if (this->mode == climate::CLIMATE_MODE_OFF) {
return HAIER_SWING_V_OFF;
}
switch (this->swing_mode) {
case climate::CLIMATE_SWING_VERTICAL:
case climate::CLIMATE_SWING_BOTH:
return HAIER_SWING_V_AUTO;
default:
if (this->mode == climate::CLIMATE_MODE_HEAT) {
return HAIER_SWING_V_1BOT;
}
return HAIER_SWING_V_1TOP; // Cool/Dry/Auto
}
}
uint8_t HaierTundra::horizontal_swing_() {
switch (this->swing_mode) {
case climate::CLIMATE_SWING_HORIZONTAL:
case climate::CLIMATE_SWING_BOTH:
return HAIER_SWING_H_AUTO;
default:
return HAIER_SWING_H_MIDDLE;
}
}
uint8_t HaierTundra::health_() { return this->health_mode_ ? 1 : 0; }
uint8_t HaierTundra::power_() { return this->mode == climate::CLIMATE_MODE_OFF ? 0 : 1; }
uint8_t HaierTundra::fan_speed_() {
switch (this->fan_mode.value_or(climate::CLIMATE_FAN_ON)) {
case climate::CLIMATE_FAN_LOW:
return HAIER_FAN_LOW;
case climate::CLIMATE_FAN_MEDIUM:
return HAIER_FAN_MED;
case climate::CLIMATE_FAN_HIGH:
return HAIER_FAN_HIGH;
case climate::CLIMATE_FAN_AUTO:
default:
return HAIER_FAN_AUTO;
}
}
uint8_t HaierTundra::quiet_() { return this->quiet_mode_ ? 1 : 0; }
uint8_t HaierTundra::turbo_() { return this->turbo_mode_ ? 1 : 0; }
uint8_t HaierTundra::operation_mode_() {
switch (this->mode) {
case climate::CLIMATE_MODE_COOL:
return HAIER_MODE_COOL;
case climate::CLIMATE_MODE_DRY:
return HAIER_MODE_DRY;
case climate::CLIMATE_MODE_HEAT:
return HAIER_MODE_HEAT;
case climate::CLIMATE_MODE_FAN_ONLY:
return HAIER_MODE_FAN;
case climate::CLIMATE_MODE_HEAT_COOL:
default:
return HAIER_MODE_AUTO;
}
}
bool HaierTundra::on_receive(remote_base::RemoteReceiveData data) {
auto haier = remote_base::HaierProtocol().decode(data);
if (haier.has_value()) {
return this->on_haier_(*haier);
}
return false;
}
bool HaierTundra::on_haier_(const remote_base::HaierData &haier) {
// Verify frame length and header
if (haier.data.size() != HAIER_TUNDRA_FRAME_SIZE || haier.data[0] != this->unit_) {
return false;
}
this->target_temperature = this->get_temperature_(haier.data[1] >> 4);
this->swing_mode = this->get_swing_mode_(haier.data[1] & 0xF, haier.data[2] >> 5);
this->health_mode_ = haier.data[3] & 0x2;
this->mode = this->get_operation_mode_(haier.data[4] & 0x40, haier.data[7] >> 5);
this->fan_mode = this->get_fan_speed_(haier.data[5] >> 5);
this->quiet_mode_ = haier.data[6] & 0x80;
this->turbo_mode_ = haier.data[6] & 0x40;
#ifdef USE_SWITCH
if (this->health_mode_switch_ != nullptr) {
this->health_mode_switch_->publish_state(this->health_mode_);
}
if (this->quiet_mode_switch_ != nullptr) {
this->quiet_mode_switch_->publish_state(this->quiet_mode_);
}
if (this->turbo_mode_switch_ != nullptr) {
this->turbo_mode_switch_->publish_state(this->turbo_mode_);
}
#endif
this->publish_state();
return true;
}
float HaierTundra::get_temperature_(uint8_t temp) { return temp + HAIER_TEMP_MIN; }
climate::ClimateSwingMode HaierTundra::get_swing_mode_(uint8_t swing_v, uint8_t swing_h) {
if (swing_v == HAIER_SWING_V_AUTO) {
if (swing_h == HAIER_SWING_H_AUTO) {
return climate::CLIMATE_SWING_BOTH;
}
return climate::CLIMATE_SWING_VERTICAL;
} else if (swing_h == HAIER_SWING_H_AUTO) {
return climate::CLIMATE_SWING_HORIZONTAL;
}
return climate::CLIMATE_SWING_OFF;
}
climate::ClimateMode HaierTundra::get_operation_mode_(uint8_t power, uint8_t mode) {
if (!power) {
return climate::CLIMATE_MODE_OFF;
}
switch (mode) {
case HAIER_MODE_COOL:
return climate::CLIMATE_MODE_COOL;
case HAIER_MODE_DRY:
return climate::CLIMATE_MODE_DRY;
case HAIER_MODE_HEAT:
return climate::CLIMATE_MODE_HEAT;
case HAIER_MODE_FAN:
return climate::CLIMATE_MODE_FAN_ONLY;
case HAIER_MODE_AUTO:
default:
return climate::CLIMATE_MODE_HEAT_COOL;
}
}
climate::ClimateFanMode HaierTundra::get_fan_speed_(uint8_t fan) {
switch (fan) {
case HAIER_FAN_LOW:
return climate::CLIMATE_FAN_LOW;
case HAIER_FAN_MED:
return climate::CLIMATE_FAN_MEDIUM;
case HAIER_FAN_HIGH:
return climate::CLIMATE_FAN_HIGH;
case HAIER_FAN_AUTO:
default:
return climate::CLIMATE_FAN_AUTO;
}
}
void HaierTundra::set_health_mode(bool health, bool transmit) {
this->health_mode_ = health;
if (transmit && this->mode != climate::CLIMATE_MODE_OFF) {
this->transmit_(HAIER_BUTTON_HEALTH);
}
}
void HaierTundra::set_quiet_mode(bool quiet, bool transmit) {
// Quiet & Turbo cannot be enabled at the same time
if (quiet) {
#ifdef USE_SWITCH
if (this->turbo_mode_switch_ != nullptr) {
this->turbo_mode_switch_->publish_state(false);
}
#endif
this->turbo_mode_ = false;
}
this->quiet_mode_ = quiet;
if (transmit)
this->transmit_(HAIER_BUTTON_TURBO_QUIET);
}
void HaierTundra::set_turbo_mode(bool turbo, bool transmit) {
// Quiet & Turbo cannot be enabled at the same time
if (turbo) {
#ifdef USE_SWITCH
if (this->quiet_mode_switch_ != nullptr) {
this->quiet_mode_switch_->publish_state(false);
}
#endif
this->quiet_mode_ = false;
}
this->turbo_mode_ = turbo;
if (transmit)
this->transmit_(HAIER_BUTTON_TURBO_QUIET);
}
void HaierTundra::toggle_light() {
if (this->mode != climate::CLIMATE_MODE_OFF) {
this->transmit_(HAIER_BUTTON_LIGHT);
}
}
void HaierTundra::start_self_clean() {
// Can be started when off
this->transmit_(HAIER_BUTTON_SELF_CLEAN);
}
} // namespace esphome::haier_tundra
@@ -0,0 +1,139 @@
#pragma once
#include "esphome/components/climate_ir/climate_ir.h"
#include "esphome/components/remote_base/haier_protocol.h"
#ifdef USE_SWITCH
#include "esphome/components/switch/switch.h"
#endif
namespace esphome::haier_tundra {
// Byte 0 - Header value (Unit ID)
enum Unit : uint8_t {
HAIER_HEADER_UNIT_B = 0x59,
HAIER_HEADER_UNIT_A = 0xA6,
};
// Byte 1[7:4] - Temperature (˚C) 0x0..0xE
static constexpr uint8_t HAIER_TEMP_MIN = 16;
static constexpr uint8_t HAIER_TEMP_MAX = 30;
// Byte 1[3:0] - Vertical Swing
static constexpr uint8_t HAIER_SWING_V_OFF = 0x0; // Power off value; from Auto, stops at current position
static constexpr uint8_t HAIER_SWING_V_2TOP = 0x1; // [|/ ]
static constexpr uint8_t HAIER_SWING_V_1TOP = 0x2; // [| ] (Not available in Heat mode)
static constexpr uint8_t HAIER_SWING_V_2BOT = 0x3; // [ //]
static constexpr uint8_t HAIER_SWING_V_1BOT = 0xA; // [ /] (Heat mode only)
static constexpr uint8_t HAIER_SWING_V_AUTO = 0xC;
// Byte 2[7:5] - Horizontal Swing
static constexpr uint8_t HAIER_SWING_H_MIDDLE = 0x0; // [ || ]
static constexpr uint8_t HAIER_SWING_H_LEFT = 0x3; // [/ ]
static constexpr uint8_t HAIER_SWING_H_MIDDLE_LEFT = 0x4; // [ | ]
static constexpr uint8_t HAIER_SWING_H_MIDDLE_RIGHT = 0x5; // [ | ]
static constexpr uint8_t HAIER_SWING_H_RIGHT = 0x6; // [ \]
static constexpr uint8_t HAIER_SWING_H_AUTO = 0x7; // [/||\]
// Byte 3[7:5] - Timer Mode
static constexpr uint8_t HAIER_TIMER_MODE_DISABLED = 0x0;
static constexpr uint8_t HAIER_TIMER_MODE_OFF = 0x1; // OFF
static constexpr uint8_t HAIER_TIMER_MODE_ON = 0x2; // ON
static constexpr uint8_t HAIER_TIMER_MODE_ON_OFF = 0x4; // ON → OFF
static constexpr uint8_t HAIER_TIMER_MODE_OFF_ON = 0x5; // ON ← OFF
// Byte 3[1] - Health
// Byte 4[6] - Power
// Byte 5[7:5] - Fan Speed
static constexpr uint8_t HAIER_FAN_HIGH = 0x1;
static constexpr uint8_t HAIER_FAN_MED = 0x2;
static constexpr uint8_t HAIER_FAN_LOW = 0x3;
static constexpr uint8_t HAIER_FAN_AUTO = 0x5;
// Byte 5[4:0] - Timer Off Hours (0-23) 0x00..0x17
// Byte 6[7] - Quiet Mode
// Byte 6[6] - Turbo Mode
// Byte 6[5:0] - Timer Off Minutes (0-59) 0x00..0x3B
// Byte 7[7:5] - Mode
static constexpr uint8_t HAIER_MODE_AUTO = 0x0;
static constexpr uint8_t HAIER_MODE_COOL = 0x1;
static constexpr uint8_t HAIER_MODE_DRY = 0x2;
static constexpr uint8_t HAIER_MODE_HEAT = 0x4;
static constexpr uint8_t HAIER_MODE_FAN = 0x6;
// Byte 7[4:0] - Timer On Hours (0-23) 0x00..0x17
// Byte 8[7] - Sleep Mode
// Byte 8[5:0] - Timer On Minutes (0-59) 0x00..0x3B
// Byte 10[4] - Self Clean
// Byte 12 - Button
static constexpr uint8_t HAIER_BUTTON_TEMP_UP = 0x00;
static constexpr uint8_t HAIER_BUTTON_TEMP_DOWN = 0x01;
static constexpr uint8_t HAIER_BUTTON_SWING_V = 0x02;
static constexpr uint8_t HAIER_BUTTON_SWING_H = 0x03;
static constexpr uint8_t HAIER_BUTTON_FAN_SPEED = 0x04;
static constexpr uint8_t HAIER_BUTTON_POWER = 0x05;
static constexpr uint8_t HAIER_BUTTON_MODE = 0x06;
static constexpr uint8_t HAIER_BUTTON_HEALTH = 0x07;
static constexpr uint8_t HAIER_BUTTON_TURBO_QUIET = 0x08;
static constexpr uint8_t HAIER_BUTTON_SLEEP = 0x0B;
static constexpr uint8_t HAIER_BUTTON_TIMER = 0x10;
static constexpr uint8_t HAIER_BUTTON_LIGHT = 0x15;
static constexpr uint8_t HAIER_BUTTON_SELF_CLEAN = 0x19;
class HaierTundra final : public climate_ir::ClimateIR {
public:
explicit HaierTundra(Unit unit)
: climate_ir::ClimateIR(HAIER_TEMP_MIN, HAIER_TEMP_MAX, 1.0f, true, true,
{climate::CLIMATE_FAN_AUTO, climate::CLIMATE_FAN_LOW, climate::CLIMATE_FAN_MEDIUM,
climate::CLIMATE_FAN_HIGH},
{climate::CLIMATE_SWING_OFF, climate::CLIMATE_SWING_VERTICAL,
climate::CLIMATE_SWING_HORIZONTAL, climate::CLIMATE_SWING_BOTH}),
unit_(unit) {}
#ifdef USE_SWITCH
SUB_SWITCH(health_mode);
SUB_SWITCH(quiet_mode);
SUB_SWITCH(turbo_mode);
#endif
void set_health_mode(bool health, bool transmit = true);
void set_quiet_mode(bool quiet, bool transmit = true);
void set_turbo_mode(bool turbo, bool transmit = true);
void toggle_light();
void start_self_clean();
protected:
// Transmit via IR the state of this climate controller.
void transmit_state() override;
void transmit_(uint8_t button);
uint8_t temperature_();
uint8_t vertical_swing_();
uint8_t horizontal_swing_();
uint8_t health_();
uint8_t power_();
uint8_t fan_speed_();
uint8_t quiet_();
uint8_t turbo_();
uint8_t operation_mode_();
// Handle received IR Buffer
bool on_receive(remote_base::RemoteReceiveData data) override;
bool on_haier_(const remote_base::HaierData &haier);
float get_temperature_(uint8_t temp);
climate::ClimateSwingMode get_swing_mode_(uint8_t swing_v, uint8_t swing_h);
climate::ClimateMode get_operation_mode_(uint8_t power, uint8_t mode);
climate::ClimateFanMode get_fan_speed_(uint8_t fan);
Unit unit_;
bool health_mode_{false};
bool quiet_mode_{false};
bool turbo_mode_{false};
};
} // namespace esphome::haier_tundra
@@ -0,0 +1,60 @@
import esphome.codegen as cg
from esphome.components import switch
import esphome.config_validation as cv
from esphome.const import DEVICE_CLASS_SWITCH, ENTITY_CATEGORY_CONFIG
from esphome.types import ConfigType
from ..climate import HaierTundra, haier_tundra_ns
CODEOWNERS = ["@fauxpark"]
HaierTundraSwitch = haier_tundra_ns.class_(
"HaierTundraSwitch", switch.Switch, cg.Component
)
SwitchKind = haier_tundra_ns.enum("SwitchKind", is_class=True)
ICON_LEAF = "mdi:leaf"
ICON_ARROW_DOWN_RIGHT = "mdi:arrow-down-right"
ICON_ARROW_UP_RIGHT_BOLD = "mdi:arrow-up-right-bold"
CONF_HAIER_TUNDRA_ID = "haier_tundra_id"
CONF_HEALTH_MODE = "health_mode"
CONF_QUIET_MODE = "quiet_mode"
CONF_TURBO_MODE = "turbo_mode"
def _switch_schema(icon: str) -> cv.Schema:
return switch.switch_schema(
HaierTundraSwitch,
icon=icon,
default_restore_mode="RESTORE_DEFAULT_OFF",
device_class=DEVICE_CLASS_SWITCH,
entity_category=ENTITY_CATEGORY_CONFIG,
)
CONFIG_SCHEMA = cv.Schema(
{
cv.Required(CONF_HAIER_TUNDRA_ID): cv.use_id(HaierTundra),
cv.Optional(CONF_HEALTH_MODE): _switch_schema(ICON_LEAF),
cv.Optional(CONF_QUIET_MODE): _switch_schema(ICON_ARROW_DOWN_RIGHT),
cv.Optional(CONF_TURBO_MODE): _switch_schema(ICON_ARROW_UP_RIGHT_BOLD),
}
)
async def to_code(config: ConfigType) -> None:
hub = await cg.get_variable(config[CONF_HAIER_TUNDRA_ID])
switches = switch.sub_switches(config)
if sw := await switches(
CONF_HEALTH_MODE, hub.set_health_mode_switch, hub, SwitchKind.SWITCH_KIND_HEALTH
):
await cg.register_component(sw, config[CONF_HEALTH_MODE])
if sw := await switches(
CONF_QUIET_MODE, hub.set_quiet_mode_switch, hub, SwitchKind.SWITCH_KIND_QUIET
):
await cg.register_component(sw, config[CONF_QUIET_MODE])
if sw := await switches(
CONF_TURBO_MODE, hub.set_turbo_mode_switch, hub, SwitchKind.SWITCH_KIND_TURBO
):
await cg.register_component(sw, config[CONF_TURBO_MODE])
@@ -0,0 +1,43 @@
#include "haier_tundra_switch.h"
#include "esphome/core/log.h"
namespace esphome::haier_tundra {
ESPHOME_LOG_TAG(TAG, "haier_tundra.switch");
void HaierTundraSwitch::setup() {
auto initial = this->get_initial_state_with_restore_mode();
if (initial.has_value()) {
const bool state = initial.value();
this->apply_(state, false);
this->publish_state(state);
}
}
void HaierTundraSwitch::dump_config() { LOG_SWITCH("", "Haier Tundra Switch", this); }
void HaierTundraSwitch::write_state(bool state) {
// Quiet and Turbo can only be turned on in Cool or Heat mode
if (state && this->kind_ != SwitchKind::SWITCH_KIND_HEALTH && this->parent_->mode != climate::CLIMATE_MODE_COOL &&
this->parent_->mode != climate::CLIMATE_MODE_HEAT) {
return;
}
this->apply_(state, true);
this->publish_state(state);
}
void HaierTundraSwitch::apply_(bool state, bool transmit) {
switch (this->kind_) {
case SwitchKind::SWITCH_KIND_HEALTH:
this->parent_->set_health_mode(state, transmit);
break;
case SwitchKind::SWITCH_KIND_QUIET:
this->parent_->set_quiet_mode(state, transmit);
break;
case SwitchKind::SWITCH_KIND_TURBO:
this->parent_->set_turbo_mode(state, transmit);
break;
}
}
} // namespace esphome::haier_tundra
@@ -0,0 +1,28 @@
#pragma once
#include "esphome/core/component.h"
#include "esphome/components/switch/switch.h"
#include "esphome/components/haier_tundra/haier_tundra.h"
namespace esphome::haier_tundra {
enum class SwitchKind : uint8_t {
SWITCH_KIND_HEALTH,
SWITCH_KIND_QUIET,
SWITCH_KIND_TURBO,
};
class HaierTundraSwitch final : public switch_::Switch, public Component, public Parented<HaierTundra> {
public:
HaierTundraSwitch(HaierTundra *parent, SwitchKind kind) : Parented(parent), kind_(kind) {}
void setup() override;
void dump_config() override;
protected:
void write_state(bool state) override;
void apply_(bool state, bool transmit);
SwitchKind kind_;
};
} // namespace esphome::haier_tundra
+45
View File
@@ -0,0 +1,45 @@
climate:
- platform: haier_tundra
name: Haier AC A
id: my_haier_ac_a
transmitter_id: xmitr
- platform: haier_tundra
name: Haier AC B
id: my_haier_ac_b
transmitter_id: xmitr
unit: b
switch:
- platform: haier_tundra
haier_tundra_id: my_haier_ac_a
quiet_mode:
name: "Quiet Mode (Unit A)"
turbo_mode:
name: "Turbo Mode (Unit A)"
health_mode:
name: "Health Mode (Unit A)"
- platform: haier_tundra
haier_tundra_id: my_haier_ac_b
quiet_mode:
name: "Quiet Mode (Unit B)"
turbo_mode:
name: "Turbo Mode (Unit B)"
health_mode:
name: "Health Mode (Unit B)"
button:
- platform: haier_tundra
haier_tundra_id: my_haier_ac_a
light:
name: "Toggle Light (Unit A)"
self_clean:
name: "Start Self Clean (Unit A)"
- platform: haier_tundra
haier_tundra_id: my_haier_ac_b
light:
name: "Toggle Light (Unit B)"
self_clean:
name: "Start Self Clean (Unit B)"
@@ -0,0 +1,3 @@
packages:
remote_transmitter: !include ../../test_build_components/common/remote_transmitter/esp32-idf.yaml
haier_tundra: !include common.yaml
@@ -0,0 +1,3 @@
packages:
remote_transmitter: !include ../../test_build_components/common/remote_transmitter/esp8266-ard.yaml
haier_tundra: !include common.yaml