[interval] Fix startup behaviour (#9793)

This commit is contained in:
Clyde Stubbs 2025-07-24 08:03:36 +10:00 committed by GitHub
parent 0744abe098
commit f9534fbd5d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 13 additions and 14 deletions

View File

@ -1,6 +1,7 @@
#pragma once #pragma once
#include "esphome/core/component.h" #include "esphome/core/component.h"
#include "esphome/core/log.h"
#include "esphome/core/automation.h" #include "esphome/core/automation.h"
namespace esphome { namespace esphome {
@ -8,16 +9,12 @@ namespace interval {
class IntervalTrigger : public Trigger<>, public PollingComponent { class IntervalTrigger : public Trigger<>, public PollingComponent {
public: public:
void update() override { void update() override { this->trigger(); }
if (this->started_)
this->trigger();
}
void setup() override { void setup() override {
if (this->startup_delay_ == 0) { if (this->startup_delay_ != 0) {
this->started_ = true; this->stop_poller();
} else { this->set_timeout(this->startup_delay_, [this] { this->start_poller(); });
this->set_timeout(this->startup_delay_, [this] { this->started_ = true; });
} }
} }
@ -25,7 +22,6 @@ class IntervalTrigger : public Trigger<>, public PollingComponent {
protected: protected:
uint32_t startup_delay_{0}; uint32_t startup_delay_{0};
bool started_{false};
}; };
} // namespace interval } // namespace interval

View File

@ -373,11 +373,10 @@ bool Component::has_overridden_loop() const {
PollingComponent::PollingComponent(uint32_t update_interval) : update_interval_(update_interval) {} PollingComponent::PollingComponent(uint32_t update_interval) : update_interval_(update_interval) {}
void PollingComponent::call_setup() { void PollingComponent::call_setup() {
// init the poller before calling setup, allowing setup to cancel it if desired
this->start_poller();
// Let the polling component subclass setup their HW. // Let the polling component subclass setup their HW.
this->setup(); this->setup();
// init the poller
this->start_poller();
} }
void PollingComponent::start_poller() { void PollingComponent::start_poller() {

View File

@ -17,6 +17,8 @@ static const char *const TAG = "scheduler";
static const uint32_t MAX_LOGICALLY_DELETED_ITEMS = 10; static const uint32_t MAX_LOGICALLY_DELETED_ITEMS = 10;
// Half the 32-bit range - used to detect rollovers vs normal time progression // Half the 32-bit range - used to detect rollovers vs normal time progression
static constexpr uint32_t HALF_MAX_UINT32 = std::numeric_limits<uint32_t>::max() / 2; static constexpr uint32_t HALF_MAX_UINT32 = std::numeric_limits<uint32_t>::max() / 2;
// max delay to start an interval sequence
static constexpr uint32_t MAX_INTERVAL_DELAY = 5000;
// Uncomment to debug scheduler // Uncomment to debug scheduler
// #define ESPHOME_DEBUG_SCHEDULER // #define ESPHOME_DEBUG_SCHEDULER
@ -100,9 +102,11 @@ void HOT Scheduler::set_timer_common_(Component *component, SchedulerItem::Type
// Type-specific setup // Type-specific setup
if (type == SchedulerItem::INTERVAL) { if (type == SchedulerItem::INTERVAL) {
item->interval = delay; item->interval = delay;
// Calculate random offset (0 to interval/2) // first execution happens immediately after a random smallish offset
uint32_t offset = (delay != 0) ? (random_uint32() % delay) / 2 : 0; // Calculate random offset (0 to min(interval/2, 5s))
uint32_t offset = (uint32_t) (std::min(delay / 2, MAX_INTERVAL_DELAY) * random_float());
item->next_execution_ = now + offset; item->next_execution_ = now + offset;
ESP_LOGV(TAG, "Scheduler interval for %s is %" PRIu32 "ms, offset %" PRIu32 "ms", name_cstr, delay, offset);
} else { } else {
item->interval = 0; item->interval = 0;
item->next_execution_ = now + delay; item->next_execution_ = now + delay;