Compare commits
17 Commits
beta
...
reorder_ap
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
82c39580df | ||
|
|
ee37d2f9c8 | ||
|
|
92ea697119 | ||
|
|
1c488d375f | ||
|
|
1a03b4949f | ||
|
|
731b7808cd | ||
|
|
d9da4cf24d | ||
|
|
666a3ee5e9 | ||
|
|
02469c2d4c | ||
|
|
2a629cae93 | ||
|
|
1f14c316a3 | ||
|
|
dac738a916 | ||
|
|
261b561bb2 | ||
|
|
0228379a2e | ||
|
|
da79215bc3 | ||
|
|
a59e1c7011 | ||
|
|
f467c79a20 |
2
Doxyfile
2
Doxyfile
@@ -48,7 +48,7 @@ PROJECT_NAME = ESPHome
|
||||
# could be handy for archiving the generated documentation or if some version
|
||||
# control system is used.
|
||||
|
||||
PROJECT_NUMBER = 2025.6.0b1
|
||||
PROJECT_NUMBER = 2025.7.0-dev
|
||||
|
||||
# Using the PROJECT_BRIEF tag one can provide an optional one line description
|
||||
# for a project that appears at the top of each page and should give viewer a
|
||||
|
||||
@@ -22,6 +22,7 @@ from esphome.cpp_generator import ( # noqa: F401
|
||||
TemplateArguments,
|
||||
add,
|
||||
add_build_flag,
|
||||
add_build_unflag,
|
||||
add_define,
|
||||
add_global,
|
||||
add_library,
|
||||
@@ -34,6 +35,7 @@ from esphome.cpp_generator import ( # noqa: F401
|
||||
process_lambda,
|
||||
progmem_array,
|
||||
safe_exp,
|
||||
set_cpp_standard,
|
||||
statement,
|
||||
static_const_array,
|
||||
templatable,
|
||||
|
||||
@@ -260,7 +260,7 @@ uint16_t APIConnection::encode_message_to_buffer(ProtoMessage &msg, uint16_t mes
|
||||
return 0; // Doesn't fit
|
||||
}
|
||||
|
||||
// Allocate exact buffer space needed (just the payload, not the overhead)
|
||||
// Allocate buffer space - pass payload size, allocation functions add header/footer space
|
||||
ProtoWriteBuffer buffer =
|
||||
is_single ? conn->allocate_single_message_buffer(size) : conn->allocate_batch_message_buffer(size);
|
||||
|
||||
|
||||
@@ -227,7 +227,7 @@ bool APIServer::check_password(const std::string &password) const {
|
||||
void APIServer::handle_disconnect(APIConnection *conn) {}
|
||||
|
||||
#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())
|
||||
return;
|
||||
for (auto &c : this->clients_)
|
||||
|
||||
@@ -54,7 +54,7 @@ class APIServer : public Component, public Controller {
|
||||
|
||||
void handle_disconnect(APIConnection *conn);
|
||||
#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
|
||||
#ifdef USE_COVER
|
||||
void on_cover_update(cover::Cover *obj) override;
|
||||
|
||||
@@ -46,12 +46,10 @@ async def async_run_logs(config: dict[str, Any], address: str) -> None:
|
||||
time_ = datetime.now()
|
||||
message: bytes = msg.message
|
||||
text = message.decode("utf8", "backslashreplace")
|
||||
if dashboard:
|
||||
text = text.replace("\033", "\\033")
|
||||
for parsed_msg in parse_log_message(
|
||||
text, f"[{time_.hour:02}:{time_.minute:02}:{time_.second:02}]"
|
||||
):
|
||||
print(parsed_msg)
|
||||
print(parsed_msg.replace("\033", "\\033") if dashboard else parsed_msg)
|
||||
|
||||
stop = await async_run(cli, on_log, name=name)
|
||||
try:
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
from logging import getLogger
|
||||
|
||||
from esphome import automation, core
|
||||
from esphome.automation import Condition, maybe_simple_id
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import mqtt, web_server
|
||||
from esphome.components.const import CONF_ON_STATE_CHANGE
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import (
|
||||
CONF_DELAY,
|
||||
@@ -98,6 +101,7 @@ IS_PLATFORM_COMPONENT = True
|
||||
|
||||
CONF_TIME_OFF = "time_off"
|
||||
CONF_TIME_ON = "time_on"
|
||||
CONF_TRIGGER_ON_INITIAL_STATE = "trigger_on_initial_state"
|
||||
|
||||
DEFAULT_DELAY = "1s"
|
||||
DEFAULT_TIME_OFF = "100ms"
|
||||
@@ -127,9 +131,17 @@ MultiClickTriggerEvent = binary_sensor_ns.struct("MultiClickTriggerEvent")
|
||||
StateTrigger = binary_sensor_ns.class_(
|
||||
"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", automation.Action
|
||||
)
|
||||
BinarySensorInvalidateAction = binary_sensor_ns.class_(
|
||||
"BinarySensorInvalidateAction", automation.Action
|
||||
)
|
||||
|
||||
# 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)
|
||||
SettleFilter = binary_sensor_ns.class_("SettleFilter", Filter, cg.Component)
|
||||
|
||||
_LOGGER = getLogger(__name__)
|
||||
|
||||
FILTER_REGISTRY = Registry()
|
||||
validate_filters = cv.validate_registry("filter", FILTER_REGISTRY)
|
||||
|
||||
@@ -386,6 +400,14 @@ def validate_click_timing(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 = (
|
||||
cv.ENTITY_BASE_SCHEMA.extend(web_server.WEBSERVER_SORTING_SCHEMA)
|
||||
.extend(cv.MQTT_COMPONENT_SCHEMA)
|
||||
@@ -395,7 +417,12 @@ _BINARY_SENSOR_SCHEMA = (
|
||||
cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(
|
||||
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_FILTERS): validate_filters,
|
||||
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.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:
|
||||
cg.add(var.set_device_class(device_class))
|
||||
if publish_initial_state := config.get(CONF_PUBLISH_INITIAL_STATE):
|
||||
cg.add(var.set_publish_initial_state(publish_initial_state))
|
||||
trigger = config.get(CONF_TRIGGER_ON_INITIAL_STATE, False) or config.get(
|
||||
CONF_PUBLISH_INITIAL_STATE, False
|
||||
)
|
||||
cg.add(var.set_trigger_on_initial_state(trigger))
|
||||
if inverted := config.get(CONF_INVERTED):
|
||||
cg.add(var.set_inverted(inverted))
|
||||
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)
|
||||
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):
|
||||
mqtt_ = cg.new_Pvariable(mqtt_id, var)
|
||||
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):
|
||||
cg.add_define("USE_BINARY_SENSOR")
|
||||
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)) {}
|
||||
|
||||
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);
|
||||
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...> {
|
||||
public:
|
||||
BinarySensorCondition(BinarySensor *parent, bool state) : parent_(parent), state_(state) {}
|
||||
@@ -154,5 +162,15 @@ template<typename... Ts> class BinarySensorPublishAction : public Action<Ts...>
|
||||
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 esphome
|
||||
|
||||
@@ -7,42 +7,25 @@ namespace binary_sensor {
|
||||
|
||||
static const char *const TAG = "binary_sensor";
|
||||
|
||||
void BinarySensor::add_on_state_callback(std::function<void(bool)> &&callback) {
|
||||
this->state_callback_.add(std::move(callback));
|
||||
}
|
||||
|
||||
void BinarySensor::publish_state(bool state) {
|
||||
if (!this->publish_dedup_.next(state))
|
||||
return;
|
||||
void BinarySensor::publish_state(bool new_state) {
|
||||
if (this->filter_list_ == nullptr) {
|
||||
this->send_state_internal(state, false);
|
||||
this->send_state_internal(new_state);
|
||||
} else {
|
||||
this->filter_list_->input(state, false);
|
||||
this->filter_list_->input(new_state);
|
||||
}
|
||||
}
|
||||
void BinarySensor::publish_initial_state(bool state) {
|
||||
if (!this->publish_dedup_.next(state))
|
||||
return;
|
||||
if (this->filter_list_ == nullptr) {
|
||||
this->send_state_internal(state, true);
|
||||
} else {
|
||||
this->filter_list_->input(state, true);
|
||||
void BinarySensor::publish_initial_state(bool new_state) {
|
||||
this->invalidate_state();
|
||||
this->publish_state(new_state);
|
||||
}
|
||||
void BinarySensor::send_state_internal(bool new_state) {
|
||||
// copy the new state to the visible property for backwards compatibility, before any callbacks
|
||||
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) {
|
||||
filter->parent_ = this;
|
||||
@@ -60,7 +43,6 @@ void BinarySensor::add_filters(const std::vector<Filter *> &filters) {
|
||||
this->add_filter(filter);
|
||||
}
|
||||
}
|
||||
bool BinarySensor::has_state() const { return this->has_state_; }
|
||||
bool BinarySensor::is_status_binary_sensor() const { return false; }
|
||||
|
||||
} // namespace binary_sensor
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/entity_base.h"
|
||||
#include "esphome/core/helpers.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
|
||||
* handles inverted inputs for you.
|
||||
*/
|
||||
class BinarySensor : public EntityBase, public EntityBase_DeviceClass {
|
||||
class BinarySensor : public StatefulEntityBase<bool>, public EntityBase_DeviceClass {
|
||||
public:
|
||||
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);
|
||||
explicit BinarySensor(){};
|
||||
|
||||
/** 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
|
||||
* 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);
|
||||
|
||||
/// The current reported state of the binary sensor.
|
||||
bool state{false};
|
||||
void publish_initial_state(bool new_state);
|
||||
|
||||
void add_filter(Filter *filter);
|
||||
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 ==========
|
||||
// (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.
|
||||
virtual bool has_state() const;
|
||||
|
||||
virtual bool is_status_binary_sensor() const;
|
||||
|
||||
// For backward compatibility, provide an accessible property
|
||||
|
||||
bool state{};
|
||||
|
||||
protected:
|
||||
CallbackManager<void(bool)> state_callback_{};
|
||||
Filter *filter_list_{nullptr};
|
||||
bool has_state_{false};
|
||||
bool publish_initial_state_{false};
|
||||
Deduplicator<bool> publish_dedup_;
|
||||
};
|
||||
|
||||
class BinarySensorInitiallyOff : public BinarySensor {
|
||||
|
||||
@@ -9,37 +9,36 @@ namespace binary_sensor {
|
||||
|
||||
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))
|
||||
return;
|
||||
|
||||
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);
|
||||
auto b = this->new_value(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) {
|
||||
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 {
|
||||
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 {};
|
||||
}
|
||||
|
||||
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) {
|
||||
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 {};
|
||||
} else {
|
||||
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; }
|
||||
|
||||
optional<bool> DelayedOffFilter::new_value(bool value, bool is_initial) {
|
||||
optional<bool> DelayedOffFilter::new_value(bool 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 {};
|
||||
} else {
|
||||
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; }
|
||||
|
||||
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)) {}
|
||||
|
||||
optional<bool> AutorepeatFilter::new_value(bool value, bool is_initial) {
|
||||
optional<bool> AutorepeatFilter::new_value(bool value) {
|
||||
if (value) {
|
||||
// Ignore if already running
|
||||
if (this->active_timing_ != 0)
|
||||
@@ -101,7 +100,7 @@ void AutorepeatFilter::next_timing_() {
|
||||
|
||||
void AutorepeatFilter::next_value_(bool val) {
|
||||
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); });
|
||||
}
|
||||
|
||||
@@ -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)) {}
|
||||
|
||||
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_) {
|
||||
this->set_timeout("SETTLE", this->delay_.value(), [this, value, is_initial]() {
|
||||
this->set_timeout("SETTLE", this->delay_.value(), [this, value]() {
|
||||
this->steady_ = true;
|
||||
this->output(value, is_initial);
|
||||
this->output(value);
|
||||
});
|
||||
return {};
|
||||
} else {
|
||||
this->steady_ = false;
|
||||
this->output(value, is_initial);
|
||||
this->output(value);
|
||||
this->set_timeout("SETTLE", this->delay_.value(), [this]() { this->steady_ = true; });
|
||||
return value;
|
||||
}
|
||||
|
||||
@@ -14,11 +14,11 @@ class BinarySensor;
|
||||
|
||||
class Filter {
|
||||
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:
|
||||
friend BinarySensor;
|
||||
@@ -30,7 +30,7 @@ class Filter {
|
||||
|
||||
class DelayedOnOffFilter : public Filter, public Component {
|
||||
public:
|
||||
optional<bool> new_value(bool value, bool is_initial) override;
|
||||
optional<bool> new_value(bool value) override;
|
||||
|
||||
float get_setup_priority() const override;
|
||||
|
||||
@@ -44,7 +44,7 @@ class DelayedOnOffFilter : public Filter, public Component {
|
||||
|
||||
class DelayedOnFilter : public Filter, public Component {
|
||||
public:
|
||||
optional<bool> new_value(bool value, bool is_initial) override;
|
||||
optional<bool> new_value(bool value) override;
|
||||
|
||||
float get_setup_priority() const override;
|
||||
|
||||
@@ -56,7 +56,7 @@ class DelayedOnFilter : public Filter, public Component {
|
||||
|
||||
class DelayedOffFilter : public Filter, public Component {
|
||||
public:
|
||||
optional<bool> new_value(bool value, bool is_initial) override;
|
||||
optional<bool> new_value(bool value) override;
|
||||
|
||||
float get_setup_priority() const override;
|
||||
|
||||
@@ -68,7 +68,7 @@ class DelayedOffFilter : public Filter, public Component {
|
||||
|
||||
class InvertFilter : public Filter {
|
||||
public:
|
||||
optional<bool> new_value(bool value, bool is_initial) override;
|
||||
optional<bool> new_value(bool value) override;
|
||||
};
|
||||
|
||||
struct AutorepeatFilterTiming {
|
||||
@@ -86,7 +86,7 @@ class AutorepeatFilter : public Filter, public Component {
|
||||
public:
|
||||
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;
|
||||
|
||||
@@ -102,7 +102,7 @@ class LambdaFilter : public Filter {
|
||||
public:
|
||||
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:
|
||||
std::function<optional<bool>(bool)> f_;
|
||||
@@ -110,7 +110,7 @@ class LambdaFilter : public Filter {
|
||||
|
||||
class SettleFilter : public Filter, public Component {
|
||||
public:
|
||||
optional<bool> new_value(bool value, bool is_initial) override;
|
||||
optional<bool> new_value(bool value) override;
|
||||
|
||||
float get_setup_priority() const override;
|
||||
|
||||
|
||||
@@ -3,4 +3,5 @@
|
||||
CODEOWNERS = ["@esphome/core"]
|
||||
|
||||
CONF_DRAW_ROUNDING = "draw_rounding"
|
||||
CONF_ON_STATE_CHANGE = "on_state_change"
|
||||
CONF_REQUEST_HEADERS = "request_headers"
|
||||
|
||||
@@ -94,6 +94,13 @@ COMPILER_OPTIMIZATIONS = {
|
||||
"SIZE": "CONFIG_COMPILER_OPTIMIZATION_SIZE",
|
||||
}
|
||||
|
||||
ARDUINO_ALLOWED_VARIANTS = [
|
||||
VARIANT_ESP32,
|
||||
VARIANT_ESP32C3,
|
||||
VARIANT_ESP32S2,
|
||||
VARIANT_ESP32S3,
|
||||
]
|
||||
|
||||
|
||||
def get_cpu_frequencies(*frequencies):
|
||||
return [str(x) + "MHZ" for x in frequencies]
|
||||
@@ -143,12 +150,17 @@ def set_core_data(config):
|
||||
CORE.data[KEY_ESP32][KEY_COMPONENTS] = {}
|
||||
elif conf[CONF_TYPE] == FRAMEWORK_ARDUINO:
|
||||
CORE.data[KEY_CORE][KEY_TARGET_FRAMEWORK] = "arduino"
|
||||
if variant not in ARDUINO_ALLOWED_VARIANTS:
|
||||
raise cv.Invalid(
|
||||
f"ESPHome does not support using the Arduino framework for the {variant}. Please use the ESP-IDF framework instead.",
|
||||
path=[CONF_FRAMEWORK, CONF_TYPE],
|
||||
)
|
||||
CORE.data[KEY_CORE][KEY_FRAMEWORK_VERSION] = cv.Version.parse(
|
||||
config[CONF_FRAMEWORK][CONF_VERSION]
|
||||
)
|
||||
|
||||
CORE.data[KEY_ESP32][KEY_BOARD] = config[CONF_BOARD]
|
||||
CORE.data[KEY_ESP32][KEY_VARIANT] = config[CONF_VARIANT]
|
||||
CORE.data[KEY_ESP32][KEY_VARIANT] = variant
|
||||
CORE.data[KEY_ESP32][KEY_EXTRA_BUILD_FILES] = {}
|
||||
|
||||
return config
|
||||
@@ -618,6 +630,21 @@ ESP_IDF_FRAMEWORK_SCHEMA = cv.All(
|
||||
)
|
||||
|
||||
|
||||
def _set_default_framework(config):
|
||||
if CONF_FRAMEWORK not in config:
|
||||
config = config.copy()
|
||||
|
||||
variant = config[CONF_VARIANT]
|
||||
if variant in ARDUINO_ALLOWED_VARIANTS:
|
||||
config[CONF_FRAMEWORK] = ARDUINO_FRAMEWORK_SCHEMA({})
|
||||
config[CONF_FRAMEWORK][CONF_TYPE] = FRAMEWORK_ARDUINO
|
||||
else:
|
||||
config[CONF_FRAMEWORK] = ESP_IDF_FRAMEWORK_SCHEMA({})
|
||||
config[CONF_FRAMEWORK][CONF_TYPE] = FRAMEWORK_ESP_IDF
|
||||
|
||||
return config
|
||||
|
||||
|
||||
FRAMEWORK_ESP_IDF = "esp-idf"
|
||||
FRAMEWORK_ARDUINO = "arduino"
|
||||
FRAMEWORK_SCHEMA = cv.typed_schema(
|
||||
@@ -627,7 +654,6 @@ FRAMEWORK_SCHEMA = cv.typed_schema(
|
||||
},
|
||||
lower=True,
|
||||
space="-",
|
||||
default_type=FRAMEWORK_ARDUINO,
|
||||
)
|
||||
|
||||
|
||||
@@ -654,10 +680,11 @@ CONFIG_SCHEMA = cv.All(
|
||||
),
|
||||
cv.Optional(CONF_PARTITIONS): cv.file_,
|
||||
cv.Optional(CONF_VARIANT): cv.one_of(*VARIANTS, upper=True),
|
||||
cv.Optional(CONF_FRAMEWORK, default={}): FRAMEWORK_SCHEMA,
|
||||
cv.Optional(CONF_FRAMEWORK): FRAMEWORK_SCHEMA,
|
||||
}
|
||||
),
|
||||
_detect_variant,
|
||||
_set_default_framework,
|
||||
set_core_data,
|
||||
)
|
||||
|
||||
@@ -668,6 +695,7 @@ FINAL_VALIDATE_SCHEMA = cv.Schema(final_validate)
|
||||
async def to_code(config):
|
||||
cg.add_platformio_option("board", config[CONF_BOARD])
|
||||
cg.add_platformio_option("board_upload.flash_size", config[CONF_FLASH_SIZE])
|
||||
cg.set_cpp_standard("gnu++17")
|
||||
cg.add_build_flag("-DUSE_ESP32")
|
||||
cg.add_define("ESPHOME_BOARD", config[CONF_BOARD])
|
||||
cg.add_build_flag(f"-DUSE_ESP32_VARIANT_{config[CONF_VARIANT]}")
|
||||
|
||||
@@ -183,6 +183,7 @@ async def to_code(config):
|
||||
|
||||
cg.add_platformio_option("board", config[CONF_BOARD])
|
||||
cg.add_build_flag("-DUSE_ESP8266")
|
||||
cg.set_cpp_standard("gnu++17")
|
||||
cg.add_define("ESPHOME_BOARD", config[CONF_BOARD])
|
||||
cg.add_define("ESPHOME_VARIANT", "ESP8266")
|
||||
|
||||
|
||||
@@ -129,6 +129,13 @@ void INA219Component::setup() {
|
||||
}
|
||||
}
|
||||
|
||||
void INA219Component::on_powerdown() {
|
||||
// Mode = 0 -> power down
|
||||
if (!this->write_byte_16(INA219_REGISTER_CONFIG, 0)) {
|
||||
ESP_LOGE(TAG, "powerdown error");
|
||||
}
|
||||
}
|
||||
|
||||
void INA219Component::dump_config() {
|
||||
ESP_LOGCONFIG(TAG, "INA219:");
|
||||
LOG_I2C_DEVICE(this);
|
||||
|
||||
@@ -15,6 +15,7 @@ class INA219Component : public PollingComponent, public i2c::I2CDevice {
|
||||
void dump_config() override;
|
||||
float get_setup_priority() const override;
|
||||
void update() override;
|
||||
void on_powerdown() override;
|
||||
|
||||
void set_shunt_resistance_ohm(float shunt_resistance_ohm) { shunt_resistance_ohm_ = shunt_resistance_ohm; }
|
||||
void set_max_current_a(float max_current_a) { max_current_a_ = max_current_a; }
|
||||
|
||||
@@ -264,6 +264,7 @@ async def component_to_code(config):
|
||||
# force using arduino framework
|
||||
cg.add_platformio_option("framework", "arduino")
|
||||
cg.add_build_flag("-DUSE_ARDUINO")
|
||||
cg.set_cpp_standard("gnu++17")
|
||||
|
||||
# disable library compatibility checks
|
||||
cg.add_platformio_option("lib_ldf_mode", "off")
|
||||
|
||||
@@ -50,7 +50,7 @@ MCP23016_PIN_SCHEMA = pins.gpio_base_schema(
|
||||
cv.int_range(min=0, max=15),
|
||||
modes=[CONF_INPUT, CONF_OUTPUT],
|
||||
mode_validator=validate_mode,
|
||||
invertable=True,
|
||||
invertible=True,
|
||||
).extend(
|
||||
{
|
||||
cv.Required(CONF_MCP23016): cv.use_id(MCP23016),
|
||||
|
||||
@@ -60,7 +60,7 @@ MCP23XXX_PIN_SCHEMA = pins.gpio_base_schema(
|
||||
cv.int_range(min=0, max=15),
|
||||
modes=[CONF_INPUT, CONF_OUTPUT, CONF_PULLUP],
|
||||
mode_validator=validate_mode,
|
||||
invertable=True,
|
||||
invertible=True,
|
||||
).extend(
|
||||
{
|
||||
cv.Required(CONF_MCP23XXX): cv.use_id(MCP23XXXBase),
|
||||
|
||||
@@ -337,23 +337,26 @@ bool Nextion::upload_tft(uint32_t baud_rate, bool exit_reparse) {
|
||||
|
||||
bool Nextion::upload_end_(bool successful) {
|
||||
ESP_LOGD(TAG, "TFT upload done: %s", YESNO(successful));
|
||||
this->is_updating_ = false;
|
||||
this->ignore_is_setup_ = false;
|
||||
|
||||
uint32_t baud_rate = this->parent_->get_baud_rate();
|
||||
if (baud_rate != this->original_baud_rate_) {
|
||||
ESP_LOGD(TAG, "Baud back: %" PRIu32 "->%" PRIu32, baud_rate, this->original_baud_rate_);
|
||||
this->parent_->set_baud_rate(this->original_baud_rate_);
|
||||
this->parent_->load_settings();
|
||||
}
|
||||
|
||||
if (successful) {
|
||||
ESP_LOGD(TAG, "Restart");
|
||||
delay(1500); // NOLINT
|
||||
App.safe_reboot();
|
||||
delay(1500); // NOLINT
|
||||
} else {
|
||||
ESP_LOGE(TAG, "TFT upload failed");
|
||||
|
||||
this->is_updating_ = false;
|
||||
this->ignore_is_setup_ = false;
|
||||
|
||||
uint32_t baud_rate = this->parent_->get_baud_rate();
|
||||
if (baud_rate != this->original_baud_rate_) {
|
||||
ESP_LOGD(TAG, "Baud back: %" PRIu32 "->%" PRIu32, baud_rate, this->original_baud_rate_);
|
||||
this->parent_->set_baud_rate(this->original_baud_rate_);
|
||||
this->parent_->load_settings();
|
||||
}
|
||||
}
|
||||
|
||||
return successful;
|
||||
}
|
||||
|
||||
|
||||
@@ -337,15 +337,6 @@ bool Nextion::upload_tft(uint32_t baud_rate, bool exit_reparse) {
|
||||
|
||||
bool Nextion::upload_end_(bool successful) {
|
||||
ESP_LOGD(TAG, "TFT upload done: %s", YESNO(successful));
|
||||
this->is_updating_ = false;
|
||||
this->ignore_is_setup_ = false;
|
||||
|
||||
uint32_t baud_rate = this->parent_->get_baud_rate();
|
||||
if (baud_rate != this->original_baud_rate_) {
|
||||
ESP_LOGD(TAG, "Baud back: %" PRIu32 "->%" PRIu32, baud_rate, this->original_baud_rate_);
|
||||
this->parent_->set_baud_rate(this->original_baud_rate_);
|
||||
this->parent_->load_settings();
|
||||
}
|
||||
|
||||
if (successful) {
|
||||
ESP_LOGD(TAG, "Restart");
|
||||
@@ -353,7 +344,18 @@ bool Nextion::upload_end_(bool successful) {
|
||||
App.safe_reboot();
|
||||
} else {
|
||||
ESP_LOGE(TAG, "TFT upload failed");
|
||||
|
||||
this->is_updating_ = false;
|
||||
this->ignore_is_setup_ = false;
|
||||
|
||||
uint32_t baud_rate = this->parent_->get_baud_rate();
|
||||
if (baud_rate != this->original_baud_rate_) {
|
||||
ESP_LOGD(TAG, "Baud back: %" PRIu32 "->%" PRIu32, baud_rate, this->original_baud_rate_);
|
||||
this->parent_->set_baud_rate(this->original_baud_rate_);
|
||||
this->parent_->load_settings();
|
||||
}
|
||||
}
|
||||
|
||||
return successful;
|
||||
}
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ PCF8574_PIN_SCHEMA = pins.gpio_base_schema(
|
||||
cv.int_range(min=0, max=17),
|
||||
modes=[CONF_INPUT, CONF_OUTPUT],
|
||||
mode_validator=validate_mode,
|
||||
invertable=True,
|
||||
invertible=True,
|
||||
).extend(
|
||||
{
|
||||
cv.Required(CONF_PCF8574): cv.use_id(PCF8574Component),
|
||||
|
||||
@@ -31,7 +31,6 @@ CONFIG_SCHEMA = cv.Schema(
|
||||
}
|
||||
),
|
||||
},
|
||||
cv.only_with_arduino,
|
||||
).extend(cv.COMPONENT_SCHEMA)
|
||||
|
||||
|
||||
|
||||
@@ -167,6 +167,7 @@ async def to_code(config):
|
||||
cg.add_platformio_option("lib_ldf_mode", "chain+")
|
||||
cg.add_platformio_option("board", config[CONF_BOARD])
|
||||
cg.add_build_flag("-DUSE_RP2040")
|
||||
cg.set_cpp_standard("gnu++17")
|
||||
cg.add_define("ESPHOME_BOARD", config[CONF_BOARD])
|
||||
cg.add_define("ESPHOME_VARIANT", "RP2040")
|
||||
|
||||
|
||||
@@ -95,7 +95,7 @@ SN74HC595_PIN_SCHEMA = pins.gpio_base_schema(
|
||||
cv.int_range(min=0, max=2047),
|
||||
modes=[CONF_OUTPUT],
|
||||
mode_validator=_validate_output_mode,
|
||||
invertable=True,
|
||||
invertible=True,
|
||||
).extend(
|
||||
{
|
||||
cv.Required(CONF_SN74HC595): cv.use_id(SN74HC595Component),
|
||||
|
||||
@@ -53,7 +53,7 @@ TCA9555_PIN_SCHEMA = pins.gpio_base_schema(
|
||||
cv.int_range(min=0, max=15),
|
||||
modes=[CONF_INPUT, CONF_OUTPUT],
|
||||
mode_validator=validate_mode,
|
||||
invertable=True,
|
||||
invertible=True,
|
||||
).extend(
|
||||
{
|
||||
cv.Required(CONF_TCA9555): cv.use_id(TCA9555Component),
|
||||
|
||||
@@ -110,15 +110,7 @@ void TemplateAlarmControlPanel::loop() {
|
||||
delay = this->arming_night_time_;
|
||||
}
|
||||
if ((millis() - this->last_update_) > delay) {
|
||||
#ifdef USE_BINARY_SENSOR
|
||||
for (auto sensor_info : this->sensor_map_) {
|
||||
// Check for sensors left on and set to bypass automatically and remove them from monitoring
|
||||
if ((sensor_info.second.flags & BINARY_SENSOR_MODE_BYPASS_AUTO) && (sensor_info.first->state)) {
|
||||
ESP_LOGW(TAG, "%s is left on and will be automatically bypassed", sensor_info.first->get_name().c_str());
|
||||
this->bypassed_sensor_indicies_.push_back(sensor_info.second.store_index);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
this->bypass_before_arming();
|
||||
this->publish_state(this->desired_state_);
|
||||
}
|
||||
return;
|
||||
@@ -259,10 +251,23 @@ void TemplateAlarmControlPanel::arm_(optional<std::string> code, alarm_control_p
|
||||
if (delay > 0) {
|
||||
this->publish_state(ACP_STATE_ARMING);
|
||||
} else {
|
||||
this->bypass_before_arming();
|
||||
this->publish_state(state);
|
||||
}
|
||||
}
|
||||
|
||||
void TemplateAlarmControlPanel::bypass_before_arming() {
|
||||
#ifdef USE_BINARY_SENSOR
|
||||
for (auto sensor_info : this->sensor_map_) {
|
||||
// Check for sensors left on and set to bypass automatically and remove them from monitoring
|
||||
if ((sensor_info.second.flags & BINARY_SENSOR_MODE_BYPASS_AUTO) && (sensor_info.first->state)) {
|
||||
ESP_LOGW(TAG, "'%s' is left on and will be automatically bypassed", sensor_info.first->get_name().c_str());
|
||||
this->bypassed_sensor_indicies_.push_back(sensor_info.second.store_index);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void TemplateAlarmControlPanel::control(const AlarmControlPanelCall &call) {
|
||||
if (call.get_state()) {
|
||||
if (call.get_state() == ACP_STATE_ARMED_AWAY) {
|
||||
|
||||
@@ -60,6 +60,7 @@ class TemplateAlarmControlPanel : public alarm_control_panel::AlarmControlPanel,
|
||||
bool get_requires_code_to_arm() const override { return this->requires_code_to_arm_; }
|
||||
bool get_all_sensors_ready() { return this->sensors_ready_; };
|
||||
void set_restore_mode(TemplateAlarmControlPanelRestoreMode restore_mode) { this->restore_mode_ = restore_mode; }
|
||||
void bypass_before_arming();
|
||||
|
||||
#ifdef USE_BINARY_SENSOR
|
||||
/** Add a binary_sensor to the alarm_panel.
|
||||
|
||||
@@ -6,16 +6,8 @@ namespace template_ {
|
||||
|
||||
static const char *const TAG = "template.binary_sensor";
|
||||
|
||||
void TemplateBinarySensor::setup() {
|
||||
if (!this->publish_initial_state_)
|
||||
return;
|
||||
void TemplateBinarySensor::setup() { this->loop(); }
|
||||
|
||||
if (this->f_ != nullptr) {
|
||||
this->publish_initial_state(this->f_().value_or(false));
|
||||
} else {
|
||||
this->publish_initial_state(false);
|
||||
}
|
||||
}
|
||||
void TemplateBinarySensor::loop() {
|
||||
if (this->f_ == nullptr)
|
||||
return;
|
||||
|
||||
@@ -555,7 +555,7 @@ std::string WebServer::button_json(button::Button *obj, JsonDetail start_config)
|
||||
#endif
|
||||
|
||||
#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())
|
||||
return;
|
||||
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
|
||||
|
||||
#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>'.
|
||||
void handle_binary_sensor_request(AsyncWebServerRequest *request, const UrlMatch &match);
|
||||
|
||||
@@ -8,8 +8,6 @@ CONFIG_SCHEMA = cv.All(
|
||||
cv.only_with_esp_idf,
|
||||
)
|
||||
|
||||
AUTO_LOAD = ["web_server"]
|
||||
|
||||
|
||||
async def to_code(config):
|
||||
# Increase the maximum supported size of headers section in HTTP request packet to be processed by the server
|
||||
|
||||
@@ -9,10 +9,12 @@
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
#include "web_server_idf.h"
|
||||
|
||||
#ifdef USE_WEBSERVER
|
||||
#include "esphome/components/web_server/web_server.h"
|
||||
#include "esphome/components/web_server/list_entities.h"
|
||||
|
||||
#include "web_server_idf.h"
|
||||
#endif // USE_WEBSERVER
|
||||
|
||||
namespace esphome {
|
||||
namespace web_server_idf {
|
||||
@@ -273,6 +275,7 @@ void AsyncResponseStream::printf(const char *fmt, ...) {
|
||||
this->print(str);
|
||||
}
|
||||
|
||||
#ifdef USE_WEBSERVER
|
||||
AsyncEventSource::~AsyncEventSource() {
|
||||
for (auto *ses : this->sessions_) {
|
||||
delete ses; // NOLINT(cppcoreguidelines-owning-memory)
|
||||
@@ -511,6 +514,7 @@ void AsyncEventSourceResponse::deferrable_send_state(void *source, const char *e
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace web_server_idf
|
||||
} // namespace esphome
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
#ifdef USE_ESP_IDF
|
||||
|
||||
#include "esphome/core/defines.h"
|
||||
#include <esp_http_server.h>
|
||||
|
||||
#include <functional>
|
||||
@@ -12,10 +13,12 @@
|
||||
#include <vector>
|
||||
|
||||
namespace esphome {
|
||||
#ifdef USE_WEBSERVER
|
||||
namespace web_server {
|
||||
class WebServer;
|
||||
class ListEntitiesIterator;
|
||||
}; // namespace web_server
|
||||
#endif
|
||||
namespace web_server_idf {
|
||||
|
||||
#define F(string_literal) (string_literal)
|
||||
@@ -220,6 +223,7 @@ class AsyncWebHandler {
|
||||
virtual bool isRequestHandlerTrivial() { return true; }
|
||||
};
|
||||
|
||||
#ifdef USE_WEBSERVER
|
||||
class AsyncEventSource;
|
||||
class AsyncEventSourceResponse;
|
||||
|
||||
@@ -307,10 +311,13 @@ class AsyncEventSource : public AsyncWebHandler {
|
||||
connect_handler_t on_connect_{};
|
||||
esphome::web_server::WebServer *web_server_;
|
||||
};
|
||||
#endif // USE_WEBSERVER
|
||||
|
||||
class DefaultHeaders {
|
||||
friend class AsyncWebServerRequest;
|
||||
#ifdef USE_WEBSERVER
|
||||
friend class AsyncEventSourceResponse;
|
||||
#endif
|
||||
|
||||
public:
|
||||
// NOLINTNEXTLINE(readability-identifier-naming)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"""Constants used by esphome."""
|
||||
|
||||
__version__ = "2025.6.0b1"
|
||||
__version__ = "2025.7.0-dev"
|
||||
|
||||
ALLOWED_NAME_CHARS = "abcdefghijklmnopqrstuvwxyz0123456789-_"
|
||||
VALID_SUBSTITUTIONS_CHARACTERS = (
|
||||
|
||||
@@ -507,6 +507,8 @@ class EsphomeCore:
|
||||
self.libraries: list[Library] = []
|
||||
# A set of build flags to set in the platformio project
|
||||
self.build_flags: set[str] = set()
|
||||
# A set of build unflags to set in the platformio project
|
||||
self.build_unflags: set[str] = set()
|
||||
# A set of defines to set for the compile process in esphome/core/defines.h
|
||||
self.defines: set[Define] = set()
|
||||
# A map of all platformio options to apply
|
||||
@@ -545,6 +547,7 @@ class EsphomeCore:
|
||||
self.global_statements = []
|
||||
self.libraries = []
|
||||
self.build_flags = set()
|
||||
self.build_unflags = set()
|
||||
self.defines = set()
|
||||
self.platformio_options = {}
|
||||
self.loaded_integrations = set()
|
||||
@@ -766,11 +769,15 @@ class EsphomeCore:
|
||||
self.libraries.append(library)
|
||||
return library
|
||||
|
||||
def add_build_flag(self, build_flag):
|
||||
def add_build_flag(self, build_flag: str) -> str:
|
||||
self.build_flags.add(build_flag)
|
||||
_LOGGER.debug("Adding build flag: %s", build_flag)
|
||||
return build_flag
|
||||
|
||||
def add_build_unflag(self, build_unflag: str) -> None:
|
||||
self.build_unflags.add(build_unflag)
|
||||
_LOGGER.debug("Adding build unflag: %s", build_unflag)
|
||||
|
||||
def add_define(self, define):
|
||||
if isinstance(define, str):
|
||||
define = Define(define)
|
||||
|
||||
@@ -117,7 +117,9 @@ void Application::loop() {
|
||||
// Use the last component's end time instead of calling millis() again
|
||||
auto elapsed = last_op_end_time - this->last_loop_;
|
||||
if (elapsed >= this->loop_interval_ || HighFrequencyLoopRequester::is_high_frequency()) {
|
||||
yield();
|
||||
// Even if we overran the loop interval, we still need to select()
|
||||
// to know if any sockets have data ready
|
||||
this->yield_with_select_(0);
|
||||
} else {
|
||||
uint32_t delay_time = this->loop_interval_ - elapsed;
|
||||
uint32_t next_schedule = this->scheduler.next_schedule_in().value_or(delay_time);
|
||||
@@ -126,7 +128,7 @@ void Application::loop() {
|
||||
next_schedule = std::max(next_schedule, delay_time / 2);
|
||||
delay_time = std::min(next_schedule, delay_time);
|
||||
|
||||
this->delay_with_select_(delay_time);
|
||||
this->yield_with_select_(delay_time);
|
||||
}
|
||||
this->last_loop_ = last_op_end_time;
|
||||
|
||||
@@ -215,7 +217,7 @@ void Application::teardown_components(uint32_t timeout_ms) {
|
||||
|
||||
// Give some time for I/O operations if components are still pending
|
||||
if (!pending_components.empty()) {
|
||||
this->delay_with_select_(1);
|
||||
this->yield_with_select_(1);
|
||||
}
|
||||
|
||||
// Update time for next iteration
|
||||
@@ -293,8 +295,6 @@ bool Application::is_socket_ready(int fd) const {
|
||||
// This function is thread-safe for reading the result of select()
|
||||
// However, it should only be called after select() has been executed in the main loop
|
||||
// The read_fds_ is only modified by select() in the main loop
|
||||
if (HighFrequencyLoopRequester::is_high_frequency())
|
||||
return true; // fd sets via select are not updated in high frequency looping - so force true fallback behavior
|
||||
if (fd < 0 || fd >= FD_SETSIZE)
|
||||
return false;
|
||||
|
||||
@@ -302,7 +302,9 @@ bool Application::is_socket_ready(int fd) const {
|
||||
}
|
||||
#endif
|
||||
|
||||
void Application::delay_with_select_(uint32_t delay_ms) {
|
||||
void Application::yield_with_select_(uint32_t delay_ms) {
|
||||
// Delay while monitoring sockets. When delay_ms is 0, always yield() to ensure other tasks run
|
||||
// since select() with 0 timeout only polls without yielding.
|
||||
#ifdef USE_SOCKET_SELECT_SUPPORT
|
||||
if (!this->socket_fds_.empty()) {
|
||||
// Update fd_set if socket list has changed
|
||||
@@ -340,6 +342,10 @@ void Application::delay_with_select_(uint32_t delay_ms) {
|
||||
ESP_LOGW(TAG, "select() failed with errno %d", errno);
|
||||
delay(delay_ms);
|
||||
}
|
||||
// When delay_ms is 0, we need to yield since select(0) doesn't yield
|
||||
if (delay_ms == 0) {
|
||||
yield();
|
||||
}
|
||||
} else {
|
||||
// No sockets registered, use regular delay
|
||||
delay(delay_ms);
|
||||
|
||||
@@ -575,7 +575,7 @@ class Application {
|
||||
void feed_wdt_arch_();
|
||||
|
||||
/// Perform a delay while also monitoring socket file descriptors for readiness
|
||||
void delay_with_select_(uint32_t delay_ms);
|
||||
void yield_with_select_(uint32_t delay_ms);
|
||||
|
||||
std::vector<Component *> components_{};
|
||||
std::vector<Component *> looping_components_{};
|
||||
@@ -649,21 +649,27 @@ class Application {
|
||||
std::string area_;
|
||||
const char *comment_{nullptr};
|
||||
const char *compilation_time_{nullptr};
|
||||
bool name_add_mac_suffix_;
|
||||
Component *current_component_{nullptr};
|
||||
uint32_t last_loop_{0};
|
||||
uint32_t loop_interval_{16};
|
||||
<<<<<<< Updated upstream
|
||||
size_t dump_config_at_{SIZE_MAX};
|
||||
uint32_t app_state_{0};
|
||||
Component *current_component_{nullptr};
|
||||
=======
|
||||
>>>>>>> Stashed changes
|
||||
uint32_t loop_component_start_time_{0};
|
||||
size_t dump_config_at_{SIZE_MAX};
|
||||
bool name_add_mac_suffix_;
|
||||
uint8_t app_state_{0};
|
||||
|
||||
#ifdef USE_SOCKET_SELECT_SUPPORT
|
||||
// Socket select management
|
||||
std::vector<int> socket_fds_; // Vector of all monitored socket file descriptors
|
||||
bool socket_fds_changed_{false}; // Flag to rebuild base_read_fds_ when socket_fds_ changes
|
||||
int max_fd_{-1}; // Highest file descriptor number for select()
|
||||
fd_set base_read_fds_{}; // Cached fd_set rebuilt only when socket_fds_ changes
|
||||
fd_set read_fds_{}; // Working fd_set for select(), copied from base_read_fds_
|
||||
int max_fd_{-1}; // Highest file descriptor number for select()
|
||||
bool socket_fds_changed_{false}; // Flag to rebuild base_read_fds_ when socket_fds_ changes
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@ extern const uint32_t STATUS_LED_OK;
|
||||
extern const uint32_t STATUS_LED_WARNING;
|
||||
extern const uint32_t STATUS_LED_ERROR;
|
||||
|
||||
enum class RetryResult { DONE, RETRY };
|
||||
enum class RetryResult : uint8_t { DONE, RETRY };
|
||||
|
||||
extern const uint32_t WARN_IF_BLOCKING_OVER_MS;
|
||||
|
||||
|
||||
@@ -7,8 +7,10 @@ namespace esphome {
|
||||
void Controller::setup_controller(bool include_internal) {
|
||||
#ifdef USE_BINARY_SENSOR
|
||||
for (auto *obj : App.get_binary_sensors()) {
|
||||
if (include_internal || !obj->is_internal())
|
||||
obj->add_on_state_callback([this, obj](bool state) { this->on_binary_sensor_update(obj, state); });
|
||||
if (include_internal || !obj->is_internal()) {
|
||||
obj->add_full_state_callback(
|
||||
[this, obj](optional<bool> previous, optional<bool> state) { this->on_binary_sensor_update(obj); });
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_FAN
|
||||
|
||||
@@ -71,7 +71,7 @@ class Controller {
|
||||
public:
|
||||
void setup_controller(bool include_internal = false);
|
||||
#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
|
||||
#ifdef USE_FAN
|
||||
virtual void on_fan_update(fan::Fan *obj){};
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
#include <string>
|
||||
#include <cstdint>
|
||||
#include "string_ref.h"
|
||||
#include "helpers.h"
|
||||
#include "log.h"
|
||||
|
||||
namespace esphome {
|
||||
|
||||
@@ -29,7 +31,7 @@ class EntityBase {
|
||||
// Get the unique Object ID of this Entity
|
||||
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;
|
||||
void set_internal(bool internal);
|
||||
|
||||
@@ -56,11 +58,12 @@ class EntityBase {
|
||||
StringRef name_;
|
||||
const char *object_id_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 internal_{false};
|
||||
bool disabled_by_default_{false};
|
||||
EntityCategory entity_category_{ENTITY_CATEGORY_NONE};
|
||||
bool has_state_{};
|
||||
};
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
||||
@@ -165,6 +165,8 @@ int esp_idf_log_vprintf_(const char *format, va_list args); // NOLINT
|
||||
#define YESNO(b) ((b) ? "YES" : "NO")
|
||||
#define ONOFF(b) ((b) ? "ON" : "OFF")
|
||||
#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)
|
||||
struct LogString;
|
||||
|
||||
@@ -52,6 +52,11 @@ template<typename T> class optional { // NOLINT
|
||||
reset();
|
||||
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) {
|
||||
has_value_ = other.has_value();
|
||||
|
||||
@@ -608,6 +608,17 @@ def add_build_flag(build_flag: str):
|
||||
CORE.add_build_flag(build_flag)
|
||||
|
||||
|
||||
def add_build_unflag(build_unflag: str) -> None:
|
||||
"""Add a global build unflag to the compiler flags."""
|
||||
CORE.add_build_unflag(build_unflag)
|
||||
|
||||
|
||||
def set_cpp_standard(standard: str) -> None:
|
||||
"""Set C++ standard with compiler flag `-std={standard}`."""
|
||||
CORE.add_build_unflag("-std=gnu++11")
|
||||
CORE.add_build_flag(f"-std={standard}")
|
||||
|
||||
|
||||
def add_define(name: str, value: SafeExpType = None):
|
||||
"""Add a global define to the auto-generated defines.h file.
|
||||
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
from collections.abc import Callable
|
||||
from functools import reduce
|
||||
from logging import Logger
|
||||
import operator
|
||||
from typing import Any
|
||||
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import (
|
||||
@@ -15,6 +18,7 @@ from esphome.const import (
|
||||
CONF_PULLUP,
|
||||
)
|
||||
from esphome.core import CORE
|
||||
from esphome.cpp_generator import MockObjClass
|
||||
|
||||
|
||||
class PinRegistry(dict):
|
||||
@@ -262,7 +266,7 @@ internal_gpio_input_pullup_pin_number = _internal_number_creator(
|
||||
)
|
||||
|
||||
|
||||
def check_strapping_pin(conf, strapping_pin_list, logger):
|
||||
def check_strapping_pin(conf, strapping_pin_list: set[int], logger: Logger):
|
||||
num = conf[CONF_NUMBER]
|
||||
if num in strapping_pin_list and not conf.get(CONF_IGNORE_STRAPPING_WARNING):
|
||||
logger.warning(
|
||||
@@ -291,11 +295,11 @@ def gpio_validate_modes(value):
|
||||
|
||||
|
||||
def gpio_base_schema(
|
||||
pin_type,
|
||||
number_validator,
|
||||
pin_type: MockObjClass,
|
||||
number_validator: Callable[[Any], Any],
|
||||
modes=GPIO_STANDARD_MODES,
|
||||
mode_validator=gpio_validate_modes,
|
||||
invertable=True,
|
||||
mode_validator: Callable[[Any], Any] = gpio_validate_modes,
|
||||
invertible: bool = True,
|
||||
):
|
||||
"""
|
||||
Generate a base gpio pin schema
|
||||
@@ -303,7 +307,7 @@ def gpio_base_schema(
|
||||
:param number_validator: A validator for the pin number
|
||||
:param modes: The available modes, default is all standard modes
|
||||
:param mode_validator: A validator function for the pin mode
|
||||
:param invertable: If the pin supports hardware inversion
|
||||
:param invertible: If the pin supports hardware inversion
|
||||
:return: A schema for the pin
|
||||
"""
|
||||
mode_default = len(modes) == 1
|
||||
@@ -328,7 +332,7 @@ def gpio_base_schema(
|
||||
}
|
||||
)
|
||||
|
||||
if invertable:
|
||||
if invertible:
|
||||
return schema.extend({cv.Optional(CONF_INVERTED, default=False): cv.boolean})
|
||||
|
||||
return schema
|
||||
|
||||
@@ -67,20 +67,6 @@ esp8266:
|
||||
"""
|
||||
|
||||
ESP32_CONFIG = """
|
||||
esp32:
|
||||
board: {board}
|
||||
framework:
|
||||
type: arduino
|
||||
"""
|
||||
|
||||
ESP32S2_CONFIG = """
|
||||
esp32:
|
||||
board: {board}
|
||||
framework:
|
||||
type: esp-idf
|
||||
"""
|
||||
|
||||
ESP32C3_CONFIG = """
|
||||
esp32:
|
||||
board: {board}
|
||||
framework:
|
||||
@@ -105,8 +91,6 @@ rtl87xx:
|
||||
HARDWARE_BASE_CONFIGS = {
|
||||
"ESP8266": ESP8266_CONFIG,
|
||||
"ESP32": ESP32_CONFIG,
|
||||
"ESP32S2": ESP32S2_CONFIG,
|
||||
"ESP32C3": ESP32C3_CONFIG,
|
||||
"RP2040": RP2040_CONFIG,
|
||||
"BK72XX": BK72XX_CONFIG,
|
||||
"RTL87XX": RTL87XX_CONFIG,
|
||||
|
||||
@@ -153,6 +153,9 @@ def get_ini_content():
|
||||
# Sort to avoid changing build flags order
|
||||
CORE.add_platformio_option("build_flags", sorted(CORE.build_flags))
|
||||
|
||||
# Sort to avoid changing build unflags order
|
||||
CORE.add_platformio_option("build_unflags", sorted(CORE.build_unflags))
|
||||
|
||||
content = "[platformio]\n"
|
||||
content += f"description = ESPHome {__version__}\n"
|
||||
|
||||
|
||||
@@ -48,6 +48,9 @@ lib_deps =
|
||||
lvgl/lvgl@8.4.0 ; lvgl
|
||||
build_flags =
|
||||
-DESPHOME_LOG_LEVEL=ESPHOME_LOG_LEVEL_VERY_VERBOSE
|
||||
-std=gnu++17
|
||||
build_unflags =
|
||||
-std=gnu++11
|
||||
src_filter =
|
||||
+<./>
|
||||
+<../tests/dummy_main.cpp>
|
||||
@@ -73,6 +76,8 @@ lib_deps =
|
||||
build_flags =
|
||||
${common.build_flags}
|
||||
-DUSE_ARDUINO
|
||||
build_unflags =
|
||||
${common.build_unflags}
|
||||
|
||||
; This are common settings for all IDF-framework based environments.
|
||||
[common:idf]
|
||||
@@ -80,6 +85,8 @@ extends = common
|
||||
build_flags =
|
||||
${common.build_flags}
|
||||
-DUSE_ESP_IDF
|
||||
build_unflags =
|
||||
${common.build_unflags}
|
||||
|
||||
; This are common settings for the ESP8266 using Arduino.
|
||||
[common:esp8266-arduino]
|
||||
@@ -104,6 +111,8 @@ build_flags =
|
||||
-Wno-nonnull-compare
|
||||
-DUSE_ESP8266
|
||||
-DUSE_ESP8266_FRAMEWORK_ARDUINO
|
||||
build_unflags =
|
||||
${common.build_unflags}
|
||||
extra_scripts = post:esphome/components/esp8266/post_build.py.script
|
||||
|
||||
; This are common settings for the ESP32 (all variants) using Arduino.
|
||||
@@ -135,6 +144,8 @@ build_flags =
|
||||
-DUSE_ESP32
|
||||
-DUSE_ESP32_FRAMEWORK_ARDUINO
|
||||
-DAUDIO_NO_SD_FS ; i2s_audio
|
||||
build_unflags =
|
||||
${common.build_unflags}
|
||||
extra_scripts = post:esphome/components/esp32/post_build.py.script
|
||||
|
||||
; This are common settings for the ESP32 (all variants) using IDF.
|
||||
@@ -155,6 +166,8 @@ build_flags =
|
||||
-Wno-nonnull-compare
|
||||
-DUSE_ESP32
|
||||
-DUSE_ESP32_FRAMEWORK_ESP_IDF
|
||||
build_unflags =
|
||||
${common.build_unflags}
|
||||
extra_scripts = post:esphome/components/esp32/post_build.py.script
|
||||
|
||||
; This are common settings for the ESP32 using the latest ESP-IDF version.
|
||||
@@ -181,6 +194,8 @@ build_flags =
|
||||
${common:arduino.build_flags}
|
||||
-DUSE_RP2040
|
||||
-DUSE_RP2040_FRAMEWORK_ARDUINO
|
||||
build_unflags =
|
||||
${common.build_unflags}
|
||||
|
||||
; This are common settings for the LibreTiny (all variants) using Arduino.
|
||||
[common:libretiny-arduino]
|
||||
@@ -192,6 +207,8 @@ lib_deps =
|
||||
build_flags =
|
||||
${common:arduino.build_flags}
|
||||
-DUSE_LIBRETINY
|
||||
build_unflags =
|
||||
${common.build_unflags}
|
||||
build_src_flags = -include Arduino.h
|
||||
|
||||
; This is the common settings for the nRF52 using Zephyr.
|
||||
@@ -224,6 +241,8 @@ board = nodemcuv2
|
||||
build_flags =
|
||||
${common:esp8266-arduino.build_flags}
|
||||
${flags:runtime.build_flags}
|
||||
build_unflags =
|
||||
${common.build_unflags}
|
||||
|
||||
[env:esp8266-arduino-tidy]
|
||||
extends = common:esp8266-arduino
|
||||
@@ -231,6 +250,8 @@ board = nodemcuv2
|
||||
build_flags =
|
||||
${common:esp8266-arduino.build_flags}
|
||||
${flags:clangtidy.build_flags}
|
||||
build_unflags =
|
||||
${common.build_unflags}
|
||||
|
||||
;;;;;;;; ESP32 ;;;;;;;;
|
||||
|
||||
@@ -242,6 +263,8 @@ build_flags =
|
||||
${common:esp32-arduino.build_flags}
|
||||
${flags:runtime.build_flags}
|
||||
-DUSE_ESP32_VARIANT_ESP32
|
||||
build_unflags =
|
||||
${common.build_unflags}
|
||||
|
||||
[env:esp32-arduino-tidy]
|
||||
extends = common:esp32-arduino
|
||||
@@ -250,6 +273,8 @@ build_flags =
|
||||
${common:esp32-arduino.build_flags}
|
||||
${flags:clangtidy.build_flags}
|
||||
-DUSE_ESP32_VARIANT_ESP32
|
||||
build_unflags =
|
||||
${common.build_unflags}
|
||||
|
||||
[env:esp32-idf]
|
||||
extends = common:esp32-idf
|
||||
@@ -259,6 +284,8 @@ build_flags =
|
||||
${common:esp32-idf.build_flags}
|
||||
${flags:runtime.build_flags}
|
||||
-DUSE_ESP32_VARIANT_ESP32
|
||||
build_unflags =
|
||||
${common.build_unflags}
|
||||
|
||||
[env:esp32-idf-5_3]
|
||||
extends = common:esp32-idf-5_3
|
||||
@@ -268,6 +295,8 @@ build_flags =
|
||||
${common:esp32-idf.build_flags}
|
||||
${flags:runtime.build_flags}
|
||||
-DUSE_ESP32_VARIANT_ESP32
|
||||
build_unflags =
|
||||
${common.build_unflags}
|
||||
|
||||
[env:esp32-idf-tidy]
|
||||
extends = common:esp32-idf
|
||||
@@ -277,6 +306,8 @@ build_flags =
|
||||
${common:esp32-idf.build_flags}
|
||||
${flags:clangtidy.build_flags}
|
||||
-DUSE_ESP32_VARIANT_ESP32
|
||||
build_unflags =
|
||||
${common.build_unflags}
|
||||
|
||||
;;;;;;;; ESP32-C3 ;;;;;;;;
|
||||
|
||||
@@ -287,6 +318,8 @@ build_flags =
|
||||
${common:esp32-arduino.build_flags}
|
||||
${flags:runtime.build_flags}
|
||||
-DUSE_ESP32_VARIANT_ESP32C3
|
||||
build_unflags =
|
||||
${common.build_unflags}
|
||||
|
||||
[env:esp32c3-arduino-tidy]
|
||||
extends = common:esp32-arduino
|
||||
@@ -295,6 +328,8 @@ build_flags =
|
||||
${common:esp32-arduino.build_flags}
|
||||
${flags:clangtidy.build_flags}
|
||||
-DUSE_ESP32_VARIANT_ESP32C3
|
||||
build_unflags =
|
||||
${common.build_unflags}
|
||||
|
||||
[env:esp32c3-idf]
|
||||
extends = common:esp32-idf
|
||||
@@ -304,6 +339,8 @@ build_flags =
|
||||
${common:esp32-idf.build_flags}
|
||||
${flags:runtime.build_flags}
|
||||
-DUSE_ESP32_VARIANT_ESP32C3
|
||||
build_unflags =
|
||||
${common.build_unflags}
|
||||
|
||||
[env:esp32c3-idf-5_3]
|
||||
extends = common:esp32-idf-5_3
|
||||
@@ -313,6 +350,8 @@ build_flags =
|
||||
${common:esp32-idf.build_flags}
|
||||
${flags:runtime.build_flags}
|
||||
-DUSE_ESP32_VARIANT_ESP32C3
|
||||
build_unflags =
|
||||
${common.build_unflags}
|
||||
|
||||
[env:esp32c3-idf-tidy]
|
||||
extends = common:esp32-idf
|
||||
@@ -322,6 +361,8 @@ build_flags =
|
||||
${common:esp32-idf.build_flags}
|
||||
${flags:clangtidy.build_flags}
|
||||
-DUSE_ESP32_VARIANT_ESP32C3
|
||||
build_unflags =
|
||||
${common.build_unflags}
|
||||
|
||||
;;;;;;;; ESP32-C6 ;;;;;;;;
|
||||
|
||||
@@ -343,6 +384,8 @@ build_flags =
|
||||
${common:esp32-arduino.build_flags}
|
||||
${flags:runtime.build_flags}
|
||||
-DUSE_ESP32_VARIANT_ESP32S2
|
||||
build_unflags =
|
||||
${common.build_unflags}
|
||||
|
||||
[env:esp32s2-arduino-tidy]
|
||||
extends = common:esp32-arduino
|
||||
@@ -351,6 +394,8 @@ build_flags =
|
||||
${common:esp32-arduino.build_flags}
|
||||
${flags:clangtidy.build_flags}
|
||||
-DUSE_ESP32_VARIANT_ESP32S2
|
||||
build_unflags =
|
||||
${common.build_unflags}
|
||||
|
||||
[env:esp32s2-idf]
|
||||
extends = common:esp32-idf
|
||||
@@ -360,6 +405,8 @@ build_flags =
|
||||
${common:esp32-idf.build_flags}
|
||||
${flags:runtime.build_flags}
|
||||
-DUSE_ESP32_VARIANT_ESP32S2
|
||||
build_unflags =
|
||||
${common.build_unflags}
|
||||
|
||||
[env:esp32s2-idf-5_3]
|
||||
extends = common:esp32-idf-5_3
|
||||
@@ -369,6 +416,8 @@ build_flags =
|
||||
${common:esp32-idf.build_flags}
|
||||
${flags:runtime.build_flags}
|
||||
-DUSE_ESP32_VARIANT_ESP32S2
|
||||
build_unflags =
|
||||
${common.build_unflags}
|
||||
|
||||
[env:esp32s2-idf-tidy]
|
||||
extends = common:esp32-idf
|
||||
@@ -378,6 +427,8 @@ build_flags =
|
||||
${common:esp32-idf.build_flags}
|
||||
${flags:clangtidy.build_flags}
|
||||
-DUSE_ESP32_VARIANT_ESP32S2
|
||||
build_unflags =
|
||||
${common.build_unflags}
|
||||
|
||||
;;;;;;;; ESP32-S3 ;;;;;;;;
|
||||
|
||||
@@ -388,6 +439,8 @@ build_flags =
|
||||
${common:esp32-arduino.build_flags}
|
||||
${flags:runtime.build_flags}
|
||||
-DUSE_ESP32_VARIANT_ESP32S3
|
||||
build_unflags =
|
||||
${common.build_unflags}
|
||||
|
||||
[env:esp32s3-arduino-tidy]
|
||||
extends = common:esp32-arduino
|
||||
@@ -396,6 +449,8 @@ build_flags =
|
||||
${common:esp32-arduino.build_flags}
|
||||
${flags:clangtidy.build_flags}
|
||||
-DUSE_ESP32_VARIANT_ESP32S3
|
||||
build_unflags =
|
||||
${common.build_unflags}
|
||||
|
||||
[env:esp32s3-idf]
|
||||
extends = common:esp32-idf
|
||||
@@ -405,6 +460,8 @@ build_flags =
|
||||
${common:esp32-idf.build_flags}
|
||||
${flags:runtime.build_flags}
|
||||
-DUSE_ESP32_VARIANT_ESP32S3
|
||||
build_unflags =
|
||||
${common.build_unflags}
|
||||
|
||||
[env:esp32s3-idf-5_3]
|
||||
extends = common:esp32-idf-5_3
|
||||
@@ -414,6 +471,8 @@ build_flags =
|
||||
${common:esp32-idf.build_flags}
|
||||
${flags:runtime.build_flags}
|
||||
-DUSE_ESP32_VARIANT_ESP32S3
|
||||
build_unflags =
|
||||
${common.build_unflags}
|
||||
|
||||
[env:esp32s3-idf-tidy]
|
||||
extends = common:esp32-idf
|
||||
@@ -423,6 +482,8 @@ build_flags =
|
||||
${common:esp32-idf.build_flags}
|
||||
${flags:clangtidy.build_flags}
|
||||
-DUSE_ESP32_VARIANT_ESP32S3
|
||||
build_unflags =
|
||||
${common.build_unflags}
|
||||
|
||||
;;;;;;;; ESP32-P4 ;;;;;;;;
|
||||
|
||||
@@ -444,6 +505,8 @@ board = rpipico
|
||||
build_flags =
|
||||
${common:rp2040-arduino.build_flags}
|
||||
${flags:runtime.build_flags}
|
||||
build_unflags =
|
||||
${common.build_unflags}
|
||||
|
||||
;;;;;;;; LibreTiny ;;;;;;;;
|
||||
|
||||
@@ -455,6 +518,8 @@ build_flags =
|
||||
${flags:runtime.build_flags}
|
||||
-DUSE_BK72XX
|
||||
-DUSE_LIBRETINY_VARIANT_BK7231N
|
||||
build_unflags =
|
||||
${common.build_unflags}
|
||||
|
||||
[env:rtl87xxb-arduino]
|
||||
extends = common:libretiny-arduino
|
||||
@@ -464,6 +529,8 @@ build_flags =
|
||||
${flags:runtime.build_flags}
|
||||
-DUSE_RTL87XX
|
||||
-DUSE_LIBRETINY_VARIANT_RTL8710B
|
||||
build_unflags =
|
||||
${common.build_unflags}
|
||||
|
||||
[env:rtl87xxc-arduino]
|
||||
extends = common:libretiny-arduino
|
||||
@@ -473,6 +540,8 @@ build_flags =
|
||||
${flags:runtime.build_flags}
|
||||
-DUSE_RTL87XX
|
||||
-DUSE_LIBRETINY_VARIANT_RTL8720C
|
||||
build_unflags =
|
||||
${common.build_unflags}
|
||||
|
||||
[env:host]
|
||||
extends = common
|
||||
@@ -483,6 +552,8 @@ build_flags =
|
||||
${common.build_flags}
|
||||
-DUSE_HOST
|
||||
-std=c++17
|
||||
build_unflags =
|
||||
${common.build_unflags}
|
||||
|
||||
;;;;;;;; nRF52 ;;;;;;;;
|
||||
|
||||
@@ -492,6 +563,8 @@ board = adafruit_feather_nrf52840
|
||||
build_flags =
|
||||
${common:nrf52-zephyr.build_flags}
|
||||
${flags:runtime.build_flags}
|
||||
build_unflags =
|
||||
${common.build_unflags}
|
||||
|
||||
[env:nrf52-tidy]
|
||||
extends = common:nrf52-zephyr
|
||||
@@ -499,3 +572,5 @@ board = adafruit_feather_nrf52840
|
||||
build_flags =
|
||||
${common:nrf52-zephyr.build_flags}
|
||||
${flags:clangtidy.build_flags}
|
||||
build_unflags =
|
||||
${common.build_unflags}
|
||||
|
||||
@@ -6,9 +6,9 @@ pre-commit
|
||||
|
||||
# Unit tests
|
||||
pytest==8.4.0
|
||||
pytest-cov==6.1.1
|
||||
pytest-cov==6.2.1
|
||||
pytest-mock==3.14.1
|
||||
pytest-asyncio==0.26.0
|
||||
pytest-asyncio==1.0.0
|
||||
pytest-xdist==3.7.0
|
||||
asyncmock==0.4.2
|
||||
hypothesis==6.92.1
|
||||
|
||||
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
|
||||
name: Pressbutton
|
||||
widget: spin_up
|
||||
publish_initial_state: true
|
||||
trigger_on_initial_state: true
|
||||
- platform: lvgl
|
||||
name: ButtonMatrix button
|
||||
widget: button_a
|
||||
|
||||
Reference in New Issue
Block a user