mirror of
https://github.com/esphome/esphome.git
synced 2024-11-25 00:18:11 +01:00
Add preset, custom_preset and custom_fan_mode support to climate (#1471)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
This commit is contained in:
parent
7bc51582f0
commit
ebadaa9660
30 changed files with 931 additions and 96 deletions
|
@ -672,11 +672,12 @@ message CameraImageRequest {
|
|||
// ==================== CLIMATE ====================
|
||||
enum ClimateMode {
|
||||
CLIMATE_MODE_OFF = 0;
|
||||
CLIMATE_MODE_AUTO = 1;
|
||||
CLIMATE_MODE_HEAT_COOL = 1;
|
||||
CLIMATE_MODE_COOL = 2;
|
||||
CLIMATE_MODE_HEAT = 3;
|
||||
CLIMATE_MODE_FAN_ONLY = 4;
|
||||
CLIMATE_MODE_DRY = 5;
|
||||
CLIMATE_MODE_AUTO = 6;
|
||||
}
|
||||
enum ClimateFanMode {
|
||||
CLIMATE_FAN_ON = 0;
|
||||
|
@ -704,6 +705,15 @@ enum ClimateAction {
|
|||
CLIMATE_ACTION_DRYING = 5;
|
||||
CLIMATE_ACTION_FAN = 6;
|
||||
}
|
||||
enum ClimatePreset {
|
||||
CLIMATE_PRESET_ECO = 0;
|
||||
CLIMATE_PRESET_AWAY = 1;
|
||||
CLIMATE_PRESET_BOOST = 2;
|
||||
CLIMATE_PRESET_COMFORT = 3;
|
||||
CLIMATE_PRESET_HOME = 4;
|
||||
CLIMATE_PRESET_SLEEP = 5;
|
||||
CLIMATE_PRESET_ACTIVITY = 6;
|
||||
}
|
||||
message ListEntitiesClimateResponse {
|
||||
option (id) = 46;
|
||||
option (source) = SOURCE_SERVER;
|
||||
|
@ -724,6 +734,9 @@ message ListEntitiesClimateResponse {
|
|||
bool supports_action = 12;
|
||||
repeated ClimateFanMode supported_fan_modes = 13;
|
||||
repeated ClimateSwingMode supported_swing_modes = 14;
|
||||
repeated string supported_custom_fan_modes = 15;
|
||||
repeated ClimatePreset supported_presets = 16;
|
||||
repeated string supported_custom_presets = 17;
|
||||
}
|
||||
message ClimateStateResponse {
|
||||
option (id) = 47;
|
||||
|
@ -741,6 +754,9 @@ message ClimateStateResponse {
|
|||
ClimateAction action = 8;
|
||||
ClimateFanMode fan_mode = 9;
|
||||
ClimateSwingMode swing_mode = 10;
|
||||
string custom_fan_mode = 11;
|
||||
ClimatePreset preset = 12;
|
||||
string custom_preset = 13;
|
||||
}
|
||||
message ClimateCommandRequest {
|
||||
option (id) = 48;
|
||||
|
@ -763,4 +779,10 @@ message ClimateCommandRequest {
|
|||
ClimateFanMode fan_mode = 13;
|
||||
bool has_swing_mode = 14;
|
||||
ClimateSwingMode swing_mode = 15;
|
||||
bool has_custom_fan_mode = 16;
|
||||
string custom_fan_mode = 17;
|
||||
bool has_preset = 18;
|
||||
ClimatePreset preset = 19;
|
||||
bool has_custom_preset = 20;
|
||||
string custom_preset = 21;
|
||||
}
|
||||
|
|
|
@ -477,8 +477,14 @@ bool APIConnection::send_climate_state(climate::Climate *climate) {
|
|||
}
|
||||
if (traits.get_supports_away())
|
||||
resp.away = climate->away;
|
||||
if (traits.get_supports_fan_modes())
|
||||
resp.fan_mode = static_cast<enums::ClimateFanMode>(climate->fan_mode);
|
||||
if (traits.get_supports_fan_modes() && climate->fan_mode.has_value())
|
||||
resp.fan_mode = static_cast<enums::ClimateFanMode>(climate->fan_mode.value());
|
||||
if (!traits.get_supported_custom_fan_modes().empty() && climate->custom_fan_mode.has_value())
|
||||
resp.custom_fan_mode = climate->custom_fan_mode.value();
|
||||
if (traits.get_supports_presets() && climate->preset.has_value())
|
||||
resp.preset = static_cast<enums::ClimatePreset>(climate->preset.value());
|
||||
if (!traits.get_supported_custom_presets().empty() && climate->custom_preset.has_value())
|
||||
resp.custom_preset = climate->custom_preset.value();
|
||||
if (traits.get_supports_swing_modes())
|
||||
resp.swing_mode = static_cast<enums::ClimateSwingMode>(climate->swing_mode);
|
||||
return this->send_climate_state_response(resp);
|
||||
|
@ -492,8 +498,9 @@ bool APIConnection::send_climate_info(climate::Climate *climate) {
|
|||
msg.unique_id = get_default_unique_id("climate", climate);
|
||||
msg.supports_current_temperature = traits.get_supports_current_temperature();
|
||||
msg.supports_two_point_target_temperature = traits.get_supports_two_point_target_temperature();
|
||||
for (auto mode : {climate::CLIMATE_MODE_AUTO, climate::CLIMATE_MODE_OFF, climate::CLIMATE_MODE_COOL,
|
||||
climate::CLIMATE_MODE_HEAT, climate::CLIMATE_MODE_DRY, climate::CLIMATE_MODE_FAN_ONLY}) {
|
||||
for (auto mode :
|
||||
{climate::CLIMATE_MODE_AUTO, climate::CLIMATE_MODE_OFF, climate::CLIMATE_MODE_COOL, climate::CLIMATE_MODE_HEAT,
|
||||
climate::CLIMATE_MODE_DRY, climate::CLIMATE_MODE_FAN_ONLY, climate::CLIMATE_MODE_HEAT_COOL}) {
|
||||
if (traits.supports_mode(mode))
|
||||
msg.supported_modes.push_back(static_cast<enums::ClimateMode>(mode));
|
||||
}
|
||||
|
@ -508,6 +515,18 @@ bool APIConnection::send_climate_info(climate::Climate *climate) {
|
|||
if (traits.supports_fan_mode(fan_mode))
|
||||
msg.supported_fan_modes.push_back(static_cast<enums::ClimateFanMode>(fan_mode));
|
||||
}
|
||||
for (auto const &custom_fan_mode : traits.get_supported_custom_fan_modes()) {
|
||||
msg.supported_custom_fan_modes.push_back(custom_fan_mode);
|
||||
}
|
||||
for (auto preset : {climate::CLIMATE_PRESET_ECO, climate::CLIMATE_PRESET_AWAY, climate::CLIMATE_PRESET_BOOST,
|
||||
climate::CLIMATE_PRESET_COMFORT, climate::CLIMATE_PRESET_HOME, climate::CLIMATE_PRESET_SLEEP,
|
||||
climate::CLIMATE_PRESET_ACTIVITY}) {
|
||||
if (traits.supports_preset(preset))
|
||||
msg.supported_presets.push_back(static_cast<enums::ClimatePreset>(preset));
|
||||
}
|
||||
for (auto const &custom_preset : traits.get_supported_custom_presets()) {
|
||||
msg.supported_custom_presets.push_back(custom_preset);
|
||||
}
|
||||
for (auto swing_mode : {climate::CLIMATE_SWING_OFF, climate::CLIMATE_SWING_BOTH, climate::CLIMATE_SWING_VERTICAL,
|
||||
climate::CLIMATE_SWING_HORIZONTAL}) {
|
||||
if (traits.supports_swing_mode(swing_mode))
|
||||
|
@ -533,6 +552,12 @@ void APIConnection::climate_command(const ClimateCommandRequest &msg) {
|
|||
call.set_away(msg.away);
|
||||
if (msg.has_fan_mode)
|
||||
call.set_fan_mode(static_cast<climate::ClimateFanMode>(msg.fan_mode));
|
||||
if (msg.has_custom_fan_mode)
|
||||
call.set_fan_mode(msg.custom_fan_mode);
|
||||
if (msg.has_preset)
|
||||
call.set_preset(static_cast<climate::ClimatePreset>(msg.preset));
|
||||
if (msg.has_custom_preset)
|
||||
call.set_preset(msg.custom_preset);
|
||||
if (msg.has_swing_mode)
|
||||
call.set_swing_mode(static_cast<climate::ClimateSwingMode>(msg.swing_mode));
|
||||
call.perform();
|
||||
|
|
|
@ -118,8 +118,8 @@ template<> const char *proto_enum_to_string<enums::ClimateMode>(enums::ClimateMo
|
|||
switch (value) {
|
||||
case enums::CLIMATE_MODE_OFF:
|
||||
return "CLIMATE_MODE_OFF";
|
||||
case enums::CLIMATE_MODE_AUTO:
|
||||
return "CLIMATE_MODE_AUTO";
|
||||
case enums::CLIMATE_MODE_HEAT_COOL:
|
||||
return "CLIMATE_MODE_HEAT_COOL";
|
||||
case enums::CLIMATE_MODE_COOL:
|
||||
return "CLIMATE_MODE_COOL";
|
||||
case enums::CLIMATE_MODE_HEAT:
|
||||
|
@ -128,6 +128,8 @@ template<> const char *proto_enum_to_string<enums::ClimateMode>(enums::ClimateMo
|
|||
return "CLIMATE_MODE_FAN_ONLY";
|
||||
case enums::CLIMATE_MODE_DRY:
|
||||
return "CLIMATE_MODE_DRY";
|
||||
case enums::CLIMATE_MODE_AUTO:
|
||||
return "CLIMATE_MODE_AUTO";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
|
@ -188,6 +190,26 @@ template<> const char *proto_enum_to_string<enums::ClimateAction>(enums::Climate
|
|||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
template<> const char *proto_enum_to_string<enums::ClimatePreset>(enums::ClimatePreset value) {
|
||||
switch (value) {
|
||||
case enums::CLIMATE_PRESET_ECO:
|
||||
return "CLIMATE_PRESET_ECO";
|
||||
case enums::CLIMATE_PRESET_AWAY:
|
||||
return "CLIMATE_PRESET_AWAY";
|
||||
case enums::CLIMATE_PRESET_BOOST:
|
||||
return "CLIMATE_PRESET_BOOST";
|
||||
case enums::CLIMATE_PRESET_COMFORT:
|
||||
return "CLIMATE_PRESET_COMFORT";
|
||||
case enums::CLIMATE_PRESET_HOME:
|
||||
return "CLIMATE_PRESET_HOME";
|
||||
case enums::CLIMATE_PRESET_SLEEP:
|
||||
return "CLIMATE_PRESET_SLEEP";
|
||||
case enums::CLIMATE_PRESET_ACTIVITY:
|
||||
return "CLIMATE_PRESET_ACTIVITY";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
bool HelloRequest::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
|
||||
switch (field_id) {
|
||||
case 1: {
|
||||
|
@ -2647,6 +2669,10 @@ bool ListEntitiesClimateResponse::decode_varint(uint32_t field_id, ProtoVarInt v
|
|||
this->supported_swing_modes.push_back(value.as_enum<enums::ClimateSwingMode>());
|
||||
return true;
|
||||
}
|
||||
case 16: {
|
||||
this->supported_presets.push_back(value.as_enum<enums::ClimatePreset>());
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
@ -2665,6 +2691,14 @@ bool ListEntitiesClimateResponse::decode_length(uint32_t field_id, ProtoLengthDe
|
|||
this->unique_id = value.as_string();
|
||||
return true;
|
||||
}
|
||||
case 15: {
|
||||
this->supported_custom_fan_modes.push_back(value.as_string());
|
||||
return true;
|
||||
}
|
||||
case 17: {
|
||||
this->supported_custom_presets.push_back(value.as_string());
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
@ -2712,6 +2746,15 @@ void ListEntitiesClimateResponse::encode(ProtoWriteBuffer buffer) const {
|
|||
for (auto &it : this->supported_swing_modes) {
|
||||
buffer.encode_enum<enums::ClimateSwingMode>(14, it, true);
|
||||
}
|
||||
for (auto &it : this->supported_custom_fan_modes) {
|
||||
buffer.encode_string(15, it, true);
|
||||
}
|
||||
for (auto &it : this->supported_presets) {
|
||||
buffer.encode_enum<enums::ClimatePreset>(16, it, true);
|
||||
}
|
||||
for (auto &it : this->supported_custom_presets) {
|
||||
buffer.encode_string(17, it, true);
|
||||
}
|
||||
}
|
||||
void ListEntitiesClimateResponse::dump_to(std::string &out) const {
|
||||
char buffer[64];
|
||||
|
@ -2781,6 +2824,24 @@ void ListEntitiesClimateResponse::dump_to(std::string &out) const {
|
|||
out.append(proto_enum_to_string<enums::ClimateSwingMode>(it));
|
||||
out.append("\n");
|
||||
}
|
||||
|
||||
for (const auto &it : this->supported_custom_fan_modes) {
|
||||
out.append(" supported_custom_fan_modes: ");
|
||||
out.append("'").append(it).append("'");
|
||||
out.append("\n");
|
||||
}
|
||||
|
||||
for (const auto &it : this->supported_presets) {
|
||||
out.append(" supported_presets: ");
|
||||
out.append(proto_enum_to_string<enums::ClimatePreset>(it));
|
||||
out.append("\n");
|
||||
}
|
||||
|
||||
for (const auto &it : this->supported_custom_presets) {
|
||||
out.append(" supported_custom_presets: ");
|
||||
out.append("'").append(it).append("'");
|
||||
out.append("\n");
|
||||
}
|
||||
out.append("}");
|
||||
}
|
||||
bool ClimateStateResponse::decode_varint(uint32_t field_id, ProtoVarInt value) {
|
||||
|
@ -2805,6 +2866,24 @@ bool ClimateStateResponse::decode_varint(uint32_t field_id, ProtoVarInt value) {
|
|||
this->swing_mode = value.as_enum<enums::ClimateSwingMode>();
|
||||
return true;
|
||||
}
|
||||
case 12: {
|
||||
this->preset = value.as_enum<enums::ClimatePreset>();
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
bool ClimateStateResponse::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
|
||||
switch (field_id) {
|
||||
case 11: {
|
||||
this->custom_fan_mode = value.as_string();
|
||||
return true;
|
||||
}
|
||||
case 13: {
|
||||
this->custom_preset = value.as_string();
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
@ -2846,6 +2925,9 @@ void ClimateStateResponse::encode(ProtoWriteBuffer buffer) const {
|
|||
buffer.encode_enum<enums::ClimateAction>(8, this->action);
|
||||
buffer.encode_enum<enums::ClimateFanMode>(9, this->fan_mode);
|
||||
buffer.encode_enum<enums::ClimateSwingMode>(10, this->swing_mode);
|
||||
buffer.encode_string(11, this->custom_fan_mode);
|
||||
buffer.encode_enum<enums::ClimatePreset>(12, this->preset);
|
||||
buffer.encode_string(13, this->custom_preset);
|
||||
}
|
||||
void ClimateStateResponse::dump_to(std::string &out) const {
|
||||
char buffer[64];
|
||||
|
@ -2894,6 +2976,18 @@ void ClimateStateResponse::dump_to(std::string &out) const {
|
|||
out.append(" swing_mode: ");
|
||||
out.append(proto_enum_to_string<enums::ClimateSwingMode>(this->swing_mode));
|
||||
out.append("\n");
|
||||
|
||||
out.append(" custom_fan_mode: ");
|
||||
out.append("'").append(this->custom_fan_mode).append("'");
|
||||
out.append("\n");
|
||||
|
||||
out.append(" preset: ");
|
||||
out.append(proto_enum_to_string<enums::ClimatePreset>(this->preset));
|
||||
out.append("\n");
|
||||
|
||||
out.append(" custom_preset: ");
|
||||
out.append("'").append(this->custom_preset).append("'");
|
||||
out.append("\n");
|
||||
out.append("}");
|
||||
}
|
||||
bool ClimateCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value) {
|
||||
|
@ -2942,6 +3036,36 @@ bool ClimateCommandRequest::decode_varint(uint32_t field_id, ProtoVarInt value)
|
|||
this->swing_mode = value.as_enum<enums::ClimateSwingMode>();
|
||||
return true;
|
||||
}
|
||||
case 16: {
|
||||
this->has_custom_fan_mode = value.as_bool();
|
||||
return true;
|
||||
}
|
||||
case 18: {
|
||||
this->has_preset = value.as_bool();
|
||||
return true;
|
||||
}
|
||||
case 19: {
|
||||
this->preset = value.as_enum<enums::ClimatePreset>();
|
||||
return true;
|
||||
}
|
||||
case 20: {
|
||||
this->has_custom_preset = value.as_bool();
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
bool ClimateCommandRequest::decode_length(uint32_t field_id, ProtoLengthDelimited value) {
|
||||
switch (field_id) {
|
||||
case 17: {
|
||||
this->custom_fan_mode = value.as_string();
|
||||
return true;
|
||||
}
|
||||
case 21: {
|
||||
this->custom_preset = value.as_string();
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
@ -2984,6 +3108,12 @@ void ClimateCommandRequest::encode(ProtoWriteBuffer buffer) const {
|
|||
buffer.encode_enum<enums::ClimateFanMode>(13, this->fan_mode);
|
||||
buffer.encode_bool(14, this->has_swing_mode);
|
||||
buffer.encode_enum<enums::ClimateSwingMode>(15, this->swing_mode);
|
||||
buffer.encode_bool(16, this->has_custom_fan_mode);
|
||||
buffer.encode_string(17, this->custom_fan_mode);
|
||||
buffer.encode_bool(18, this->has_preset);
|
||||
buffer.encode_enum<enums::ClimatePreset>(19, this->preset);
|
||||
buffer.encode_bool(20, this->has_custom_preset);
|
||||
buffer.encode_string(21, this->custom_preset);
|
||||
}
|
||||
void ClimateCommandRequest::dump_to(std::string &out) const {
|
||||
char buffer[64];
|
||||
|
@ -3051,6 +3181,30 @@ void ClimateCommandRequest::dump_to(std::string &out) const {
|
|||
out.append(" swing_mode: ");
|
||||
out.append(proto_enum_to_string<enums::ClimateSwingMode>(this->swing_mode));
|
||||
out.append("\n");
|
||||
|
||||
out.append(" has_custom_fan_mode: ");
|
||||
out.append(YESNO(this->has_custom_fan_mode));
|
||||
out.append("\n");
|
||||
|
||||
out.append(" custom_fan_mode: ");
|
||||
out.append("'").append(this->custom_fan_mode).append("'");
|
||||
out.append("\n");
|
||||
|
||||
out.append(" has_preset: ");
|
||||
out.append(YESNO(this->has_preset));
|
||||
out.append("\n");
|
||||
|
||||
out.append(" preset: ");
|
||||
out.append(proto_enum_to_string<enums::ClimatePreset>(this->preset));
|
||||
out.append("\n");
|
||||
|
||||
out.append(" has_custom_preset: ");
|
||||
out.append(YESNO(this->has_custom_preset));
|
||||
out.append("\n");
|
||||
|
||||
out.append(" custom_preset: ");
|
||||
out.append("'").append(this->custom_preset).append("'");
|
||||
out.append("\n");
|
||||
out.append("}");
|
||||
}
|
||||
|
||||
|
|
|
@ -57,11 +57,12 @@ enum ServiceArgType : uint32_t {
|
|||
};
|
||||
enum ClimateMode : uint32_t {
|
||||
CLIMATE_MODE_OFF = 0,
|
||||
CLIMATE_MODE_AUTO = 1,
|
||||
CLIMATE_MODE_HEAT_COOL = 1,
|
||||
CLIMATE_MODE_COOL = 2,
|
||||
CLIMATE_MODE_HEAT = 3,
|
||||
CLIMATE_MODE_FAN_ONLY = 4,
|
||||
CLIMATE_MODE_DRY = 5,
|
||||
CLIMATE_MODE_AUTO = 6,
|
||||
};
|
||||
enum ClimateFanMode : uint32_t {
|
||||
CLIMATE_FAN_ON = 0,
|
||||
|
@ -88,6 +89,15 @@ enum ClimateAction : uint32_t {
|
|||
CLIMATE_ACTION_DRYING = 5,
|
||||
CLIMATE_ACTION_FAN = 6,
|
||||
};
|
||||
enum ClimatePreset : uint32_t {
|
||||
CLIMATE_PRESET_ECO = 0,
|
||||
CLIMATE_PRESET_AWAY = 1,
|
||||
CLIMATE_PRESET_BOOST = 2,
|
||||
CLIMATE_PRESET_COMFORT = 3,
|
||||
CLIMATE_PRESET_HOME = 4,
|
||||
CLIMATE_PRESET_SLEEP = 5,
|
||||
CLIMATE_PRESET_ACTIVITY = 6,
|
||||
};
|
||||
|
||||
} // namespace enums
|
||||
|
||||
|
@ -687,20 +697,23 @@ class CameraImageRequest : public ProtoMessage {
|
|||
};
|
||||
class ListEntitiesClimateResponse : public ProtoMessage {
|
||||
public:
|
||||
std::string object_id{};
|
||||
uint32_t key{0};
|
||||
std::string name{};
|
||||
std::string unique_id{};
|
||||
bool supports_current_temperature{false};
|
||||
bool supports_two_point_target_temperature{false};
|
||||
std::vector<enums::ClimateMode> supported_modes{};
|
||||
float visual_min_temperature{0.0f};
|
||||
float visual_max_temperature{0.0f};
|
||||
float visual_temperature_step{0.0f};
|
||||
bool supports_away{false};
|
||||
bool supports_action{false};
|
||||
std::vector<enums::ClimateFanMode> supported_fan_modes{};
|
||||
std::vector<enums::ClimateSwingMode> supported_swing_modes{};
|
||||
std::string object_id{}; // NOLINT
|
||||
uint32_t key{0}; // NOLINT
|
||||
std::string name{}; // NOLINT
|
||||
std::string unique_id{}; // NOLINT
|
||||
bool supports_current_temperature{false}; // NOLINT
|
||||
bool supports_two_point_target_temperature{false}; // NOLINT
|
||||
std::vector<enums::ClimateMode> supported_modes{}; // NOLINT
|
||||
float visual_min_temperature{0.0f}; // NOLINT
|
||||
float visual_max_temperature{0.0f}; // NOLINT
|
||||
float visual_temperature_step{0.0f}; // NOLINT
|
||||
bool supports_away{false}; // NOLINT
|
||||
bool supports_action{false}; // NOLINT
|
||||
std::vector<enums::ClimateFanMode> supported_fan_modes{}; // NOLINT
|
||||
std::vector<enums::ClimateSwingMode> supported_swing_modes{}; // NOLINT
|
||||
std::vector<std::string> supported_custom_fan_modes{}; // NOLINT
|
||||
std::vector<enums::ClimatePreset> supported_presets{}; // NOLINT
|
||||
std::vector<std::string> supported_custom_presets{}; // NOLINT
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void dump_to(std::string &out) const override;
|
||||
|
||||
|
@ -711,45 +724,56 @@ class ListEntitiesClimateResponse : public ProtoMessage {
|
|||
};
|
||||
class ClimateStateResponse : public ProtoMessage {
|
||||
public:
|
||||
uint32_t key{0};
|
||||
enums::ClimateMode mode{};
|
||||
float current_temperature{0.0f};
|
||||
float target_temperature{0.0f};
|
||||
float target_temperature_low{0.0f};
|
||||
float target_temperature_high{0.0f};
|
||||
bool away{false};
|
||||
enums::ClimateAction action{};
|
||||
enums::ClimateFanMode fan_mode{};
|
||||
enums::ClimateSwingMode swing_mode{};
|
||||
uint32_t key{0}; // NOLINT
|
||||
enums::ClimateMode mode{}; // NOLINT
|
||||
float current_temperature{0.0f}; // NOLINT
|
||||
float target_temperature{0.0f}; // NOLINT
|
||||
float target_temperature_low{0.0f}; // NOLINT
|
||||
float target_temperature_high{0.0f}; // NOLINT
|
||||
bool away{false}; // NOLINT
|
||||
enums::ClimateAction action{}; // NOLINT
|
||||
enums::ClimateFanMode fan_mode{}; // NOLINT
|
||||
enums::ClimateSwingMode swing_mode{}; // NOLINT
|
||||
std::string custom_fan_mode{}; // NOLINT
|
||||
enums::ClimatePreset preset{}; // NOLINT
|
||||
std::string custom_preset{}; // NOLINT
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void dump_to(std::string &out) const override;
|
||||
|
||||
protected:
|
||||
bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
|
||||
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
|
||||
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
|
||||
};
|
||||
class ClimateCommandRequest : public ProtoMessage {
|
||||
public:
|
||||
uint32_t key{0};
|
||||
bool has_mode{false};
|
||||
enums::ClimateMode mode{};
|
||||
bool has_target_temperature{false};
|
||||
float target_temperature{0.0f};
|
||||
bool has_target_temperature_low{false};
|
||||
float target_temperature_low{0.0f};
|
||||
bool has_target_temperature_high{false};
|
||||
float target_temperature_high{0.0f};
|
||||
bool has_away{false};
|
||||
bool away{false};
|
||||
bool has_fan_mode{false};
|
||||
enums::ClimateFanMode fan_mode{};
|
||||
bool has_swing_mode{false};
|
||||
enums::ClimateSwingMode swing_mode{};
|
||||
uint32_t key{0}; // NOLINT
|
||||
bool has_mode{false}; // NOLINT
|
||||
enums::ClimateMode mode{}; // NOLINT
|
||||
bool has_target_temperature{false}; // NOLINT
|
||||
float target_temperature{0.0f}; // NOLINT
|
||||
bool has_target_temperature_low{false}; // NOLINT
|
||||
float target_temperature_low{0.0f}; // NOLINT
|
||||
bool has_target_temperature_high{false}; // NOLINT
|
||||
float target_temperature_high{0.0f}; // NOLINT
|
||||
bool has_away{false}; // NOLINT
|
||||
bool away{false}; // NOLINT
|
||||
bool has_fan_mode{false}; // NOLINT
|
||||
enums::ClimateFanMode fan_mode{}; // NOLINT
|
||||
bool has_swing_mode{false}; // NOLINT
|
||||
enums::ClimateSwingMode swing_mode{}; // NOLINT
|
||||
bool has_custom_fan_mode{false}; // NOLINT
|
||||
std::string custom_fan_mode{}; // NOLINT
|
||||
bool has_preset{false}; // NOLINT
|
||||
enums::ClimatePreset preset{}; // NOLINT
|
||||
bool has_custom_preset{false}; // NOLINT
|
||||
std::string custom_preset{}; // NOLINT
|
||||
void encode(ProtoWriteBuffer buffer) const override;
|
||||
void dump_to(std::string &out) const override;
|
||||
|
||||
protected:
|
||||
bool decode_32bit(uint32_t field_id, Proto32Bit value) override;
|
||||
bool decode_length(uint32_t field_id, ProtoLengthDelimited value) override;
|
||||
bool decode_varint(uint32_t field_id, ProtoVarInt value) override;
|
||||
};
|
||||
|
||||
|
|
|
@ -4,11 +4,14 @@ from esphome import automation
|
|||
from esphome.components import mqtt
|
||||
from esphome.const import (
|
||||
CONF_AWAY,
|
||||
CONF_CUSTOM_FAN_MODE,
|
||||
CONF_CUSTOM_PRESET,
|
||||
CONF_ID,
|
||||
CONF_INTERNAL,
|
||||
CONF_MAX_TEMPERATURE,
|
||||
CONF_MIN_TEMPERATURE,
|
||||
CONF_MODE,
|
||||
CONF_PRESET,
|
||||
CONF_TARGET_TEMPERATURE,
|
||||
CONF_TARGET_TEMPERATURE_HIGH,
|
||||
CONF_TARGET_TEMPERATURE_LOW,
|
||||
|
@ -33,11 +36,12 @@ ClimateTraits = climate_ns.class_("ClimateTraits")
|
|||
ClimateMode = climate_ns.enum("ClimateMode")
|
||||
CLIMATE_MODES = {
|
||||
"OFF": ClimateMode.CLIMATE_MODE_OFF,
|
||||
"AUTO": ClimateMode.CLIMATE_MODE_AUTO,
|
||||
"HEAT_COOL": ClimateMode.CLIMATE_HEAT_COOL,
|
||||
"COOL": ClimateMode.CLIMATE_MODE_COOL,
|
||||
"HEAT": ClimateMode.CLIMATE_MODE_HEAT,
|
||||
"DRY": ClimateMode.CLIMATE_MODE_DRY,
|
||||
"FAN_ONLY": ClimateMode.CLIMATE_MODE_FAN_ONLY,
|
||||
"AUTO": ClimateMode.CLIMATE_MODE_AUTO,
|
||||
}
|
||||
validate_climate_mode = cv.enum(CLIMATE_MODES, upper=True)
|
||||
|
||||
|
@ -56,6 +60,19 @@ CLIMATE_FAN_MODES = {
|
|||
|
||||
validate_climate_fan_mode = cv.enum(CLIMATE_FAN_MODES, upper=True)
|
||||
|
||||
ClimatePreset = climate_ns.enum("ClimatePreset")
|
||||
CLIMATE_PRESETS = {
|
||||
"ECO": ClimatePreset.CLIMATE_PRESET_ECO,
|
||||
"AWAY": ClimatePreset.CLIMATE_PRESET_AWAY,
|
||||
"BOOST": ClimatePreset.CLIMATE_PRESET_BOOST,
|
||||
"COMFORT": ClimatePreset.CLIMATE_PRESET_COMFORT,
|
||||
"HOME": ClimatePreset.CLIMATE_PRESET_HOME,
|
||||
"SLEEP": ClimatePreset.CLIMATE_PRESET_SLEEP,
|
||||
"ACTIVITY": ClimatePreset.CLIMATE_PRESET_ACTIVITY,
|
||||
}
|
||||
|
||||
validate_climate_preset = cv.enum(CLIMATE_PRESETS, upper=True)
|
||||
|
||||
ClimateSwingMode = climate_ns.enum("ClimateSwingMode")
|
||||
CLIMATE_SWING_MODES = {
|
||||
"OFF": ClimateSwingMode.CLIMATE_SWING_OFF,
|
||||
|
@ -117,7 +134,12 @@ CLIMATE_CONTROL_ACTION_SCHEMA = cv.Schema(
|
|||
cv.Optional(CONF_TARGET_TEMPERATURE_LOW): cv.templatable(cv.temperature),
|
||||
cv.Optional(CONF_TARGET_TEMPERATURE_HIGH): cv.templatable(cv.temperature),
|
||||
cv.Optional(CONF_AWAY): cv.templatable(cv.boolean),
|
||||
cv.Optional(CONF_FAN_MODE): cv.templatable(validate_climate_fan_mode),
|
||||
cv.Exclusive(CONF_FAN_MODE, "fan_mode"): cv.templatable(
|
||||
validate_climate_fan_mode
|
||||
),
|
||||
cv.Exclusive(CONF_CUSTOM_FAN_MODE, "fan_mode"): cv.string_strict,
|
||||
cv.Exclusive(CONF_PRESET, "preset"): cv.templatable(validate_climate_preset),
|
||||
cv.Exclusive(CONF_CUSTOM_PRESET, "preset"): cv.string_strict,
|
||||
cv.Optional(CONF_SWING_MODE): cv.templatable(validate_climate_swing_mode),
|
||||
}
|
||||
)
|
||||
|
@ -151,6 +173,15 @@ async def climate_control_to_code(config, action_id, template_arg, args):
|
|||
if CONF_FAN_MODE in config:
|
||||
template_ = await cg.templatable(config[CONF_FAN_MODE], args, ClimateFanMode)
|
||||
cg.add(var.set_fan_mode(template_))
|
||||
if CONF_CUSTOM_FAN_MODE in config:
|
||||
template_ = await cg.templatable(config[CONF_CUSTOM_FAN_MODE], args, str)
|
||||
cg.add(var.set_custom_fan_mode(template_))
|
||||
if CONF_PRESET in config:
|
||||
template_ = await cg.templatable(config[CONF_PRESET], args, ClimatePreset)
|
||||
cg.add(var.set_preset(template_))
|
||||
if CONF_CUSTOM_PRESET in config:
|
||||
template_ = await cg.templatable(config[CONF_CUSTOM_PRESET], args, str)
|
||||
cg.add(var.set_custom_preset(template_))
|
||||
if CONF_SWING_MODE in config:
|
||||
template_ = await cg.templatable(
|
||||
config[CONF_SWING_MODE], args, ClimateSwingMode
|
||||
|
|
|
@ -16,6 +16,9 @@ template<typename... Ts> class ControlAction : public Action<Ts...> {
|
|||
TEMPLATABLE_VALUE(float, target_temperature_high)
|
||||
TEMPLATABLE_VALUE(bool, away)
|
||||
TEMPLATABLE_VALUE(ClimateFanMode, fan_mode)
|
||||
TEMPLATABLE_VALUE(std::string, custom_fan_mode)
|
||||
TEMPLATABLE_VALUE(ClimatePreset, preset)
|
||||
TEMPLATABLE_VALUE(std::string, custom_preset)
|
||||
TEMPLATABLE_VALUE(ClimateSwingMode, swing_mode)
|
||||
|
||||
void play(Ts... x) override {
|
||||
|
@ -26,6 +29,9 @@ template<typename... Ts> class ControlAction : public Action<Ts...> {
|
|||
call.set_target_temperature_high(this->target_temperature_high_.optional_value(x...));
|
||||
call.set_away(this->away_.optional_value(x...));
|
||||
call.set_fan_mode(this->fan_mode_.optional_value(x...));
|
||||
call.set_fan_mode(this->custom_fan_mode_.optional_value(x...));
|
||||
call.set_preset(this->preset_.optional_value(x...));
|
||||
call.set_preset(this->custom_preset_.optional_value(x...));
|
||||
call.set_swing_mode(this->swing_mode_.optional_value(x...));
|
||||
call.perform();
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
#include "climate.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace climate {
|
||||
|
@ -13,10 +12,24 @@ void ClimateCall::perform() {
|
|||
const char *mode_s = climate_mode_to_string(*this->mode_);
|
||||
ESP_LOGD(TAG, " Mode: %s", mode_s);
|
||||
}
|
||||
if (this->custom_fan_mode_.has_value()) {
|
||||
this->fan_mode_.reset();
|
||||
ESP_LOGD(TAG, " Custom Fan: %s", this->custom_fan_mode_.value().c_str());
|
||||
}
|
||||
if (this->fan_mode_.has_value()) {
|
||||
this->custom_fan_mode_.reset();
|
||||
const char *fan_mode_s = climate_fan_mode_to_string(*this->fan_mode_);
|
||||
ESP_LOGD(TAG, " Fan: %s", fan_mode_s);
|
||||
}
|
||||
if (this->custom_preset_.has_value()) {
|
||||
this->preset_.reset();
|
||||
ESP_LOGD(TAG, " Custom Preset: %s", this->custom_preset_.value().c_str());
|
||||
}
|
||||
if (this->preset_.has_value()) {
|
||||
this->custom_preset_.reset();
|
||||
const char *preset_s = climate_preset_to_string(*this->preset_);
|
||||
ESP_LOGD(TAG, " Preset: %s", preset_s);
|
||||
}
|
||||
if (this->swing_mode_.has_value()) {
|
||||
const char *swing_mode_s = climate_swing_mode_to_string(*this->swing_mode_);
|
||||
ESP_LOGD(TAG, " Swing: %s", swing_mode_s);
|
||||
|
@ -44,13 +57,32 @@ void ClimateCall::validate_() {
|
|||
this->mode_.reset();
|
||||
}
|
||||
}
|
||||
if (this->fan_mode_.has_value()) {
|
||||
if (this->custom_fan_mode_.has_value()) {
|
||||
auto custom_fan_mode = *this->custom_fan_mode_;
|
||||
if (!traits.supports_custom_fan_mode(custom_fan_mode)) {
|
||||
ESP_LOGW(TAG, " Fan Mode %s is not supported by this device!", custom_fan_mode.c_str());
|
||||
this->custom_fan_mode_.reset();
|
||||
}
|
||||
} else if (this->fan_mode_.has_value()) {
|
||||
auto fan_mode = *this->fan_mode_;
|
||||
if (!traits.supports_fan_mode(fan_mode)) {
|
||||
ESP_LOGW(TAG, " Fan Mode %s is not supported by this device!", climate_fan_mode_to_string(fan_mode));
|
||||
this->fan_mode_.reset();
|
||||
}
|
||||
}
|
||||
if (this->custom_preset_.has_value()) {
|
||||
auto custom_preset = *this->custom_preset_;
|
||||
if (!traits.supports_custom_preset(custom_preset)) {
|
||||
ESP_LOGW(TAG, " Preset %s is not supported by this device!", custom_preset.c_str());
|
||||
this->custom_preset_.reset();
|
||||
}
|
||||
} else if (this->preset_.has_value()) {
|
||||
auto preset = *this->preset_;
|
||||
if (!traits.supports_preset(preset)) {
|
||||
ESP_LOGW(TAG, " Preset %s is not supported by this device!", climate_preset_to_string(preset));
|
||||
this->preset_.reset();
|
||||
}
|
||||
}
|
||||
if (this->swing_mode_.has_value()) {
|
||||
auto swing_mode = *this->swing_mode_;
|
||||
if (!traits.supports_swing_mode(swing_mode)) {
|
||||
|
@ -117,6 +149,8 @@ ClimateCall &ClimateCall::set_mode(const std::string &mode) {
|
|||
this->set_mode(CLIMATE_MODE_FAN_ONLY);
|
||||
} else if (str_equals_case_insensitive(mode, "DRY")) {
|
||||
this->set_mode(CLIMATE_MODE_DRY);
|
||||
} else if (str_equals_case_insensitive(mode, "HEAT_COOL")) {
|
||||
this->set_mode(CLIMATE_MODE_HEAT_COOL);
|
||||
} else {
|
||||
ESP_LOGW(TAG, "'%s' - Unrecognized mode %s", this->parent_->get_name().c_str(), mode.c_str());
|
||||
}
|
||||
|
@ -124,6 +158,7 @@ ClimateCall &ClimateCall::set_mode(const std::string &mode) {
|
|||
}
|
||||
ClimateCall &ClimateCall::set_fan_mode(ClimateFanMode fan_mode) {
|
||||
this->fan_mode_ = fan_mode;
|
||||
this->custom_fan_mode_.reset();
|
||||
return *this;
|
||||
}
|
||||
ClimateCall &ClimateCall::set_fan_mode(const std::string &fan_mode) {
|
||||
|
@ -146,11 +181,59 @@ ClimateCall &ClimateCall::set_fan_mode(const std::string &fan_mode) {
|
|||
} else if (str_equals_case_insensitive(fan_mode, "DIFFUSE")) {
|
||||
this->set_fan_mode(CLIMATE_FAN_DIFFUSE);
|
||||
} else {
|
||||
ESP_LOGW(TAG, "'%s' - Unrecognized fan mode %s", this->parent_->get_name().c_str(), fan_mode.c_str());
|
||||
auto custom_fan_modes = this->parent_->get_traits().get_supported_custom_fan_modes();
|
||||
if (std::find(custom_fan_modes.begin(), custom_fan_modes.end(), fan_mode) != custom_fan_modes.end()) {
|
||||
this->custom_fan_mode_ = fan_mode;
|
||||
this->fan_mode_.reset();
|
||||
} else {
|
||||
ESP_LOGW(TAG, "'%s' - Unrecognized fan mode %s", this->parent_->get_name().c_str(), fan_mode.c_str());
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
ClimateCall &ClimateCall::set_fan_mode(optional<std::string> fan_mode) {
|
||||
if (fan_mode.has_value()) {
|
||||
this->set_fan_mode(fan_mode.value());
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
ClimateCall &ClimateCall::set_preset(ClimatePreset preset) {
|
||||
this->preset_ = preset;
|
||||
this->custom_preset_.reset();
|
||||
return *this;
|
||||
}
|
||||
ClimateCall &ClimateCall::set_preset(const std::string &preset) {
|
||||
if (str_equals_case_insensitive(preset, "ECO")) {
|
||||
this->set_preset(CLIMATE_PRESET_ECO);
|
||||
} else if (str_equals_case_insensitive(preset, "AWAY")) {
|
||||
this->set_preset(CLIMATE_PRESET_AWAY);
|
||||
} else if (str_equals_case_insensitive(preset, "BOOST")) {
|
||||
this->set_preset(CLIMATE_PRESET_BOOST);
|
||||
} else if (str_equals_case_insensitive(preset, "COMFORT")) {
|
||||
this->set_preset(CLIMATE_PRESET_COMFORT);
|
||||
} else if (str_equals_case_insensitive(preset, "HOME")) {
|
||||
this->set_preset(CLIMATE_PRESET_HOME);
|
||||
} else if (str_equals_case_insensitive(preset, "SLEEP")) {
|
||||
this->set_preset(CLIMATE_PRESET_SLEEP);
|
||||
} else if (str_equals_case_insensitive(preset, "ACTIVITY")) {
|
||||
this->set_preset(CLIMATE_PRESET_ACTIVITY);
|
||||
} else {
|
||||
auto custom_presets = this->parent_->get_traits().get_supported_custom_presets();
|
||||
if (std::find(custom_presets.begin(), custom_presets.end(), preset) != custom_presets.end()) {
|
||||
this->custom_preset_ = preset;
|
||||
this->preset_.reset();
|
||||
} else {
|
||||
ESP_LOGW(TAG, "'%s' - Unrecognized preset %s", this->parent_->get_name().c_str(), preset.c_str());
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
ClimateCall &ClimateCall::set_preset(optional<std::string> preset) {
|
||||
if (preset.has_value()) {
|
||||
this->set_preset(preset.value());
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
ClimateCall &ClimateCall::set_swing_mode(ClimateSwingMode swing_mode) {
|
||||
this->swing_mode_ = swing_mode;
|
||||
return *this;
|
||||
|
@ -188,6 +271,9 @@ const optional<float> &ClimateCall::get_target_temperature_low() const { return
|
|||
const optional<float> &ClimateCall::get_target_temperature_high() const { return this->target_temperature_high_; }
|
||||
const optional<bool> &ClimateCall::get_away() const { return this->away_; }
|
||||
const optional<ClimateFanMode> &ClimateCall::get_fan_mode() const { return this->fan_mode_; }
|
||||
const optional<std::string> &ClimateCall::get_custom_fan_mode() const { return this->custom_fan_mode_; }
|
||||
const optional<ClimatePreset> &ClimateCall::get_preset() const { return this->preset_; }
|
||||
const optional<std::string> &ClimateCall::get_custom_preset() const { return this->custom_preset_; }
|
||||
const optional<ClimateSwingMode> &ClimateCall::get_swing_mode() const { return this->swing_mode_; }
|
||||
ClimateCall &ClimateCall::set_away(bool away) {
|
||||
this->away_ = away;
|
||||
|
@ -215,6 +301,12 @@ ClimateCall &ClimateCall::set_mode(optional<ClimateMode> mode) {
|
|||
}
|
||||
ClimateCall &ClimateCall::set_fan_mode(optional<ClimateFanMode> fan_mode) {
|
||||
this->fan_mode_ = fan_mode;
|
||||
this->custom_fan_mode_.reset();
|
||||
return *this;
|
||||
}
|
||||
ClimateCall &ClimateCall::set_preset(optional<ClimatePreset> preset) {
|
||||
this->preset_ = preset;
|
||||
this->custom_preset_.reset();
|
||||
return *this;
|
||||
}
|
||||
ClimateCall &ClimateCall::set_swing_mode(optional<ClimateSwingMode> swing_mode) {
|
||||
|
@ -249,8 +341,31 @@ void Climate::save_state_() {
|
|||
if (traits.get_supports_away()) {
|
||||
state.away = this->away;
|
||||
}
|
||||
if (traits.get_supports_fan_modes()) {
|
||||
state.fan_mode = this->fan_mode;
|
||||
if (traits.get_supports_fan_modes() && fan_mode.has_value()) {
|
||||
state.uses_custom_fan_mode = false;
|
||||
state.fan_mode = this->fan_mode.value();
|
||||
}
|
||||
if (!traits.get_supported_custom_fan_modes().empty() && custom_fan_mode.has_value()) {
|
||||
state.uses_custom_fan_mode = true;
|
||||
auto &custom_fan_modes = traits.get_supported_custom_fan_modes();
|
||||
auto it = std::find(custom_fan_modes.begin(), custom_fan_modes.end(), this->custom_fan_mode.value());
|
||||
// only set custom fan mode if value exists, otherwise leave it as is
|
||||
if (it != custom_fan_modes.cend()) {
|
||||
state.custom_fan_mode = std::distance(custom_fan_modes.begin(), it);
|
||||
}
|
||||
}
|
||||
if (traits.get_supports_presets() && preset.has_value()) {
|
||||
state.uses_custom_preset = false;
|
||||
state.preset = this->preset.value();
|
||||
}
|
||||
if (!traits.get_supported_custom_presets().empty() && custom_preset.has_value()) {
|
||||
state.uses_custom_preset = true;
|
||||
auto custom_presets = traits.get_supported_custom_presets();
|
||||
auto it = std::find(custom_presets.begin(), custom_presets.end(), this->custom_preset.value());
|
||||
// only set custom preset if value exists, otherwise leave it as is
|
||||
if (it != custom_presets.cend()) {
|
||||
state.custom_preset = std::distance(custom_presets.begin(), it);
|
||||
}
|
||||
}
|
||||
if (traits.get_supports_swing_modes()) {
|
||||
state.swing_mode = this->swing_mode;
|
||||
|
@ -266,8 +381,17 @@ void Climate::publish_state() {
|
|||
if (traits.get_supports_action()) {
|
||||
ESP_LOGD(TAG, " Action: %s", climate_action_to_string(this->action));
|
||||
}
|
||||
if (traits.get_supports_fan_modes()) {
|
||||
ESP_LOGD(TAG, " Fan Mode: %s", climate_fan_mode_to_string(this->fan_mode));
|
||||
if (traits.get_supports_fan_modes() && this->fan_mode.has_value()) {
|
||||
ESP_LOGD(TAG, " Fan Mode: %s", climate_fan_mode_to_string(this->fan_mode.value()));
|
||||
}
|
||||
if (!traits.get_supported_custom_fan_modes().empty() && this->custom_fan_mode.has_value()) {
|
||||
ESP_LOGD(TAG, " Custom Fan Mode: %s", this->custom_fan_mode.value().c_str());
|
||||
}
|
||||
if (traits.get_supports_presets() && this->preset.has_value()) {
|
||||
ESP_LOGD(TAG, " Preset: %s", climate_preset_to_string(this->preset.value()));
|
||||
}
|
||||
if (!traits.get_supported_custom_presets().empty() && this->custom_preset.has_value()) {
|
||||
ESP_LOGD(TAG, " Custom Preset: %s", this->custom_preset.value().c_str());
|
||||
}
|
||||
if (traits.get_supports_swing_modes()) {
|
||||
ESP_LOGD(TAG, " Swing Mode: %s", climate_swing_mode_to_string(this->swing_mode));
|
||||
|
@ -332,9 +456,12 @@ ClimateCall ClimateDeviceRestoreState::to_call(Climate *climate) {
|
|||
if (traits.get_supports_away()) {
|
||||
call.set_away(this->away);
|
||||
}
|
||||
if (traits.get_supports_fan_modes()) {
|
||||
if (traits.get_supports_fan_modes() || !traits.get_supported_custom_fan_modes().empty()) {
|
||||
call.set_fan_mode(this->fan_mode);
|
||||
}
|
||||
if (traits.get_supports_presets() || !traits.get_supported_custom_presets().empty()) {
|
||||
call.set_preset(this->preset);
|
||||
}
|
||||
if (traits.get_supports_swing_modes()) {
|
||||
call.set_swing_mode(this->swing_mode);
|
||||
}
|
||||
|
@ -352,9 +479,21 @@ void ClimateDeviceRestoreState::apply(Climate *climate) {
|
|||
if (traits.get_supports_away()) {
|
||||
climate->away = this->away;
|
||||
}
|
||||
if (traits.get_supports_fan_modes()) {
|
||||
if (traits.get_supports_fan_modes() && !this->uses_custom_fan_mode) {
|
||||
climate->fan_mode = this->fan_mode;
|
||||
}
|
||||
if (!traits.get_supported_custom_fan_modes().empty() && this->uses_custom_fan_mode) {
|
||||
climate->custom_fan_mode = traits.get_supported_custom_fan_modes()[this->custom_fan_mode];
|
||||
}
|
||||
if (traits.get_supports_presets() && !this->uses_custom_preset) {
|
||||
climate->preset = this->preset;
|
||||
}
|
||||
if (!traits.get_supported_custom_presets().empty() && this->uses_custom_preset) {
|
||||
climate->custom_preset = traits.get_supported_custom_presets()[this->custom_preset];
|
||||
}
|
||||
if (!traits.get_supported_custom_presets().empty() && uses_custom_preset) {
|
||||
climate->custom_preset = traits.get_supported_custom_presets()[this->preset];
|
||||
}
|
||||
if (traits.get_supports_swing_modes()) {
|
||||
climate->swing_mode = this->swing_mode;
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/preferences.h"
|
||||
#include "esphome/core/log.h"
|
||||
#include "climate_mode.h"
|
||||
#include "climate_traits.h"
|
||||
|
||||
|
@ -70,12 +71,22 @@ class ClimateCall {
|
|||
ClimateCall &set_fan_mode(optional<ClimateFanMode> fan_mode);
|
||||
/// Set the fan mode of the climate device based on a string.
|
||||
ClimateCall &set_fan_mode(const std::string &fan_mode);
|
||||
/// Set the fan mode of the climate device based on a string.
|
||||
ClimateCall &set_fan_mode(optional<std::string> fan_mode);
|
||||
/// Set the swing mode of the climate device.
|
||||
ClimateCall &set_swing_mode(ClimateSwingMode swing_mode);
|
||||
/// Set the swing mode of the climate device.
|
||||
ClimateCall &set_swing_mode(optional<ClimateSwingMode> swing_mode);
|
||||
/// Set the swing mode of the climate device based on a string.
|
||||
ClimateCall &set_swing_mode(const std::string &swing_mode);
|
||||
/// Set the preset of the climate device.
|
||||
ClimateCall &set_preset(ClimatePreset preset);
|
||||
/// Set the preset of the climate device.
|
||||
ClimateCall &set_preset(optional<ClimatePreset> preset);
|
||||
/// Set the preset of the climate device based on a string.
|
||||
ClimateCall &set_preset(const std::string &preset);
|
||||
/// Set the preset of the climate device based on a string.
|
||||
ClimateCall &set_preset(optional<std::string> preset);
|
||||
|
||||
void perform();
|
||||
|
||||
|
@ -86,6 +97,9 @@ class ClimateCall {
|
|||
const optional<bool> &get_away() const;
|
||||
const optional<ClimateFanMode> &get_fan_mode() const;
|
||||
const optional<ClimateSwingMode> &get_swing_mode() const;
|
||||
const optional<std::string> &get_custom_fan_mode() const;
|
||||
const optional<ClimatePreset> &get_preset() const;
|
||||
const optional<std::string> &get_custom_preset() const;
|
||||
|
||||
protected:
|
||||
void validate_();
|
||||
|
@ -98,13 +112,25 @@ class ClimateCall {
|
|||
optional<bool> away_;
|
||||
optional<ClimateFanMode> fan_mode_;
|
||||
optional<ClimateSwingMode> swing_mode_;
|
||||
optional<std::string> custom_fan_mode_;
|
||||
optional<ClimatePreset> preset_;
|
||||
optional<std::string> custom_preset_;
|
||||
};
|
||||
|
||||
/// Struct used to save the state of the climate device in restore memory.
|
||||
struct ClimateDeviceRestoreState {
|
||||
ClimateMode mode;
|
||||
bool away;
|
||||
ClimateFanMode fan_mode;
|
||||
bool uses_custom_fan_mode{false};
|
||||
union {
|
||||
ClimateFanMode fan_mode;
|
||||
uint8_t custom_fan_mode;
|
||||
};
|
||||
bool uses_custom_preset{false};
|
||||
union {
|
||||
ClimatePreset preset;
|
||||
uint8_t custom_preset;
|
||||
};
|
||||
ClimateSwingMode swing_mode;
|
||||
union {
|
||||
float target_temperature;
|
||||
|
@ -168,11 +194,20 @@ class Climate : public Nameable {
|
|||
bool away{false};
|
||||
|
||||
/// The active fan mode of the climate device.
|
||||
ClimateFanMode fan_mode;
|
||||
optional<ClimateFanMode> fan_mode;
|
||||
|
||||
/// The active swing mode of the climate device.
|
||||
ClimateSwingMode swing_mode;
|
||||
|
||||
/// The active custom fan mode of the climate device.
|
||||
optional<std::string> custom_fan_mode;
|
||||
|
||||
/// The active preset of the climate device.
|
||||
optional<ClimatePreset> preset;
|
||||
|
||||
/// The active custom preset mode of the climate device.
|
||||
optional<std::string> custom_preset;
|
||||
|
||||
/** Add a callback for the climate device state, each time the state of the climate device is updated
|
||||
* (using publish_state), this callback will be called.
|
||||
*
|
||||
|
|
|
@ -17,6 +17,8 @@ const char *climate_mode_to_string(ClimateMode mode) {
|
|||
return "FAN_ONLY";
|
||||
case CLIMATE_MODE_DRY:
|
||||
return "DRY";
|
||||
case CLIMATE_MODE_HEAT_COOL:
|
||||
return "HEAT_COOL";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
|
@ -80,5 +82,26 @@ const char *climate_swing_mode_to_string(ClimateSwingMode swing_mode) {
|
|||
}
|
||||
}
|
||||
|
||||
const char *climate_preset_to_string(ClimatePreset preset) {
|
||||
switch (preset) {
|
||||
case climate::CLIMATE_PRESET_ECO:
|
||||
return "ECO";
|
||||
case climate::CLIMATE_PRESET_AWAY:
|
||||
return "AWAY";
|
||||
case climate::CLIMATE_PRESET_BOOST:
|
||||
return "BOOST";
|
||||
case climate::CLIMATE_PRESET_COMFORT:
|
||||
return "COMFORT";
|
||||
case climate::CLIMATE_PRESET_HOME:
|
||||
return "HOME";
|
||||
case climate::CLIMATE_PRESET_SLEEP:
|
||||
return "SLEEP";
|
||||
case climate::CLIMATE_PRESET_ACTIVITY:
|
||||
return "ACTIVITY";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace climate
|
||||
} // namespace esphome
|
||||
|
|
|
@ -10,7 +10,7 @@ enum ClimateMode : uint8_t {
|
|||
/// The climate device is off (not in auto, heat or cool mode)
|
||||
CLIMATE_MODE_OFF = 0,
|
||||
/// The climate device is set to automatically change the heating/cooling cycle
|
||||
CLIMATE_MODE_AUTO = 1,
|
||||
CLIMATE_MODE_HEAT_COOL = 1,
|
||||
/// The climate device is manually set to cool mode (not in auto mode!)
|
||||
CLIMATE_MODE_COOL = 2,
|
||||
/// The climate device is manually set to heat mode (not in auto mode!)
|
||||
|
@ -19,6 +19,8 @@ enum ClimateMode : uint8_t {
|
|||
CLIMATE_MODE_FAN_ONLY = 4,
|
||||
/// The climate device is manually set to dry mode
|
||||
CLIMATE_MODE_DRY = 5,
|
||||
/// The climate device is manually set to heat-cool mode
|
||||
CLIMATE_MODE_AUTO = 6
|
||||
};
|
||||
|
||||
/// Enum for the current action of the climate device. Values match those of ClimateMode.
|
||||
|
@ -61,7 +63,7 @@ enum ClimateFanMode : uint8_t {
|
|||
|
||||
/// Enum for all modes a climate swing can be in
|
||||
enum ClimateSwingMode : uint8_t {
|
||||
/// The sing mode is set to Off
|
||||
/// The swing mode is set to Off
|
||||
CLIMATE_SWING_OFF = 0,
|
||||
/// The fan mode is set to Both
|
||||
CLIMATE_SWING_BOTH = 1,
|
||||
|
@ -71,6 +73,24 @@ enum ClimateSwingMode : uint8_t {
|
|||
CLIMATE_SWING_HORIZONTAL = 3,
|
||||
};
|
||||
|
||||
/// Enum for all modes a climate swing can be in
|
||||
enum ClimatePreset : uint8_t {
|
||||
/// Preset is set to ECO
|
||||
CLIMATE_PRESET_ECO = 0,
|
||||
/// Preset is set to AWAY
|
||||
CLIMATE_PRESET_AWAY = 1,
|
||||
/// Preset is set to BOOST
|
||||
CLIMATE_PRESET_BOOST = 2,
|
||||
/// Preset is set to COMFORT
|
||||
CLIMATE_PRESET_COMFORT = 3,
|
||||
/// Preset is set to HOME
|
||||
CLIMATE_PRESET_HOME = 4,
|
||||
/// Preset is set to SLEEP
|
||||
CLIMATE_PRESET_SLEEP = 5,
|
||||
/// Preset is set to ACTIVITY
|
||||
CLIMATE_PRESET_ACTIVITY = 6,
|
||||
};
|
||||
|
||||
/// Convert the given ClimateMode to a human-readable string.
|
||||
const char *climate_mode_to_string(ClimateMode mode);
|
||||
|
||||
|
@ -83,5 +103,8 @@ const char *climate_fan_mode_to_string(ClimateFanMode mode);
|
|||
/// Convert the given ClimateSwingMode to a human-readable string.
|
||||
const char *climate_swing_mode_to_string(ClimateSwingMode mode);
|
||||
|
||||
/// Convert the given ClimateSwingMode to a human-readable string.
|
||||
const char *climate_preset_to_string(ClimatePreset preset);
|
||||
|
||||
} // namespace climate
|
||||
} // namespace esphome
|
||||
|
|
|
@ -119,6 +119,71 @@ bool ClimateTraits::get_supports_fan_modes() const {
|
|||
this->supports_fan_mode_low_ || this->supports_fan_mode_medium_ || this->supports_fan_mode_high_ ||
|
||||
this->supports_fan_mode_middle_ || this->supports_fan_mode_focus_ || this->supports_fan_mode_diffuse_;
|
||||
}
|
||||
void ClimateTraits::set_supported_custom_fan_modes(std::vector<std::string> &supported_custom_fan_modes) {
|
||||
this->supported_custom_fan_modes_ = supported_custom_fan_modes;
|
||||
}
|
||||
const std::vector<std::string> ClimateTraits::get_supported_custom_fan_modes() const {
|
||||
return this->supported_custom_fan_modes_;
|
||||
}
|
||||
bool ClimateTraits::supports_custom_fan_mode(std::string &custom_fan_mode) const {
|
||||
return std::count(this->supported_custom_fan_modes_.begin(), this->supported_custom_fan_modes_.end(),
|
||||
custom_fan_mode);
|
||||
}
|
||||
bool ClimateTraits::supports_preset(ClimatePreset preset) const {
|
||||
switch (preset) {
|
||||
case climate::CLIMATE_PRESET_ECO:
|
||||
return this->supports_preset_eco_;
|
||||
case climate::CLIMATE_PRESET_AWAY:
|
||||
return this->supports_preset_away_;
|
||||
case climate::CLIMATE_PRESET_BOOST:
|
||||
return this->supports_preset_boost_;
|
||||
case climate::CLIMATE_PRESET_COMFORT:
|
||||
return this->supports_preset_comfort_;
|
||||
case climate::CLIMATE_PRESET_HOME:
|
||||
return this->supports_preset_home_;
|
||||
case climate::CLIMATE_PRESET_SLEEP:
|
||||
return this->supports_preset_sleep_;
|
||||
case climate::CLIMATE_PRESET_ACTIVITY:
|
||||
return this->supports_preset_activity_;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
void ClimateTraits::set_supports_preset_eco(bool supports_preset_eco) {
|
||||
this->supports_preset_eco_ = supports_preset_eco;
|
||||
}
|
||||
void ClimateTraits::set_supports_preset_away(bool supports_preset_away) {
|
||||
this->supports_preset_away_ = supports_preset_away;
|
||||
}
|
||||
void ClimateTraits::set_supports_preset_boost(bool supports_preset_boost) {
|
||||
this->supports_preset_boost_ = supports_preset_boost;
|
||||
}
|
||||
void ClimateTraits::set_supports_preset_comfort(bool supports_preset_comfort) {
|
||||
this->supports_preset_comfort_ = supports_preset_comfort;
|
||||
}
|
||||
void ClimateTraits::set_supports_preset_home(bool supports_preset_home) {
|
||||
this->supports_preset_home_ = supports_preset_home;
|
||||
}
|
||||
void ClimateTraits::set_supports_preset_sleep(bool supports_preset_sleep) {
|
||||
this->supports_preset_sleep_ = supports_preset_sleep;
|
||||
}
|
||||
void ClimateTraits::set_supports_preset_activity(bool supports_preset_activity) {
|
||||
this->supports_preset_activity_ = supports_preset_activity;
|
||||
}
|
||||
bool ClimateTraits::get_supports_presets() const {
|
||||
return this->supports_preset_eco_ || this->supports_preset_away_ || this->supports_preset_boost_ ||
|
||||
this->supports_preset_comfort_ || this->supports_preset_home_ || this->supports_preset_sleep_ ||
|
||||
this->supports_preset_activity_;
|
||||
}
|
||||
void ClimateTraits::set_supported_custom_presets(std::vector<std::string> &supported_custom_presets) {
|
||||
this->supported_custom_presets_ = supported_custom_presets;
|
||||
}
|
||||
const std::vector<std::string> ClimateTraits::get_supported_custom_presets() const {
|
||||
return this->supported_custom_presets_;
|
||||
}
|
||||
bool ClimateTraits::supports_custom_preset(std::string &custom_preset) const {
|
||||
return std::count(this->supported_custom_presets_.begin(), this->supported_custom_presets_.end(), custom_preset);
|
||||
}
|
||||
void ClimateTraits::set_supports_swing_mode_off(bool supports_swing_mode_off) {
|
||||
this->supports_swing_mode_off_ = supports_swing_mode_off;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "climate_mode.h"
|
||||
|
||||
namespace esphome {
|
||||
|
@ -65,6 +66,21 @@ class ClimateTraits {
|
|||
void set_supports_fan_mode_diffuse(bool supports_fan_mode_diffuse);
|
||||
bool supports_fan_mode(ClimateFanMode fan_mode) const;
|
||||
bool get_supports_fan_modes() const;
|
||||
void set_supported_custom_fan_modes(std::vector<std::string> &supported_custom_fan_modes);
|
||||
const std::vector<std::string> get_supported_custom_fan_modes() const;
|
||||
bool supports_custom_fan_mode(std::string &custom_fan_mode) const;
|
||||
bool supports_preset(ClimatePreset preset) const;
|
||||
void set_supports_preset_eco(bool supports_preset_eco);
|
||||
void set_supports_preset_away(bool supports_preset_away);
|
||||
void set_supports_preset_boost(bool supports_preset_boost);
|
||||
void set_supports_preset_comfort(bool supports_preset_comfort);
|
||||
void set_supports_preset_home(bool supports_preset_home);
|
||||
void set_supports_preset_sleep(bool supports_preset_sleep);
|
||||
void set_supports_preset_activity(bool supports_preset_activity);
|
||||
bool get_supports_presets() const;
|
||||
void set_supported_custom_presets(std::vector<std::string> &supported_custom_presets);
|
||||
const std::vector<std::string> get_supported_custom_presets() const;
|
||||
bool supports_custom_preset(std::string &custom_preset) const;
|
||||
void set_supports_swing_mode_off(bool supports_swing_mode_off);
|
||||
void set_supports_swing_mode_both(bool supports_swing_mode_both);
|
||||
void set_supports_swing_mode_vertical(bool supports_swing_mode_vertical);
|
||||
|
@ -103,6 +119,15 @@ class ClimateTraits {
|
|||
bool supports_swing_mode_both_{false};
|
||||
bool supports_swing_mode_vertical_{false};
|
||||
bool supports_swing_mode_horizontal_{false};
|
||||
bool supports_preset_eco_{false};
|
||||
bool supports_preset_away_{false};
|
||||
bool supports_preset_boost_{false};
|
||||
bool supports_preset_comfort_{false};
|
||||
bool supports_preset_home_{false};
|
||||
bool supports_preset_sleep_{false};
|
||||
bool supports_preset_activity_{false};
|
||||
std::vector<std::string> supported_custom_fan_modes_;
|
||||
std::vector<std::string> supported_custom_presets_;
|
||||
|
||||
float visual_min_temperature_{10};
|
||||
float visual_max_temperature_{30};
|
||||
|
|
|
@ -72,7 +72,7 @@ void LgIrClimate::transmit_state() {
|
|||
remote_state |= FAN_AUTO;
|
||||
} else if (this->mode == climate::CLIMATE_MODE_COOL || this->mode == climate::CLIMATE_MODE_DRY ||
|
||||
this->mode == climate::CLIMATE_MODE_HEAT) {
|
||||
switch (this->fan_mode) {
|
||||
switch (this->fan_mode.value()) {
|
||||
case climate::CLIMATE_FAN_HIGH:
|
||||
remote_state |= FAN_MAX;
|
||||
break;
|
||||
|
|
|
@ -93,7 +93,7 @@ void CoolixClimate::transmit_state() {
|
|||
this->fan_mode = climate::CLIMATE_FAN_AUTO;
|
||||
remote_state |= COOLIX_FAN_MODE_AUTO_DRY;
|
||||
} else {
|
||||
switch (this->fan_mode) {
|
||||
switch (this->fan_mode.value()) {
|
||||
case climate::CLIMATE_FAN_HIGH:
|
||||
remote_state |= COOLIX_FAN_MAX;
|
||||
break;
|
||||
|
|
|
@ -94,7 +94,7 @@ uint8_t DaikinClimate::operation_mode_() {
|
|||
|
||||
uint16_t DaikinClimate::fan_speed_() {
|
||||
uint16_t fan_speed;
|
||||
switch (this->fan_mode) {
|
||||
switch (this->fan_mode.value()) {
|
||||
case climate::CLIMATE_FAN_LOW:
|
||||
fan_speed = DAIKIN_FAN_1 << 8;
|
||||
break;
|
||||
|
|
|
@ -140,7 +140,7 @@ void FujitsuGeneralClimate::transmit_state() {
|
|||
}
|
||||
|
||||
// Set fan
|
||||
switch (this->fan_mode) {
|
||||
switch (this->fan_mode.value()) {
|
||||
case climate::CLIMATE_FAN_HIGH:
|
||||
SET_NIBBLE(remote_state, FUJITSU_GENERAL_FAN_NIBBLE, FUJITSU_GENERAL_FAN_HIGH);
|
||||
break;
|
||||
|
|
|
@ -164,11 +164,13 @@ void HitachiClimate::transmit_state() {
|
|||
case climate::CLIMATE_MODE_OFF:
|
||||
set_power_(false);
|
||||
break;
|
||||
default:
|
||||
ESP_LOGW(TAG, "Unsupported mode: %s", climate_mode_to_string(this->mode));
|
||||
}
|
||||
|
||||
set_temp_(static_cast<uint8_t>(this->target_temperature));
|
||||
|
||||
switch (this->fan_mode) {
|
||||
switch (this->fan_mode.value()) {
|
||||
case climate::CLIMATE_FAN_LOW:
|
||||
set_fan_(HITACHI_AC344_FAN_LOW);
|
||||
break;
|
||||
|
|
|
@ -2,7 +2,12 @@ from esphome.components import climate, sensor
|
|||
import esphome.config_validation as cv
|
||||
import esphome.codegen as cg
|
||||
from esphome.const import (
|
||||
CONF_CUSTOM_FAN_MODES,
|
||||
CONF_CUSTOM_PRESETS,
|
||||
CONF_ID,
|
||||
CONF_PRESET_BOOST,
|
||||
CONF_PRESET_ECO,
|
||||
CONF_PRESET_SLEEP,
|
||||
STATE_CLASS_MEASUREMENT,
|
||||
UNIT_CELSIUS,
|
||||
UNIT_PERCENT,
|
||||
|
@ -18,7 +23,6 @@ from esphome.components.midea_dongle import CONF_MIDEA_DONGLE_ID, MideaDongle
|
|||
|
||||
AUTO_LOAD = ["climate", "sensor", "midea_dongle"]
|
||||
CODEOWNERS = ["@dudanov"]
|
||||
|
||||
CONF_BEEPER = "beeper"
|
||||
CONF_SWING_HORIZONTAL = "swing_horizontal"
|
||||
CONF_SWING_BOTH = "swing_both"
|
||||
|
@ -28,14 +32,36 @@ CONF_HUMIDITY_SETPOINT = "humidity_setpoint"
|
|||
midea_ac_ns = cg.esphome_ns.namespace("midea_ac")
|
||||
MideaAC = midea_ac_ns.class_("MideaAC", climate.Climate, cg.Component)
|
||||
|
||||
CLIMATE_CUSTOM_FAN_MODES = {
|
||||
"SILENT": "silent",
|
||||
"TURBO": "turbo",
|
||||
}
|
||||
|
||||
validate_climate_custom_fan_mode = cv.enum(CLIMATE_CUSTOM_FAN_MODES, upper=True)
|
||||
|
||||
CLIMATE_CUSTOM_PRESETS = {
|
||||
"FREEZE_PROTECTION": "freeze protection",
|
||||
}
|
||||
|
||||
validate_climate_custom_preset = cv.enum(CLIMATE_CUSTOM_PRESETS, upper=True)
|
||||
|
||||
CONFIG_SCHEMA = cv.All(
|
||||
climate.CLIMATE_SCHEMA.extend(
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(MideaAC),
|
||||
cv.GenerateID(CONF_MIDEA_DONGLE_ID): cv.use_id(MideaDongle),
|
||||
cv.Optional(CONF_BEEPER, default=False): cv.boolean,
|
||||
cv.Optional(CONF_CUSTOM_FAN_MODES): cv.ensure_list(
|
||||
validate_climate_custom_fan_mode
|
||||
),
|
||||
cv.Optional(CONF_CUSTOM_PRESETS): cv.ensure_list(
|
||||
validate_climate_custom_preset
|
||||
),
|
||||
cv.Optional(CONF_SWING_HORIZONTAL, default=False): cv.boolean,
|
||||
cv.Optional(CONF_SWING_BOTH, default=False): cv.boolean,
|
||||
cv.Optional(CONF_PRESET_ECO, default=False): cv.boolean,
|
||||
cv.Optional(CONF_PRESET_SLEEP, default=False): cv.boolean,
|
||||
cv.Optional(CONF_PRESET_BOOST, default=False): cv.boolean,
|
||||
cv.Optional(CONF_OUTDOOR_TEMPERATURE): sensor.sensor_schema(
|
||||
UNIT_CELSIUS,
|
||||
ICON_THERMOMETER,
|
||||
|
@ -65,8 +91,15 @@ async def to_code(config):
|
|||
paren = await cg.get_variable(config[CONF_MIDEA_DONGLE_ID])
|
||||
cg.add(var.set_midea_dongle_parent(paren))
|
||||
cg.add(var.set_beeper_feedback(config[CONF_BEEPER]))
|
||||
if CONF_CUSTOM_FAN_MODES in config:
|
||||
cg.add(var.set_custom_fan_modes(config[CONF_CUSTOM_FAN_MODES]))
|
||||
if CONF_CUSTOM_PRESETS in config:
|
||||
cg.add(var.set_custom_presets(config[CONF_CUSTOM_PRESETS]))
|
||||
cg.add(var.set_swing_horizontal(config[CONF_SWING_HORIZONTAL]))
|
||||
cg.add(var.set_swing_both(config[CONF_SWING_BOTH]))
|
||||
cg.add(var.set_preset_eco(config[CONF_PRESET_ECO]))
|
||||
cg.add(var.set_preset_sleep(config[CONF_PRESET_SLEEP]))
|
||||
cg.add(var.set_preset_boost(config[CONF_PRESET_BOOST]))
|
||||
if CONF_OUTDOOR_TEMPERATURE in config:
|
||||
sens = await sensor.new_sensor(config[CONF_OUTDOOR_TEMPERATURE])
|
||||
cg.add(var.set_outdoor_temperature_sensor(sens))
|
||||
|
|
|
@ -40,8 +40,24 @@ void MideaAC::on_frame(const midea_dongle::Frame &frame) {
|
|||
set_property(this->mode, p.get_mode(), need_publish);
|
||||
set_property(this->target_temperature, p.get_target_temp(), need_publish);
|
||||
set_property(this->current_temperature, p.get_indoor_temp(), need_publish);
|
||||
set_property(this->fan_mode, p.get_fan_mode(), need_publish);
|
||||
if (p.is_custom_fan_mode()) {
|
||||
this->fan_mode.reset();
|
||||
optional<std::string> mode = p.get_custom_fan_mode();
|
||||
set_property(this->custom_fan_mode, mode, need_publish);
|
||||
} else {
|
||||
this->custom_fan_mode.reset();
|
||||
optional<climate::ClimateFanMode> mode = p.get_fan_mode();
|
||||
set_property(this->fan_mode, mode, need_publish);
|
||||
}
|
||||
set_property(this->swing_mode, p.get_swing_mode(), need_publish);
|
||||
if (p.is_custom_preset()) {
|
||||
this->preset.reset();
|
||||
optional<std::string> preset = p.get_custom_preset();
|
||||
set_property(this->custom_preset, preset, need_publish);
|
||||
} else {
|
||||
this->custom_preset.reset();
|
||||
set_property(this->preset, p.get_preset(), need_publish);
|
||||
}
|
||||
if (need_publish)
|
||||
this->publish_state();
|
||||
set_sensor(this->outdoor_sensor_, p.get_outdoor_temp());
|
||||
|
@ -61,6 +77,48 @@ void MideaAC::on_update() {
|
|||
}
|
||||
}
|
||||
|
||||
bool MideaAC::allow_preset(climate::ClimatePreset preset) const {
|
||||
switch (preset) {
|
||||
case climate::CLIMATE_PRESET_ECO:
|
||||
if (this->mode == climate::CLIMATE_MODE_COOL) {
|
||||
return true;
|
||||
} else {
|
||||
ESP_LOGD(TAG, "ECO preset is only available in COOL mode");
|
||||
}
|
||||
break;
|
||||
case climate::CLIMATE_PRESET_SLEEP:
|
||||
if (this->mode == climate::CLIMATE_MODE_FAN_ONLY || this->mode == climate::CLIMATE_MODE_DRY) {
|
||||
ESP_LOGD(TAG, "SLEEP preset is not available in FAN_ONLY or DRY mode");
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case climate::CLIMATE_PRESET_BOOST:
|
||||
if (this->mode == climate::CLIMATE_MODE_HEAT || this->mode == climate::CLIMATE_MODE_COOL) {
|
||||
return true;
|
||||
} else {
|
||||
ESP_LOGD(TAG, "BOOST preset is only available in HEAT or COOL mode");
|
||||
}
|
||||
break;
|
||||
case climate::CLIMATE_PRESET_HOME:
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MideaAC::allow_custom_preset(const std::string &custom_preset) const {
|
||||
if (custom_preset == MIDEA_FREEZE_PROTECTION_PRESET) {
|
||||
if (this->mode == climate::CLIMATE_MODE_HEAT) {
|
||||
return true;
|
||||
} else {
|
||||
ESP_LOGD(TAG, "%s is only available in HEAT mode", MIDEA_FREEZE_PROTECTION_PRESET.c_str());
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void MideaAC::control(const climate::ClimateCall &call) {
|
||||
if (call.get_mode().has_value() && call.get_mode().value() != this->mode) {
|
||||
this->cmd_frame_.set_mode(call.get_mode().value());
|
||||
|
@ -70,14 +128,34 @@ void MideaAC::control(const climate::ClimateCall &call) {
|
|||
this->cmd_frame_.set_target_temp(call.get_target_temperature().value());
|
||||
this->ctrl_request_ = true;
|
||||
}
|
||||
if (call.get_fan_mode().has_value() && call.get_fan_mode().value() != this->fan_mode) {
|
||||
if (call.get_fan_mode().has_value() &&
|
||||
(!this->fan_mode.has_value() || this->fan_mode.value() != call.get_fan_mode().value())) {
|
||||
this->custom_fan_mode.reset();
|
||||
this->cmd_frame_.set_fan_mode(call.get_fan_mode().value());
|
||||
this->ctrl_request_ = true;
|
||||
}
|
||||
if (call.get_custom_fan_mode().has_value() &&
|
||||
(!this->custom_fan_mode.has_value() || this->custom_fan_mode.value() != call.get_custom_fan_mode().value())) {
|
||||
this->fan_mode.reset();
|
||||
this->cmd_frame_.set_custom_fan_mode(call.get_custom_fan_mode().value());
|
||||
this->ctrl_request_ = true;
|
||||
}
|
||||
if (call.get_swing_mode().has_value() && call.get_swing_mode().value() != this->swing_mode) {
|
||||
this->cmd_frame_.set_swing_mode(call.get_swing_mode().value());
|
||||
this->ctrl_request_ = true;
|
||||
}
|
||||
if (call.get_preset().has_value() && this->allow_preset(call.get_preset().value()) &&
|
||||
(!this->preset.has_value() || this->preset.value() != call.get_preset().value())) {
|
||||
this->custom_preset.reset();
|
||||
this->cmd_frame_.set_preset(call.get_preset().value());
|
||||
this->ctrl_request_ = true;
|
||||
}
|
||||
if (call.get_custom_preset().has_value() && this->allow_custom_preset(call.get_custom_preset().value()) &&
|
||||
(!this->custom_preset.has_value() || this->custom_preset.value() != call.get_custom_preset().value())) {
|
||||
this->preset.reset();
|
||||
this->cmd_frame_.set_custom_preset(call.get_custom_preset().value());
|
||||
this->ctrl_request_ = true;
|
||||
}
|
||||
if (this->ctrl_request_) {
|
||||
this->cmd_frame_.set_beeper_feedback(this->beeper_feedback_);
|
||||
this->cmd_frame_.finalize();
|
||||
|
@ -98,10 +176,16 @@ climate::ClimateTraits MideaAC::traits() {
|
|||
traits.set_supports_fan_mode_low(true);
|
||||
traits.set_supports_fan_mode_medium(true);
|
||||
traits.set_supports_fan_mode_high(true);
|
||||
traits.set_supported_custom_fan_modes(this->traits_custom_fan_modes_);
|
||||
traits.set_supports_swing_mode_off(true);
|
||||
traits.set_supports_swing_mode_vertical(true);
|
||||
traits.set_supports_swing_mode_horizontal(this->traits_swing_horizontal_);
|
||||
traits.set_supports_swing_mode_both(this->traits_swing_both_);
|
||||
traits.set_supports_preset_home(true);
|
||||
traits.set_supports_preset_eco(this->traits_preset_eco_);
|
||||
traits.set_supports_preset_sleep(this->traits_preset_sleep_);
|
||||
traits.set_supports_preset_boost(this->traits_preset_boost_);
|
||||
traits.set_supported_custom_presets(this->traits_custom_presets_);
|
||||
traits.set_supports_current_temperature(true);
|
||||
return traits;
|
||||
}
|
||||
|
|
|
@ -22,6 +22,15 @@ class MideaAC : public midea_dongle::MideaAppliance, public climate::Climate, pu
|
|||
void set_beeper_feedback(bool state) { this->beeper_feedback_ = state; }
|
||||
void set_swing_horizontal(bool state) { this->traits_swing_horizontal_ = state; }
|
||||
void set_swing_both(bool state) { this->traits_swing_both_ = state; }
|
||||
void set_preset_eco(bool state) { this->traits_preset_eco_ = state; }
|
||||
void set_preset_sleep(bool state) { this->traits_preset_sleep_ = state; }
|
||||
void set_preset_boost(bool state) { this->traits_preset_boost_ = state; }
|
||||
bool allow_preset(climate::ClimatePreset preset) const;
|
||||
void set_custom_fan_modes(std::vector<std::string> custom_fan_modes) {
|
||||
this->traits_custom_fan_modes_ = custom_fan_modes;
|
||||
}
|
||||
void set_custom_presets(std::vector<std::string> custom_presets) { this->traits_custom_presets_ = custom_presets; }
|
||||
bool allow_custom_preset(const std::string &custom_preset) const;
|
||||
|
||||
protected:
|
||||
/// Override control to change settings of the climate device.
|
||||
|
@ -41,6 +50,11 @@ class MideaAC : public midea_dongle::MideaAppliance, public climate::Climate, pu
|
|||
bool beeper_feedback_{false};
|
||||
bool traits_swing_horizontal_{false};
|
||||
bool traits_swing_both_{false};
|
||||
bool traits_preset_eco_{false};
|
||||
bool traits_preset_sleep_{false};
|
||||
bool traits_preset_boost_{false};
|
||||
std::vector<std::string> traits_custom_fan_modes_{{}};
|
||||
std::vector<std::string> traits_custom_presets_{{}};
|
||||
};
|
||||
|
||||
} // namespace midea_ac
|
||||
|
|
|
@ -3,6 +3,11 @@
|
|||
namespace esphome {
|
||||
namespace midea_ac {
|
||||
|
||||
static const char *TAG = "midea_ac";
|
||||
const std::string MIDEA_SILENT_FAN_MODE = "silent";
|
||||
const std::string MIDEA_TURBO_FAN_MODE = "turbo";
|
||||
const std::string MIDEA_FREEZE_PROTECTION_PRESET = "freeze protection";
|
||||
|
||||
const uint8_t QueryFrame::INIT[] = {0xAA, 0x22, 0xAC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x41, 0x00,
|
||||
0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0x68};
|
||||
|
@ -80,6 +85,54 @@ void PropertiesFrame::set_mode(climate::ClimateMode mode) {
|
|||
this->pbuf_[12] |= m << 5;
|
||||
}
|
||||
|
||||
optional<climate::ClimatePreset> PropertiesFrame::get_preset() const {
|
||||
if (this->get_eco_mode()) {
|
||||
return climate::CLIMATE_PRESET_ECO;
|
||||
} else if (this->get_sleep_mode()) {
|
||||
return climate::CLIMATE_PRESET_SLEEP;
|
||||
} else if (this->get_turbo_mode()) {
|
||||
return climate::CLIMATE_PRESET_BOOST;
|
||||
} else {
|
||||
return climate::CLIMATE_PRESET_HOME;
|
||||
}
|
||||
}
|
||||
|
||||
void PropertiesFrame::set_preset(climate::ClimatePreset preset) {
|
||||
switch (preset) {
|
||||
case climate::CLIMATE_PRESET_ECO:
|
||||
this->set_eco_mode(true);
|
||||
break;
|
||||
case climate::CLIMATE_PRESET_SLEEP:
|
||||
this->set_sleep_mode(true);
|
||||
break;
|
||||
case climate::CLIMATE_PRESET_BOOST:
|
||||
this->set_turbo_mode(true);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool PropertiesFrame::is_custom_preset() const { return this->get_freeze_protection_mode(); }
|
||||
|
||||
const std::string &PropertiesFrame::get_custom_preset() const { return midea_ac::MIDEA_FREEZE_PROTECTION_PRESET; };
|
||||
|
||||
void PropertiesFrame::set_custom_preset(const std::string &preset) {
|
||||
if (preset == MIDEA_FREEZE_PROTECTION_PRESET) {
|
||||
this->set_freeze_protection_mode(true);
|
||||
}
|
||||
}
|
||||
|
||||
bool PropertiesFrame::is_custom_fan_mode() const {
|
||||
switch (this->pbuf_[13]) {
|
||||
case MIDEA_FAN_SILENT:
|
||||
case MIDEA_FAN_TURBO:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
climate::ClimateFanMode PropertiesFrame::get_fan_mode() const {
|
||||
switch (this->pbuf_[13]) {
|
||||
case MIDEA_FAN_LOW:
|
||||
|
@ -112,6 +165,25 @@ void PropertiesFrame::set_fan_mode(climate::ClimateFanMode mode) {
|
|||
this->pbuf_[13] = m;
|
||||
}
|
||||
|
||||
const std::string &PropertiesFrame::get_custom_fan_mode() const {
|
||||
switch (this->pbuf_[13]) {
|
||||
case MIDEA_FAN_SILENT:
|
||||
return MIDEA_SILENT_FAN_MODE;
|
||||
default:
|
||||
return MIDEA_TURBO_FAN_MODE;
|
||||
}
|
||||
}
|
||||
|
||||
void PropertiesFrame::set_custom_fan_mode(const std::string &mode) {
|
||||
uint8_t m;
|
||||
if (mode == MIDEA_SILENT_FAN_MODE) {
|
||||
m = MIDEA_FAN_SILENT;
|
||||
} else {
|
||||
m = MIDEA_FAN_TURBO;
|
||||
}
|
||||
this->pbuf_[13] = m;
|
||||
}
|
||||
|
||||
climate::ClimateSwingMode PropertiesFrame::get_swing_mode() const {
|
||||
switch (this->pbuf_[17] & 0x0F) {
|
||||
case MIDEA_SWING_VERTICAL:
|
||||
|
|
|
@ -5,6 +5,10 @@
|
|||
namespace esphome {
|
||||
namespace midea_ac {
|
||||
|
||||
extern const std::string MIDEA_SILENT_FAN_MODE;
|
||||
extern const std::string MIDEA_TURBO_FAN_MODE;
|
||||
extern const std::string MIDEA_FREEZE_PROTECTION_PRESET;
|
||||
|
||||
/// Enum for all modes a Midea device can be in.
|
||||
enum MideaMode : uint8_t {
|
||||
/// The Midea device is set to automatically change the heating/cooling cycle
|
||||
|
@ -23,12 +27,16 @@ enum MideaMode : uint8_t {
|
|||
enum MideaFanMode : uint8_t {
|
||||
/// The fan mode is set to Auto
|
||||
MIDEA_FAN_AUTO = 102,
|
||||
/// The fan mode is set to Silent
|
||||
MIDEA_FAN_SILENT = 20,
|
||||
/// The fan mode is set to Low
|
||||
MIDEA_FAN_LOW = 40,
|
||||
/// The fan mode is set to Medium
|
||||
MIDEA_FAN_MEDIUM = 60,
|
||||
/// The fan mode is set to High
|
||||
MIDEA_FAN_HIGH = 80,
|
||||
/// The fan mode is set to Turbo
|
||||
MIDEA_FAN_TURBO = 100,
|
||||
};
|
||||
|
||||
/// Enum for all modes a Midea swing can be in
|
||||
|
@ -65,9 +73,13 @@ class PropertiesFrame : public midea_dongle::BaseFrame {
|
|||
void set_mode(climate::ClimateMode mode);
|
||||
|
||||
/* FAN SPEED */
|
||||
bool is_custom_fan_mode() const;
|
||||
climate::ClimateFanMode get_fan_mode() const;
|
||||
void set_fan_mode(climate::ClimateFanMode mode);
|
||||
|
||||
const std::string &get_custom_fan_mode() const;
|
||||
void set_custom_fan_mode(const std::string &mode);
|
||||
|
||||
/* SWING MODE */
|
||||
climate::ClimateSwingMode get_swing_mode() const;
|
||||
void set_swing_mode(climate::ClimateSwingMode mode);
|
||||
|
@ -82,16 +94,28 @@ class PropertiesFrame : public midea_dongle::BaseFrame {
|
|||
float get_humidity_setpoint() const;
|
||||
|
||||
/* ECO MODE */
|
||||
bool get_eco_mode() const { return this->pbuf_[19]; }
|
||||
void set_eco_mode(bool state) { this->set_bytemask_(19, 0xFF, state); }
|
||||
bool get_eco_mode() const { return this->pbuf_[19] & 0x10; }
|
||||
void set_eco_mode(bool state) { this->set_bytemask_(19, 0x80, state); }
|
||||
|
||||
/* SLEEP MODE */
|
||||
bool get_sleep_mode() const { return this->pbuf_[20] & 0x01; }
|
||||
void set_sleep_mode(bool state) { this->set_bytemask_(20, 0x01, state); }
|
||||
|
||||
/* TURBO MODE */
|
||||
bool get_turbo_mode() const { return this->pbuf_[20] & 0x02; }
|
||||
void set_turbo_mode(bool state) { this->set_bytemask_(20, 0x02, state); }
|
||||
bool get_turbo_mode() const { return this->pbuf_[18] & 0x20; }
|
||||
void set_turbo_mode(bool state) { this->set_bytemask_(18, 0x20, state); }
|
||||
|
||||
/* FREEZE PROTECTION */
|
||||
bool get_freeze_protection_mode() const { return this->pbuf_[31] & 0x80; }
|
||||
void set_freeze_protection_mode(bool state) { this->set_bytemask_(31, 0x80, state); }
|
||||
|
||||
/* PRESET */
|
||||
optional<climate::ClimatePreset> get_preset() const;
|
||||
void set_preset(climate::ClimatePreset preset);
|
||||
|
||||
bool is_custom_preset() const;
|
||||
const std::string &get_custom_preset() const;
|
||||
void set_custom_preset(const std::string &preset);
|
||||
|
||||
/* POWER USAGE */
|
||||
float get_power_usage() const;
|
||||
|
|
|
@ -35,6 +35,8 @@ void MQTTClimateComponent::send_discovery(JsonObject &root, mqtt::SendDiscoveryC
|
|||
modes.add("fan_only");
|
||||
if (traits.supports_mode(CLIMATE_MODE_DRY))
|
||||
modes.add("dry");
|
||||
if (traits.supports_mode(CLIMATE_MODE_HEAT_COOL))
|
||||
modes.add("heat_cool");
|
||||
|
||||
if (traits.get_supports_two_point_target_temperature()) {
|
||||
// temperature_low_command_topic
|
||||
|
@ -231,6 +233,9 @@ bool MQTTClimateComponent::publish_state_() {
|
|||
case CLIMATE_MODE_DRY:
|
||||
mode_s = "dry";
|
||||
break;
|
||||
case CLIMATE_MODE_HEAT_COOL:
|
||||
mode_s = "heat_cool";
|
||||
break;
|
||||
}
|
||||
bool success = true;
|
||||
if (!this->publish(this->get_mode_state_topic(), mode_s))
|
||||
|
@ -287,7 +292,7 @@ bool MQTTClimateComponent::publish_state_() {
|
|||
|
||||
if (traits.get_supports_fan_modes()) {
|
||||
const char *payload = "";
|
||||
switch (this->device_->fan_mode) {
|
||||
switch (this->device_->fan_mode.value()) {
|
||||
case CLIMATE_FAN_ON:
|
||||
payload = "on";
|
||||
break;
|
||||
|
|
|
@ -88,7 +88,7 @@ void Tcl112Climate::transmit_state() {
|
|||
|
||||
// Set fan
|
||||
uint8_t selected_fan;
|
||||
switch (this->fan_mode) {
|
||||
switch (this->fan_mode.value()) {
|
||||
case climate::CLIMATE_FAN_HIGH:
|
||||
selected_fan = TCL112_FAN_HIGH;
|
||||
break;
|
||||
|
|
|
@ -33,7 +33,7 @@ float ThermostatClimate::hysteresis() { return this->hysteresis_; }
|
|||
void ThermostatClimate::refresh() {
|
||||
this->switch_to_mode_(this->mode);
|
||||
this->switch_to_action_(compute_action_());
|
||||
this->switch_to_fan_mode_(this->fan_mode);
|
||||
this->switch_to_fan_mode_(this->fan_mode.value());
|
||||
this->switch_to_swing_mode_(this->swing_mode);
|
||||
this->publish_state();
|
||||
}
|
||||
|
|
|
@ -81,7 +81,7 @@ void WhirlpoolClimate::transmit_state() {
|
|||
remote_state[3] |= (uint8_t)(temp - this->temperature_min_()) << 4;
|
||||
|
||||
// Fan speed
|
||||
switch (this->fan_mode) {
|
||||
switch (this->fan_mode.value()) {
|
||||
case climate::CLIMATE_FAN_HIGH:
|
||||
remote_state[2] |= WHIRLPOOL_FAN_HIGH;
|
||||
break;
|
||||
|
|
|
@ -145,6 +145,10 @@ CONF_CSS_URL = "css_url"
|
|||
CONF_CURRENT = "current"
|
||||
CONF_CURRENT_OPERATION = "current_operation"
|
||||
CONF_CURRENT_RESISTOR = "current_resistor"
|
||||
CONF_CUSTOM_FAN_MODE = "custom_fan_mode"
|
||||
CONF_CUSTOM_FAN_MODES = "custom_fan_modes"
|
||||
CONF_CUSTOM_PRESET = "custom_preset"
|
||||
CONF_CUSTOM_PRESETS = "custom_presets"
|
||||
CONF_DALLAS_ID = "dallas_id"
|
||||
CONF_DATA = "data"
|
||||
CONF_DATA_PIN = "data_pin"
|
||||
|
@ -449,6 +453,10 @@ CONF_POWER_FACTOR = "power_factor"
|
|||
CONF_POWER_ON_VALUE = "power_on_value"
|
||||
CONF_POWER_SAVE_MODE = "power_save_mode"
|
||||
CONF_POWER_SUPPLY = "power_supply"
|
||||
CONF_PRESET = "preset"
|
||||
CONF_PRESET_BOOST = "preset_boost"
|
||||
CONF_PRESET_ECO = "preset_eco"
|
||||
CONF_PRESET_SLEEP = "preset_sleep"
|
||||
CONF_PRESSURE = "pressure"
|
||||
CONF_PRIORITY = "priority"
|
||||
CONF_PROTOCOL = "protocol"
|
||||
|
|
|
@ -1525,23 +1525,6 @@ climate:
|
|||
name: Toshiba Climate
|
||||
- platform: hitachi_ac344
|
||||
name: Hitachi Climate
|
||||
- platform: midea_ac
|
||||
visual:
|
||||
min_temperature: 18 °C
|
||||
max_temperature: 25 °C
|
||||
temperature_step: 0.1 °C
|
||||
name: 'Electrolux EACS'
|
||||
beeper: true
|
||||
outdoor_temperature:
|
||||
name: 'Temp'
|
||||
power_usage:
|
||||
name: 'Power'
|
||||
humidity_setpoint:
|
||||
name: 'Hum'
|
||||
|
||||
midea_dongle:
|
||||
uart_id: uart0
|
||||
strength_icon: true
|
||||
|
||||
switch:
|
||||
- platform: gpio
|
||||
|
|
|
@ -658,6 +658,17 @@ script:
|
|||
- id: my_script
|
||||
then:
|
||||
- lambda: 'ESP_LOGD("main", "Hello World!");'
|
||||
- id: climate_custom
|
||||
then:
|
||||
- climate.control:
|
||||
id: midea_ac_unit
|
||||
custom_preset: FREEZE_PROTECTION
|
||||
custom_fan_mode: SILENT
|
||||
- id: climate_preset
|
||||
then:
|
||||
- climate.control:
|
||||
id: midea_ac_unit
|
||||
preset: SLEEP
|
||||
|
||||
sm2135:
|
||||
data_pin: GPIO12
|
||||
|
@ -819,6 +830,32 @@ climate:
|
|||
kp: 0.0
|
||||
ki: 0.0
|
||||
kd: 0.0
|
||||
- platform: midea_ac
|
||||
id: midea_ac_unit
|
||||
visual:
|
||||
min_temperature: 18 °C
|
||||
max_temperature: 25 °C
|
||||
temperature_step: 0.1 °C
|
||||
name: "Electrolux EACS"
|
||||
beeper: true
|
||||
custom_fan_modes:
|
||||
- SILENT
|
||||
- TURBO
|
||||
preset_eco: true
|
||||
preset_sleep: true
|
||||
preset_boost: true
|
||||
custom_presets:
|
||||
- FREEZE_PROTECTION
|
||||
outdoor_temperature:
|
||||
name: "Temp"
|
||||
power_usage:
|
||||
name: "Power"
|
||||
humidity_setpoint:
|
||||
name: "Hum"
|
||||
|
||||
midea_dongle:
|
||||
uart_id: uart1
|
||||
strength_icon: true
|
||||
|
||||
cover:
|
||||
- platform: endstop
|
||||
|
|
|
@ -166,6 +166,7 @@ display:
|
|||
it.rectangle(3, 3, it.get_width()-6, it.get_height()-6, red);
|
||||
rotation: 0°
|
||||
update_interval: 16ms
|
||||
|
||||
- platform: waveshare_epaper
|
||||
cs_pin: GPIO23
|
||||
dc_pin: GPIO23
|
||||
|
|
Loading…
Reference in a new issue