mirror of
https://github.com/esphome/esphome.git
synced 2025-07-29 06:36:45 +00:00
[binary_sensor] Add action to invalidate state and pass to HA (#8961)
Co-authored-by: J. Nick Koston <nick@koston.org>
This commit is contained in:
parent
0228379a2e
commit
261b561bb2
@ -227,7 +227,7 @@ bool APIServer::check_password(const std::string &password) const {
|
|||||||
void APIServer::handle_disconnect(APIConnection *conn) {}
|
void APIServer::handle_disconnect(APIConnection *conn) {}
|
||||||
|
|
||||||
#ifdef USE_BINARY_SENSOR
|
#ifdef USE_BINARY_SENSOR
|
||||||
void APIServer::on_binary_sensor_update(binary_sensor::BinarySensor *obj, bool state) {
|
void APIServer::on_binary_sensor_update(binary_sensor::BinarySensor *obj) {
|
||||||
if (obj->is_internal())
|
if (obj->is_internal())
|
||||||
return;
|
return;
|
||||||
for (auto &c : this->clients_)
|
for (auto &c : this->clients_)
|
||||||
|
@ -54,7 +54,7 @@ class APIServer : public Component, public Controller {
|
|||||||
|
|
||||||
void handle_disconnect(APIConnection *conn);
|
void handle_disconnect(APIConnection *conn);
|
||||||
#ifdef USE_BINARY_SENSOR
|
#ifdef USE_BINARY_SENSOR
|
||||||
void on_binary_sensor_update(binary_sensor::BinarySensor *obj, bool state) override;
|
void on_binary_sensor_update(binary_sensor::BinarySensor *obj) override;
|
||||||
#endif
|
#endif
|
||||||
#ifdef USE_COVER
|
#ifdef USE_COVER
|
||||||
void on_cover_update(cover::Cover *obj) override;
|
void on_cover_update(cover::Cover *obj) override;
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
|
from logging import getLogger
|
||||||
|
|
||||||
from esphome import automation, core
|
from esphome import automation, core
|
||||||
from esphome.automation import Condition, maybe_simple_id
|
from esphome.automation import Condition, maybe_simple_id
|
||||||
import esphome.codegen as cg
|
import esphome.codegen as cg
|
||||||
from esphome.components import mqtt, web_server
|
from esphome.components import mqtt, web_server
|
||||||
|
from esphome.components.const import CONF_ON_STATE_CHANGE
|
||||||
import esphome.config_validation as cv
|
import esphome.config_validation as cv
|
||||||
from esphome.const import (
|
from esphome.const import (
|
||||||
CONF_DELAY,
|
CONF_DELAY,
|
||||||
@ -98,6 +101,7 @@ IS_PLATFORM_COMPONENT = True
|
|||||||
|
|
||||||
CONF_TIME_OFF = "time_off"
|
CONF_TIME_OFF = "time_off"
|
||||||
CONF_TIME_ON = "time_on"
|
CONF_TIME_ON = "time_on"
|
||||||
|
CONF_TRIGGER_ON_INITIAL_STATE = "trigger_on_initial_state"
|
||||||
|
|
||||||
DEFAULT_DELAY = "1s"
|
DEFAULT_DELAY = "1s"
|
||||||
DEFAULT_TIME_OFF = "100ms"
|
DEFAULT_TIME_OFF = "100ms"
|
||||||
@ -127,9 +131,17 @@ MultiClickTriggerEvent = binary_sensor_ns.struct("MultiClickTriggerEvent")
|
|||||||
StateTrigger = binary_sensor_ns.class_(
|
StateTrigger = binary_sensor_ns.class_(
|
||||||
"StateTrigger", automation.Trigger.template(bool)
|
"StateTrigger", automation.Trigger.template(bool)
|
||||||
)
|
)
|
||||||
|
StateChangeTrigger = binary_sensor_ns.class_(
|
||||||
|
"StateChangeTrigger",
|
||||||
|
automation.Trigger.template(cg.optional.template(bool), cg.optional.template(bool)),
|
||||||
|
)
|
||||||
|
|
||||||
BinarySensorPublishAction = binary_sensor_ns.class_(
|
BinarySensorPublishAction = binary_sensor_ns.class_(
|
||||||
"BinarySensorPublishAction", automation.Action
|
"BinarySensorPublishAction", automation.Action
|
||||||
)
|
)
|
||||||
|
BinarySensorInvalidateAction = binary_sensor_ns.class_(
|
||||||
|
"BinarySensorInvalidateAction", automation.Action
|
||||||
|
)
|
||||||
|
|
||||||
# Condition
|
# Condition
|
||||||
BinarySensorCondition = binary_sensor_ns.class_("BinarySensorCondition", Condition)
|
BinarySensorCondition = binary_sensor_ns.class_("BinarySensorCondition", Condition)
|
||||||
@ -144,6 +156,8 @@ AutorepeatFilter = binary_sensor_ns.class_("AutorepeatFilter", Filter, cg.Compon
|
|||||||
LambdaFilter = binary_sensor_ns.class_("LambdaFilter", Filter)
|
LambdaFilter = binary_sensor_ns.class_("LambdaFilter", Filter)
|
||||||
SettleFilter = binary_sensor_ns.class_("SettleFilter", Filter, cg.Component)
|
SettleFilter = binary_sensor_ns.class_("SettleFilter", Filter, cg.Component)
|
||||||
|
|
||||||
|
_LOGGER = getLogger(__name__)
|
||||||
|
|
||||||
FILTER_REGISTRY = Registry()
|
FILTER_REGISTRY = Registry()
|
||||||
validate_filters = cv.validate_registry("filter", FILTER_REGISTRY)
|
validate_filters = cv.validate_registry("filter", FILTER_REGISTRY)
|
||||||
|
|
||||||
@ -386,6 +400,14 @@ def validate_click_timing(value):
|
|||||||
return value
|
return value
|
||||||
|
|
||||||
|
|
||||||
|
def validate_publish_initial_state(value):
|
||||||
|
value = cv.boolean(value)
|
||||||
|
_LOGGER.warning(
|
||||||
|
"The 'publish_initial_state' option has been replaced by 'trigger_on_initial_state' and will be removed in a future release"
|
||||||
|
)
|
||||||
|
return value
|
||||||
|
|
||||||
|
|
||||||
_BINARY_SENSOR_SCHEMA = (
|
_BINARY_SENSOR_SCHEMA = (
|
||||||
cv.ENTITY_BASE_SCHEMA.extend(web_server.WEBSERVER_SORTING_SCHEMA)
|
cv.ENTITY_BASE_SCHEMA.extend(web_server.WEBSERVER_SORTING_SCHEMA)
|
||||||
.extend(cv.MQTT_COMPONENT_SCHEMA)
|
.extend(cv.MQTT_COMPONENT_SCHEMA)
|
||||||
@ -395,7 +417,12 @@ _BINARY_SENSOR_SCHEMA = (
|
|||||||
cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(
|
cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(
|
||||||
mqtt.MQTTBinarySensorComponent
|
mqtt.MQTTBinarySensorComponent
|
||||||
),
|
),
|
||||||
cv.Optional(CONF_PUBLISH_INITIAL_STATE): cv.boolean,
|
cv.Exclusive(
|
||||||
|
CONF_PUBLISH_INITIAL_STATE, CONF_TRIGGER_ON_INITIAL_STATE
|
||||||
|
): validate_publish_initial_state,
|
||||||
|
cv.Exclusive(
|
||||||
|
CONF_TRIGGER_ON_INITIAL_STATE, CONF_TRIGGER_ON_INITIAL_STATE
|
||||||
|
): cv.boolean,
|
||||||
cv.Optional(CONF_DEVICE_CLASS): validate_device_class,
|
cv.Optional(CONF_DEVICE_CLASS): validate_device_class,
|
||||||
cv.Optional(CONF_FILTERS): validate_filters,
|
cv.Optional(CONF_FILTERS): validate_filters,
|
||||||
cv.Optional(CONF_ON_PRESS): automation.validate_automation(
|
cv.Optional(CONF_ON_PRESS): automation.validate_automation(
|
||||||
@ -454,6 +481,11 @@ _BINARY_SENSOR_SCHEMA = (
|
|||||||
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(StateTrigger),
|
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(StateTrigger),
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
|
cv.Optional(CONF_ON_STATE_CHANGE): automation.validate_automation(
|
||||||
|
{
|
||||||
|
cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(StateChangeTrigger),
|
||||||
|
}
|
||||||
|
),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@ -493,8 +525,10 @@ async def setup_binary_sensor_core_(var, config):
|
|||||||
|
|
||||||
if (device_class := config.get(CONF_DEVICE_CLASS)) is not None:
|
if (device_class := config.get(CONF_DEVICE_CLASS)) is not None:
|
||||||
cg.add(var.set_device_class(device_class))
|
cg.add(var.set_device_class(device_class))
|
||||||
if publish_initial_state := config.get(CONF_PUBLISH_INITIAL_STATE):
|
trigger = config.get(CONF_TRIGGER_ON_INITIAL_STATE, False) or config.get(
|
||||||
cg.add(var.set_publish_initial_state(publish_initial_state))
|
CONF_PUBLISH_INITIAL_STATE, False
|
||||||
|
)
|
||||||
|
cg.add(var.set_trigger_on_initial_state(trigger))
|
||||||
if inverted := config.get(CONF_INVERTED):
|
if inverted := config.get(CONF_INVERTED):
|
||||||
cg.add(var.set_inverted(inverted))
|
cg.add(var.set_inverted(inverted))
|
||||||
if filters_config := config.get(CONF_FILTERS):
|
if filters_config := config.get(CONF_FILTERS):
|
||||||
@ -542,6 +576,17 @@ async def setup_binary_sensor_core_(var, config):
|
|||||||
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
|
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
|
||||||
await automation.build_automation(trigger, [(bool, "x")], conf)
|
await automation.build_automation(trigger, [(bool, "x")], conf)
|
||||||
|
|
||||||
|
for conf in config.get(CONF_ON_STATE_CHANGE, []):
|
||||||
|
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
|
||||||
|
await automation.build_automation(
|
||||||
|
trigger,
|
||||||
|
[
|
||||||
|
(cg.optional.template(bool), "x_previous"),
|
||||||
|
(cg.optional.template(bool), "x"),
|
||||||
|
],
|
||||||
|
conf,
|
||||||
|
)
|
||||||
|
|
||||||
if mqtt_id := config.get(CONF_MQTT_ID):
|
if mqtt_id := config.get(CONF_MQTT_ID):
|
||||||
mqtt_ = cg.new_Pvariable(mqtt_id, var)
|
mqtt_ = cg.new_Pvariable(mqtt_id, var)
|
||||||
await mqtt.register_mqtt_component(mqtt_, config)
|
await mqtt.register_mqtt_component(mqtt_, config)
|
||||||
@ -591,3 +636,18 @@ async def binary_sensor_is_off_to_code(config, condition_id, template_arg, args)
|
|||||||
async def to_code(config):
|
async def to_code(config):
|
||||||
cg.add_define("USE_BINARY_SENSOR")
|
cg.add_define("USE_BINARY_SENSOR")
|
||||||
cg.add_global(binary_sensor_ns.using)
|
cg.add_global(binary_sensor_ns.using)
|
||||||
|
|
||||||
|
|
||||||
|
@automation.register_action(
|
||||||
|
"binary_sensor.invalidate_state",
|
||||||
|
BinarySensorInvalidateAction,
|
||||||
|
cv.maybe_simple_value(
|
||||||
|
{
|
||||||
|
cv.Required(CONF_ID): cv.use_id(BinarySensor),
|
||||||
|
},
|
||||||
|
key=CONF_ID,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
async def binary_sensor_invalidate_state_to_code(config, action_id, template_arg, args):
|
||||||
|
paren = await cg.get_variable(config[CONF_ID])
|
||||||
|
return cg.new_Pvariable(action_id, template_arg, paren)
|
||||||
|
@ -96,7 +96,7 @@ class MultiClickTrigger : public Trigger<>, public Component {
|
|||||||
: parent_(parent), timing_(std::move(timing)) {}
|
: parent_(parent), timing_(std::move(timing)) {}
|
||||||
|
|
||||||
void setup() override {
|
void setup() override {
|
||||||
this->last_state_ = this->parent_->state;
|
this->last_state_ = this->parent_->get_state_default(false);
|
||||||
auto f = std::bind(&MultiClickTrigger::on_state_, this, std::placeholders::_1);
|
auto f = std::bind(&MultiClickTrigger::on_state_, this, std::placeholders::_1);
|
||||||
this->parent_->add_on_state_callback(f);
|
this->parent_->add_on_state_callback(f);
|
||||||
}
|
}
|
||||||
@ -130,6 +130,14 @@ class StateTrigger : public Trigger<bool> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class StateChangeTrigger : public Trigger<optional<bool>, optional<bool> > {
|
||||||
|
public:
|
||||||
|
explicit StateChangeTrigger(BinarySensor *parent) {
|
||||||
|
parent->add_full_state_callback(
|
||||||
|
[this](optional<bool> old_state, optional<bool> state) { this->trigger(old_state, state); });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
template<typename... Ts> class BinarySensorCondition : public Condition<Ts...> {
|
template<typename... Ts> class BinarySensorCondition : public Condition<Ts...> {
|
||||||
public:
|
public:
|
||||||
BinarySensorCondition(BinarySensor *parent, bool state) : parent_(parent), state_(state) {}
|
BinarySensorCondition(BinarySensor *parent, bool state) : parent_(parent), state_(state) {}
|
||||||
@ -154,5 +162,15 @@ template<typename... Ts> class BinarySensorPublishAction : public Action<Ts...>
|
|||||||
BinarySensor *sensor_;
|
BinarySensor *sensor_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<typename... Ts> class BinarySensorInvalidateAction : public Action<Ts...> {
|
||||||
|
public:
|
||||||
|
explicit BinarySensorInvalidateAction(BinarySensor *sensor) : sensor_(sensor) {}
|
||||||
|
|
||||||
|
void play(Ts... x) override { this->sensor_->invalidate_state(); }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
BinarySensor *sensor_;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace binary_sensor
|
} // namespace binary_sensor
|
||||||
} // namespace esphome
|
} // namespace esphome
|
||||||
|
@ -7,42 +7,25 @@ namespace binary_sensor {
|
|||||||
|
|
||||||
static const char *const TAG = "binary_sensor";
|
static const char *const TAG = "binary_sensor";
|
||||||
|
|
||||||
void BinarySensor::add_on_state_callback(std::function<void(bool)> &&callback) {
|
void BinarySensor::publish_state(bool new_state) {
|
||||||
this->state_callback_.add(std::move(callback));
|
|
||||||
}
|
|
||||||
|
|
||||||
void BinarySensor::publish_state(bool state) {
|
|
||||||
if (!this->publish_dedup_.next(state))
|
|
||||||
return;
|
|
||||||
if (this->filter_list_ == nullptr) {
|
if (this->filter_list_ == nullptr) {
|
||||||
this->send_state_internal(state, false);
|
this->send_state_internal(new_state);
|
||||||
} else {
|
} else {
|
||||||
this->filter_list_->input(state, false);
|
this->filter_list_->input(new_state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void BinarySensor::publish_initial_state(bool state) {
|
void BinarySensor::publish_initial_state(bool new_state) {
|
||||||
if (!this->publish_dedup_.next(state))
|
this->invalidate_state();
|
||||||
return;
|
this->publish_state(new_state);
|
||||||
if (this->filter_list_ == nullptr) {
|
}
|
||||||
this->send_state_internal(state, true);
|
void BinarySensor::send_state_internal(bool new_state) {
|
||||||
} else {
|
// copy the new state to the visible property for backwards compatibility, before any callbacks
|
||||||
this->filter_list_->input(state, true);
|
this->state = new_state;
|
||||||
|
// Note that set_state_ de-dups and will only trigger callbacks if the state has actually changed
|
||||||
|
if (this->set_state_(new_state)) {
|
||||||
|
ESP_LOGD(TAG, "'%s': New state is %s", this->get_name().c_str(), ONOFF(new_state));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void BinarySensor::send_state_internal(bool state, bool is_initial) {
|
|
||||||
if (is_initial) {
|
|
||||||
ESP_LOGD(TAG, "'%s': Sending initial state %s", this->get_name().c_str(), ONOFF(state));
|
|
||||||
} else {
|
|
||||||
ESP_LOGD(TAG, "'%s': Sending state %s", this->get_name().c_str(), ONOFF(state));
|
|
||||||
}
|
|
||||||
this->has_state_ = true;
|
|
||||||
this->state = state;
|
|
||||||
if (!is_initial || this->publish_initial_state_) {
|
|
||||||
this->state_callback_.call(state);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BinarySensor::BinarySensor() : state(false) {}
|
|
||||||
|
|
||||||
void BinarySensor::add_filter(Filter *filter) {
|
void BinarySensor::add_filter(Filter *filter) {
|
||||||
filter->parent_ = this;
|
filter->parent_ = this;
|
||||||
@ -60,7 +43,6 @@ void BinarySensor::add_filters(const std::vector<Filter *> &filters) {
|
|||||||
this->add_filter(filter);
|
this->add_filter(filter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bool BinarySensor::has_state() const { return this->has_state_; }
|
|
||||||
bool BinarySensor::is_status_binary_sensor() const { return false; }
|
bool BinarySensor::is_status_binary_sensor() const { return false; }
|
||||||
|
|
||||||
} // namespace binary_sensor
|
} // namespace binary_sensor
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "esphome/core/component.h"
|
|
||||||
#include "esphome/core/entity_base.h"
|
#include "esphome/core/entity_base.h"
|
||||||
#include "esphome/core/helpers.h"
|
#include "esphome/core/helpers.h"
|
||||||
#include "esphome/components/binary_sensor/filter.h"
|
#include "esphome/components/binary_sensor/filter.h"
|
||||||
@ -34,52 +33,39 @@ namespace binary_sensor {
|
|||||||
* The sub classes should notify the front-end of new states via the publish_state() method which
|
* The sub classes should notify the front-end of new states via the publish_state() method which
|
||||||
* handles inverted inputs for you.
|
* handles inverted inputs for you.
|
||||||
*/
|
*/
|
||||||
class BinarySensor : public EntityBase, public EntityBase_DeviceClass {
|
class BinarySensor : public StatefulEntityBase<bool>, public EntityBase_DeviceClass {
|
||||||
public:
|
public:
|
||||||
explicit BinarySensor();
|
explicit BinarySensor(){};
|
||||||
|
|
||||||
/** Add a callback to be notified of state changes.
|
|
||||||
*
|
|
||||||
* @param callback The void(bool) callback.
|
|
||||||
*/
|
|
||||||
void add_on_state_callback(std::function<void(bool)> &&callback);
|
|
||||||
|
|
||||||
/** Publish a new state to the front-end.
|
/** Publish a new state to the front-end.
|
||||||
*
|
*
|
||||||
* @param state The new state.
|
* @param new_state The new state.
|
||||||
*/
|
*/
|
||||||
void publish_state(bool state);
|
void publish_state(bool new_state);
|
||||||
|
|
||||||
/** Publish the initial state, this will not make the callback manager send callbacks
|
/** Publish the initial state, this will not make the callback manager send callbacks
|
||||||
* and is meant only for the initial state on boot.
|
* and is meant only for the initial state on boot.
|
||||||
*
|
*
|
||||||
* @param state The new state.
|
* @param new_state The new state.
|
||||||
*/
|
*/
|
||||||
void publish_initial_state(bool state);
|
void publish_initial_state(bool new_state);
|
||||||
|
|
||||||
/// The current reported state of the binary sensor.
|
|
||||||
bool state{false};
|
|
||||||
|
|
||||||
void add_filter(Filter *filter);
|
void add_filter(Filter *filter);
|
||||||
void add_filters(const std::vector<Filter *> &filters);
|
void add_filters(const std::vector<Filter *> &filters);
|
||||||
|
|
||||||
void set_publish_initial_state(bool publish_initial_state) { this->publish_initial_state_ = publish_initial_state; }
|
|
||||||
|
|
||||||
// ========== INTERNAL METHODS ==========
|
// ========== INTERNAL METHODS ==========
|
||||||
// (In most use cases you won't need these)
|
// (In most use cases you won't need these)
|
||||||
void send_state_internal(bool state, bool is_initial);
|
void send_state_internal(bool new_state);
|
||||||
|
|
||||||
/// Return whether this binary sensor has outputted a state.
|
/// Return whether this binary sensor has outputted a state.
|
||||||
virtual bool has_state() const;
|
|
||||||
|
|
||||||
virtual bool is_status_binary_sensor() const;
|
virtual bool is_status_binary_sensor() const;
|
||||||
|
|
||||||
|
// For backward compatibility, provide an accessible property
|
||||||
|
|
||||||
|
bool state{};
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
CallbackManager<void(bool)> state_callback_{};
|
|
||||||
Filter *filter_list_{nullptr};
|
Filter *filter_list_{nullptr};
|
||||||
bool has_state_{false};
|
|
||||||
bool publish_initial_state_{false};
|
|
||||||
Deduplicator<bool> publish_dedup_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class BinarySensorInitiallyOff : public BinarySensor {
|
class BinarySensorInitiallyOff : public BinarySensor {
|
||||||
|
@ -9,37 +9,36 @@ namespace binary_sensor {
|
|||||||
|
|
||||||
static const char *const TAG = "sensor.filter";
|
static const char *const TAG = "sensor.filter";
|
||||||
|
|
||||||
void Filter::output(bool value, bool is_initial) {
|
void Filter::output(bool value) {
|
||||||
|
if (this->next_ == nullptr) {
|
||||||
|
this->parent_->send_state_internal(value);
|
||||||
|
} else {
|
||||||
|
this->next_->input(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void Filter::input(bool value) {
|
||||||
if (!this->dedup_.next(value))
|
if (!this->dedup_.next(value))
|
||||||
return;
|
return;
|
||||||
|
auto b = this->new_value(value);
|
||||||
if (this->next_ == nullptr) {
|
|
||||||
this->parent_->send_state_internal(value, is_initial);
|
|
||||||
} else {
|
|
||||||
this->next_->input(value, is_initial);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void Filter::input(bool value, bool is_initial) {
|
|
||||||
auto b = this->new_value(value, is_initial);
|
|
||||||
if (b.has_value()) {
|
if (b.has_value()) {
|
||||||
this->output(*b, is_initial);
|
this->output(*b);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
optional<bool> DelayedOnOffFilter::new_value(bool value, bool is_initial) {
|
optional<bool> DelayedOnOffFilter::new_value(bool value) {
|
||||||
if (value) {
|
if (value) {
|
||||||
this->set_timeout("ON_OFF", this->on_delay_.value(), [this, is_initial]() { this->output(true, is_initial); });
|
this->set_timeout("ON_OFF", this->on_delay_.value(), [this]() { this->output(true); });
|
||||||
} else {
|
} else {
|
||||||
this->set_timeout("ON_OFF", this->off_delay_.value(), [this, is_initial]() { this->output(false, is_initial); });
|
this->set_timeout("ON_OFF", this->off_delay_.value(), [this]() { this->output(false); });
|
||||||
}
|
}
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
float DelayedOnOffFilter::get_setup_priority() const { return setup_priority::HARDWARE; }
|
float DelayedOnOffFilter::get_setup_priority() const { return setup_priority::HARDWARE; }
|
||||||
|
|
||||||
optional<bool> DelayedOnFilter::new_value(bool value, bool is_initial) {
|
optional<bool> DelayedOnFilter::new_value(bool value) {
|
||||||
if (value) {
|
if (value) {
|
||||||
this->set_timeout("ON", this->delay_.value(), [this, is_initial]() { this->output(true, is_initial); });
|
this->set_timeout("ON", this->delay_.value(), [this]() { this->output(true); });
|
||||||
return {};
|
return {};
|
||||||
} else {
|
} else {
|
||||||
this->cancel_timeout("ON");
|
this->cancel_timeout("ON");
|
||||||
@ -49,9 +48,9 @@ optional<bool> DelayedOnFilter::new_value(bool value, bool is_initial) {
|
|||||||
|
|
||||||
float DelayedOnFilter::get_setup_priority() const { return setup_priority::HARDWARE; }
|
float DelayedOnFilter::get_setup_priority() const { return setup_priority::HARDWARE; }
|
||||||
|
|
||||||
optional<bool> DelayedOffFilter::new_value(bool value, bool is_initial) {
|
optional<bool> DelayedOffFilter::new_value(bool value) {
|
||||||
if (!value) {
|
if (!value) {
|
||||||
this->set_timeout("OFF", this->delay_.value(), [this, is_initial]() { this->output(false, is_initial); });
|
this->set_timeout("OFF", this->delay_.value(), [this]() { this->output(false); });
|
||||||
return {};
|
return {};
|
||||||
} else {
|
} else {
|
||||||
this->cancel_timeout("OFF");
|
this->cancel_timeout("OFF");
|
||||||
@ -61,11 +60,11 @@ optional<bool> DelayedOffFilter::new_value(bool value, bool is_initial) {
|
|||||||
|
|
||||||
float DelayedOffFilter::get_setup_priority() const { return setup_priority::HARDWARE; }
|
float DelayedOffFilter::get_setup_priority() const { return setup_priority::HARDWARE; }
|
||||||
|
|
||||||
optional<bool> InvertFilter::new_value(bool value, bool is_initial) { return !value; }
|
optional<bool> InvertFilter::new_value(bool value) { return !value; }
|
||||||
|
|
||||||
AutorepeatFilter::AutorepeatFilter(std::vector<AutorepeatFilterTiming> timings) : timings_(std::move(timings)) {}
|
AutorepeatFilter::AutorepeatFilter(std::vector<AutorepeatFilterTiming> timings) : timings_(std::move(timings)) {}
|
||||||
|
|
||||||
optional<bool> AutorepeatFilter::new_value(bool value, bool is_initial) {
|
optional<bool> AutorepeatFilter::new_value(bool value) {
|
||||||
if (value) {
|
if (value) {
|
||||||
// Ignore if already running
|
// Ignore if already running
|
||||||
if (this->active_timing_ != 0)
|
if (this->active_timing_ != 0)
|
||||||
@ -101,7 +100,7 @@ void AutorepeatFilter::next_timing_() {
|
|||||||
|
|
||||||
void AutorepeatFilter::next_value_(bool val) {
|
void AutorepeatFilter::next_value_(bool val) {
|
||||||
const AutorepeatFilterTiming &timing = this->timings_[this->active_timing_ - 2];
|
const AutorepeatFilterTiming &timing = this->timings_[this->active_timing_ - 2];
|
||||||
this->output(val, false); // This is at least the second one so not initial
|
this->output(val); // This is at least the second one so not initial
|
||||||
this->set_timeout("ON_OFF", val ? timing.time_on : timing.time_off, [this, val]() { this->next_value_(!val); });
|
this->set_timeout("ON_OFF", val ? timing.time_on : timing.time_off, [this, val]() { this->next_value_(!val); });
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,18 +108,18 @@ float AutorepeatFilter::get_setup_priority() const { return setup_priority::HARD
|
|||||||
|
|
||||||
LambdaFilter::LambdaFilter(std::function<optional<bool>(bool)> f) : f_(std::move(f)) {}
|
LambdaFilter::LambdaFilter(std::function<optional<bool>(bool)> f) : f_(std::move(f)) {}
|
||||||
|
|
||||||
optional<bool> LambdaFilter::new_value(bool value, bool is_initial) { return this->f_(value); }
|
optional<bool> LambdaFilter::new_value(bool value) { return this->f_(value); }
|
||||||
|
|
||||||
optional<bool> SettleFilter::new_value(bool value, bool is_initial) {
|
optional<bool> SettleFilter::new_value(bool value) {
|
||||||
if (!this->steady_) {
|
if (!this->steady_) {
|
||||||
this->set_timeout("SETTLE", this->delay_.value(), [this, value, is_initial]() {
|
this->set_timeout("SETTLE", this->delay_.value(), [this, value]() {
|
||||||
this->steady_ = true;
|
this->steady_ = true;
|
||||||
this->output(value, is_initial);
|
this->output(value);
|
||||||
});
|
});
|
||||||
return {};
|
return {};
|
||||||
} else {
|
} else {
|
||||||
this->steady_ = false;
|
this->steady_ = false;
|
||||||
this->output(value, is_initial);
|
this->output(value);
|
||||||
this->set_timeout("SETTLE", this->delay_.value(), [this]() { this->steady_ = true; });
|
this->set_timeout("SETTLE", this->delay_.value(), [this]() { this->steady_ = true; });
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
@ -14,11 +14,11 @@ class BinarySensor;
|
|||||||
|
|
||||||
class Filter {
|
class Filter {
|
||||||
public:
|
public:
|
||||||
virtual optional<bool> new_value(bool value, bool is_initial) = 0;
|
virtual optional<bool> new_value(bool value) = 0;
|
||||||
|
|
||||||
void input(bool value, bool is_initial);
|
void input(bool value);
|
||||||
|
|
||||||
void output(bool value, bool is_initial);
|
void output(bool value);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
friend BinarySensor;
|
friend BinarySensor;
|
||||||
@ -30,7 +30,7 @@ class Filter {
|
|||||||
|
|
||||||
class DelayedOnOffFilter : public Filter, public Component {
|
class DelayedOnOffFilter : public Filter, public Component {
|
||||||
public:
|
public:
|
||||||
optional<bool> new_value(bool value, bool is_initial) override;
|
optional<bool> new_value(bool value) override;
|
||||||
|
|
||||||
float get_setup_priority() const override;
|
float get_setup_priority() const override;
|
||||||
|
|
||||||
@ -44,7 +44,7 @@ class DelayedOnOffFilter : public Filter, public Component {
|
|||||||
|
|
||||||
class DelayedOnFilter : public Filter, public Component {
|
class DelayedOnFilter : public Filter, public Component {
|
||||||
public:
|
public:
|
||||||
optional<bool> new_value(bool value, bool is_initial) override;
|
optional<bool> new_value(bool value) override;
|
||||||
|
|
||||||
float get_setup_priority() const override;
|
float get_setup_priority() const override;
|
||||||
|
|
||||||
@ -56,7 +56,7 @@ class DelayedOnFilter : public Filter, public Component {
|
|||||||
|
|
||||||
class DelayedOffFilter : public Filter, public Component {
|
class DelayedOffFilter : public Filter, public Component {
|
||||||
public:
|
public:
|
||||||
optional<bool> new_value(bool value, bool is_initial) override;
|
optional<bool> new_value(bool value) override;
|
||||||
|
|
||||||
float get_setup_priority() const override;
|
float get_setup_priority() const override;
|
||||||
|
|
||||||
@ -68,7 +68,7 @@ class DelayedOffFilter : public Filter, public Component {
|
|||||||
|
|
||||||
class InvertFilter : public Filter {
|
class InvertFilter : public Filter {
|
||||||
public:
|
public:
|
||||||
optional<bool> new_value(bool value, bool is_initial) override;
|
optional<bool> new_value(bool value) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AutorepeatFilterTiming {
|
struct AutorepeatFilterTiming {
|
||||||
@ -86,7 +86,7 @@ class AutorepeatFilter : public Filter, public Component {
|
|||||||
public:
|
public:
|
||||||
explicit AutorepeatFilter(std::vector<AutorepeatFilterTiming> timings);
|
explicit AutorepeatFilter(std::vector<AutorepeatFilterTiming> timings);
|
||||||
|
|
||||||
optional<bool> new_value(bool value, bool is_initial) override;
|
optional<bool> new_value(bool value) override;
|
||||||
|
|
||||||
float get_setup_priority() const override;
|
float get_setup_priority() const override;
|
||||||
|
|
||||||
@ -102,7 +102,7 @@ class LambdaFilter : public Filter {
|
|||||||
public:
|
public:
|
||||||
explicit LambdaFilter(std::function<optional<bool>(bool)> f);
|
explicit LambdaFilter(std::function<optional<bool>(bool)> f);
|
||||||
|
|
||||||
optional<bool> new_value(bool value, bool is_initial) override;
|
optional<bool> new_value(bool value) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::function<optional<bool>(bool)> f_;
|
std::function<optional<bool>(bool)> f_;
|
||||||
@ -110,7 +110,7 @@ class LambdaFilter : public Filter {
|
|||||||
|
|
||||||
class SettleFilter : public Filter, public Component {
|
class SettleFilter : public Filter, public Component {
|
||||||
public:
|
public:
|
||||||
optional<bool> new_value(bool value, bool is_initial) override;
|
optional<bool> new_value(bool value) override;
|
||||||
|
|
||||||
float get_setup_priority() const override;
|
float get_setup_priority() const override;
|
||||||
|
|
||||||
|
@ -3,4 +3,5 @@
|
|||||||
CODEOWNERS = ["@esphome/core"]
|
CODEOWNERS = ["@esphome/core"]
|
||||||
|
|
||||||
CONF_DRAW_ROUNDING = "draw_rounding"
|
CONF_DRAW_ROUNDING = "draw_rounding"
|
||||||
|
CONF_ON_STATE_CHANGE = "on_state_change"
|
||||||
CONF_REQUEST_HEADERS = "request_headers"
|
CONF_REQUEST_HEADERS = "request_headers"
|
||||||
|
@ -6,16 +6,8 @@ namespace template_ {
|
|||||||
|
|
||||||
static const char *const TAG = "template.binary_sensor";
|
static const char *const TAG = "template.binary_sensor";
|
||||||
|
|
||||||
void TemplateBinarySensor::setup() {
|
void TemplateBinarySensor::setup() { this->loop(); }
|
||||||
if (!this->publish_initial_state_)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (this->f_ != nullptr) {
|
|
||||||
this->publish_initial_state(this->f_().value_or(false));
|
|
||||||
} else {
|
|
||||||
this->publish_initial_state(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void TemplateBinarySensor::loop() {
|
void TemplateBinarySensor::loop() {
|
||||||
if (this->f_ == nullptr)
|
if (this->f_ == nullptr)
|
||||||
return;
|
return;
|
||||||
|
@ -555,7 +555,7 @@ std::string WebServer::button_json(button::Button *obj, JsonDetail start_config)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USE_BINARY_SENSOR
|
#ifdef USE_BINARY_SENSOR
|
||||||
void WebServer::on_binary_sensor_update(binary_sensor::BinarySensor *obj, bool state) {
|
void WebServer::on_binary_sensor_update(binary_sensor::BinarySensor *obj) {
|
||||||
if (this->events_.empty())
|
if (this->events_.empty())
|
||||||
return;
|
return;
|
||||||
this->events_.deferrable_send_state(obj, "state", binary_sensor_state_json_generator);
|
this->events_.deferrable_send_state(obj, "state", binary_sensor_state_json_generator);
|
||||||
|
@ -269,7 +269,7 @@ class WebServer : public Controller, public Component, public AsyncWebHandler {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USE_BINARY_SENSOR
|
#ifdef USE_BINARY_SENSOR
|
||||||
void on_binary_sensor_update(binary_sensor::BinarySensor *obj, bool state) override;
|
void on_binary_sensor_update(binary_sensor::BinarySensor *obj) override;
|
||||||
|
|
||||||
/// Handle a binary sensor request under '/binary_sensor/<id>'.
|
/// Handle a binary sensor request under '/binary_sensor/<id>'.
|
||||||
void handle_binary_sensor_request(AsyncWebServerRequest *request, const UrlMatch &match);
|
void handle_binary_sensor_request(AsyncWebServerRequest *request, const UrlMatch &match);
|
||||||
|
@ -7,8 +7,10 @@ namespace esphome {
|
|||||||
void Controller::setup_controller(bool include_internal) {
|
void Controller::setup_controller(bool include_internal) {
|
||||||
#ifdef USE_BINARY_SENSOR
|
#ifdef USE_BINARY_SENSOR
|
||||||
for (auto *obj : App.get_binary_sensors()) {
|
for (auto *obj : App.get_binary_sensors()) {
|
||||||
if (include_internal || !obj->is_internal())
|
if (include_internal || !obj->is_internal()) {
|
||||||
obj->add_on_state_callback([this, obj](bool state) { this->on_binary_sensor_update(obj, state); });
|
obj->add_full_state_callback(
|
||||||
|
[this, obj](optional<bool> previous, optional<bool> state) { this->on_binary_sensor_update(obj); });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#ifdef USE_FAN
|
#ifdef USE_FAN
|
||||||
|
@ -71,7 +71,7 @@ class Controller {
|
|||||||
public:
|
public:
|
||||||
void setup_controller(bool include_internal = false);
|
void setup_controller(bool include_internal = false);
|
||||||
#ifdef USE_BINARY_SENSOR
|
#ifdef USE_BINARY_SENSOR
|
||||||
virtual void on_binary_sensor_update(binary_sensor::BinarySensor *obj, bool state){};
|
virtual void on_binary_sensor_update(binary_sensor::BinarySensor *obj){};
|
||||||
#endif
|
#endif
|
||||||
#ifdef USE_FAN
|
#ifdef USE_FAN
|
||||||
virtual void on_fan_update(fan::Fan *obj){};
|
virtual void on_fan_update(fan::Fan *obj){};
|
||||||
|
@ -3,6 +3,8 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include "string_ref.h"
|
#include "string_ref.h"
|
||||||
|
#include "helpers.h"
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
|
|
||||||
@ -29,7 +31,7 @@ class EntityBase {
|
|||||||
// Get the unique Object ID of this Entity
|
// Get the unique Object ID of this Entity
|
||||||
uint32_t get_object_id_hash();
|
uint32_t get_object_id_hash();
|
||||||
|
|
||||||
// Get/set whether this Entity should be hidden from outside of ESPHome
|
// Get/set whether this Entity should be hidden outside ESPHome
|
||||||
bool is_internal() const;
|
bool is_internal() const;
|
||||||
void set_internal(bool internal);
|
void set_internal(bool internal);
|
||||||
|
|
||||||
@ -56,11 +58,12 @@ class EntityBase {
|
|||||||
StringRef name_;
|
StringRef name_;
|
||||||
const char *object_id_c_str_{nullptr};
|
const char *object_id_c_str_{nullptr};
|
||||||
const char *icon_c_str_{nullptr};
|
const char *icon_c_str_{nullptr};
|
||||||
uint32_t object_id_hash_;
|
uint32_t object_id_hash_{};
|
||||||
bool has_own_name_{false};
|
bool has_own_name_{false};
|
||||||
bool internal_{false};
|
bool internal_{false};
|
||||||
bool disabled_by_default_{false};
|
bool disabled_by_default_{false};
|
||||||
EntityCategory entity_category_{ENTITY_CATEGORY_NONE};
|
EntityCategory entity_category_{ENTITY_CATEGORY_NONE};
|
||||||
|
bool has_state_{};
|
||||||
};
|
};
|
||||||
|
|
||||||
class EntityBase_DeviceClass { // NOLINT(readability-identifier-naming)
|
class EntityBase_DeviceClass { // NOLINT(readability-identifier-naming)
|
||||||
@ -85,4 +88,58 @@ class EntityBase_UnitOfMeasurement { // NOLINT(readability-identifier-naming)
|
|||||||
const char *unit_of_measurement_{nullptr}; ///< Unit of measurement override
|
const char *unit_of_measurement_{nullptr}; ///< Unit of measurement override
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An entity that has a state.
|
||||||
|
* @tparam T The type of the state
|
||||||
|
*/
|
||||||
|
template<typename T> class StatefulEntityBase : public EntityBase {
|
||||||
|
public:
|
||||||
|
virtual bool has_state() const { return this->state_.has_value(); }
|
||||||
|
virtual const T &get_state() const { return this->state_.value(); }
|
||||||
|
virtual T get_state_default(T default_value) const { return this->state_.value_or(default_value); }
|
||||||
|
void invalidate_state() { this->set_state_({}); }
|
||||||
|
|
||||||
|
void add_full_state_callback(std::function<void(optional<T> previous, optional<T> current)> &&callback) {
|
||||||
|
if (this->full_state_callbacks_ == nullptr)
|
||||||
|
this->full_state_callbacks_ = new CallbackManager<void(optional<T> previous, optional<T> current)>(); // NOLINT
|
||||||
|
this->full_state_callbacks_->add(std::move(callback));
|
||||||
|
}
|
||||||
|
void add_on_state_callback(std::function<void(T)> &&callback) {
|
||||||
|
if (this->state_callbacks_ == nullptr)
|
||||||
|
this->state_callbacks_ = new CallbackManager<void(T)>(); // NOLINT
|
||||||
|
this->state_callbacks_->add(std::move(callback));
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_trigger_on_initial_state(bool trigger_on_initial_state) {
|
||||||
|
this->trigger_on_initial_state_ = trigger_on_initial_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
optional<T> state_{};
|
||||||
|
/**
|
||||||
|
* Set a new state for this entity. This will trigger callbacks only if the new state is different from the previous.
|
||||||
|
*
|
||||||
|
* @param state The new state.
|
||||||
|
* @return True if the state was changed, false if it was the same as before.
|
||||||
|
*/
|
||||||
|
bool set_state_(const optional<T> &state) {
|
||||||
|
if (this->state_ != state) {
|
||||||
|
// call the full state callbacks with the previous and new state
|
||||||
|
if (this->full_state_callbacks_ != nullptr)
|
||||||
|
this->full_state_callbacks_->call(this->state_, state);
|
||||||
|
// trigger legacy callbacks only if the new state is valid and either the trigger on initial state is enabled or
|
||||||
|
// the previous state was valid
|
||||||
|
auto had_state = this->has_state();
|
||||||
|
this->state_ = state;
|
||||||
|
if (this->state_callbacks_ != nullptr && state.has_value() && (this->trigger_on_initial_state_ || had_state))
|
||||||
|
this->state_callbacks_->call(state.value());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
bool trigger_on_initial_state_{true};
|
||||||
|
// callbacks with full state and previous state
|
||||||
|
CallbackManager<void(optional<T> previous, optional<T> current)> *full_state_callbacks_{};
|
||||||
|
CallbackManager<void(T)> *state_callbacks_{};
|
||||||
|
};
|
||||||
} // namespace esphome
|
} // namespace esphome
|
||||||
|
@ -165,6 +165,8 @@ int esp_idf_log_vprintf_(const char *format, va_list args); // NOLINT
|
|||||||
#define YESNO(b) ((b) ? "YES" : "NO")
|
#define YESNO(b) ((b) ? "YES" : "NO")
|
||||||
#define ONOFF(b) ((b) ? "ON" : "OFF")
|
#define ONOFF(b) ((b) ? "ON" : "OFF")
|
||||||
#define TRUEFALSE(b) ((b) ? "TRUE" : "FALSE")
|
#define TRUEFALSE(b) ((b) ? "TRUE" : "FALSE")
|
||||||
|
// for use with optional values
|
||||||
|
#define ONOFFMAYBE(b) (((b).has_value()) ? ONOFF((b).value()) : "UNKNOWN")
|
||||||
|
|
||||||
// Helper class that identifies strings that may be stored in flash storage (similar to Arduino's __FlashStringHelper)
|
// Helper class that identifies strings that may be stored in flash storage (similar to Arduino's __FlashStringHelper)
|
||||||
struct LogString;
|
struct LogString;
|
||||||
|
@ -52,6 +52,11 @@ template<typename T> class optional { // NOLINT
|
|||||||
reset();
|
reset();
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
bool operator==(optional<T> const &rhs) const {
|
||||||
|
if (has_value() && rhs.has_value())
|
||||||
|
return value() == rhs.value();
|
||||||
|
return !has_value() && !rhs.has_value();
|
||||||
|
}
|
||||||
|
|
||||||
template<class U> optional &operator=(optional<U> const &other) {
|
template<class U> optional &operator=(optional<U> const &other) {
|
||||||
has_value_ = other.has_value();
|
has_value_ = other.has_value();
|
||||||
|
15
tests/components/binary_sensor/common.yaml
Normal file
15
tests/components/binary_sensor/common.yaml
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
binary_sensor:
|
||||||
|
- platform: template
|
||||||
|
trigger_on_initial_state: true
|
||||||
|
id: some_binary_sensor
|
||||||
|
name: "Random binary"
|
||||||
|
lambda: return (random_uint32() & 1) == 0;
|
||||||
|
on_state_change:
|
||||||
|
then:
|
||||||
|
- logger.log:
|
||||||
|
format: "Old state was %s"
|
||||||
|
args: ['x_previous.has_value() ? ONOFF(x_previous) : "Unknown"']
|
||||||
|
- logger.log:
|
||||||
|
format: "New state is %s"
|
||||||
|
args: ['x.has_value() ? ONOFF(x) : "Unknown"']
|
||||||
|
- binary_sensor.invalidate_state: some_binary_sensor
|
2
tests/components/binary_sensor/test.bk72xx-ard.yaml
Normal file
2
tests/components/binary_sensor/test.bk72xx-ard.yaml
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
packages:
|
||||||
|
common: !include common.yaml
|
2
tests/components/binary_sensor/test.esp32-ard.yaml
Normal file
2
tests/components/binary_sensor/test.esp32-ard.yaml
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
packages:
|
||||||
|
common: !include common.yaml
|
2
tests/components/binary_sensor/test.esp32-c3-ard.yaml
Normal file
2
tests/components/binary_sensor/test.esp32-c3-ard.yaml
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
packages:
|
||||||
|
common: !include common.yaml
|
2
tests/components/binary_sensor/test.esp32-c3-idf.yaml
Normal file
2
tests/components/binary_sensor/test.esp32-c3-idf.yaml
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
packages:
|
||||||
|
common: !include common.yaml
|
2
tests/components/binary_sensor/test.esp32-idf.yaml
Normal file
2
tests/components/binary_sensor/test.esp32-idf.yaml
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
packages:
|
||||||
|
common: !include common.yaml
|
2
tests/components/binary_sensor/test.esp32-s3-idf.yaml
Normal file
2
tests/components/binary_sensor/test.esp32-s3-idf.yaml
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
packages:
|
||||||
|
common: !include common.yaml
|
2
tests/components/binary_sensor/test.esp8266-ard.yaml
Normal file
2
tests/components/binary_sensor/test.esp8266-ard.yaml
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
packages:
|
||||||
|
common: !include common.yaml
|
2
tests/components/binary_sensor/test.rp2040-ard.yaml
Normal file
2
tests/components/binary_sensor/test.rp2040-ard.yaml
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
packages:
|
||||||
|
common: !include common.yaml
|
@ -63,7 +63,7 @@ binary_sensor:
|
|||||||
id: lvgl_pressbutton
|
id: lvgl_pressbutton
|
||||||
name: Pressbutton
|
name: Pressbutton
|
||||||
widget: spin_up
|
widget: spin_up
|
||||||
publish_initial_state: true
|
trigger_on_initial_state: true
|
||||||
- platform: lvgl
|
- platform: lvgl
|
||||||
name: ButtonMatrix button
|
name: ButtonMatrix button
|
||||||
widget: button_a
|
widget: button_a
|
||||||
|
Loading…
x
Reference in New Issue
Block a user