mirror of
https://github.com/esphome/esphome.git
synced 2026-01-09 19:50:49 -07:00
[gree] turbo, light, health, xfan switches (#12160)
Co-authored-by: clydebarrow <2366188+clydebarrow@users.noreply.github.com>
This commit is contained in:
@@ -190,6 +190,7 @@ esphome/components/gps/* @coogle @ximex
|
||||
esphome/components/graph/* @synco
|
||||
esphome/components/graphical_display_menu/* @MrMDavidson
|
||||
esphome/components/gree/* @orestismers
|
||||
esphome/components/gree/switch/* @nagyrobi
|
||||
esphome/components/grove_gas_mc_v2/* @YorkshireIoT
|
||||
esphome/components/grove_tb6612fng/* @max246
|
||||
esphome/components/growatt_solar/* @leeuwte
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
import esphome.codegen as cg
|
||||
|
||||
gree_ns = cg.esphome_ns.namespace("gree")
|
||||
|
||||
@@ -3,11 +3,11 @@ from esphome.components import climate_ir
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import CONF_MODEL
|
||||
|
||||
from . import gree_ns
|
||||
|
||||
CODEOWNERS = ["@orestismers"]
|
||||
|
||||
AUTO_LOAD = ["climate_ir"]
|
||||
|
||||
gree_ns = cg.esphome_ns.namespace("gree")
|
||||
GreeClimate = gree_ns.class_("GreeClimate", climate_ir.ClimateIR)
|
||||
|
||||
Model = gree_ns.enum("Model")
|
||||
@@ -23,7 +23,7 @@ MODELS = {
|
||||
|
||||
CONFIG_SCHEMA = climate_ir.climate_ir_with_receiver_schema(GreeClimate).extend(
|
||||
{
|
||||
cv.Required(CONF_MODEL): cv.enum(MODELS),
|
||||
cv.Required(CONF_MODEL): cv.enum(MODELS, lower=True),
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@@ -16,13 +16,28 @@ void GreeClimate::set_model(Model model) {
|
||||
this->model_ = model;
|
||||
}
|
||||
|
||||
void GreeClimate::set_mode_bit(uint8_t bit_mask, bool enabled) {
|
||||
if (enabled) {
|
||||
this->mode_bits_ |= bit_mask;
|
||||
} else {
|
||||
this->mode_bits_ &= ~bit_mask;
|
||||
}
|
||||
this->transmit_state();
|
||||
}
|
||||
|
||||
void GreeClimate::transmit_state() {
|
||||
uint8_t remote_state[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00};
|
||||
|
||||
remote_state[0] = this->fan_speed_() | this->operation_mode_();
|
||||
remote_state[1] = this->temperature_();
|
||||
|
||||
if (this->model_ == GREE_YAN || this->model_ == GREE_YX1FF || this->model_ == GREE_YAG) {
|
||||
if (this->model_ == GREE_YAN) {
|
||||
remote_state[2] = 0x20; // bits 0..3 always 0000, bits 4..7 TURBO, LIGHT, HEALTH, X-FAN
|
||||
remote_state[3] = 0x50; // bits 4..7 always 0101
|
||||
remote_state[4] = this->vertical_swing_();
|
||||
}
|
||||
|
||||
if (this->model_ == GREE_YX1FF || this->model_ == GREE_YAG) {
|
||||
remote_state[2] = 0x60;
|
||||
remote_state[3] = 0x50;
|
||||
remote_state[4] = this->vertical_swing_();
|
||||
@@ -41,7 +56,7 @@ void GreeClimate::transmit_state() {
|
||||
}
|
||||
|
||||
if (this->model_ == GREE_YAA || this->model_ == GREE_YAC || this->model_ == GREE_YAC1FB9) {
|
||||
remote_state[2] = 0x20; // bits 0..3 always 0000, bits 4..7 TURBO,LIGHT,HEALTH,X-FAN
|
||||
remote_state[2] = 0x20; // bits 0..3 always 0000, bits 4..7 TURBO, LIGHT, HEALTH, X-FAN
|
||||
remote_state[3] = 0x50; // bits 4..7 always 0101
|
||||
remote_state[6] = 0x20; // YAA1FB, FAA1FB1, YB1F2 bits 4..7 always 0010
|
||||
|
||||
@@ -52,6 +67,13 @@ void GreeClimate::transmit_state() {
|
||||
}
|
||||
}
|
||||
|
||||
if (this->model_ == GREE_YAN || this->model_ == GREE_YAA || this->model_ == GREE_YAC ||
|
||||
this->model_ == GREE_YAC1FB9) {
|
||||
// Merge the mode bits into remote_state[2]
|
||||
// Clear the mode bits (bits 4-7) and OR in the current mode_bits_
|
||||
remote_state[2] = (remote_state[2] & 0x0F) | this->mode_bits_;
|
||||
}
|
||||
|
||||
if (this->model_ == GREE_YX1FF) {
|
||||
if (this->fan_speed_() == GREE_FAN_TURBO) {
|
||||
remote_state[2] |= GREE_FAN_TURBO_BIT;
|
||||
|
||||
@@ -2,80 +2,79 @@
|
||||
|
||||
#include "esphome/components/climate_ir/climate_ir.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace gree {
|
||||
namespace esphome::gree {
|
||||
|
||||
// Values for GREE IR Controllers
|
||||
// Temperature
|
||||
const uint8_t GREE_TEMP_MIN = 16; // Celsius
|
||||
const uint8_t GREE_TEMP_MAX = 30; // Celsius
|
||||
static constexpr uint8_t GREE_TEMP_MIN = 16; // Celsius
|
||||
static constexpr uint8_t GREE_TEMP_MAX = 30; // Celsius
|
||||
|
||||
// Modes
|
||||
const uint8_t GREE_MODE_AUTO = 0x00;
|
||||
const uint8_t GREE_MODE_COOL = 0x01;
|
||||
const uint8_t GREE_MODE_HEAT = 0x04;
|
||||
const uint8_t GREE_MODE_DRY = 0x02;
|
||||
const uint8_t GREE_MODE_FAN = 0x03;
|
||||
static constexpr uint8_t GREE_MODE_AUTO = 0x00;
|
||||
static constexpr uint8_t GREE_MODE_COOL = 0x01;
|
||||
static constexpr uint8_t GREE_MODE_HEAT = 0x04;
|
||||
static constexpr uint8_t GREE_MODE_DRY = 0x02;
|
||||
static constexpr uint8_t GREE_MODE_FAN = 0x03;
|
||||
|
||||
const uint8_t GREE_MODE_OFF = 0x00;
|
||||
const uint8_t GREE_MODE_ON = 0x08;
|
||||
static constexpr uint8_t GREE_MODE_OFF = 0x00;
|
||||
static constexpr uint8_t GREE_MODE_ON = 0x08;
|
||||
|
||||
// Fan Speed
|
||||
const uint8_t GREE_FAN_AUTO = 0x00;
|
||||
const uint8_t GREE_FAN_1 = 0x10;
|
||||
const uint8_t GREE_FAN_2 = 0x20;
|
||||
const uint8_t GREE_FAN_3 = 0x30;
|
||||
static constexpr uint8_t GREE_FAN_AUTO = 0x00;
|
||||
static constexpr uint8_t GREE_FAN_1 = 0x10;
|
||||
static constexpr uint8_t GREE_FAN_2 = 0x20;
|
||||
static constexpr uint8_t GREE_FAN_3 = 0x30;
|
||||
|
||||
// IR Transmission
|
||||
const uint32_t GREE_IR_FREQUENCY = 38000;
|
||||
const uint32_t GREE_HEADER_MARK = 9000;
|
||||
const uint32_t GREE_HEADER_SPACE = 4000;
|
||||
const uint32_t GREE_BIT_MARK = 620;
|
||||
const uint32_t GREE_ONE_SPACE = 1600;
|
||||
const uint32_t GREE_ZERO_SPACE = 540;
|
||||
const uint32_t GREE_MESSAGE_SPACE = 19000;
|
||||
static constexpr uint32_t GREE_IR_FREQUENCY = 38000;
|
||||
static constexpr uint32_t GREE_HEADER_MARK = 9000;
|
||||
static constexpr uint32_t GREE_HEADER_SPACE = 4000;
|
||||
static constexpr uint32_t GREE_BIT_MARK = 620;
|
||||
static constexpr uint32_t GREE_ONE_SPACE = 1600;
|
||||
static constexpr uint32_t GREE_ZERO_SPACE = 540;
|
||||
static constexpr uint32_t GREE_MESSAGE_SPACE = 19000;
|
||||
|
||||
// Timing specific for YAC features (I-Feel mode)
|
||||
const uint32_t GREE_YAC_HEADER_MARK = 6000;
|
||||
const uint32_t GREE_YAC_HEADER_SPACE = 3000;
|
||||
const uint32_t GREE_YAC_BIT_MARK = 650;
|
||||
static constexpr uint32_t GREE_YAC_HEADER_MARK = 6000;
|
||||
static constexpr uint32_t GREE_YAC_HEADER_SPACE = 3000;
|
||||
static constexpr uint32_t GREE_YAC_BIT_MARK = 650;
|
||||
|
||||
// Timing specific to YAC1FB9
|
||||
const uint32_t GREE_YAC1FB9_HEADER_SPACE = 4500;
|
||||
const uint32_t GREE_YAC1FB9_MESSAGE_SPACE = 19980;
|
||||
static constexpr uint32_t GREE_YAC1FB9_HEADER_SPACE = 4500;
|
||||
static constexpr uint32_t GREE_YAC1FB9_MESSAGE_SPACE = 19980;
|
||||
|
||||
// State Frame size
|
||||
const uint8_t GREE_STATE_FRAME_SIZE = 8;
|
||||
static constexpr uint8_t GREE_STATE_FRAME_SIZE = 8;
|
||||
|
||||
// Only available on YAN
|
||||
// Vertical air directions. Note that these cannot be set on all heat pumps
|
||||
const uint8_t GREE_VDIR_AUTO = 0x00;
|
||||
const uint8_t GREE_VDIR_MANUAL = 0x00;
|
||||
const uint8_t GREE_VDIR_SWING = 0x01;
|
||||
const uint8_t GREE_VDIR_UP = 0x02;
|
||||
const uint8_t GREE_VDIR_MUP = 0x03;
|
||||
const uint8_t GREE_VDIR_MIDDLE = 0x04;
|
||||
const uint8_t GREE_VDIR_MDOWN = 0x05;
|
||||
const uint8_t GREE_VDIR_DOWN = 0x06;
|
||||
static constexpr uint8_t GREE_VDIR_AUTO = 0x00;
|
||||
static constexpr uint8_t GREE_VDIR_MANUAL = 0x00;
|
||||
static constexpr uint8_t GREE_VDIR_SWING = 0x01;
|
||||
static constexpr uint8_t GREE_VDIR_UP = 0x02;
|
||||
static constexpr uint8_t GREE_VDIR_MUP = 0x03;
|
||||
static constexpr uint8_t GREE_VDIR_MIDDLE = 0x04;
|
||||
static constexpr uint8_t GREE_VDIR_MDOWN = 0x05;
|
||||
static constexpr uint8_t GREE_VDIR_DOWN = 0x06;
|
||||
|
||||
// Only available on YAC/YAG
|
||||
// Horizontal air directions. Note that these cannot be set on all heat pumps
|
||||
const uint8_t GREE_HDIR_AUTO = 0x00;
|
||||
const uint8_t GREE_HDIR_MANUAL = 0x00;
|
||||
const uint8_t GREE_HDIR_SWING = 0x01;
|
||||
const uint8_t GREE_HDIR_LEFT = 0x02;
|
||||
const uint8_t GREE_HDIR_MLEFT = 0x03;
|
||||
const uint8_t GREE_HDIR_MIDDLE = 0x04;
|
||||
const uint8_t GREE_HDIR_MRIGHT = 0x05;
|
||||
const uint8_t GREE_HDIR_RIGHT = 0x06;
|
||||
static constexpr uint8_t GREE_HDIR_AUTO = 0x00;
|
||||
static constexpr uint8_t GREE_HDIR_MANUAL = 0x00;
|
||||
static constexpr uint8_t GREE_HDIR_SWING = 0x01;
|
||||
static constexpr uint8_t GREE_HDIR_LEFT = 0x02;
|
||||
static constexpr uint8_t GREE_HDIR_MLEFT = 0x03;
|
||||
static constexpr uint8_t GREE_HDIR_MIDDLE = 0x04;
|
||||
static constexpr uint8_t GREE_HDIR_MRIGHT = 0x05;
|
||||
static constexpr uint8_t GREE_HDIR_RIGHT = 0x06;
|
||||
|
||||
// Only available on YX1FF
|
||||
// Turbo (high) fan mode + sleep preset mode
|
||||
const uint8_t GREE_FAN_TURBO = 0x80;
|
||||
const uint8_t GREE_FAN_TURBO_BIT = 0x10;
|
||||
const uint8_t GREE_PRESET_NONE = 0x00;
|
||||
const uint8_t GREE_PRESET_SLEEP = 0x01;
|
||||
const uint8_t GREE_PRESET_SLEEP_BIT = 0x80;
|
||||
static constexpr uint8_t GREE_FAN_TURBO = 0x80;
|
||||
static constexpr uint8_t GREE_FAN_TURBO_BIT = 0x10;
|
||||
static constexpr uint8_t GREE_PRESET_NONE = 0x00;
|
||||
static constexpr uint8_t GREE_PRESET_SLEEP = 0x01;
|
||||
static constexpr uint8_t GREE_PRESET_SLEEP_BIT = 0x80;
|
||||
|
||||
// Model codes
|
||||
enum Model { GREE_GENERIC, GREE_YAN, GREE_YAA, GREE_YAC, GREE_YAC1FB9, GREE_YX1FF, GREE_YAG };
|
||||
@@ -90,6 +89,7 @@ class GreeClimate : public climate_ir::ClimateIR {
|
||||
climate::CLIMATE_SWING_HORIZONTAL, climate::CLIMATE_SWING_BOTH}) {}
|
||||
|
||||
void set_model(Model model);
|
||||
void set_mode_bit(uint8_t bit_mask, bool enabled);
|
||||
|
||||
protected:
|
||||
// Transmit via IR the state of this climate controller.
|
||||
@@ -103,7 +103,7 @@ class GreeClimate : public climate_ir::ClimateIR {
|
||||
uint8_t preset_();
|
||||
|
||||
Model model_{};
|
||||
uint8_t mode_bits_{0}; // Combined mode bits for remote_state[2]
|
||||
};
|
||||
|
||||
} // namespace gree
|
||||
} // namespace esphome
|
||||
} // namespace esphome::gree
|
||||
|
||||
74
esphome/components/gree/switch/__init__.py
Normal file
74
esphome/components/gree/switch/__init__.py
Normal file
@@ -0,0 +1,74 @@
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import switch
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import CONF_LIGHT, DEVICE_CLASS_SWITCH, ENTITY_CATEGORY_CONFIG
|
||||
import esphome.final_validate as fv
|
||||
|
||||
from .. import gree_ns
|
||||
from ..climate import CONF_MODEL, GreeClimate
|
||||
|
||||
CODEOWNERS = ["@nagyrobi"]
|
||||
|
||||
GreeModeBitSwitch = gree_ns.class_("GreeModeBitSwitch", switch.Switch, cg.Component)
|
||||
|
||||
CONF_TURBO = "turbo"
|
||||
CONF_HEALTH = "health"
|
||||
CONF_XFAN = "xfan"
|
||||
CONF_GREE_ID = "gree_id"
|
||||
|
||||
# Switch configurations: (config_key, display_name, bit_mask, icon)
|
||||
SWITCH_CONFIGS = (
|
||||
(CONF_TURBO, "Gree Turbo Switch", 0x10, "mdi:car-turbocharger"),
|
||||
(CONF_LIGHT, "Gree Light Switch", 0x20, "mdi:led-outline"),
|
||||
(CONF_HEALTH, "Gree Health Switch", 0x40, "mdi:pine-tree"),
|
||||
(CONF_XFAN, "Gree X-FAN Switch", 0x80, "mdi:wall-sconce-flat"),
|
||||
)
|
||||
|
||||
SUPPORTED_MODELS = {
|
||||
"yan",
|
||||
"yaa",
|
||||
"yac",
|
||||
"yac1fb9",
|
||||
}
|
||||
|
||||
CONFIG_SCHEMA = cv.Schema(
|
||||
{
|
||||
cv.Required(CONF_GREE_ID): cv.use_id(GreeClimate),
|
||||
**{
|
||||
cv.Optional(key): switch.switch_schema(
|
||||
GreeModeBitSwitch,
|
||||
icon=icon,
|
||||
default_restore_mode="RESTORE_DEFAULT_OFF",
|
||||
device_class=DEVICE_CLASS_SWITCH,
|
||||
entity_category=ENTITY_CATEGORY_CONFIG,
|
||||
)
|
||||
for key, _, _, icon in SWITCH_CONFIGS
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def _validate_model(config):
|
||||
full_config = fv.full_config.get()
|
||||
climate_path = full_config.get_path_for_id(config[CONF_GREE_ID])[:-1]
|
||||
climate_conf = full_config.get_config_for_path(climate_path)
|
||||
if climate_conf[CONF_MODEL] not in SUPPORTED_MODELS:
|
||||
raise cv.Invalid(
|
||||
"Gree switches are only supported for the "
|
||||
+ ", ".join(SUPPORTED_MODELS)
|
||||
+ " models"
|
||||
)
|
||||
|
||||
|
||||
FINAL_VALIDATE_SCHEMA = _validate_model
|
||||
|
||||
|
||||
async def to_code(config):
|
||||
parent = await cg.get_variable(config[CONF_GREE_ID])
|
||||
|
||||
for conf_key, name, bit_mask, _ in SWITCH_CONFIGS:
|
||||
if switch_conf := config.get(conf_key):
|
||||
sw = cg.new_Pvariable(switch_conf[cv.CONF_ID], name, bit_mask)
|
||||
await switch.register_switch(sw, switch_conf)
|
||||
await cg.register_component(sw, switch_conf)
|
||||
await cg.register_parented(sw, parent)
|
||||
24
esphome/components/gree/switch/gree_switch.cpp
Normal file
24
esphome/components/gree/switch/gree_switch.cpp
Normal file
@@ -0,0 +1,24 @@
|
||||
#include "gree_switch.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace gree {
|
||||
|
||||
static const char *const TAG = "gree.switch";
|
||||
|
||||
void GreeModeBitSwitch::setup() {
|
||||
auto initial = this->get_initial_state_with_restore_mode();
|
||||
if (initial.has_value()) {
|
||||
this->write_state(*initial);
|
||||
}
|
||||
}
|
||||
|
||||
void GreeModeBitSwitch::dump_config() { log_switch(TAG, " ", this->name_, this); }
|
||||
|
||||
void GreeModeBitSwitch::write_state(bool state) {
|
||||
this->parent_->set_mode_bit(this->bit_mask_, state);
|
||||
this->publish_state(state);
|
||||
}
|
||||
|
||||
} // namespace gree
|
||||
} // namespace esphome
|
||||
24
esphome/components/gree/switch/gree_switch.h
Normal file
24
esphome/components/gree/switch/gree_switch.h
Normal file
@@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/components/switch/switch.h"
|
||||
#include "esphome/components/gree/gree.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace gree {
|
||||
|
||||
class GreeModeBitSwitch : public switch_::Switch, public Component, public Parented<GreeClimate> {
|
||||
public:
|
||||
GreeModeBitSwitch(const char *name, uint8_t bit_mask) : name_(name), bit_mask_(bit_mask) {}
|
||||
|
||||
void setup() override;
|
||||
void dump_config() override;
|
||||
void write_state(bool state) override;
|
||||
|
||||
protected:
|
||||
const char *name_;
|
||||
uint8_t bit_mask_;
|
||||
};
|
||||
|
||||
} // namespace gree
|
||||
} // namespace esphome
|
||||
@@ -1,5 +1,18 @@
|
||||
climate:
|
||||
- platform: gree
|
||||
name: GREE
|
||||
model: generic
|
||||
id: my_gree_ac
|
||||
model: YAN
|
||||
transmitter_id: xmitr
|
||||
|
||||
switch:
|
||||
- platform: gree
|
||||
gree_id: my_gree_ac
|
||||
light:
|
||||
name: "AC Lights"
|
||||
turbo:
|
||||
name: "AC Turbo"
|
||||
health:
|
||||
name: "AC Health"
|
||||
xfan:
|
||||
name: "AC X-Fan"
|
||||
|
||||
Reference in New Issue
Block a user