mirror of
https://github.com/esphome/esphome.git
synced 2026-02-03 12:49:40 -07:00
Compare commits
3 Commits
template_t
...
task_prio
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0b444f5504 | ||
|
|
6f6c252b84 | ||
|
|
0b325b5a0a |
@@ -1287,6 +1287,18 @@ async def to_code(config):
|
||||
# Increase freertos tick speed from 100Hz to 1kHz so that delay() resolution is 1ms
|
||||
add_idf_sdkconfig_option("CONFIG_FREERTOS_HZ", 1000)
|
||||
|
||||
# Reduce FreeRTOS max priorities from 25 to 16 to save RAM
|
||||
# pxReadyTasksLists uses 20 bytes per priority level, so this saves 180 bytes
|
||||
# All ESPHome tasks use relative priorities (configMAX_PRIORITIES - X) to scale automatically
|
||||
# See https://github.com/espressif/esp-idf/issues/13041 for context
|
||||
add_idf_sdkconfig_option("CONFIG_FREERTOS_MAX_PRIORITIES", 16)
|
||||
|
||||
# Set LWIP TCP/IP task priority to fit within reduced priority range (0-15)
|
||||
# Default is 18, which would be invalid with MAX_PRIORITIES=16
|
||||
# Priority 8 maintains the original hierarchy: I2S speaker (10) > LWIP (8) > mixer (6)
|
||||
# This ensures audio I/O tasks aren't blocked by network, while network isn't starved by mixing
|
||||
add_idf_sdkconfig_option("CONFIG_LWIP_TCPIP_TASK_PRIO", 8)
|
||||
|
||||
# Place non-ISR FreeRTOS functions into flash instead of IRAM
|
||||
# This saves up to 8KB of IRAM. ISR-safe functions (FromISR variants) stay in IRAM.
|
||||
# In ESP-IDF 6.0 this becomes the default and CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "esphome/core/defines.h"
|
||||
#include "esphome/core/hal.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/task_priorities.h"
|
||||
#include "preferences.h"
|
||||
#include <esp_clk_tree.h>
|
||||
#include <esp_cpu.h>
|
||||
@@ -66,10 +67,14 @@ void loop_task(void *pv_params) {
|
||||
extern "C" void app_main() {
|
||||
initArduino();
|
||||
esp32::setup_preferences();
|
||||
// TASK_PRIORITY_APPLICATION: baseline priority for main loop - all component loops
|
||||
// run here. Higher priority tasks (audio, network) preempt this when needed.
|
||||
#if CONFIG_FREERTOS_UNICORE
|
||||
xTaskCreate(loop_task, "loopTask", ESPHOME_LOOP_TASK_STACK_SIZE, nullptr, 1, &loop_task_handle);
|
||||
xTaskCreate(loop_task, "loopTask", ESPHOME_LOOP_TASK_STACK_SIZE, nullptr, TASK_PRIORITY_APPLICATION,
|
||||
&loop_task_handle);
|
||||
#else
|
||||
xTaskCreatePinnedToCore(loop_task, "loopTask", ESPHOME_LOOP_TASK_STACK_SIZE, nullptr, 1, &loop_task_handle, 1);
|
||||
xTaskCreatePinnedToCore(loop_task, "loopTask", ESPHOME_LOOP_TASK_STACK_SIZE, nullptr, TASK_PRIORITY_APPLICATION,
|
||||
&loop_task_handle, 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "esphome/core/application.h"
|
||||
#include "esphome/core/hal.h"
|
||||
#include "esphome/core/log.h"
|
||||
#include "esphome/core/task_priorities.h"
|
||||
|
||||
#include <freertos/task.h>
|
||||
|
||||
@@ -42,11 +43,13 @@ void ESP32Camera::setup() {
|
||||
/* initialize RTOS */
|
||||
this->framebuffer_get_queue_ = xQueueCreate(1, sizeof(camera_fb_t *));
|
||||
this->framebuffer_return_queue_ = xQueueCreate(1, sizeof(camera_fb_t *));
|
||||
// TASK_PRIORITY_APPLICATION: same as main loop - camera capture is buffered,
|
||||
// not real-time critical like audio
|
||||
xTaskCreatePinnedToCore(&ESP32Camera::framebuffer_task,
|
||||
"framebuffer_task", // name
|
||||
FRAMEBUFFER_TASK_STACK_SIZE, // stack size
|
||||
this, // task pv params
|
||||
1, // priority
|
||||
TASK_PRIORITY_APPLICATION, // priority
|
||||
nullptr, // handle
|
||||
1 // core
|
||||
);
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
|
||||
#include "esphome/core/application.h"
|
||||
#include "esphome/core/version.h"
|
||||
#ifdef USE_ESP32
|
||||
#include "esphome/core/task_priorities.h"
|
||||
#endif
|
||||
|
||||
#include "esphome/components/json/json_util.h"
|
||||
#include "esphome/components/network/util.h"
|
||||
@@ -46,7 +49,9 @@ void HttpRequestUpdate::update() {
|
||||
return;
|
||||
}
|
||||
#ifdef USE_ESP32
|
||||
xTaskCreate(HttpRequestUpdate::update_task, "update_task", 8192, (void *) this, 1, &this->update_task_handle_);
|
||||
// TASK_PRIORITY_APPLICATION: same as main loop - update check is background work
|
||||
xTaskCreate(HttpRequestUpdate::update_task, "update_task", 8192, (void *) this, TASK_PRIORITY_APPLICATION,
|
||||
&this->update_task_handle_);
|
||||
#else
|
||||
this->update_task(this);
|
||||
#endif
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
#include "esphome/core/hal.h"
|
||||
#include "esphome/core/log.h"
|
||||
#include "esphome/core/task_priorities.h"
|
||||
|
||||
#include "esphome/components/audio/audio.h"
|
||||
|
||||
@@ -22,7 +23,6 @@ static const UBaseType_t MAX_LISTENERS = 16;
|
||||
static const uint32_t READ_DURATION_MS = 16;
|
||||
|
||||
static const size_t TASK_STACK_SIZE = 4096;
|
||||
static const ssize_t TASK_PRIORITY = 23;
|
||||
|
||||
static const char *const TAG = "i2s_audio.microphone";
|
||||
|
||||
@@ -520,8 +520,10 @@ void I2SAudioMicrophone::loop() {
|
||||
}
|
||||
|
||||
if (this->task_handle_ == nullptr) {
|
||||
xTaskCreate(I2SAudioMicrophone::mic_task, "mic_task", TASK_STACK_SIZE, (void *) this, TASK_PRIORITY,
|
||||
&this->task_handle_);
|
||||
// TASK_PRIORITY_AUDIO_CAPTURE: highest application priority - real-time audio
|
||||
// input cannot tolerate delays without dropping samples
|
||||
xTaskCreate(I2SAudioMicrophone::mic_task, "mic_task", TASK_STACK_SIZE, (void *) this,
|
||||
TASK_PRIORITY_AUDIO_CAPTURE, &this->task_handle_);
|
||||
|
||||
if (this->task_handle_ == nullptr) {
|
||||
ESP_LOGE(TAG, "Task failed to start, retrying in 1 second");
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "esphome/core/application.h"
|
||||
#include "esphome/core/hal.h"
|
||||
#include "esphome/core/log.h"
|
||||
#include "esphome/core/task_priorities.h"
|
||||
|
||||
#include "esp_timer.h"
|
||||
|
||||
@@ -24,7 +25,6 @@ static const uint32_t DMA_BUFFER_DURATION_MS = 15;
|
||||
static const size_t DMA_BUFFERS_COUNT = 4;
|
||||
|
||||
static const size_t TASK_STACK_SIZE = 4096;
|
||||
static const ssize_t TASK_PRIORITY = 19;
|
||||
|
||||
static const size_t I2S_EVENT_QUEUE_COUNT = DMA_BUFFERS_COUNT + 1;
|
||||
|
||||
@@ -151,8 +151,10 @@ void I2SAudioSpeaker::loop() {
|
||||
}
|
||||
|
||||
if (this->speaker_task_handle_ == nullptr) {
|
||||
xTaskCreate(I2SAudioSpeaker::speaker_task, "speaker_task", TASK_STACK_SIZE, (void *) this, TASK_PRIORITY,
|
||||
&this->speaker_task_handle_);
|
||||
// TASK_PRIORITY_AUDIO_OUTPUT: high priority for real-time audio output,
|
||||
// below capture (TASK_PRIORITY_AUDIO_CAPTURE) but above network tasks
|
||||
xTaskCreate(I2SAudioSpeaker::speaker_task, "speaker_task", TASK_STACK_SIZE, (void *) this,
|
||||
TASK_PRIORITY_AUDIO_OUTPUT, &this->speaker_task_handle_);
|
||||
|
||||
if (this->speaker_task_handle_ == nullptr) {
|
||||
ESP_LOGE(TAG, "Task failed to start, retrying in 1 second");
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "esphome/core/hal.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/log.h"
|
||||
#include "esphome/core/task_priorities.h"
|
||||
|
||||
#include "esphome/components/audio/audio_transfer_buffer.h"
|
||||
|
||||
@@ -25,7 +26,6 @@ static const size_t DATA_TIMEOUT_MS = 50;
|
||||
static const uint32_t RING_BUFFER_DURATION_MS = 120;
|
||||
|
||||
static const uint32_t INFERENCE_TASK_STACK_SIZE = 3072;
|
||||
static const UBaseType_t INFERENCE_TASK_PRIORITY = 3;
|
||||
|
||||
enum EventGroupBits : uint32_t {
|
||||
COMMAND_STOP = (1 << 0), // Signals the inference task should stop
|
||||
@@ -305,8 +305,10 @@ void MicroWakeWord::loop() {
|
||||
return;
|
||||
}
|
||||
|
||||
// TASK_PRIORITY_INFERENCE: above main loop (TASK_PRIORITY_APPLICATION) but below
|
||||
// protocol tasks (TASK_PRIORITY_PROTOCOL) - ML inference is background work
|
||||
xTaskCreate(MicroWakeWord::inference_task, "mww", INFERENCE_TASK_STACK_SIZE, (void *) this,
|
||||
INFERENCE_TASK_PRIORITY, &this->inference_task_handle_);
|
||||
TASK_PRIORITY_INFERENCE, &this->inference_task_handle_);
|
||||
|
||||
if (this->inference_task_handle_ == nullptr) {
|
||||
FrontendFreeStateContents(&this->frontend_state_); // Deallocate frontend state
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "esphome/core/hal.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/log.h"
|
||||
#include "esphome/core/task_priorities.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
@@ -12,8 +13,6 @@
|
||||
namespace esphome {
|
||||
namespace mixer_speaker {
|
||||
|
||||
static const UBaseType_t MIXER_TASK_PRIORITY = 10;
|
||||
|
||||
static const uint32_t TRANSFER_BUFFER_DURATION_MS = 50;
|
||||
static const uint32_t TASK_DELAY_MS = 25;
|
||||
|
||||
@@ -385,8 +384,10 @@ esp_err_t MixerSpeaker::start_task_() {
|
||||
}
|
||||
|
||||
if (this->task_handle_ == nullptr) {
|
||||
// TASK_PRIORITY_AUDIO_MIXER: below I2S tasks (TASK_PRIORITY_AUDIO_OUTPUT) but
|
||||
// above protocol tasks - mixing is buffered but feeds real-time output
|
||||
this->task_handle_ = xTaskCreateStatic(audio_mixer_task, "mixer", TASK_STACK_SIZE, (void *) this,
|
||||
MIXER_TASK_PRIORITY, this->task_stack_buffer_, &this->task_stack_);
|
||||
TASK_PRIORITY_AUDIO_MIXER, this->task_stack_buffer_, &this->task_stack_);
|
||||
}
|
||||
|
||||
if (this->task_handle_ == nullptr) {
|
||||
|
||||
@@ -61,7 +61,10 @@ bool MQTTBackendESP32::initialize_() {
|
||||
// Create the task only after MQTT client is initialized successfully
|
||||
// Use larger stack size when TLS is enabled
|
||||
size_t stack_size = this->ca_certificate_.has_value() ? TASK_STACK_SIZE_TLS : TASK_STACK_SIZE;
|
||||
xTaskCreate(esphome_mqtt_task, "esphome_mqtt", stack_size, (void *) this, TASK_PRIORITY, &this->task_handle_);
|
||||
// TASK_PRIORITY_PROTOCOL: above main loop (TASK_PRIORITY_APPLICATION) but below
|
||||
// audio tasks - MQTT needs responsive scheduling for message handling
|
||||
xTaskCreate(esphome_mqtt_task, "esphome_mqtt", stack_size, (void *) this, TASK_PRIORITY_PROTOCOL,
|
||||
&this->task_handle_);
|
||||
if (this->task_handle_ == nullptr) {
|
||||
ESP_LOGE(TAG, "Failed to create MQTT task");
|
||||
// Clean up MQTT client since we can't start the async task
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/lock_free_queue.h"
|
||||
#include "esphome/core/event_pool.h"
|
||||
#include "esphome/core/task_priorities.h"
|
||||
|
||||
namespace esphome::mqtt {
|
||||
|
||||
@@ -117,8 +118,7 @@ class MQTTBackendESP32 final : public MQTTBackend {
|
||||
static const size_t MQTT_BUFFER_SIZE = 4096;
|
||||
static const size_t TASK_STACK_SIZE = 3072;
|
||||
static const size_t TASK_STACK_SIZE_TLS = 4096; // Larger stack for TLS operations
|
||||
static const ssize_t TASK_PRIORITY = 5;
|
||||
static const uint8_t MQTT_QUEUE_LENGTH = 30; // 30*12 bytes = 360
|
||||
static const uint8_t MQTT_QUEUE_LENGTH = 30; // 30*12 bytes = 360
|
||||
|
||||
void set_keep_alive(uint16_t keep_alive) final { this->keep_alive_ = keep_alive; }
|
||||
void set_client_id(const char *client_id) final { this->client_id_ = client_id; }
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "esp_task_wdt.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/log.h"
|
||||
#include "esphome/core/task_priorities.h"
|
||||
|
||||
#include "esp_err.h"
|
||||
#include "esp_event.h"
|
||||
@@ -39,12 +40,14 @@ void OpenThreadComponent::setup() {
|
||||
ESP_ERROR_CHECK(esp_netif_init());
|
||||
ESP_ERROR_CHECK(esp_vfs_eventfd_register(&eventfd_config));
|
||||
|
||||
// TASK_PRIORITY_PROTOCOL: same as USB host/MQTT - network protocol tasks need
|
||||
// responsive scheduling but below audio tasks
|
||||
xTaskCreate(
|
||||
[](void *arg) {
|
||||
static_cast<OpenThreadComponent *>(arg)->ot_main();
|
||||
vTaskDelete(nullptr);
|
||||
},
|
||||
"ot_main", 10240, this, 5, nullptr);
|
||||
"ot_main", 10240, this, TASK_PRIORITY_PROTOCOL, nullptr);
|
||||
}
|
||||
|
||||
static esp_netif_t *init_openthread_netif(const esp_openthread_platform_config_t *config) {
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/log.h"
|
||||
#include "esphome/core/task_priorities.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
@@ -13,8 +14,6 @@
|
||||
namespace esphome {
|
||||
namespace resampler {
|
||||
|
||||
static const UBaseType_t RESAMPLER_TASK_PRIORITY = 1;
|
||||
|
||||
static const uint32_t TRANSFER_BUFFER_DURATION_MS = 50;
|
||||
|
||||
static const uint32_t TASK_DELAY_MS = 20;
|
||||
@@ -185,8 +184,10 @@ esp_err_t ResamplerSpeaker::start_task_() {
|
||||
}
|
||||
|
||||
if (this->task_handle_ == nullptr) {
|
||||
// TASK_PRIORITY_APPLICATION: same as main loop - resampling is buffered audio
|
||||
// processing, not real-time I/O
|
||||
this->task_handle_ = xTaskCreateStatic(resample_task, "sample", TASK_STACK_SIZE, (void *) this,
|
||||
RESAMPLER_TASK_PRIORITY, this->task_stack_buffer_, &this->task_stack_);
|
||||
TASK_PRIORITY_APPLICATION, this->task_stack_buffer_, &this->task_stack_);
|
||||
}
|
||||
|
||||
if (this->task_handle_ == nullptr) {
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#ifdef USE_ESP32
|
||||
|
||||
#include "esphome/core/log.h"
|
||||
#include "esphome/core/task_priorities.h"
|
||||
|
||||
#include "esphome/components/audio/audio.h"
|
||||
#ifdef USE_OTA
|
||||
@@ -45,9 +46,6 @@ namespace speaker {
|
||||
|
||||
static const uint32_t MEDIA_CONTROLS_QUEUE_LENGTH = 20;
|
||||
|
||||
static const UBaseType_t MEDIA_PIPELINE_TASK_PRIORITY = 1;
|
||||
static const UBaseType_t ANNOUNCEMENT_PIPELINE_TASK_PRIORITY = 1;
|
||||
|
||||
static const char *const TAG = "speaker_media_player";
|
||||
|
||||
void SpeakerMediaPlayer::setup() {
|
||||
@@ -70,9 +68,10 @@ void SpeakerMediaPlayer::setup() {
|
||||
ota::get_global_ota_callback()->add_global_state_listener(this);
|
||||
#endif
|
||||
|
||||
this->announcement_pipeline_ =
|
||||
make_unique<AudioPipeline>(this->announcement_speaker_, this->buffer_size_, this->task_stack_in_psram_, "ann",
|
||||
ANNOUNCEMENT_PIPELINE_TASK_PRIORITY);
|
||||
// TASK_PRIORITY_APPLICATION: same as main loop - media pipelines handle buffered
|
||||
// audio streaming, not real-time I/O, so they don't need elevated priority
|
||||
this->announcement_pipeline_ = make_unique<AudioPipeline>(
|
||||
this->announcement_speaker_, this->buffer_size_, this->task_stack_in_psram_, "ann", TASK_PRIORITY_APPLICATION);
|
||||
|
||||
if (this->announcement_pipeline_ == nullptr) {
|
||||
ESP_LOGE(TAG, "Failed to create announcement pipeline");
|
||||
@@ -81,7 +80,7 @@ void SpeakerMediaPlayer::setup() {
|
||||
|
||||
if (!this->single_pipeline_()) {
|
||||
this->media_pipeline_ = make_unique<AudioPipeline>(this->media_speaker_, this->buffer_size_,
|
||||
this->task_stack_in_psram_, "med", MEDIA_PIPELINE_TASK_PRIORITY);
|
||||
this->task_stack_in_psram_, "med", TASK_PRIORITY_APPLICATION);
|
||||
|
||||
if (this->media_pipeline_ == nullptr) {
|
||||
ESP_LOGE(TAG, "Failed to create media pipeline");
|
||||
|
||||
@@ -79,19 +79,16 @@ async def to_code(config):
|
||||
var.get_close_trigger(), [], config[CONF_CLOSE_ACTION]
|
||||
)
|
||||
if CONF_STOP_ACTION in config:
|
||||
cg.add_define("USE_TEMPLATE_COVER_STOP_TRIGGER")
|
||||
await automation.build_automation(
|
||||
var.get_stop_trigger(), [], config[CONF_STOP_ACTION]
|
||||
)
|
||||
cg.add(var.set_has_stop(True))
|
||||
if CONF_TOGGLE_ACTION in config:
|
||||
cg.add_define("USE_TEMPLATE_COVER_TOGGLE_TRIGGER")
|
||||
await automation.build_automation(
|
||||
var.get_toggle_trigger(), [], config[CONF_TOGGLE_ACTION]
|
||||
)
|
||||
cg.add(var.set_has_toggle(True))
|
||||
if CONF_TILT_ACTION in config:
|
||||
cg.add_define("USE_TEMPLATE_COVER_TILT_TRIGGER")
|
||||
await automation.build_automation(
|
||||
var.get_tilt_trigger(), [(float, "tilt")], config[CONF_TILT_ACTION]
|
||||
)
|
||||
@@ -102,7 +99,6 @@ async def to_code(config):
|
||||
)
|
||||
cg.add(var.set_tilt_lambda(tilt_template_))
|
||||
if CONF_POSITION_ACTION in config:
|
||||
cg.add_define("USE_TEMPLATE_COVER_POSITION_TRIGGER")
|
||||
await automation.build_automation(
|
||||
var.get_position_trigger(), [(float, "pos")], config[CONF_POSITION_ACTION]
|
||||
)
|
||||
|
||||
@@ -9,25 +9,11 @@ static const char *const TAG = "template.cover";
|
||||
|
||||
TemplateCover::TemplateCover()
|
||||
: open_trigger_(new Trigger<>()),
|
||||
close_trigger_(new Trigger<>())
|
||||
#ifdef USE_TEMPLATE_COVER_STOP_TRIGGER
|
||||
,
|
||||
stop_trigger_(new Trigger<>())
|
||||
#endif
|
||||
#ifdef USE_TEMPLATE_COVER_TOGGLE_TRIGGER
|
||||
,
|
||||
toggle_trigger_(new Trigger<>())
|
||||
#endif
|
||||
#ifdef USE_TEMPLATE_COVER_POSITION_TRIGGER
|
||||
,
|
||||
position_trigger_(new Trigger<float>())
|
||||
#endif
|
||||
#ifdef USE_TEMPLATE_COVER_TILT_TRIGGER
|
||||
,
|
||||
tilt_trigger_(new Trigger<float>())
|
||||
#endif
|
||||
{
|
||||
}
|
||||
close_trigger_(new Trigger<>),
|
||||
stop_trigger_(new Trigger<>()),
|
||||
toggle_trigger_(new Trigger<>()),
|
||||
position_trigger_(new Trigger<float>()),
|
||||
tilt_trigger_(new Trigger<float>()) {}
|
||||
void TemplateCover::setup() {
|
||||
switch (this->restore_mode_) {
|
||||
case COVER_NO_RESTORE:
|
||||
@@ -78,30 +64,22 @@ void TemplateCover::set_assumed_state(bool assumed_state) { this->assumed_state_
|
||||
float TemplateCover::get_setup_priority() const { return setup_priority::HARDWARE; }
|
||||
Trigger<> *TemplateCover::get_open_trigger() const { return this->open_trigger_; }
|
||||
Trigger<> *TemplateCover::get_close_trigger() const { return this->close_trigger_; }
|
||||
#ifdef USE_TEMPLATE_COVER_STOP_TRIGGER
|
||||
Trigger<> *TemplateCover::get_stop_trigger() const { return this->stop_trigger_; }
|
||||
#endif
|
||||
#ifdef USE_TEMPLATE_COVER_TOGGLE_TRIGGER
|
||||
Trigger<> *TemplateCover::get_toggle_trigger() const { return this->toggle_trigger_; }
|
||||
#endif
|
||||
void TemplateCover::dump_config() { LOG_COVER("", "Template Cover", this); }
|
||||
void TemplateCover::control(const CoverCall &call) {
|
||||
#ifdef USE_TEMPLATE_COVER_STOP_TRIGGER
|
||||
if (call.get_stop()) {
|
||||
this->stop_prev_trigger_();
|
||||
this->stop_trigger_->trigger();
|
||||
this->prev_command_trigger_ = this->stop_trigger_;
|
||||
this->publish_state();
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_TEMPLATE_COVER_TOGGLE_TRIGGER
|
||||
if (call.get_toggle().has_value()) {
|
||||
this->stop_prev_trigger_();
|
||||
this->toggle_trigger_->trigger();
|
||||
this->prev_command_trigger_ = this->toggle_trigger_;
|
||||
this->publish_state();
|
||||
}
|
||||
#endif
|
||||
if (call.get_position().has_value()) {
|
||||
auto pos = *call.get_position();
|
||||
this->stop_prev_trigger_();
|
||||
@@ -112,19 +90,15 @@ void TemplateCover::control(const CoverCall &call) {
|
||||
} else if (pos == COVER_CLOSED) {
|
||||
this->close_trigger_->trigger();
|
||||
this->prev_command_trigger_ = this->close_trigger_;
|
||||
}
|
||||
#ifdef USE_TEMPLATE_COVER_POSITION_TRIGGER
|
||||
else {
|
||||
} else {
|
||||
this->position_trigger_->trigger(pos);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (this->optimistic_) {
|
||||
this->position = pos;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USE_TEMPLATE_COVER_TILT_TRIGGER
|
||||
if (call.get_tilt().has_value()) {
|
||||
auto tilt = *call.get_tilt();
|
||||
this->tilt_trigger_->trigger(tilt);
|
||||
@@ -133,53 +107,24 @@ void TemplateCover::control(const CoverCall &call) {
|
||||
this->tilt = tilt;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
this->publish_state();
|
||||
}
|
||||
CoverTraits TemplateCover::get_traits() {
|
||||
auto traits = CoverTraits();
|
||||
traits.set_is_assumed_state(this->assumed_state_);
|
||||
#ifdef USE_TEMPLATE_COVER_STOP_TRIGGER
|
||||
traits.set_supports_stop(this->has_stop_);
|
||||
#else
|
||||
traits.set_supports_stop(false);
|
||||
#endif
|
||||
#ifdef USE_TEMPLATE_COVER_TOGGLE_TRIGGER
|
||||
traits.set_supports_toggle(this->has_toggle_);
|
||||
#else
|
||||
traits.set_supports_toggle(false);
|
||||
#endif
|
||||
#ifdef USE_TEMPLATE_COVER_POSITION_TRIGGER
|
||||
traits.set_supports_position(this->has_position_);
|
||||
#else
|
||||
traits.set_supports_position(false);
|
||||
#endif
|
||||
#ifdef USE_TEMPLATE_COVER_TILT_TRIGGER
|
||||
traits.set_supports_tilt(this->has_tilt_);
|
||||
#else
|
||||
traits.set_supports_tilt(false);
|
||||
#endif
|
||||
return traits;
|
||||
}
|
||||
#ifdef USE_TEMPLATE_COVER_POSITION_TRIGGER
|
||||
Trigger<float> *TemplateCover::get_position_trigger() const { return this->position_trigger_; }
|
||||
#endif
|
||||
#ifdef USE_TEMPLATE_COVER_TILT_TRIGGER
|
||||
Trigger<float> *TemplateCover::get_tilt_trigger() const { return this->tilt_trigger_; }
|
||||
#endif
|
||||
#ifdef USE_TEMPLATE_COVER_STOP_TRIGGER
|
||||
void TemplateCover::set_has_stop(bool has_stop) { this->has_stop_ = has_stop; }
|
||||
#endif
|
||||
#ifdef USE_TEMPLATE_COVER_TOGGLE_TRIGGER
|
||||
void TemplateCover::set_has_toggle(bool has_toggle) { this->has_toggle_ = has_toggle; }
|
||||
#endif
|
||||
#ifdef USE_TEMPLATE_COVER_POSITION_TRIGGER
|
||||
void TemplateCover::set_has_position(bool has_position) { this->has_position_ = has_position; }
|
||||
#endif
|
||||
#ifdef USE_TEMPLATE_COVER_TILT_TRIGGER
|
||||
void TemplateCover::set_has_tilt(bool has_tilt) { this->has_tilt_ = has_tilt; }
|
||||
#endif
|
||||
void TemplateCover::stop_prev_trigger_() {
|
||||
if (this->prev_command_trigger_ != nullptr) {
|
||||
this->prev_command_trigger_->stop_action();
|
||||
|
||||
@@ -21,32 +21,16 @@ class TemplateCover final : public cover::Cover, public Component {
|
||||
template<typename F> void set_tilt_lambda(F &&f) { this->tilt_f_.set(std::forward<F>(f)); }
|
||||
Trigger<> *get_open_trigger() const;
|
||||
Trigger<> *get_close_trigger() const;
|
||||
#ifdef USE_TEMPLATE_COVER_STOP_TRIGGER
|
||||
Trigger<> *get_stop_trigger() const;
|
||||
#endif
|
||||
#ifdef USE_TEMPLATE_COVER_TOGGLE_TRIGGER
|
||||
Trigger<> *get_toggle_trigger() const;
|
||||
#endif
|
||||
#ifdef USE_TEMPLATE_COVER_POSITION_TRIGGER
|
||||
Trigger<float> *get_position_trigger() const;
|
||||
#endif
|
||||
#ifdef USE_TEMPLATE_COVER_TILT_TRIGGER
|
||||
Trigger<float> *get_tilt_trigger() const;
|
||||
#endif
|
||||
void set_optimistic(bool optimistic);
|
||||
void set_assumed_state(bool assumed_state);
|
||||
#ifdef USE_TEMPLATE_COVER_STOP_TRIGGER
|
||||
void set_has_stop(bool has_stop);
|
||||
#endif
|
||||
#ifdef USE_TEMPLATE_COVER_POSITION_TRIGGER
|
||||
void set_has_position(bool has_position);
|
||||
#endif
|
||||
#ifdef USE_TEMPLATE_COVER_TILT_TRIGGER
|
||||
void set_has_tilt(bool has_tilt);
|
||||
#endif
|
||||
#ifdef USE_TEMPLATE_COVER_TOGGLE_TRIGGER
|
||||
void set_has_toggle(bool has_toggle);
|
||||
#endif
|
||||
void set_restore_mode(TemplateCoverRestoreMode restore_mode) { restore_mode_ = restore_mode; }
|
||||
|
||||
void setup() override;
|
||||
@@ -60,39 +44,22 @@ class TemplateCover final : public cover::Cover, public Component {
|
||||
cover::CoverTraits get_traits() override;
|
||||
void stop_prev_trigger_();
|
||||
|
||||
// Ordered to minimize padding on 32-bit: 4-byte members first, then smaller
|
||||
TemplateCoverRestoreMode restore_mode_{COVER_RESTORE};
|
||||
TemplateLambda<float> state_f_;
|
||||
TemplateLambda<float> tilt_f_;
|
||||
Trigger<> *open_trigger_;
|
||||
Trigger<> *close_trigger_;
|
||||
Trigger<> *prev_command_trigger_{nullptr};
|
||||
#ifdef USE_TEMPLATE_COVER_STOP_TRIGGER
|
||||
Trigger<> *stop_trigger_;
|
||||
#endif
|
||||
#ifdef USE_TEMPLATE_COVER_TOGGLE_TRIGGER
|
||||
Trigger<> *toggle_trigger_;
|
||||
#endif
|
||||
#ifdef USE_TEMPLATE_COVER_POSITION_TRIGGER
|
||||
Trigger<float> *position_trigger_;
|
||||
#endif
|
||||
#ifdef USE_TEMPLATE_COVER_TILT_TRIGGER
|
||||
Trigger<float> *tilt_trigger_;
|
||||
#endif
|
||||
bool assumed_state_{false};
|
||||
bool optimistic_{false};
|
||||
#ifdef USE_TEMPLATE_COVER_STOP_TRIGGER
|
||||
Trigger<> *open_trigger_;
|
||||
Trigger<> *close_trigger_;
|
||||
bool has_stop_{false};
|
||||
#endif
|
||||
#ifdef USE_TEMPLATE_COVER_TOGGLE_TRIGGER
|
||||
bool has_toggle_{false};
|
||||
#endif
|
||||
#ifdef USE_TEMPLATE_COVER_POSITION_TRIGGER
|
||||
Trigger<> *stop_trigger_;
|
||||
Trigger<> *toggle_trigger_;
|
||||
Trigger<> *prev_command_trigger_{nullptr};
|
||||
Trigger<float> *position_trigger_;
|
||||
bool has_position_{false};
|
||||
#endif
|
||||
#ifdef USE_TEMPLATE_COVER_TILT_TRIGGER
|
||||
Trigger<float> *tilt_trigger_;
|
||||
bool has_tilt_{false};
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace esphome::template_
|
||||
|
||||
@@ -141,12 +141,6 @@ async def to_code(config):
|
||||
cg.add(var.set_initial_value(datetime_struct))
|
||||
|
||||
if CONF_SET_ACTION in config:
|
||||
if config[CONF_TYPE] == "DATE":
|
||||
cg.add_define("USE_TEMPLATE_DATE_SET_TRIGGER")
|
||||
elif config[CONF_TYPE] == "TIME":
|
||||
cg.add_define("USE_TEMPLATE_TIME_SET_TRIGGER")
|
||||
elif config[CONF_TYPE] == "DATETIME":
|
||||
cg.add_define("USE_TEMPLATE_DATETIME_SET_TRIGGER")
|
||||
await automation.build_automation(
|
||||
var.get_set_trigger(),
|
||||
[(cg.ESPTime, "x")],
|
||||
|
||||
@@ -62,9 +62,7 @@ void TemplateDate::control(const datetime::DateCall &call) {
|
||||
if (has_day)
|
||||
value.day_of_month = *call.get_day();
|
||||
|
||||
#ifdef USE_TEMPLATE_DATE_SET_TRIGGER
|
||||
this->set_trigger_->trigger(value);
|
||||
#endif
|
||||
|
||||
if (this->optimistic_) {
|
||||
if (has_year)
|
||||
|
||||
@@ -22,9 +22,7 @@ class TemplateDate final : public datetime::DateEntity, public PollingComponent
|
||||
void dump_config() override;
|
||||
float get_setup_priority() const override { return setup_priority::HARDWARE; }
|
||||
|
||||
#ifdef USE_TEMPLATE_DATE_SET_TRIGGER
|
||||
Trigger<ESPTime> *get_set_trigger() const { return this->set_trigger_; }
|
||||
#endif
|
||||
void set_optimistic(bool optimistic) { this->optimistic_ = optimistic; }
|
||||
|
||||
void set_initial_value(ESPTime initial_value) { this->initial_value_ = initial_value; }
|
||||
@@ -36,9 +34,7 @@ class TemplateDate final : public datetime::DateEntity, public PollingComponent
|
||||
bool optimistic_{false};
|
||||
ESPTime initial_value_{};
|
||||
bool restore_value_{false};
|
||||
#ifdef USE_TEMPLATE_DATE_SET_TRIGGER
|
||||
Trigger<ESPTime> *set_trigger_ = new Trigger<ESPTime>();
|
||||
#endif
|
||||
TemplateLambda<ESPTime> f_;
|
||||
|
||||
ESPPreferenceObject pref_;
|
||||
|
||||
@@ -80,9 +80,7 @@ void TemplateDateTime::control(const datetime::DateTimeCall &call) {
|
||||
if (has_second)
|
||||
value.second = *call.get_second();
|
||||
|
||||
#ifdef USE_TEMPLATE_DATETIME_SET_TRIGGER
|
||||
this->set_trigger_->trigger(value);
|
||||
#endif
|
||||
|
||||
if (this->optimistic_) {
|
||||
if (has_year)
|
||||
|
||||
@@ -22,9 +22,7 @@ class TemplateDateTime final : public datetime::DateTimeEntity, public PollingCo
|
||||
void dump_config() override;
|
||||
float get_setup_priority() const override { return setup_priority::HARDWARE; }
|
||||
|
||||
#ifdef USE_TEMPLATE_DATETIME_SET_TRIGGER
|
||||
Trigger<ESPTime> *get_set_trigger() const { return this->set_trigger_; }
|
||||
#endif
|
||||
void set_optimistic(bool optimistic) { this->optimistic_ = optimistic; }
|
||||
|
||||
void set_initial_value(ESPTime initial_value) { this->initial_value_ = initial_value; }
|
||||
@@ -36,9 +34,7 @@ class TemplateDateTime final : public datetime::DateTimeEntity, public PollingCo
|
||||
bool optimistic_{false};
|
||||
ESPTime initial_value_{};
|
||||
bool restore_value_{false};
|
||||
#ifdef USE_TEMPLATE_DATETIME_SET_TRIGGER
|
||||
Trigger<ESPTime> *set_trigger_ = new Trigger<ESPTime>();
|
||||
#endif
|
||||
TemplateLambda<ESPTime> f_;
|
||||
|
||||
ESPPreferenceObject pref_;
|
||||
|
||||
@@ -62,9 +62,7 @@ void TemplateTime::control(const datetime::TimeCall &call) {
|
||||
if (has_second)
|
||||
value.second = *call.get_second();
|
||||
|
||||
#ifdef USE_TEMPLATE_TIME_SET_TRIGGER
|
||||
this->set_trigger_->trigger(value);
|
||||
#endif
|
||||
|
||||
if (this->optimistic_) {
|
||||
if (has_hour)
|
||||
|
||||
@@ -22,9 +22,7 @@ class TemplateTime final : public datetime::TimeEntity, public PollingComponent
|
||||
void dump_config() override;
|
||||
float get_setup_priority() const override { return setup_priority::HARDWARE; }
|
||||
|
||||
#ifdef USE_TEMPLATE_TIME_SET_TRIGGER
|
||||
Trigger<ESPTime> *get_set_trigger() const { return this->set_trigger_; }
|
||||
#endif
|
||||
void set_optimistic(bool optimistic) { this->optimistic_ = optimistic; }
|
||||
|
||||
void set_initial_value(ESPTime initial_value) { this->initial_value_ = initial_value; }
|
||||
@@ -36,9 +34,7 @@ class TemplateTime final : public datetime::TimeEntity, public PollingComponent
|
||||
bool optimistic_{false};
|
||||
ESPTime initial_value_{};
|
||||
bool restore_value_{false};
|
||||
#ifdef USE_TEMPLATE_TIME_SET_TRIGGER
|
||||
Trigger<ESPTime> *set_trigger_ = new Trigger<ESPTime>();
|
||||
#endif
|
||||
TemplateLambda<ESPTime> f_;
|
||||
|
||||
ESPPreferenceObject pref_;
|
||||
|
||||
@@ -64,17 +64,14 @@ async def to_code(config):
|
||||
)
|
||||
cg.add(var.set_state_lambda(template_))
|
||||
if CONF_UNLOCK_ACTION in config:
|
||||
cg.add_define("USE_TEMPLATE_LOCK_UNLOCK_TRIGGER")
|
||||
await automation.build_automation(
|
||||
var.get_unlock_trigger(), [], config[CONF_UNLOCK_ACTION]
|
||||
)
|
||||
if CONF_LOCK_ACTION in config:
|
||||
cg.add_define("USE_TEMPLATE_LOCK_LOCK_TRIGGER")
|
||||
await automation.build_automation(
|
||||
var.get_lock_trigger(), [], config[CONF_LOCK_ACTION]
|
||||
)
|
||||
if CONF_OPEN_ACTION in config:
|
||||
cg.add_define("USE_TEMPLATE_LOCK_OPEN_TRIGGER")
|
||||
await automation.build_automation(
|
||||
var.get_open_trigger(), [], config[CONF_OPEN_ACTION]
|
||||
)
|
||||
|
||||
@@ -8,27 +8,7 @@ using namespace esphome::lock;
|
||||
static const char *const TAG = "template.lock";
|
||||
|
||||
TemplateLock::TemplateLock()
|
||||
#ifdef USE_TEMPLATE_LOCK_LOCK_TRIGGER
|
||||
: lock_trigger_(new Trigger<>())
|
||||
#ifdef USE_TEMPLATE_LOCK_UNLOCK_TRIGGER
|
||||
,
|
||||
unlock_trigger_(new Trigger<>())
|
||||
#endif
|
||||
#ifdef USE_TEMPLATE_LOCK_OPEN_TRIGGER
|
||||
,
|
||||
open_trigger_(new Trigger<>())
|
||||
#endif
|
||||
#elif defined(USE_TEMPLATE_LOCK_UNLOCK_TRIGGER)
|
||||
: unlock_trigger_(new Trigger<>())
|
||||
#ifdef USE_TEMPLATE_LOCK_OPEN_TRIGGER
|
||||
,
|
||||
open_trigger_(new Trigger<>())
|
||||
#endif
|
||||
#elif defined(USE_TEMPLATE_LOCK_OPEN_TRIGGER)
|
||||
: open_trigger_(new Trigger<>())
|
||||
#endif
|
||||
{
|
||||
}
|
||||
: lock_trigger_(new Trigger<>()), unlock_trigger_(new Trigger<>()), open_trigger_(new Trigger<>()) {}
|
||||
|
||||
void TemplateLock::setup() {
|
||||
if (!this->f_.has_value())
|
||||
@@ -42,55 +22,34 @@ void TemplateLock::loop() {
|
||||
}
|
||||
}
|
||||
void TemplateLock::control(const lock::LockCall &call) {
|
||||
#if defined(USE_TEMPLATE_LOCK_LOCK_TRIGGER) || defined(USE_TEMPLATE_LOCK_UNLOCK_TRIGGER) || \
|
||||
defined(USE_TEMPLATE_LOCK_OPEN_TRIGGER)
|
||||
if (this->prev_trigger_ != nullptr) {
|
||||
this->prev_trigger_->stop_action();
|
||||
}
|
||||
#endif
|
||||
|
||||
auto state = *call.get_state();
|
||||
#ifdef USE_TEMPLATE_LOCK_LOCK_TRIGGER
|
||||
if (state == LOCK_STATE_LOCKED) {
|
||||
this->prev_trigger_ = this->lock_trigger_;
|
||||
this->lock_trigger_->trigger();
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_TEMPLATE_LOCK_UNLOCK_TRIGGER
|
||||
#ifdef USE_TEMPLATE_LOCK_LOCK_TRIGGER
|
||||
else
|
||||
#endif
|
||||
if (state == LOCK_STATE_UNLOCKED) {
|
||||
} else if (state == LOCK_STATE_UNLOCKED) {
|
||||
this->prev_trigger_ = this->unlock_trigger_;
|
||||
this->unlock_trigger_->trigger();
|
||||
}
|
||||
#endif
|
||||
|
||||
if (this->optimistic_)
|
||||
this->publish_state(state);
|
||||
}
|
||||
void TemplateLock::open_latch() {
|
||||
#ifdef USE_TEMPLATE_LOCK_OPEN_TRIGGER
|
||||
#if defined(USE_TEMPLATE_LOCK_LOCK_TRIGGER) || defined(USE_TEMPLATE_LOCK_UNLOCK_TRIGGER)
|
||||
if (this->prev_trigger_ != nullptr) {
|
||||
this->prev_trigger_->stop_action();
|
||||
}
|
||||
#endif
|
||||
this->prev_trigger_ = this->open_trigger_;
|
||||
this->open_trigger_->trigger();
|
||||
#endif
|
||||
}
|
||||
void TemplateLock::set_optimistic(bool optimistic) { this->optimistic_ = optimistic; }
|
||||
float TemplateLock::get_setup_priority() const { return setup_priority::HARDWARE; }
|
||||
#ifdef USE_TEMPLATE_LOCK_LOCK_TRIGGER
|
||||
Trigger<> *TemplateLock::get_lock_trigger() const { return this->lock_trigger_; }
|
||||
#endif
|
||||
#ifdef USE_TEMPLATE_LOCK_UNLOCK_TRIGGER
|
||||
Trigger<> *TemplateLock::get_unlock_trigger() const { return this->unlock_trigger_; }
|
||||
#endif
|
||||
#ifdef USE_TEMPLATE_LOCK_OPEN_TRIGGER
|
||||
Trigger<> *TemplateLock::get_open_trigger() const { return this->open_trigger_; }
|
||||
#endif
|
||||
void TemplateLock::dump_config() {
|
||||
LOG_LOCK("", "Template Lock", this);
|
||||
ESP_LOGCONFIG(TAG, " Optimistic: %s", YESNO(this->optimistic_));
|
||||
|
||||
@@ -15,15 +15,9 @@ class TemplateLock final : public lock::Lock, public Component {
|
||||
void dump_config() override;
|
||||
|
||||
template<typename F> void set_state_lambda(F &&f) { this->f_.set(std::forward<F>(f)); }
|
||||
#ifdef USE_TEMPLATE_LOCK_LOCK_TRIGGER
|
||||
Trigger<> *get_lock_trigger() const;
|
||||
#endif
|
||||
#ifdef USE_TEMPLATE_LOCK_UNLOCK_TRIGGER
|
||||
Trigger<> *get_unlock_trigger() const;
|
||||
#endif
|
||||
#ifdef USE_TEMPLATE_LOCK_OPEN_TRIGGER
|
||||
Trigger<> *get_open_trigger() const;
|
||||
#endif
|
||||
void set_optimistic(bool optimistic);
|
||||
void loop() override;
|
||||
|
||||
@@ -35,19 +29,10 @@ class TemplateLock final : public lock::Lock, public Component {
|
||||
|
||||
TemplateLambda<lock::LockState> f_;
|
||||
bool optimistic_{false};
|
||||
#ifdef USE_TEMPLATE_LOCK_LOCK_TRIGGER
|
||||
Trigger<> *lock_trigger_;
|
||||
#endif
|
||||
#ifdef USE_TEMPLATE_LOCK_UNLOCK_TRIGGER
|
||||
Trigger<> *unlock_trigger_;
|
||||
#endif
|
||||
#ifdef USE_TEMPLATE_LOCK_OPEN_TRIGGER
|
||||
Trigger<> *open_trigger_;
|
||||
#endif
|
||||
#if defined(USE_TEMPLATE_LOCK_LOCK_TRIGGER) || defined(USE_TEMPLATE_LOCK_UNLOCK_TRIGGER) || \
|
||||
defined(USE_TEMPLATE_LOCK_OPEN_TRIGGER)
|
||||
Trigger<> *prev_trigger_{nullptr};
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace esphome::template_
|
||||
|
||||
@@ -89,7 +89,6 @@ async def to_code(config):
|
||||
cg.add(var.set_restore_value(config[CONF_RESTORE_VALUE]))
|
||||
|
||||
if CONF_SET_ACTION in config:
|
||||
cg.add_define("USE_TEMPLATE_NUMBER_SET_TRIGGER")
|
||||
await automation.build_automation(
|
||||
var.get_set_trigger(), [(float, "x")], config[CONF_SET_ACTION]
|
||||
)
|
||||
|
||||
@@ -36,9 +36,7 @@ void TemplateNumber::update() {
|
||||
}
|
||||
|
||||
void TemplateNumber::control(float value) {
|
||||
#ifdef USE_TEMPLATE_NUMBER_SET_TRIGGER
|
||||
this->set_trigger_->trigger(value);
|
||||
#endif
|
||||
|
||||
if (this->optimistic_)
|
||||
this->publish_state(value);
|
||||
|
||||
@@ -17,9 +17,7 @@ class TemplateNumber final : public number::Number, public PollingComponent {
|
||||
void dump_config() override;
|
||||
float get_setup_priority() const override { return setup_priority::HARDWARE; }
|
||||
|
||||
#ifdef USE_TEMPLATE_NUMBER_SET_TRIGGER
|
||||
Trigger<float> *get_set_trigger() const { return set_trigger_; }
|
||||
#endif
|
||||
void set_optimistic(bool optimistic) { optimistic_ = optimistic; }
|
||||
void set_initial_value(float initial_value) { initial_value_ = initial_value; }
|
||||
void set_restore_value(bool restore_value) { this->restore_value_ = restore_value; }
|
||||
@@ -29,9 +27,7 @@ class TemplateNumber final : public number::Number, public PollingComponent {
|
||||
bool optimistic_{false};
|
||||
float initial_value_{NAN};
|
||||
bool restore_value_{false};
|
||||
#ifdef USE_TEMPLATE_NUMBER_SET_TRIGGER
|
||||
Trigger<float> *set_trigger_ = new Trigger<float>();
|
||||
#endif
|
||||
TemplateLambda<float> f_;
|
||||
|
||||
ESPPreferenceObject pref_;
|
||||
|
||||
@@ -87,7 +87,6 @@ async def to_code(config):
|
||||
cg.add(var.set_restore_value(True))
|
||||
|
||||
if CONF_SET_ACTION in config:
|
||||
cg.add_define("USE_TEMPLATE_SELECT_SET_TRIGGER")
|
||||
await automation.build_automation(
|
||||
var.get_set_trigger(), [(cg.StringRef, "x")], config[CONF_SET_ACTION]
|
||||
)
|
||||
|
||||
@@ -41,9 +41,7 @@ void TemplateSelect::update() {
|
||||
}
|
||||
|
||||
void TemplateSelect::control(size_t index) {
|
||||
#ifdef USE_TEMPLATE_SELECT_SET_TRIGGER
|
||||
this->set_trigger_->trigger(StringRef(this->option_at(index)));
|
||||
#endif
|
||||
|
||||
if (this->optimistic_)
|
||||
this->publish_state(index);
|
||||
|
||||
@@ -18,9 +18,7 @@ class TemplateSelect final : public select::Select, public PollingComponent {
|
||||
void dump_config() override;
|
||||
float get_setup_priority() const override { return setup_priority::HARDWARE; }
|
||||
|
||||
#ifdef USE_TEMPLATE_SELECT_SET_TRIGGER
|
||||
Trigger<StringRef> *get_set_trigger() const { return this->set_trigger_; }
|
||||
#endif
|
||||
void set_optimistic(bool optimistic) { this->optimistic_ = optimistic; }
|
||||
void set_initial_option_index(size_t initial_option_index) { this->initial_option_index_ = initial_option_index; }
|
||||
void set_restore_value(bool restore_value) { this->restore_value_ = restore_value; }
|
||||
@@ -30,9 +28,7 @@ class TemplateSelect final : public select::Select, public PollingComponent {
|
||||
bool optimistic_ = false;
|
||||
size_t initial_option_index_{0};
|
||||
bool restore_value_ = false;
|
||||
#ifdef USE_TEMPLATE_SELECT_SET_TRIGGER
|
||||
Trigger<StringRef> *set_trigger_ = new Trigger<StringRef>();
|
||||
#endif
|
||||
TemplateLambda<std::string> f_;
|
||||
|
||||
ESPPreferenceObject pref_;
|
||||
|
||||
@@ -60,12 +60,10 @@ async def to_code(config):
|
||||
)
|
||||
cg.add(var.set_state_lambda(template_))
|
||||
if CONF_TURN_OFF_ACTION in config:
|
||||
cg.add_define("USE_TEMPLATE_SWITCH_TURN_OFF_TRIGGER")
|
||||
await automation.build_automation(
|
||||
var.get_turn_off_trigger(), [], config[CONF_TURN_OFF_ACTION]
|
||||
)
|
||||
if CONF_TURN_ON_ACTION in config:
|
||||
cg.add_define("USE_TEMPLATE_SWITCH_TURN_ON_TRIGGER")
|
||||
await automation.build_automation(
|
||||
var.get_turn_on_trigger(), [], config[CONF_TURN_ON_ACTION]
|
||||
)
|
||||
|
||||
@@ -5,18 +5,7 @@ namespace esphome::template_ {
|
||||
|
||||
static const char *const TAG = "template.switch";
|
||||
|
||||
TemplateSwitch::TemplateSwitch()
|
||||
#ifdef USE_TEMPLATE_SWITCH_TURN_ON_TRIGGER
|
||||
: turn_on_trigger_(new Trigger<>())
|
||||
#ifdef USE_TEMPLATE_SWITCH_TURN_OFF_TRIGGER
|
||||
,
|
||||
turn_off_trigger_(new Trigger<>())
|
||||
#endif
|
||||
#elif defined(USE_TEMPLATE_SWITCH_TURN_OFF_TRIGGER)
|
||||
: turn_off_trigger_(new Trigger<>())
|
||||
#endif
|
||||
{
|
||||
}
|
||||
TemplateSwitch::TemplateSwitch() : turn_on_trigger_(new Trigger<>()), turn_off_trigger_(new Trigger<>()) {}
|
||||
|
||||
void TemplateSwitch::loop() {
|
||||
auto s = this->f_();
|
||||
@@ -25,22 +14,16 @@ void TemplateSwitch::loop() {
|
||||
}
|
||||
}
|
||||
void TemplateSwitch::write_state(bool state) {
|
||||
#if defined(USE_TEMPLATE_SWITCH_TURN_ON_TRIGGER) || defined(USE_TEMPLATE_SWITCH_TURN_OFF_TRIGGER)
|
||||
if (this->prev_trigger_ != nullptr) {
|
||||
this->prev_trigger_->stop_action();
|
||||
}
|
||||
#endif
|
||||
|
||||
if (state) {
|
||||
#ifdef USE_TEMPLATE_SWITCH_TURN_ON_TRIGGER
|
||||
this->prev_trigger_ = this->turn_on_trigger_;
|
||||
this->turn_on_trigger_->trigger();
|
||||
#endif
|
||||
} else {
|
||||
#ifdef USE_TEMPLATE_SWITCH_TURN_OFF_TRIGGER
|
||||
this->prev_trigger_ = this->turn_off_trigger_;
|
||||
this->turn_off_trigger_->trigger();
|
||||
#endif
|
||||
}
|
||||
|
||||
if (this->optimistic_)
|
||||
@@ -49,12 +32,8 @@ void TemplateSwitch::write_state(bool state) {
|
||||
void TemplateSwitch::set_optimistic(bool optimistic) { this->optimistic_ = optimistic; }
|
||||
bool TemplateSwitch::assumed_state() { return this->assumed_state_; }
|
||||
float TemplateSwitch::get_setup_priority() const { return setup_priority::HARDWARE - 2.0f; }
|
||||
#ifdef USE_TEMPLATE_SWITCH_TURN_ON_TRIGGER
|
||||
Trigger<> *TemplateSwitch::get_turn_on_trigger() const { return this->turn_on_trigger_; }
|
||||
#endif
|
||||
#ifdef USE_TEMPLATE_SWITCH_TURN_OFF_TRIGGER
|
||||
Trigger<> *TemplateSwitch::get_turn_off_trigger() const { return this->turn_off_trigger_; }
|
||||
#endif
|
||||
void TemplateSwitch::setup() {
|
||||
if (!this->f_.has_value())
|
||||
this->disable_loop();
|
||||
|
||||
@@ -15,12 +15,8 @@ class TemplateSwitch final : public switch_::Switch, public Component {
|
||||
void dump_config() override;
|
||||
|
||||
template<typename F> void set_state_lambda(F &&f) { this->f_.set(std::forward<F>(f)); }
|
||||
#ifdef USE_TEMPLATE_SWITCH_TURN_ON_TRIGGER
|
||||
Trigger<> *get_turn_on_trigger() const;
|
||||
#endif
|
||||
#ifdef USE_TEMPLATE_SWITCH_TURN_OFF_TRIGGER
|
||||
Trigger<> *get_turn_off_trigger() const;
|
||||
#endif
|
||||
void set_optimistic(bool optimistic);
|
||||
void set_assumed_state(bool assumed_state);
|
||||
void loop() override;
|
||||
@@ -35,15 +31,9 @@ class TemplateSwitch final : public switch_::Switch, public Component {
|
||||
TemplateLambda<bool> f_;
|
||||
bool optimistic_{false};
|
||||
bool assumed_state_{false};
|
||||
#ifdef USE_TEMPLATE_SWITCH_TURN_ON_TRIGGER
|
||||
Trigger<> *turn_on_trigger_;
|
||||
#endif
|
||||
#ifdef USE_TEMPLATE_SWITCH_TURN_OFF_TRIGGER
|
||||
Trigger<> *turn_off_trigger_;
|
||||
#endif
|
||||
#if defined(USE_TEMPLATE_SWITCH_TURN_ON_TRIGGER) || defined(USE_TEMPLATE_SWITCH_TURN_OFF_TRIGGER)
|
||||
Trigger<> *prev_trigger_{nullptr};
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace esphome::template_
|
||||
|
||||
@@ -89,7 +89,6 @@ async def to_code(config):
|
||||
cg.add(var.set_value_saver(saver))
|
||||
|
||||
if CONF_SET_ACTION in config:
|
||||
cg.add_define("USE_TEMPLATE_TEXT_SET_TRIGGER")
|
||||
await automation.build_automation(
|
||||
var.get_set_trigger(), [(cg.std_string, "x")], config[CONF_SET_ACTION]
|
||||
)
|
||||
|
||||
@@ -47,9 +47,7 @@ void TemplateText::update() {
|
||||
}
|
||||
|
||||
void TemplateText::control(const std::string &value) {
|
||||
#ifdef USE_TEMPLATE_TEXT_SET_TRIGGER
|
||||
this->set_trigger_->trigger(value);
|
||||
#endif
|
||||
|
||||
if (this->optimistic_)
|
||||
this->publish_state(value);
|
||||
|
||||
@@ -68,9 +68,7 @@ class TemplateText final : public text::Text, public PollingComponent {
|
||||
void dump_config() override;
|
||||
float get_setup_priority() const override { return setup_priority::HARDWARE; }
|
||||
|
||||
#ifdef USE_TEMPLATE_TEXT_SET_TRIGGER
|
||||
Trigger<std::string> *get_set_trigger() const { return this->set_trigger_; }
|
||||
#endif
|
||||
void set_optimistic(bool optimistic) { this->optimistic_ = optimistic; }
|
||||
void set_initial_value(const char *initial_value) { this->initial_value_ = initial_value; }
|
||||
/// Prevent accidental use of std::string which would dangle
|
||||
@@ -81,9 +79,7 @@ class TemplateText final : public text::Text, public PollingComponent {
|
||||
void control(const std::string &value) override;
|
||||
bool optimistic_ = false;
|
||||
const char *initial_value_{nullptr};
|
||||
#ifdef USE_TEMPLATE_TEXT_SET_TRIGGER
|
||||
Trigger<std::string> *set_trigger_ = new Trigger<std::string>();
|
||||
#endif
|
||||
TemplateLambda<std::string> f_{};
|
||||
|
||||
TemplateTextSaverBase *pref_ = nullptr;
|
||||
|
||||
@@ -78,19 +78,16 @@ async def to_code(config):
|
||||
var.get_close_trigger(), [], close_action_config
|
||||
)
|
||||
if stop_action_config := config.get(CONF_STOP_ACTION):
|
||||
cg.add_define("USE_TEMPLATE_VALVE_STOP_TRIGGER")
|
||||
await automation.build_automation(
|
||||
var.get_stop_trigger(), [], stop_action_config
|
||||
)
|
||||
cg.add(var.set_has_stop(True))
|
||||
if toggle_action_config := config.get(CONF_TOGGLE_ACTION):
|
||||
cg.add_define("USE_TEMPLATE_VALVE_TOGGLE_TRIGGER")
|
||||
await automation.build_automation(
|
||||
var.get_toggle_trigger(), [], toggle_action_config
|
||||
)
|
||||
cg.add(var.set_has_toggle(True))
|
||||
if position_action_config := config.get(CONF_POSITION_ACTION):
|
||||
cg.add_define("USE_TEMPLATE_VALVE_POSITION_TRIGGER")
|
||||
await automation.build_automation(
|
||||
var.get_position_trigger(), [(float, "pos")], position_action_config
|
||||
)
|
||||
|
||||
@@ -9,21 +9,10 @@ static const char *const TAG = "template.valve";
|
||||
|
||||
TemplateValve::TemplateValve()
|
||||
: open_trigger_(new Trigger<>()),
|
||||
close_trigger_(new Trigger<>())
|
||||
#ifdef USE_TEMPLATE_VALVE_STOP_TRIGGER
|
||||
,
|
||||
stop_trigger_(new Trigger<>())
|
||||
#endif
|
||||
#ifdef USE_TEMPLATE_VALVE_TOGGLE_TRIGGER
|
||||
,
|
||||
toggle_trigger_(new Trigger<>())
|
||||
#endif
|
||||
#ifdef USE_TEMPLATE_VALVE_POSITION_TRIGGER
|
||||
,
|
||||
position_trigger_(new Trigger<float>())
|
||||
#endif
|
||||
{
|
||||
}
|
||||
close_trigger_(new Trigger<>),
|
||||
stop_trigger_(new Trigger<>()),
|
||||
toggle_trigger_(new Trigger<>()),
|
||||
position_trigger_(new Trigger<float>()) {}
|
||||
|
||||
void TemplateValve::setup() {
|
||||
switch (this->restore_mode_) {
|
||||
@@ -69,12 +58,8 @@ float TemplateValve::get_setup_priority() const { return setup_priority::HARDWAR
|
||||
|
||||
Trigger<> *TemplateValve::get_open_trigger() const { return this->open_trigger_; }
|
||||
Trigger<> *TemplateValve::get_close_trigger() const { return this->close_trigger_; }
|
||||
#ifdef USE_TEMPLATE_VALVE_STOP_TRIGGER
|
||||
Trigger<> *TemplateValve::get_stop_trigger() const { return this->stop_trigger_; }
|
||||
#endif
|
||||
#ifdef USE_TEMPLATE_VALVE_TOGGLE_TRIGGER
|
||||
Trigger<> *TemplateValve::get_toggle_trigger() const { return this->toggle_trigger_; }
|
||||
#endif
|
||||
|
||||
void TemplateValve::dump_config() {
|
||||
LOG_VALVE("", "Template Valve", this);
|
||||
@@ -85,22 +70,18 @@ void TemplateValve::dump_config() {
|
||||
}
|
||||
|
||||
void TemplateValve::control(const ValveCall &call) {
|
||||
#ifdef USE_TEMPLATE_VALVE_STOP_TRIGGER
|
||||
if (call.get_stop()) {
|
||||
this->stop_prev_trigger_();
|
||||
this->stop_trigger_->trigger();
|
||||
this->prev_command_trigger_ = this->stop_trigger_;
|
||||
this->publish_state();
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_TEMPLATE_VALVE_TOGGLE_TRIGGER
|
||||
if (call.get_toggle().has_value()) {
|
||||
this->stop_prev_trigger_();
|
||||
this->toggle_trigger_->trigger();
|
||||
this->prev_command_trigger_ = this->toggle_trigger_;
|
||||
this->publish_state();
|
||||
}
|
||||
#endif
|
||||
if (call.get_position().has_value()) {
|
||||
auto pos = *call.get_position();
|
||||
this->stop_prev_trigger_();
|
||||
@@ -111,12 +92,9 @@ void TemplateValve::control(const ValveCall &call) {
|
||||
} else if (pos == VALVE_CLOSED) {
|
||||
this->close_trigger_->trigger();
|
||||
this->prev_command_trigger_ = this->close_trigger_;
|
||||
}
|
||||
#ifdef USE_TEMPLATE_VALVE_POSITION_TRIGGER
|
||||
else {
|
||||
} else {
|
||||
this->position_trigger_->trigger(pos);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (this->optimistic_) {
|
||||
this->position = pos;
|
||||
@@ -129,37 +107,17 @@ void TemplateValve::control(const ValveCall &call) {
|
||||
ValveTraits TemplateValve::get_traits() {
|
||||
auto traits = ValveTraits();
|
||||
traits.set_is_assumed_state(this->assumed_state_);
|
||||
#ifdef USE_TEMPLATE_VALVE_STOP_TRIGGER
|
||||
traits.set_supports_stop(this->has_stop_);
|
||||
#else
|
||||
traits.set_supports_stop(false);
|
||||
#endif
|
||||
#ifdef USE_TEMPLATE_VALVE_TOGGLE_TRIGGER
|
||||
traits.set_supports_toggle(this->has_toggle_);
|
||||
#else
|
||||
traits.set_supports_toggle(false);
|
||||
#endif
|
||||
#ifdef USE_TEMPLATE_VALVE_POSITION_TRIGGER
|
||||
traits.set_supports_position(this->has_position_);
|
||||
#else
|
||||
traits.set_supports_position(false);
|
||||
#endif
|
||||
return traits;
|
||||
}
|
||||
|
||||
#ifdef USE_TEMPLATE_VALVE_POSITION_TRIGGER
|
||||
Trigger<float> *TemplateValve::get_position_trigger() const { return this->position_trigger_; }
|
||||
#endif
|
||||
|
||||
#ifdef USE_TEMPLATE_VALVE_STOP_TRIGGER
|
||||
void TemplateValve::set_has_stop(bool has_stop) { this->has_stop_ = has_stop; }
|
||||
#endif
|
||||
#ifdef USE_TEMPLATE_VALVE_TOGGLE_TRIGGER
|
||||
void TemplateValve::set_has_toggle(bool has_toggle) { this->has_toggle_ = has_toggle; }
|
||||
#endif
|
||||
#ifdef USE_TEMPLATE_VALVE_POSITION_TRIGGER
|
||||
void TemplateValve::set_has_position(bool has_position) { this->has_position_ = has_position; }
|
||||
#endif
|
||||
|
||||
void TemplateValve::stop_prev_trigger_() {
|
||||
if (this->prev_command_trigger_ != nullptr) {
|
||||
|
||||
@@ -20,26 +20,14 @@ class TemplateValve final : public valve::Valve, public Component {
|
||||
template<typename F> void set_state_lambda(F &&f) { this->state_f_.set(std::forward<F>(f)); }
|
||||
Trigger<> *get_open_trigger() const;
|
||||
Trigger<> *get_close_trigger() const;
|
||||
#ifdef USE_TEMPLATE_VALVE_STOP_TRIGGER
|
||||
Trigger<> *get_stop_trigger() const;
|
||||
#endif
|
||||
#ifdef USE_TEMPLATE_VALVE_TOGGLE_TRIGGER
|
||||
Trigger<> *get_toggle_trigger() const;
|
||||
#endif
|
||||
#ifdef USE_TEMPLATE_VALVE_POSITION_TRIGGER
|
||||
Trigger<float> *get_position_trigger() const;
|
||||
#endif
|
||||
void set_optimistic(bool optimistic);
|
||||
void set_assumed_state(bool assumed_state);
|
||||
#ifdef USE_TEMPLATE_VALVE_STOP_TRIGGER
|
||||
void set_has_stop(bool has_stop);
|
||||
#endif
|
||||
#ifdef USE_TEMPLATE_VALVE_POSITION_TRIGGER
|
||||
void set_has_position(bool has_position);
|
||||
#endif
|
||||
#ifdef USE_TEMPLATE_VALVE_TOGGLE_TRIGGER
|
||||
void set_has_toggle(bool has_toggle);
|
||||
#endif
|
||||
void set_restore_mode(TemplateValveRestoreMode restore_mode) { restore_mode_ = restore_mode; }
|
||||
|
||||
void setup() override;
|
||||
@@ -53,32 +41,19 @@ class TemplateValve final : public valve::Valve, public Component {
|
||||
valve::ValveTraits get_traits() override;
|
||||
void stop_prev_trigger_();
|
||||
|
||||
// Ordered to minimize padding on 32-bit: 4-byte members first, then smaller
|
||||
TemplateValveRestoreMode restore_mode_{VALVE_NO_RESTORE};
|
||||
TemplateLambda<float> state_f_;
|
||||
Trigger<> *open_trigger_;
|
||||
Trigger<> *close_trigger_;
|
||||
Trigger<> *prev_command_trigger_{nullptr};
|
||||
#ifdef USE_TEMPLATE_VALVE_STOP_TRIGGER
|
||||
Trigger<> *stop_trigger_;
|
||||
#endif
|
||||
#ifdef USE_TEMPLATE_VALVE_TOGGLE_TRIGGER
|
||||
Trigger<> *toggle_trigger_;
|
||||
#endif
|
||||
#ifdef USE_TEMPLATE_VALVE_POSITION_TRIGGER
|
||||
Trigger<float> *position_trigger_;
|
||||
#endif
|
||||
bool assumed_state_{false};
|
||||
bool optimistic_{false};
|
||||
#ifdef USE_TEMPLATE_VALVE_STOP_TRIGGER
|
||||
Trigger<> *open_trigger_;
|
||||
Trigger<> *close_trigger_;
|
||||
bool has_stop_{false};
|
||||
#endif
|
||||
#ifdef USE_TEMPLATE_VALVE_TOGGLE_TRIGGER
|
||||
bool has_toggle_{false};
|
||||
#endif
|
||||
#ifdef USE_TEMPLATE_VALVE_POSITION_TRIGGER
|
||||
Trigger<> *stop_trigger_;
|
||||
Trigger<> *toggle_trigger_;
|
||||
Trigger<> *prev_command_trigger_{nullptr};
|
||||
Trigger<float> *position_trigger_;
|
||||
bool has_position_{false};
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace esphome::template_
|
||||
|
||||
@@ -64,7 +64,6 @@ async def to_code(config: ConfigType) -> None:
|
||||
cg.add(var.set_optimistic(config[CONF_OPTIMISTIC]))
|
||||
|
||||
if CONF_SET_ACTION in config:
|
||||
cg.add_define("USE_TEMPLATE_WATER_HEATER_SET_TRIGGER")
|
||||
await automation.build_automation(
|
||||
var.get_set_trigger(), [], config[CONF_SET_ACTION]
|
||||
)
|
||||
|
||||
@@ -5,12 +5,7 @@ namespace esphome::template_ {
|
||||
|
||||
static const char *const TAG = "template.water_heater";
|
||||
|
||||
TemplateWaterHeater::TemplateWaterHeater()
|
||||
#ifdef USE_TEMPLATE_WATER_HEATER_SET_TRIGGER
|
||||
: set_trigger_(new Trigger<>())
|
||||
#endif
|
||||
{
|
||||
}
|
||||
TemplateWaterHeater::TemplateWaterHeater() : set_trigger_(new Trigger<>()) {}
|
||||
|
||||
void TemplateWaterHeater::setup() {
|
||||
if (this->restore_mode_ == TemplateWaterHeaterRestoreMode::WATER_HEATER_RESTORE ||
|
||||
@@ -83,9 +78,7 @@ void TemplateWaterHeater::control(const water_heater::WaterHeaterCall &call) {
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USE_TEMPLATE_WATER_HEATER_SET_TRIGGER
|
||||
this->set_trigger_->trigger();
|
||||
#endif
|
||||
|
||||
if (this->optimistic_) {
|
||||
this->publish_state();
|
||||
|
||||
@@ -28,9 +28,7 @@ class TemplateWaterHeater : public Component, public water_heater::WaterHeater {
|
||||
this->supported_modes_ = modes;
|
||||
}
|
||||
|
||||
#ifdef USE_TEMPLATE_WATER_HEATER_SET_TRIGGER
|
||||
Trigger<> *get_set_trigger() const { return this->set_trigger_; }
|
||||
#endif
|
||||
|
||||
void setup() override;
|
||||
void loop() override;
|
||||
@@ -44,9 +42,7 @@ class TemplateWaterHeater : public Component, public water_heater::WaterHeater {
|
||||
water_heater::WaterHeaterTraits traits() override;
|
||||
|
||||
// Ordered to minimize padding on 32-bit: 4-byte members first, then smaller
|
||||
#ifdef USE_TEMPLATE_WATER_HEATER_SET_TRIGGER
|
||||
Trigger<> *set_trigger_;
|
||||
#endif
|
||||
TemplateLambda<float> current_temperature_f_;
|
||||
TemplateLambda<water_heater::WaterHeaterMode> mode_f_;
|
||||
TemplateWaterHeaterRestoreMode restore_mode_{WATER_HEATER_NO_RESTORE};
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/log.h"
|
||||
#include "esphome/core/gpio.h"
|
||||
#include "esphome/core/task_priorities.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "soc/gpio_num.h"
|
||||
#include "soc/uart_pins.h"
|
||||
@@ -367,12 +368,13 @@ void IDFUARTComponent::check_logger_conflict() {}
|
||||
|
||||
#ifdef USE_UART_WAKE_LOOP_ON_RX
|
||||
void IDFUARTComponent::start_rx_event_task_() {
|
||||
// Create FreeRTOS task to monitor UART events
|
||||
BaseType_t result = xTaskCreate(rx_event_task_func, // Task function
|
||||
"uart_rx_evt", // Task name (max 16 chars)
|
||||
2240, // Stack size in bytes (~2.2KB); increase if needed for logging
|
||||
this, // Task parameter (this pointer)
|
||||
tskIDLE_PRIORITY + 1, // Priority (low, just above idle)
|
||||
// TASK_PRIORITY_APPLICATION: same as main loop - UART RX monitoring is lightweight,
|
||||
// just wakes main loop when data arrives
|
||||
BaseType_t result = xTaskCreate(rx_event_task_func, // Task function
|
||||
"uart_rx_evt", // Task name (max 16 chars)
|
||||
2240, // Stack size in bytes (~2.2KB)
|
||||
this, // Task parameter (this pointer)
|
||||
TASK_PRIORITY_APPLICATION,
|
||||
&this->rx_event_task_handle_ // Task handle
|
||||
);
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "usb_cdc_acm.h"
|
||||
#include "esphome/core/application.h"
|
||||
#include "esphome/core/log.h"
|
||||
#include "esphome/core/task_priorities.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <sys/param.h>
|
||||
@@ -162,7 +163,9 @@ void USBCDCACMInstance::setup() {
|
||||
// Create a simple, unique task name per interface
|
||||
char task_name[] = "usb_tx_0";
|
||||
task_name[sizeof(task_name) - 1] = format_hex_char(static_cast<char>(this->itf_));
|
||||
xTaskCreate(usb_tx_task_fn, task_name, stack_size, this, 4, &this->usb_tx_task_handle_);
|
||||
// TASK_PRIORITY_USB_SERIAL: above main loop (TASK_PRIORITY_APPLICATION) and
|
||||
// wake word (TASK_PRIORITY_INFERENCE), below protocol tasks (TASK_PRIORITY_PROTOCOL)
|
||||
xTaskCreate(usb_tx_task_fn, task_name, stack_size, this, TASK_PRIORITY_USB_SERIAL, &this->usb_tx_task_handle_);
|
||||
|
||||
if (this->usb_tx_task_handle_ == nullptr) {
|
||||
ESP_LOGE(TAG, "Failed to create USB TX task for itf %d", this->itf_);
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#if defined(USE_ESP32_VARIANT_ESP32P4) || defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3)
|
||||
#include "esphome/core/defines.h"
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/task_priorities.h"
|
||||
#include <vector>
|
||||
#include "usb/usb_host.h"
|
||||
#include <freertos/FreeRTOS.h>
|
||||
@@ -69,7 +70,6 @@ static constexpr trq_bitmask_t ALL_REQUESTS_IN_USE = MAX_REQUESTS == 32 ? ~0 : (
|
||||
|
||||
static constexpr size_t USB_EVENT_QUEUE_SIZE = 32; // Size of event queue between USB task and main loop
|
||||
static constexpr size_t USB_TASK_STACK_SIZE = 4096; // Stack size for USB task (same as ESP-IDF USB examples)
|
||||
static constexpr UBaseType_t USB_TASK_PRIORITY = 5; // Higher priority than main loop (tskIDLE_PRIORITY + 5)
|
||||
|
||||
// used to report a transfer status
|
||||
struct TransferStatus {
|
||||
|
||||
@@ -215,11 +215,12 @@ void USBClient::setup() {
|
||||
}
|
||||
|
||||
// Create and start USB task
|
||||
// TASK_PRIORITY_PROTOCOL: above main loop (TASK_PRIORITY_APPLICATION) but below
|
||||
// audio tasks - USB host needs responsive scheduling for device communication
|
||||
xTaskCreate(usb_task_fn, "usb_task",
|
||||
USB_TASK_STACK_SIZE, // Stack size
|
||||
this, // Task parameter
|
||||
USB_TASK_PRIORITY, // Priority (higher than main loop)
|
||||
&this->usb_task_handle_);
|
||||
TASK_PRIORITY_PROTOCOL, &this->usb_task_handle_);
|
||||
|
||||
if (this->usb_task_handle_ == nullptr) {
|
||||
ESP_LOGE(TAG, "Failed to create USB task");
|
||||
|
||||
@@ -232,25 +232,6 @@
|
||||
#define ESPHOME_WIFI_CONNECT_STATE_LISTENERS 2
|
||||
#define ESPHOME_WIFI_POWER_SAVE_LISTENERS 2
|
||||
#define USE_WIFI_RUNTIME_POWER_SAVE
|
||||
#define USE_TEMPLATE_NUMBER_SET_TRIGGER
|
||||
#define USE_TEMPLATE_SELECT_SET_TRIGGER
|
||||
#define USE_TEMPLATE_TEXT_SET_TRIGGER
|
||||
#define USE_TEMPLATE_SWITCH_TURN_ON_TRIGGER
|
||||
#define USE_TEMPLATE_SWITCH_TURN_OFF_TRIGGER
|
||||
#define USE_TEMPLATE_DATE_SET_TRIGGER
|
||||
#define USE_TEMPLATE_TIME_SET_TRIGGER
|
||||
#define USE_TEMPLATE_DATETIME_SET_TRIGGER
|
||||
#define USE_TEMPLATE_WATER_HEATER_SET_TRIGGER
|
||||
#define USE_TEMPLATE_LOCK_LOCK_TRIGGER
|
||||
#define USE_TEMPLATE_LOCK_UNLOCK_TRIGGER
|
||||
#define USE_TEMPLATE_LOCK_OPEN_TRIGGER
|
||||
#define USE_TEMPLATE_COVER_STOP_TRIGGER
|
||||
#define USE_TEMPLATE_COVER_TOGGLE_TRIGGER
|
||||
#define USE_TEMPLATE_COVER_POSITION_TRIGGER
|
||||
#define USE_TEMPLATE_COVER_TILT_TRIGGER
|
||||
#define USE_TEMPLATE_VALVE_STOP_TRIGGER
|
||||
#define USE_TEMPLATE_VALVE_TOGGLE_TRIGGER
|
||||
#define USE_TEMPLATE_VALVE_POSITION_TRIGGER
|
||||
#define USB_HOST_MAX_REQUESTS 16
|
||||
|
||||
#ifdef USE_ARDUINO
|
||||
|
||||
61
esphome/core/task_priorities.h
Normal file
61
esphome/core/task_priorities.h
Normal file
@@ -0,0 +1,61 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef USE_ESP32
|
||||
|
||||
#include <freertos/FreeRTOS.h>
|
||||
|
||||
namespace esphome {
|
||||
|
||||
/// @brief FreeRTOS task priority definitions for ESPHome
|
||||
///
|
||||
/// All priorities use relative values based on configMAX_PRIORITIES so they
|
||||
/// scale automatically if CONFIG_FREERTOS_MAX_PRIORITIES changes.
|
||||
///
|
||||
/// Priority hierarchy (with CONFIG_FREERTOS_MAX_PRIORITIES = 16):
|
||||
///
|
||||
/// 14: Audio capture (I2S microphone) - highest, real-time audio input
|
||||
/// 10: Audio output (I2S speaker) - real-time audio output
|
||||
/// 8: Network stack (LWIP TCP/IP) - set via CONFIG_LWIP_TCPIP_TASK_PRIO
|
||||
/// 6: Audio mixing - buffered audio processing
|
||||
/// 5: Protocol tasks (MQTT, USB host, OpenThread) - communication
|
||||
/// 4: USB serial TX - serial communication
|
||||
/// 3: ML inference (wake word) - background ML processing
|
||||
/// 1: Application (main loop, media pipelines, camera, UART RX) - baseline
|
||||
/// 0: Idle task (FreeRTOS system)
|
||||
///
|
||||
/// Guidelines:
|
||||
/// - Real-time audio I/O tasks need highest priorities to prevent glitches
|
||||
/// - Network/protocol tasks should be above application but below audio
|
||||
/// - Background processing (ML, media decoding) can run at low priority
|
||||
|
||||
/// Audio capture task priority (I2S microphone)
|
||||
/// Highest application priority - audio input cannot tolerate delays
|
||||
static constexpr UBaseType_t TASK_PRIORITY_AUDIO_CAPTURE = configMAX_PRIORITIES - 2;
|
||||
|
||||
/// Audio output task priority (I2S speaker)
|
||||
/// High priority - audio output needs consistent timing
|
||||
static constexpr UBaseType_t TASK_PRIORITY_AUDIO_OUTPUT = configMAX_PRIORITIES - 6;
|
||||
|
||||
/// Audio mixer task priority
|
||||
/// Medium-high - mixing is buffered but feeds real-time output
|
||||
static constexpr UBaseType_t TASK_PRIORITY_AUDIO_MIXER = configMAX_PRIORITIES - 10;
|
||||
|
||||
/// Protocol/communication task priority (MQTT, USB host, OpenThread)
|
||||
/// Above application tasks for responsive network handling
|
||||
static constexpr UBaseType_t TASK_PRIORITY_PROTOCOL = configMAX_PRIORITIES - 11;
|
||||
|
||||
/// USB serial TX task priority
|
||||
/// Slightly below protocol tasks
|
||||
static constexpr UBaseType_t TASK_PRIORITY_USB_SERIAL = configMAX_PRIORITIES - 12;
|
||||
|
||||
/// ML inference task priority (wake word detection)
|
||||
/// Background processing - can yield to communication tasks
|
||||
static constexpr UBaseType_t TASK_PRIORITY_INFERENCE = configMAX_PRIORITIES - 13;
|
||||
|
||||
/// Application task priority (main loop, media pipelines, camera, etc.)
|
||||
/// Baseline priority - just above idle task
|
||||
static constexpr UBaseType_t TASK_PRIORITY_APPLICATION = tskIDLE_PRIORITY + 1;
|
||||
|
||||
} // namespace esphome
|
||||
|
||||
#endif // USE_ESP32
|
||||
Reference in New Issue
Block a user