mirror of
https://github.com/esphome/esphome.git
synced 2024-11-30 18:54:14 +01:00
Add switches for sleep mode and light, update tests
This commit is contained in:
parent
83df28fc9a
commit
05e87edcd4
13 changed files with 253 additions and 2 deletions
|
@ -6,6 +6,45 @@ namespace airton {
|
||||||
|
|
||||||
static const char *const TAG = "airton.climate";
|
static const char *const TAG = "airton.climate";
|
||||||
|
|
||||||
|
void AirtonClimate::set_sleep_state(bool state) {
|
||||||
|
if (state != this->settings_.sleep_state) {
|
||||||
|
this->settings_.sleep_state = state;
|
||||||
|
#ifdef USE_SWITCH
|
||||||
|
this->sleep_switch_->publish_state(state);
|
||||||
|
#endif
|
||||||
|
this->airton_rtc_.save(&this->settings_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AirtonClimate::get_sleep_state() const { return this->settings_.sleep_state; }
|
||||||
|
|
||||||
|
void AirtonClimate::set_display_state(bool state) {
|
||||||
|
if (state != this->settings_.display_state) {
|
||||||
|
this->settings_.display_state = state;
|
||||||
|
#ifdef USE_SWITCH
|
||||||
|
this->display_switch_->publish_state(state);
|
||||||
|
#endif
|
||||||
|
this->airton_rtc_.save(&this->settings_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AirtonClimate::get_display_state() const { return this->settings_.display_state; }
|
||||||
|
|
||||||
|
#ifdef USE_SWITCH
|
||||||
|
void AirtonClimate::set_sleep_switch(switch_::Switch *sw) {
|
||||||
|
this->sleep_switch_ = sw;
|
||||||
|
if (this->sleep_switch_ != nullptr) {
|
||||||
|
this->sleep_switch_->publish_state(this->get_sleep_state());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void AirtonClimate::set_display_switch(switch_::Switch *sw) {
|
||||||
|
this->display_switch_ = sw;
|
||||||
|
if (this->display_switch_ != nullptr) {
|
||||||
|
this->display_switch_->publish_state(this->get_display_state());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // USE_SWITCH
|
||||||
|
|
||||||
uint8_t AirtonClimate::get_previous_mode_() { return previous_mode_; }
|
uint8_t AirtonClimate::get_previous_mode_() { return previous_mode_; }
|
||||||
|
|
||||||
void AirtonClimate::set_previous_mode_(uint8_t mode) { previous_mode_ = mode; }
|
void AirtonClimate::set_previous_mode_(uint8_t mode) { previous_mode_ = mode; }
|
||||||
|
@ -115,7 +154,6 @@ bool AirtonClimate::turbo_control_() {
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t AirtonClimate::temperature_() {
|
uint8_t AirtonClimate::temperature_() {
|
||||||
// Force 20C degrees in Fan only mode
|
|
||||||
switch (this->mode) {
|
switch (this->mode) {
|
||||||
case climate::CLIMATE_MODE_HEAT_COOL:
|
case climate::CLIMATE_MODE_HEAT_COOL:
|
||||||
// Fixed 25C setpoint in Auto mode
|
// Fixed 25C setpoint in Auto mode
|
||||||
|
@ -146,7 +184,13 @@ uint8_t AirtonClimate::operation_settings_() {
|
||||||
if (this->mode == climate::CLIMATE_MODE_HEAT) { // Set heating bit if on the corresponding mode
|
if (this->mode == climate::CLIMATE_MODE_HEAT) { // Set heating bit if on the corresponding mode
|
||||||
settings |= (1 << 4);
|
settings |= (1 << 4);
|
||||||
}
|
}
|
||||||
settings |= 0b11000100; // Set Light, Health and NotAutoOn bits as per default
|
if (this->get_display_state()) { // Set LED display
|
||||||
|
settings |= (1 << 7);
|
||||||
|
}
|
||||||
|
if (this->get_sleep_state()) { // Set sleep mode
|
||||||
|
settings |= (1 << 1);
|
||||||
|
}
|
||||||
|
settings |= 0b01000100; // Set Health and NotAutoOn bits as per default
|
||||||
return settings;
|
return settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -217,6 +261,12 @@ bool AirtonClimate::parse_state_frame_(uint8_t const frame[]) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint8_t display_light = frame[5] & 0b10000000; // Mask anything but the MSB
|
||||||
|
this->set_display_state(display_light != 0);
|
||||||
|
|
||||||
|
uint8_t sleep_mode = frame[5] & 0b00000010; // Mask anything but the second bit
|
||||||
|
this->set_sleep_state(sleep_mode != 0);
|
||||||
|
|
||||||
this->publish_state();
|
this->publish_state();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,10 @@
|
||||||
|
|
||||||
#include "esphome/components/climate_ir/climate_ir.h"
|
#include "esphome/components/climate_ir/climate_ir.h"
|
||||||
|
|
||||||
|
#ifdef USE_SWITCH
|
||||||
|
#include "esphome/components/switch/switch.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace airton {
|
namespace airton {
|
||||||
|
|
||||||
|
@ -37,13 +41,32 @@ const uint32_t AIRTON_MESSAGE_SPACE = 100000;
|
||||||
// State Frame size
|
// State Frame size
|
||||||
const uint8_t AIRTON_STATE_FRAME_SIZE = 7;
|
const uint8_t AIRTON_STATE_FRAME_SIZE = 7;
|
||||||
|
|
||||||
|
// Specific internal unit settings
|
||||||
|
struct AirtonSettings {
|
||||||
|
bool sleep_state;
|
||||||
|
bool display_state;
|
||||||
|
};
|
||||||
|
|
||||||
class AirtonClimate : public climate_ir::ClimateIR {
|
class AirtonClimate : public climate_ir::ClimateIR {
|
||||||
|
#ifdef USE_SWITCH
|
||||||
|
public:
|
||||||
|
void set_sleep_switch(switch_::Switch *sw);
|
||||||
|
void set_display_switch(switch_::Switch *sw);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
switch_::Switch *sleep_switch_{nullptr};
|
||||||
|
switch_::Switch *display_switch_{nullptr};
|
||||||
|
#endif
|
||||||
public:
|
public:
|
||||||
AirtonClimate()
|
AirtonClimate()
|
||||||
: climate_ir::ClimateIR(AIRTON_TEMP_MIN, AIRTON_TEMP_MAX, 1.0f, true, true,
|
: climate_ir::ClimateIR(AIRTON_TEMP_MIN, AIRTON_TEMP_MAX, 1.0f, true, true,
|
||||||
{climate::CLIMATE_FAN_AUTO, climate::CLIMATE_FAN_LOW, climate::CLIMATE_FAN_MEDIUM,
|
{climate::CLIMATE_FAN_AUTO, climate::CLIMATE_FAN_LOW, climate::CLIMATE_FAN_MEDIUM,
|
||||||
climate::CLIMATE_FAN_HIGH},
|
climate::CLIMATE_FAN_HIGH},
|
||||||
{climate::CLIMATE_SWING_OFF, climate::CLIMATE_SWING_VERTICAL}) {}
|
{climate::CLIMATE_SWING_OFF, climate::CLIMATE_SWING_VERTICAL}) {}
|
||||||
|
void set_sleep_state(bool state);
|
||||||
|
bool get_sleep_state() const;
|
||||||
|
void set_display_state(bool state);
|
||||||
|
bool get_display_state() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Save the previous operation mode inside instance
|
// Save the previous operation mode inside instance
|
||||||
|
@ -52,6 +75,8 @@ class AirtonClimate : public climate_ir::ClimateIR {
|
||||||
protected:
|
protected:
|
||||||
uint8_t get_previous_mode_();
|
uint8_t get_previous_mode_();
|
||||||
void set_previous_mode_(uint8_t mode);
|
void set_previous_mode_(uint8_t mode);
|
||||||
|
AirtonSettings settings_;
|
||||||
|
ESPPreferenceObject airton_rtc_;
|
||||||
|
|
||||||
// IR transmission payload builder
|
// IR transmission payload builder
|
||||||
void transmit_state() override;
|
void transmit_state() override;
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
from esphome import automation
|
||||||
import esphome.codegen as cg
|
import esphome.codegen as cg
|
||||||
from esphome.components import climate_ir
|
from esphome.components import climate_ir
|
||||||
import esphome.config_validation as cv
|
import esphome.config_validation as cv
|
||||||
|
@ -8,12 +9,49 @@ AUTO_LOAD = ["climate_ir"]
|
||||||
airton_ns = cg.esphome_ns.namespace("airton")
|
airton_ns = cg.esphome_ns.namespace("airton")
|
||||||
AirtonClimate = airton_ns.class_("AirtonClimate", climate_ir.ClimateIR)
|
AirtonClimate = airton_ns.class_("AirtonClimate", climate_ir.ClimateIR)
|
||||||
|
|
||||||
|
CONF_AIRTON_ID = "airton_id"
|
||||||
|
|
||||||
CONFIG_SCHEMA = climate_ir.CLIMATE_IR_WITH_RECEIVER_SCHEMA.extend(
|
CONFIG_SCHEMA = climate_ir.CLIMATE_IR_WITH_RECEIVER_SCHEMA.extend(
|
||||||
{
|
{
|
||||||
cv.GenerateID(): cv.declare_id(AirtonClimate),
|
cv.GenerateID(): cv.declare_id(AirtonClimate),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
DisplayOnAction = airton_ns.class_("DisplayOnAction", automation.Action)
|
||||||
|
DisplayOffAction = airton_ns.class_("DisplayOffAction", automation.Action)
|
||||||
|
SleepOnAction = airton_ns.class_("SleepOnAction", automation.Action)
|
||||||
|
SleepOffAction = airton_ns.class_("SleepOffAction", automation.Action)
|
||||||
|
|
||||||
|
AIRTON_ACTION_SCHEMA = automation.maybe_simple_id(
|
||||||
|
{
|
||||||
|
cv.GenerateID(): cv.use_id(AirtonClimate),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@automation.register_action(
|
||||||
|
"climate_ir.airton.display_on", DisplayOnAction, AIRTON_ACTION_SCHEMA
|
||||||
|
)
|
||||||
|
@automation.register_action(
|
||||||
|
"climate_ir.airton.display_off", DisplayOffAction, AIRTON_ACTION_SCHEMA
|
||||||
|
)
|
||||||
|
async def display_action_to_code(config, action_id, template_arg, args):
|
||||||
|
paren = await cg.get_variable(config[CONF_ID])
|
||||||
|
var = cg.new_Pvariable(action_id, template_arg, paren)
|
||||||
|
return var
|
||||||
|
|
||||||
|
|
||||||
|
@automation.register_action(
|
||||||
|
"climate_ir.airton.sleep_on", SleepOnAction, AIRTON_ACTION_SCHEMA
|
||||||
|
)
|
||||||
|
@automation.register_action(
|
||||||
|
"climate_ir.airton.sleep_off", SleepOffAction, AIRTON_ACTION_SCHEMA
|
||||||
|
)
|
||||||
|
async def sleep_action_to_code(config, action_id, template_arg, args):
|
||||||
|
paren = await cg.get_variable(config[CONF_ID])
|
||||||
|
var = cg.new_Pvariable(action_id, template_arg, paren)
|
||||||
|
return var
|
||||||
|
|
||||||
|
|
||||||
async def to_code(config):
|
async def to_code(config):
|
||||||
var = cg.new_Pvariable(config[CONF_ID])
|
var = cg.new_Pvariable(config[CONF_ID])
|
||||||
|
|
39
esphome/components/airton/switch/__init__.py
Normal file
39
esphome/components/airton/switch/__init__.py
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
import esphome.codegen as cg
|
||||||
|
from esphome.components import switch
|
||||||
|
import esphome.config_validation as cv
|
||||||
|
from esphome.const import CONF_DISPLAY, ENTITY_CATEGORY_CONFIG
|
||||||
|
|
||||||
|
from ..climate import CONF_AIRTON_ID, AirtonClimate, airton_ns
|
||||||
|
|
||||||
|
CODEOWNERS = ["@procsiab"]
|
||||||
|
|
||||||
|
CONF_SLEEP_MODE = "sleep"
|
||||||
|
|
||||||
|
SleepSwitch = airton_ns.class_("SleepSwitch", switch.Switch)
|
||||||
|
DisplaySwitch = airton_ns.class_("DisplaySwitch", switch.Switch)
|
||||||
|
|
||||||
|
CONFIG_SCHEMA = cv.Schema(
|
||||||
|
{
|
||||||
|
cv.GenerateID(CONF_AIRTON_ID): cv.use_id(AirtonClimate),
|
||||||
|
cv.Optional(CONF_DISPLAY): switch.switch_schema(
|
||||||
|
DisplaySwitch,
|
||||||
|
entity_category=ENTITY_CATEGORY_CONFIG,
|
||||||
|
default_restore_mode="DISABLED",
|
||||||
|
),
|
||||||
|
cv.Optional(CONF_SLEEP_MODE): switch.switch_schema(
|
||||||
|
SleepSwitch,
|
||||||
|
entity_category=ENTITY_CATEGORY_CONFIG,
|
||||||
|
default_restore_mode="DISABLED",
|
||||||
|
),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def to_code(config):
|
||||||
|
parent = await cg.get_variable(config[CONF_AIRTON_ID])
|
||||||
|
|
||||||
|
for switch_type in [CONF_DISPLAY, CONF_SLEEP_MODE]:
|
||||||
|
if conf := config.get(switch_type):
|
||||||
|
sw_var = await switch.new_switch(conf)
|
||||||
|
await cg.register_parented(sw_var, parent)
|
||||||
|
cg.add(getattr(parent, f"set_{switch_type}_switch")(sw_var))
|
14
esphome/components/airton/switch/display.cpp
Normal file
14
esphome/components/airton/switch/display.cpp
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
#include "display.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace airton {
|
||||||
|
|
||||||
|
void DisplaySwitch::write_state(bool state) {
|
||||||
|
if (this->parent_->get_display_state() != state) {
|
||||||
|
this->parent_->set_display_state(state);
|
||||||
|
}
|
||||||
|
this->publish_state(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace airton
|
||||||
|
} // namespace esphome
|
18
esphome/components/airton/switch/display.h
Normal file
18
esphome/components/airton/switch/display.h
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "esphome/components/switch/switch.h"
|
||||||
|
#include "../airton.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace airton {
|
||||||
|
|
||||||
|
class DisplaySwitch : public switch_::Switch, public Parented<AirtonClimate> {
|
||||||
|
public:
|
||||||
|
DisplaySwitch() = default;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void write_state(bool state) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace airton
|
||||||
|
} // namespace esphome
|
14
esphome/components/airton/switch/sleep.cpp
Normal file
14
esphome/components/airton/switch/sleep.cpp
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
#include "sleep.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace airton {
|
||||||
|
|
||||||
|
void SleepSwitch::write_state(bool state) {
|
||||||
|
if (this->parent_->get_sleep_state() != state) {
|
||||||
|
this->parent_->set_sleep_state(state);
|
||||||
|
}
|
||||||
|
this->publish_state(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace airton
|
||||||
|
} // namespace esphome
|
18
esphome/components/airton/switch/sleep.h
Normal file
18
esphome/components/airton/switch/sleep.h
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "esphome/components/switch/switch.h"
|
||||||
|
#include "../airton.h"
|
||||||
|
|
||||||
|
namespace esphome {
|
||||||
|
namespace airton {
|
||||||
|
|
||||||
|
class SleepSwitch : public switch_::Switch, public Parented<AirtonClimate> {
|
||||||
|
public:
|
||||||
|
SleepSwitch() = default;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void write_state(bool state) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace airton
|
||||||
|
} // namespace esphome
|
|
@ -23,3 +23,10 @@ sensor:
|
||||||
- platform: template
|
- platform: template
|
||||||
id: airton_sensor
|
id: airton_sensor
|
||||||
lambda: "return 21;"
|
lambda: "return 21;"
|
||||||
|
|
||||||
|
switch:
|
||||||
|
- platform: airton
|
||||||
|
sleep:
|
||||||
|
name: "sleep mode"
|
||||||
|
display:
|
||||||
|
name: "display light"
|
||||||
|
|
|
@ -23,3 +23,10 @@ sensor:
|
||||||
- platform: template
|
- platform: template
|
||||||
id: airton_sensor
|
id: airton_sensor
|
||||||
lambda: "return 21;"
|
lambda: "return 21;"
|
||||||
|
|
||||||
|
switch:
|
||||||
|
- platform: airton
|
||||||
|
sleep:
|
||||||
|
name: "sleep mode"
|
||||||
|
display:
|
||||||
|
name: "display light"
|
||||||
|
|
|
@ -23,3 +23,10 @@ sensor:
|
||||||
- platform: template
|
- platform: template
|
||||||
id: airton_sensor
|
id: airton_sensor
|
||||||
lambda: "return 21;"
|
lambda: "return 21;"
|
||||||
|
|
||||||
|
switch:
|
||||||
|
- platform: airton
|
||||||
|
sleep:
|
||||||
|
name: "sleep mode"
|
||||||
|
display:
|
||||||
|
name: "display light"
|
||||||
|
|
|
@ -23,3 +23,10 @@ sensor:
|
||||||
- platform: template
|
- platform: template
|
||||||
id: airton_sensor
|
id: airton_sensor
|
||||||
lambda: "return 21;"
|
lambda: "return 21;"
|
||||||
|
|
||||||
|
switch:
|
||||||
|
- platform: airton
|
||||||
|
sleep:
|
||||||
|
name: "sleep mode"
|
||||||
|
display:
|
||||||
|
name: "display light"
|
||||||
|
|
|
@ -23,3 +23,10 @@ sensor:
|
||||||
- platform: template
|
- platform: template
|
||||||
id: airton_sensor
|
id: airton_sensor
|
||||||
lambda: "return 21;"
|
lambda: "return 21;"
|
||||||
|
|
||||||
|
switch:
|
||||||
|
- platform: airton
|
||||||
|
sleep:
|
||||||
|
name: "sleep mode"
|
||||||
|
display:
|
||||||
|
name: "display light"
|
||||||
|
|
Loading…
Reference in a new issue