mirror of
https://github.com/esphome/esphome.git
synced 2026-09-11 23:37:34 +00:00
a0ac226e6c0d6888998cbda2b857c72169e042fe
Restructures Application::loop() into two independent phases to stop the scheduler from silently pulling the component loop cadence forward. Before: Application::loop() bounded its sleep by min(loop_interval_ - elapsed, next_schedule_in()) with a delay_time/2 floor. Any scheduler item due sooner than loop_interval_/2 dragged the whole component phase with it. On a typical ESP32 config with default loop_interval_=16ms, combined scheduler activity from api / esp32_ble / esp32_ble_tracker / debug was keeping every component's loop() running at ~128 Hz instead of the documented ~62 Hz. This has become more visible recently as more components convert to PollingComponent (which uses set_interval internally) and more in-tree code uses set_interval / set_timeout directly. Adding or removing any scheduled item silently changed every other component's loop cadence. App.set_loop_interval() for power savings was also silently defeated. After: - Phase A (every tick): drain wake notifications, run scheduler.call(), feed WDT - Phase B (gated by loop_interval_ or HighFrequencyLoopRequester): iterate registered components and update last_loop_ Sleep = min(time-until-next-component-phase, next_schedule_in()). When a scheduler event wakes us early, Phase A services it and the component phase stays gated independently. loop_interval_ is now a true minimum interval between component phases. The delay_time/2 floor is removed. Any legitimate need to wake faster than loop_interval_ has proper mechanisms: - HighFrequencyLoopRequester for sustained fast-loop needs - Application::wake_loop_threadsafe() from any context (new in 2026.4.0) for one-shot wake-on-event Also guards against set_interval(0) misuse — it asks the main loop to spin forever, which was never the intended API. Warns at creation time pointing authors at HighFrequencyLoopRequester. set_timeout(0)/defer() is unaffected; zero-delay one-shots remain legitimate. Runtime stats: process_pending_stats is now called on every tick (not just when the component phase runs) so log_interval_ isn't quantized to the component-phase cadence. Added an inline fast-path gate in runtime_stats.h that early-outs unless now >= next_log_time_, keeping Application::loop() slim; the log_stats_ work stays out-of-line. Ordering constraints preserved: - defer() callbacks still FIFO before components same-tick (Phase A runs before Phase B) - Scheduled items still execute before components when both due - Scheduled callbacks still run on main thread only - loop_component_start_time_ is still set fresh at each component's loop - WDT is still fed at least once per tick
Description
ESPHome is a system to control your ESP8266/ESP32 by simple yet powerful configuration files and control them remotely through Home Automation systems.
Readme
Multiple Licenses
591 MiB
Languages
C++
55.8%
Python
43.6%
C
0.3%
JavaScript
0.2%
