mirror of
https://github.com/esphome/esphome.git
synced 2025-11-01 15:41:52 +00:00
fix template regression
This commit is contained in:
@@ -6,17 +6,19 @@ namespace template_ {
|
||||
|
||||
static const char *const TAG = "template.binary_sensor";
|
||||
|
||||
void TemplateBinarySensor::setup() { this->loop(); }
|
||||
void TemplateBinarySensor::setup() {
|
||||
if (!this->f_.has_value())
|
||||
this->disable_loop();
|
||||
this->loop();
|
||||
}
|
||||
|
||||
void TemplateBinarySensor::loop() {
|
||||
if (!this->f_.has_value())
|
||||
return;
|
||||
|
||||
auto s = (*this->f_)();
|
||||
auto s = this->f_();
|
||||
if (s.has_value()) {
|
||||
this->publish_state(*s);
|
||||
}
|
||||
}
|
||||
|
||||
void TemplateBinarySensor::dump_config() { LOG_BINARY_SENSOR("", "Template Binary Sensor", this); }
|
||||
|
||||
} // namespace template_
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/template_lambda.h"
|
||||
#include "esphome/components/binary_sensor/binary_sensor.h"
|
||||
|
||||
namespace esphome {
|
||||
@@ -8,7 +9,10 @@ namespace template_ {
|
||||
|
||||
class TemplateBinarySensor : public Component, public binary_sensor::BinarySensor {
|
||||
public:
|
||||
void set_template(optional<bool> (*f)()) { this->f_ = f; }
|
||||
template<typename F> void set_template(F &&f) {
|
||||
this->f_.set(std::forward<F>(f));
|
||||
this->enable_loop();
|
||||
}
|
||||
|
||||
void setup() override;
|
||||
void loop() override;
|
||||
@@ -17,7 +21,7 @@ class TemplateBinarySensor : public Component, public binary_sensor::BinarySenso
|
||||
float get_setup_priority() const override { return setup_priority::HARDWARE; }
|
||||
|
||||
protected:
|
||||
optional<optional<bool> (*)()> f_;
|
||||
TemplateLambda<bool> f_;
|
||||
};
|
||||
|
||||
} // namespace template_
|
||||
|
||||
@@ -33,28 +33,27 @@ void TemplateCover::setup() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!this->state_f_.has_value() && !this->tilt_f_.has_value())
|
||||
this->disable_loop();
|
||||
}
|
||||
void TemplateCover::loop() {
|
||||
bool changed = false;
|
||||
|
||||
if (this->state_f_.has_value()) {
|
||||
auto s = (*this->state_f_)();
|
||||
if (s.has_value()) {
|
||||
auto pos = clamp(*s, 0.0f, 1.0f);
|
||||
if (pos != this->position) {
|
||||
this->position = pos;
|
||||
changed = true;
|
||||
}
|
||||
auto s = this->state_f_();
|
||||
if (s.has_value()) {
|
||||
auto pos = clamp(*s, 0.0f, 1.0f);
|
||||
if (pos != this->position) {
|
||||
this->position = pos;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
if (this->tilt_f_.has_value()) {
|
||||
auto s = (*this->tilt_f_)();
|
||||
if (s.has_value()) {
|
||||
auto tilt = clamp(*s, 0.0f, 1.0f);
|
||||
if (tilt != this->tilt) {
|
||||
this->tilt = tilt;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
auto tilt = this->tilt_f_();
|
||||
if (tilt.has_value()) {
|
||||
auto tilt_val = clamp(*tilt, 0.0f, 1.0f);
|
||||
if (tilt_val != this->tilt) {
|
||||
this->tilt = tilt_val;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,7 +62,6 @@ void TemplateCover::loop() {
|
||||
}
|
||||
void TemplateCover::set_optimistic(bool optimistic) { this->optimistic_ = optimistic; }
|
||||
void TemplateCover::set_assumed_state(bool assumed_state) { this->assumed_state_ = assumed_state; }
|
||||
void TemplateCover::set_state_lambda(optional<float> (*f)()) { this->state_f_ = f; }
|
||||
float TemplateCover::get_setup_priority() const { return setup_priority::HARDWARE; }
|
||||
Trigger<> *TemplateCover::get_open_trigger() const { return this->open_trigger_; }
|
||||
Trigger<> *TemplateCover::get_close_trigger() const { return this->close_trigger_; }
|
||||
@@ -124,7 +122,6 @@ CoverTraits TemplateCover::get_traits() {
|
||||
}
|
||||
Trigger<float> *TemplateCover::get_position_trigger() const { return this->position_trigger_; }
|
||||
Trigger<float> *TemplateCover::get_tilt_trigger() const { return this->tilt_trigger_; }
|
||||
void TemplateCover::set_tilt_lambda(optional<float> (*tilt_f)()) { this->tilt_f_ = tilt_f; }
|
||||
void TemplateCover::set_has_stop(bool has_stop) { this->has_stop_ = has_stop; }
|
||||
void TemplateCover::set_has_toggle(bool has_toggle) { this->has_toggle_ = has_toggle; }
|
||||
void TemplateCover::set_has_position(bool has_position) { this->has_position_ = has_position; }
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/automation.h"
|
||||
#include "esphome/core/template_lambda.h"
|
||||
#include "esphome/components/cover/cover.h"
|
||||
|
||||
namespace esphome {
|
||||
@@ -17,7 +18,14 @@ class TemplateCover : public cover::Cover, public Component {
|
||||
public:
|
||||
TemplateCover();
|
||||
|
||||
void set_state_lambda(optional<float> (*f)());
|
||||
template<typename F> void set_state_lambda(F &&f) {
|
||||
this->state_f_.set(std::forward<F>(f));
|
||||
this->enable_loop();
|
||||
}
|
||||
template<typename F> void set_tilt_lambda(F &&f) {
|
||||
this->tilt_f_.set(std::forward<F>(f));
|
||||
this->enable_loop();
|
||||
}
|
||||
Trigger<> *get_open_trigger() const;
|
||||
Trigger<> *get_close_trigger() const;
|
||||
Trigger<> *get_stop_trigger() const;
|
||||
@@ -26,7 +34,6 @@ class TemplateCover : public cover::Cover, public Component {
|
||||
Trigger<float> *get_tilt_trigger() const;
|
||||
void set_optimistic(bool optimistic);
|
||||
void set_assumed_state(bool assumed_state);
|
||||
void set_tilt_lambda(optional<float> (*tilt_f)());
|
||||
void set_has_stop(bool has_stop);
|
||||
void set_has_position(bool has_position);
|
||||
void set_has_tilt(bool has_tilt);
|
||||
@@ -45,8 +52,8 @@ class TemplateCover : public cover::Cover, public Component {
|
||||
void stop_prev_trigger_();
|
||||
|
||||
TemplateCoverRestoreMode restore_mode_{COVER_RESTORE};
|
||||
optional<optional<float> (*)()> state_f_;
|
||||
optional<optional<float> (*)()> tilt_f_;
|
||||
TemplateLambda<float> state_f_;
|
||||
TemplateLambda<float> tilt_f_;
|
||||
bool assumed_state_{false};
|
||||
bool optimistic_{false};
|
||||
Trigger<> *open_trigger_;
|
||||
|
||||
@@ -37,17 +37,13 @@ void TemplateDate::setup() {
|
||||
}
|
||||
|
||||
void TemplateDate::update() {
|
||||
if (!this->f_.has_value())
|
||||
return;
|
||||
|
||||
auto val = (*this->f_)();
|
||||
if (!val.has_value())
|
||||
return;
|
||||
|
||||
this->year_ = val->year;
|
||||
this->month_ = val->month;
|
||||
this->day_ = val->day_of_month;
|
||||
this->publish_state();
|
||||
auto val = this->f_();
|
||||
if (val.has_value()) {
|
||||
this->year_ = val->year;
|
||||
this->month_ = val->month;
|
||||
this->day_ = val->day_of_month;
|
||||
this->publish_state();
|
||||
}
|
||||
}
|
||||
|
||||
void TemplateDate::control(const datetime::DateCall &call) {
|
||||
|
||||
@@ -9,13 +9,14 @@
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/preferences.h"
|
||||
#include "esphome/core/time.h"
|
||||
#include "esphome/core/template_lambda.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace template_ {
|
||||
|
||||
class TemplateDate : public datetime::DateEntity, public PollingComponent {
|
||||
public:
|
||||
void set_template(optional<ESPTime> (*f)()) { this->f_ = f; }
|
||||
template<typename F> void set_template(F &&f) { this->f_.set(std::forward<F>(f)); }
|
||||
|
||||
void setup() override;
|
||||
void update() override;
|
||||
@@ -35,7 +36,7 @@ class TemplateDate : public datetime::DateEntity, public PollingComponent {
|
||||
ESPTime initial_value_{};
|
||||
bool restore_value_{false};
|
||||
Trigger<ESPTime> *set_trigger_ = new Trigger<ESPTime>();
|
||||
optional<optional<ESPTime> (*)()> f_;
|
||||
TemplateLambda<ESPTime> f_;
|
||||
|
||||
ESPPreferenceObject pref_;
|
||||
};
|
||||
|
||||
@@ -40,20 +40,16 @@ void TemplateDateTime::setup() {
|
||||
}
|
||||
|
||||
void TemplateDateTime::update() {
|
||||
if (!this->f_.has_value())
|
||||
return;
|
||||
|
||||
auto val = (*this->f_)();
|
||||
if (!val.has_value())
|
||||
return;
|
||||
|
||||
this->year_ = val->year;
|
||||
this->month_ = val->month;
|
||||
this->day_ = val->day_of_month;
|
||||
this->hour_ = val->hour;
|
||||
this->minute_ = val->minute;
|
||||
this->second_ = val->second;
|
||||
this->publish_state();
|
||||
auto val = this->f_();
|
||||
if (val.has_value()) {
|
||||
this->year_ = val->year;
|
||||
this->month_ = val->month;
|
||||
this->day_ = val->day_of_month;
|
||||
this->hour_ = val->hour;
|
||||
this->minute_ = val->minute;
|
||||
this->second_ = val->second;
|
||||
this->publish_state();
|
||||
}
|
||||
}
|
||||
|
||||
void TemplateDateTime::control(const datetime::DateTimeCall &call) {
|
||||
|
||||
@@ -9,13 +9,14 @@
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/preferences.h"
|
||||
#include "esphome/core/time.h"
|
||||
#include "esphome/core/template_lambda.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace template_ {
|
||||
|
||||
class TemplateDateTime : public datetime::DateTimeEntity, public PollingComponent {
|
||||
public:
|
||||
void set_template(optional<ESPTime> (*f)()) { this->f_ = f; }
|
||||
template<typename F> void set_template(F &&f) { this->f_.set(std::forward<F>(f)); }
|
||||
|
||||
void setup() override;
|
||||
void update() override;
|
||||
@@ -35,7 +36,7 @@ class TemplateDateTime : public datetime::DateTimeEntity, public PollingComponen
|
||||
ESPTime initial_value_{};
|
||||
bool restore_value_{false};
|
||||
Trigger<ESPTime> *set_trigger_ = new Trigger<ESPTime>();
|
||||
optional<optional<ESPTime> (*)()> f_;
|
||||
TemplateLambda<ESPTime> f_;
|
||||
|
||||
ESPPreferenceObject pref_;
|
||||
};
|
||||
|
||||
@@ -37,17 +37,13 @@ void TemplateTime::setup() {
|
||||
}
|
||||
|
||||
void TemplateTime::update() {
|
||||
if (!this->f_.has_value())
|
||||
return;
|
||||
|
||||
auto val = (*this->f_)();
|
||||
if (!val.has_value())
|
||||
return;
|
||||
|
||||
this->hour_ = val->hour;
|
||||
this->minute_ = val->minute;
|
||||
this->second_ = val->second;
|
||||
this->publish_state();
|
||||
auto val = this->f_();
|
||||
if (val.has_value()) {
|
||||
this->hour_ = val->hour;
|
||||
this->minute_ = val->minute;
|
||||
this->second_ = val->second;
|
||||
this->publish_state();
|
||||
}
|
||||
}
|
||||
|
||||
void TemplateTime::control(const datetime::TimeCall &call) {
|
||||
|
||||
@@ -9,13 +9,14 @@
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/preferences.h"
|
||||
#include "esphome/core/time.h"
|
||||
#include "esphome/core/template_lambda.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace template_ {
|
||||
|
||||
class TemplateTime : public datetime::TimeEntity, public PollingComponent {
|
||||
public:
|
||||
void set_template(optional<ESPTime> (*f)()) { this->f_ = f; }
|
||||
template<typename F> void set_template(F &&f) { this->f_.set(std::forward<F>(f)); }
|
||||
|
||||
void setup() override;
|
||||
void update() override;
|
||||
@@ -35,7 +36,7 @@ class TemplateTime : public datetime::TimeEntity, public PollingComponent {
|
||||
ESPTime initial_value_{};
|
||||
bool restore_value_{false};
|
||||
Trigger<ESPTime> *set_trigger_ = new Trigger<ESPTime>();
|
||||
optional<optional<ESPTime> (*)()> f_;
|
||||
TemplateLambda<ESPTime> f_;
|
||||
|
||||
ESPPreferenceObject pref_;
|
||||
};
|
||||
|
||||
@@ -12,13 +12,10 @@ TemplateLock::TemplateLock()
|
||||
: lock_trigger_(new Trigger<>()), unlock_trigger_(new Trigger<>()), open_trigger_(new Trigger<>()) {}
|
||||
|
||||
void TemplateLock::loop() {
|
||||
if (!this->f_.has_value())
|
||||
return;
|
||||
auto val = (*this->f_)();
|
||||
if (!val.has_value())
|
||||
return;
|
||||
|
||||
this->publish_state(*val);
|
||||
auto val = this->f_();
|
||||
if (val.has_value()) {
|
||||
this->publish_state(*val);
|
||||
}
|
||||
}
|
||||
void TemplateLock::control(const lock::LockCall &call) {
|
||||
if (this->prev_trigger_ != nullptr) {
|
||||
@@ -45,7 +42,6 @@ void TemplateLock::open_latch() {
|
||||
this->open_trigger_->trigger();
|
||||
}
|
||||
void TemplateLock::set_optimistic(bool optimistic) { this->optimistic_ = optimistic; }
|
||||
void TemplateLock::set_state_lambda(optional<lock::LockState> (*f)()) { this->f_ = f; }
|
||||
float TemplateLock::get_setup_priority() const { return setup_priority::HARDWARE; }
|
||||
Trigger<> *TemplateLock::get_lock_trigger() const { return this->lock_trigger_; }
|
||||
Trigger<> *TemplateLock::get_unlock_trigger() const { return this->unlock_trigger_; }
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/automation.h"
|
||||
#include "esphome/core/template_lambda.h"
|
||||
#include "esphome/components/lock/lock.h"
|
||||
|
||||
namespace esphome {
|
||||
@@ -13,7 +14,10 @@ class TemplateLock : public lock::Lock, public Component {
|
||||
|
||||
void dump_config() override;
|
||||
|
||||
void set_state_lambda(optional<lock::LockState> (*f)());
|
||||
template<typename F> void set_state_lambda(F &&f) {
|
||||
this->f_.set(std::forward<F>(f));
|
||||
this->enable_loop();
|
||||
}
|
||||
Trigger<> *get_lock_trigger() const;
|
||||
Trigger<> *get_unlock_trigger() const;
|
||||
Trigger<> *get_open_trigger() const;
|
||||
@@ -26,7 +30,7 @@ class TemplateLock : public lock::Lock, public Component {
|
||||
void control(const lock::LockCall &call) override;
|
||||
void open_latch() override;
|
||||
|
||||
optional<optional<lock::LockState> (*)()> f_;
|
||||
TemplateLambda<lock::LockState> f_;
|
||||
bool optimistic_{false};
|
||||
Trigger<> *lock_trigger_;
|
||||
Trigger<> *unlock_trigger_;
|
||||
|
||||
@@ -27,14 +27,10 @@ void TemplateNumber::setup() {
|
||||
}
|
||||
|
||||
void TemplateNumber::update() {
|
||||
if (!this->f_.has_value())
|
||||
return;
|
||||
|
||||
auto val = (*this->f_)();
|
||||
if (!val.has_value())
|
||||
return;
|
||||
|
||||
this->publish_state(*val);
|
||||
auto val = this->f_();
|
||||
if (val.has_value()) {
|
||||
this->publish_state(*val);
|
||||
}
|
||||
}
|
||||
|
||||
void TemplateNumber::control(float value) {
|
||||
|
||||
@@ -4,13 +4,14 @@
|
||||
#include "esphome/core/automation.h"
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/preferences.h"
|
||||
#include "esphome/core/template_lambda.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace template_ {
|
||||
|
||||
class TemplateNumber : public number::Number, public PollingComponent {
|
||||
public:
|
||||
void set_template(optional<float> (*f)()) { this->f_ = f; }
|
||||
template<typename F> void set_template(F &&f) { this->f_.set(std::forward<F>(f)); }
|
||||
|
||||
void setup() override;
|
||||
void update() override;
|
||||
@@ -28,7 +29,7 @@ class TemplateNumber : public number::Number, public PollingComponent {
|
||||
float initial_value_{NAN};
|
||||
bool restore_value_{false};
|
||||
Trigger<float> *set_trigger_ = new Trigger<float>();
|
||||
optional<optional<float> (*)()> f_;
|
||||
TemplateLambda<float> f_;
|
||||
|
||||
ESPPreferenceObject pref_;
|
||||
};
|
||||
|
||||
@@ -28,19 +28,14 @@ void TemplateSelect::setup() {
|
||||
}
|
||||
|
||||
void TemplateSelect::update() {
|
||||
if (!this->f_.has_value())
|
||||
return;
|
||||
|
||||
auto val = (*this->f_)();
|
||||
if (!val.has_value())
|
||||
return;
|
||||
|
||||
if (!this->has_option(*val)) {
|
||||
ESP_LOGE(TAG, "Lambda returned an invalid option: %s", (*val).c_str());
|
||||
return;
|
||||
auto val = this->f_();
|
||||
if (val.has_value()) {
|
||||
if (!this->has_option(*val)) {
|
||||
ESP_LOGE(TAG, "Lambda returned an invalid option: %s", (*val).c_str());
|
||||
return;
|
||||
}
|
||||
this->publish_state(*val);
|
||||
}
|
||||
|
||||
this->publish_state(*val);
|
||||
}
|
||||
|
||||
void TemplateSelect::control(const std::string &value) {
|
||||
|
||||
@@ -4,13 +4,14 @@
|
||||
#include "esphome/core/automation.h"
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/preferences.h"
|
||||
#include "esphome/core/template_lambda.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace template_ {
|
||||
|
||||
class TemplateSelect : public select::Select, public PollingComponent {
|
||||
public:
|
||||
void set_template(optional<std::string> (*f)()) { this->f_ = f; }
|
||||
template<typename F> void set_template(F &&f) { this->f_.set(std::forward<F>(f)); }
|
||||
|
||||
void setup() override;
|
||||
void update() override;
|
||||
@@ -28,7 +29,7 @@ class TemplateSelect : public select::Select, public PollingComponent {
|
||||
size_t initial_option_index_{0};
|
||||
bool restore_value_ = false;
|
||||
Trigger<std::string> *set_trigger_ = new Trigger<std::string>();
|
||||
optional<optional<std::string> (*)()> f_;
|
||||
TemplateLambda<std::string> f_;
|
||||
|
||||
ESPPreferenceObject pref_;
|
||||
};
|
||||
|
||||
@@ -8,16 +8,14 @@ namespace template_ {
|
||||
static const char *const TAG = "template.sensor";
|
||||
|
||||
void TemplateSensor::update() {
|
||||
if (!this->f_.has_value())
|
||||
return;
|
||||
|
||||
auto val = (*this->f_)();
|
||||
auto val = this->f_();
|
||||
if (val.has_value()) {
|
||||
this->publish_state(*val);
|
||||
}
|
||||
}
|
||||
|
||||
float TemplateSensor::get_setup_priority() const { return setup_priority::HARDWARE; }
|
||||
void TemplateSensor::set_template(optional<float> (*f)()) { this->f_ = f; }
|
||||
|
||||
void TemplateSensor::dump_config() {
|
||||
LOG_SENSOR("", "Template Sensor", this);
|
||||
LOG_UPDATE_INTERVAL(this);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/template_lambda.h"
|
||||
#include "esphome/components/sensor/sensor.h"
|
||||
|
||||
namespace esphome {
|
||||
@@ -8,7 +9,7 @@ namespace template_ {
|
||||
|
||||
class TemplateSensor : public sensor::Sensor, public PollingComponent {
|
||||
public:
|
||||
void set_template(optional<float> (*f)());
|
||||
template<typename F> void set_template(F &&f) { this->f_.set(std::forward<F>(f)); }
|
||||
|
||||
void update() override;
|
||||
|
||||
@@ -17,7 +18,7 @@ class TemplateSensor : public sensor::Sensor, public PollingComponent {
|
||||
float get_setup_priority() const override;
|
||||
|
||||
protected:
|
||||
optional<optional<float> (*)()> f_;
|
||||
TemplateLambda<float> f_;
|
||||
};
|
||||
|
||||
} // namespace template_
|
||||
|
||||
@@ -9,13 +9,10 @@ static const char *const TAG = "template.switch";
|
||||
TemplateSwitch::TemplateSwitch() : turn_on_trigger_(new Trigger<>()), turn_off_trigger_(new Trigger<>()) {}
|
||||
|
||||
void TemplateSwitch::loop() {
|
||||
if (!this->f_.has_value())
|
||||
return;
|
||||
auto s = (*this->f_)();
|
||||
if (!s.has_value())
|
||||
return;
|
||||
|
||||
this->publish_state(*s);
|
||||
auto s = this->f_();
|
||||
if (s.has_value()) {
|
||||
this->publish_state(*s);
|
||||
}
|
||||
}
|
||||
void TemplateSwitch::write_state(bool state) {
|
||||
if (this->prev_trigger_ != nullptr) {
|
||||
@@ -35,11 +32,13 @@ void TemplateSwitch::write_state(bool state) {
|
||||
}
|
||||
void TemplateSwitch::set_optimistic(bool optimistic) { this->optimistic_ = optimistic; }
|
||||
bool TemplateSwitch::assumed_state() { return this->assumed_state_; }
|
||||
void TemplateSwitch::set_state_lambda(optional<bool> (*f)()) { this->f_ = f; }
|
||||
float TemplateSwitch::get_setup_priority() const { return setup_priority::HARDWARE - 2.0f; }
|
||||
Trigger<> *TemplateSwitch::get_turn_on_trigger() const { return this->turn_on_trigger_; }
|
||||
Trigger<> *TemplateSwitch::get_turn_off_trigger() const { return this->turn_off_trigger_; }
|
||||
void TemplateSwitch::setup() {
|
||||
if (!this->f_.has_value())
|
||||
this->disable_loop();
|
||||
|
||||
optional<bool> initial_state = this->get_initial_state_with_restore_mode();
|
||||
|
||||
if (initial_state.has_value()) {
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/automation.h"
|
||||
#include "esphome/core/template_lambda.h"
|
||||
#include "esphome/components/switch/switch.h"
|
||||
|
||||
namespace esphome {
|
||||
@@ -14,7 +15,10 @@ class TemplateSwitch : public switch_::Switch, public Component {
|
||||
void setup() override;
|
||||
void dump_config() override;
|
||||
|
||||
void set_state_lambda(optional<bool> (*f)());
|
||||
template<typename F> void set_state_lambda(F &&f) {
|
||||
this->f_.set(std::forward<F>(f));
|
||||
this->enable_loop();
|
||||
}
|
||||
Trigger<> *get_turn_on_trigger() const;
|
||||
Trigger<> *get_turn_off_trigger() const;
|
||||
void set_optimistic(bool optimistic);
|
||||
@@ -28,7 +32,7 @@ class TemplateSwitch : public switch_::Switch, public Component {
|
||||
|
||||
void write_state(bool state) override;
|
||||
|
||||
optional<optional<bool> (*)()> f_;
|
||||
TemplateLambda<bool> f_;
|
||||
bool optimistic_{false};
|
||||
bool assumed_state_{false};
|
||||
Trigger<> *turn_on_trigger_;
|
||||
|
||||
@@ -7,10 +7,8 @@ namespace template_ {
|
||||
static const char *const TAG = "template.text";
|
||||
|
||||
void TemplateText::setup() {
|
||||
if (!(this->f_ == nullptr)) {
|
||||
if (this->f_.has_value())
|
||||
return;
|
||||
}
|
||||
if (this->f_.has_value())
|
||||
return;
|
||||
std::string value = this->initial_value_;
|
||||
if (!this->pref_) {
|
||||
ESP_LOGD(TAG, "State from initial: %s", value.c_str());
|
||||
@@ -26,17 +24,10 @@ void TemplateText::setup() {
|
||||
}
|
||||
|
||||
void TemplateText::update() {
|
||||
if (this->f_ == nullptr)
|
||||
return;
|
||||
|
||||
if (!this->f_.has_value())
|
||||
return;
|
||||
|
||||
auto val = (*this->f_)();
|
||||
if (!val.has_value())
|
||||
return;
|
||||
|
||||
this->publish_state(*val);
|
||||
auto val = this->f_();
|
||||
if (val.has_value()) {
|
||||
this->publish_state(*val);
|
||||
}
|
||||
}
|
||||
|
||||
void TemplateText::control(const std::string &value) {
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "esphome/core/automation.h"
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/preferences.h"
|
||||
#include "esphome/core/template_lambda.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace template_ {
|
||||
@@ -61,7 +62,7 @@ template<uint8_t SZ> class TextSaver : public TemplateTextSaverBase {
|
||||
|
||||
class TemplateText : public text::Text, public PollingComponent {
|
||||
public:
|
||||
void set_template(optional<std::string> (*f)()) { this->f_ = f; }
|
||||
template<typename F> void set_template(F &&f) { this->f_.set(std::forward<F>(f)); }
|
||||
|
||||
void setup() override;
|
||||
void update() override;
|
||||
@@ -78,7 +79,7 @@ class TemplateText : public text::Text, public PollingComponent {
|
||||
bool optimistic_ = false;
|
||||
std::string initial_value_;
|
||||
Trigger<std::string> *set_trigger_ = new Trigger<std::string>();
|
||||
optional<optional<std::string> (*)()> f_{nullptr};
|
||||
TemplateLambda<std::string> f_{};
|
||||
|
||||
TemplateTextSaverBase *pref_ = nullptr;
|
||||
};
|
||||
|
||||
@@ -7,16 +7,14 @@ namespace template_ {
|
||||
static const char *const TAG = "template.text_sensor";
|
||||
|
||||
void TemplateTextSensor::update() {
|
||||
if (!this->f_.has_value())
|
||||
return;
|
||||
|
||||
auto val = (*this->f_)();
|
||||
auto val = this->f_();
|
||||
if (val.has_value()) {
|
||||
this->publish_state(*val);
|
||||
}
|
||||
}
|
||||
|
||||
float TemplateTextSensor::get_setup_priority() const { return setup_priority::HARDWARE; }
|
||||
void TemplateTextSensor::set_template(optional<std::string> (*f)()) { this->f_ = f; }
|
||||
|
||||
void TemplateTextSensor::dump_config() { LOG_TEXT_SENSOR("", "Template Sensor", this); }
|
||||
|
||||
} // namespace template_
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/automation.h"
|
||||
#include "esphome/core/template_lambda.h"
|
||||
#include "esphome/components/text_sensor/text_sensor.h"
|
||||
|
||||
namespace esphome {
|
||||
@@ -9,7 +10,7 @@ namespace template_ {
|
||||
|
||||
class TemplateTextSensor : public text_sensor::TextSensor, public PollingComponent {
|
||||
public:
|
||||
void set_template(optional<std::string> (*f)());
|
||||
template<typename F> void set_template(F &&f) { this->f_.set(std::forward<F>(f)); }
|
||||
|
||||
void update() override;
|
||||
|
||||
@@ -18,7 +19,7 @@ class TemplateTextSensor : public text_sensor::TextSensor, public PollingCompone
|
||||
void dump_config() override;
|
||||
|
||||
protected:
|
||||
optional<optional<std::string> (*)()> f_{};
|
||||
TemplateLambda<std::string> f_{};
|
||||
};
|
||||
|
||||
} // namespace template_
|
||||
|
||||
@@ -33,19 +33,19 @@ void TemplateValve::setup() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!this->state_f_.has_value())
|
||||
this->disable_loop();
|
||||
}
|
||||
|
||||
void TemplateValve::loop() {
|
||||
bool changed = false;
|
||||
|
||||
if (this->state_f_.has_value()) {
|
||||
auto s = (*this->state_f_)();
|
||||
if (s.has_value()) {
|
||||
auto pos = clamp(*s, 0.0f, 1.0f);
|
||||
if (pos != this->position) {
|
||||
this->position = pos;
|
||||
changed = true;
|
||||
}
|
||||
auto s = this->state_f_();
|
||||
if (s.has_value()) {
|
||||
auto pos = clamp(*s, 0.0f, 1.0f);
|
||||
if (pos != this->position) {
|
||||
this->position = pos;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,7 +55,6 @@ void TemplateValve::loop() {
|
||||
|
||||
void TemplateValve::set_optimistic(bool optimistic) { this->optimistic_ = optimistic; }
|
||||
void TemplateValve::set_assumed_state(bool assumed_state) { this->assumed_state_ = assumed_state; }
|
||||
void TemplateValve::set_state_lambda(optional<float> (*f)()) { this->state_f_ = f; }
|
||||
float TemplateValve::get_setup_priority() const { return setup_priority::HARDWARE; }
|
||||
|
||||
Trigger<> *TemplateValve::get_open_trigger() const { return this->open_trigger_; }
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/automation.h"
|
||||
#include "esphome/core/template_lambda.h"
|
||||
#include "esphome/components/valve/valve.h"
|
||||
|
||||
namespace esphome {
|
||||
@@ -17,7 +18,10 @@ class TemplateValve : public valve::Valve, public Component {
|
||||
public:
|
||||
TemplateValve();
|
||||
|
||||
void set_state_lambda(optional<float> (*f)());
|
||||
template<typename F> void set_state_lambda(F &&f) {
|
||||
this->state_f_.set(std::forward<F>(f));
|
||||
this->enable_loop();
|
||||
}
|
||||
Trigger<> *get_open_trigger() const;
|
||||
Trigger<> *get_close_trigger() const;
|
||||
Trigger<> *get_stop_trigger() const;
|
||||
@@ -42,7 +46,7 @@ class TemplateValve : public valve::Valve, public Component {
|
||||
void stop_prev_trigger_();
|
||||
|
||||
TemplateValveRestoreMode restore_mode_{VALVE_NO_RESTORE};
|
||||
optional<optional<float> (*)()> state_f_;
|
||||
TemplateLambda<float> state_f_;
|
||||
bool assumed_state_{false};
|
||||
bool optimistic_{false};
|
||||
Trigger<> *open_trigger_;
|
||||
|
||||
120
esphome/core/template_lambda.h
Normal file
120
esphome/core/template_lambda.h
Normal file
@@ -0,0 +1,120 @@
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <concepts>
|
||||
#include "esphome/core/optional.h"
|
||||
|
||||
namespace esphome {
|
||||
|
||||
/** Helper class for template platforms that stores either a stateless lambda (function pointer)
|
||||
* or a stateful lambda (std::function pointer).
|
||||
*
|
||||
* This provides backward compatibility with PR #11555 while maintaining the optimization:
|
||||
* - Stateless lambdas (no capture) → function pointer (4 bytes on ESP32)
|
||||
* - Stateful lambdas (with capture) → pointer to std::function (4 bytes on ESP32)
|
||||
* Total size: enum (1 byte) + union (4 bytes) + padding = 8 bytes (same as PR #11555)
|
||||
*
|
||||
* Both lambda types must return optional<T> (as YAML codegen does) to support the pattern:
|
||||
* return {}; // Don't publish a value
|
||||
* return 42.0; // Publish this value
|
||||
*
|
||||
* operator() returns optional<T>, returning nullopt when no lambda is set (type == NONE).
|
||||
* This eliminates redundant "is lambda set" checks by reusing optional's discriminator.
|
||||
*
|
||||
* @tparam T The return type (e.g., float for TemplateLambda<optional<float>>)
|
||||
* @tparam Args Optional arguments for the lambda
|
||||
*/
|
||||
template<typename T, typename... Args> class TemplateLambda {
|
||||
public:
|
||||
TemplateLambda() : type_(NONE) {}
|
||||
|
||||
// For stateless lambdas: use function pointer
|
||||
template<typename F>
|
||||
requires std::invocable<F, Args...> && std::convertible_to < F, optional<T>(*)
|
||||
(Args...) > void set(F f) {
|
||||
this->reset();
|
||||
this->type_ = STATELESS_LAMBDA;
|
||||
this->stateless_f_ = f; // Implicit conversion to function pointer
|
||||
}
|
||||
|
||||
// For stateful lambdas: use std::function pointer
|
||||
template<typename F>
|
||||
requires std::invocable<F, Args...> &&
|
||||
(!std::convertible_to<F, optional<T> (*)(Args...)>) &&std::convertible_to<std::invoke_result_t<F, Args...>,
|
||||
optional<T>> void set(F &&f) {
|
||||
this->reset();
|
||||
this->type_ = LAMBDA;
|
||||
this->f_ = new std::function<optional<T>(Args...)>(std::forward<F>(f));
|
||||
}
|
||||
|
||||
~TemplateLambda() { this->reset(); }
|
||||
|
||||
// Copy constructor
|
||||
TemplateLambda(const TemplateLambda &) = delete;
|
||||
TemplateLambda &operator=(const TemplateLambda &) = delete;
|
||||
|
||||
// Move constructor
|
||||
TemplateLambda(TemplateLambda &&other) noexcept : type_(other.type_) {
|
||||
if (type_ == LAMBDA) {
|
||||
this->f_ = other.f_;
|
||||
other.f_ = nullptr;
|
||||
} else if (type_ == STATELESS_LAMBDA) {
|
||||
this->stateless_f_ = other.stateless_f_;
|
||||
}
|
||||
other.type_ = NONE;
|
||||
}
|
||||
|
||||
TemplateLambda &operator=(TemplateLambda &&other) noexcept {
|
||||
if (this != &other) {
|
||||
this->reset();
|
||||
this->type_ = other.type_;
|
||||
if (type_ == LAMBDA) {
|
||||
this->f_ = other.f_;
|
||||
other.f_ = nullptr;
|
||||
} else if (type_ == STATELESS_LAMBDA) {
|
||||
this->stateless_f_ = other.stateless_f_;
|
||||
}
|
||||
other.type_ = NONE;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool has_value() const { return this->type_ != NONE; }
|
||||
|
||||
// Returns optional<T>, returning nullopt if no lambda is set
|
||||
optional<T> operator()(Args... args) {
|
||||
switch (this->type_) {
|
||||
case STATELESS_LAMBDA:
|
||||
return this->stateless_f_(args...); // Direct function pointer call
|
||||
case LAMBDA:
|
||||
return (*this->f_)(args...); // std::function call via pointer
|
||||
case NONE:
|
||||
default:
|
||||
return nullopt; // No lambda set
|
||||
}
|
||||
}
|
||||
|
||||
optional<T> call(Args... args) { return (*this)(args...); }
|
||||
|
||||
protected:
|
||||
void reset() {
|
||||
if (this->type_ == LAMBDA) {
|
||||
delete this->f_;
|
||||
this->f_ = nullptr;
|
||||
}
|
||||
this->type_ = NONE;
|
||||
}
|
||||
|
||||
enum : uint8_t {
|
||||
NONE,
|
||||
STATELESS_LAMBDA,
|
||||
LAMBDA,
|
||||
} type_;
|
||||
|
||||
union {
|
||||
optional<T> (*stateless_f_)(Args...); // Function pointer (4 bytes on ESP32)
|
||||
std::function<optional<T>(Args...)> *f_; // Pointer to std::function (4 bytes on ESP32)
|
||||
};
|
||||
};
|
||||
|
||||
} // namespace esphome
|
||||
Reference in New Issue
Block a user