Commit Graph
436 Commits
Author SHA1 Message Date
J. Nick Koston 5c015ede77 Merge remote-tracking branch 'upstream/fix-flaky-host-mode-climate-basic-state' into integration 2026-05-03 18:20:34 -05:00
J. Nick Koston 37a44a8a6f [tests] Fix flaky host_mode_climate_basic_state by ignoring prior MEMORY state
The fixture shares the `host-climate-test` build dir with
host_mode_climate_control.yaml. When the control test runs first and
leaves the thermostat in HEAT mode, MEMORY restore on the next basic_state
boot picked up HEAT and the initial-state assertion failed
(`assert ClimateMode.HEAT == ClimateMode.OFF`).
2026-05-03 17:39:39 -05:00
J. Nick Koston 3d69169141 [climate] Fold ControlAction fields into a single stateless lambda (#16044) 2026-04-30 19:16:16 -05:00
J. Nick Koston 20743e3e9a Merge branch 'scheduler-pool-unbounded-freelist' into integration 2026-04-30 11:06:46 -05:00
J. Nick Koston 2a451cb870 [core] Strengthen scheduler-pool integration test with lower-bound check
Adds an assertion that the observed peak pool size exceeds the old
MAX_POOL_SIZE=5 cap. Without this, a silent regression that re-introduced a
small cap could pass the existing pool_full_count == 0 invariant. Phase 5 + 6
of the fixture schedule 8 + 10 same-component timeouts, so the peak should
comfortably exceed 5.

Address Copilot review feedback on PR.
2026-04-30 10:57:11 -05:00
J. Nick Koston f9b87d0ede [core] Replace scheduler pool vector with unbounded intrusive freelist
The fixed MAX_POOL_SIZE=5 cap was the source of the heap churn the pool was
meant to prevent: any device with more than 5 concurrent timers (e.g. a board
with 30+ LD2450 sensors) hit a steady-state oscillation of recycle->delete and
acquire->new on every loop iteration.

Replace std::vector<SchedulerItem*> with a singly-linked freelist threaded
through SchedulerItem::next_free, which shares storage with `component` via an
anonymous union (zero per-item overhead -- the component pointer is dead while
pooled). Drop the cap entirely: the freelist quiesces at the application's
natural concurrent-timer high-water mark, which is the working set the device
already needs while those timers are active.

No std::vector means no growth-doubling slack and no realloc copies during
warm-up. Caller of get_item_from_pool_locked_() must overwrite item->component
before unlocking (already true at the sole call site); nullptr remains a valid
live `component` value for SELF_POINTER items, so we cannot pre-clear it.
2026-04-30 10:42:46 -05:00
J. Nick Koston 8246b09445 Merge branch 'ota-watchdogmanager' into integration 2026-04-29 14:34:36 -05:00
J. Nick Koston c41f38e16d [scheduler] Add self-keyed timer API for callers without a Component (#16127) 2026-04-29 13:24:37 -05:00
J. Nick Koston e5b1991cf7 [fan] Add tests for fan.turn_on action field combinations (#16125) 2026-04-29 12:46:06 -05:00
J. Nick Koston 7fba57ce51 [valve] Add tests for valve.control action field combinations (#16126) 2026-04-29 12:45:30 -05:00
J. Nick Koston e6f86b343c Merge remote-tracking branch 'upstream/binary-sensor-filters-drop-component' into integration 2026-04-29 11:08:17 -05:00
J. Nick Koston e3fdea8ce1 [scheduler] Address Copilot feedback: %p type, NameType doc, test docstring
- Strip const for the %p varargs call (the format spec takes void*, not
  const void*; same representation everywhere but pedantically correct).
- Mention SELF_POINTER in the NameType discriminator comment.
- Update test docstring to match the actual const void * signatures.
2026-04-29 11:06:04 -05:00
J. Nick Koston ba34021e8e Merge remote-tracking branch 'upstream/sensor-filters-drop-component' into integration 2026-04-29 10:21:49 -05:00
J. Nick Koston 9745a3299e [scheduler] Address review feedback (const void *, %p cast, buffer size) 2026-04-29 09:34:45 -05:00
J. Nick Koston 241d7797e3 [scheduler] Add self-keyed timer API for callers without a Component 2026-04-29 09:18:09 -05:00
J. Nick Koston dc48f2df13 Merge remote-tracking branch 'origin/cover-action-bitmask' into integration 2026-04-29 07:41:16 -05:00
J. Nick Koston 01a4769a5d Merge remote-tracking branch 'origin/climate-control-action-bitmask' into integration 2026-04-29 07:41:08 -05:00
J. Nick Koston f7c8df8234 [cover] Address review feedback (const ref args, drop mask numbering) 2026-04-29 06:56:18 -05:00
J. Nick Koston a7a45a556b [climate] Address review feedback (const ref args, utf-8 byte length, comments) 2026-04-29 06:54:23 -05:00
J. Nick Koston 6f79312fa7 Merge branch 'dev' into cover-action-bitmask 2026-04-29 05:42:09 -05:00
J. Nick Koston 1ea7d20d98 Merge branch 'dev' into climate-control-action-bitmask 2026-04-29 05:42:01 -05:00
J. Nick Koston 5a33c50015 [light] Use constexpr template for DimRelativeAction transition_length (#16038) 2026-04-29 14:26:38 +12:00
J. Nick Koston 0d150dc57e [light] Use constexpr template for ToggleAction transition_length (#16037) 2026-04-29 14:25:18 +12:00
J. Nick Koston f72173550d Merge remote-tracking branch 'origin/webserver-list-entities-xmacro' into integration 2026-04-28 10:39:10 -05:00
Bonne EgglestonandJ. Nick Koston 52e8c50f45 [modbus] Split modbus_server from modbus_controller (#15509)
Co-authored-by: J. Nick Koston <nick+github@koston.org>
2026-04-28 10:21:25 -05:00
J. Nick Koston d26e29d89c Merge remote-tracking branch 'origin/light-toggle-action-constexpr-template' into integration 2026-04-27 06:46:06 -05:00
J. Nick Koston 4ed7956094 Merge remote-tracking branch 'origin/light-dim-relative-constexpr-template' into integration 2026-04-27 06:46:00 -05:00
J. Nick Koston 1135eeaf99 Merge remote-tracking branch 'origin/cover-action-bitmask' into integration 2026-04-27 06:45:48 -05:00
J. Nick Koston 9089cc968e [climate] Use heat_cool_mode (not auto_mode) to enable HEAT_COOL in test fixture 2026-04-27 05:42:18 -05:00
J. Nick Koston 6770a6b87f [cover] Address Copilot review on integration test fixture and macro comments 2026-04-27 05:39:21 -05:00
J. Nick Koston fdb183f772 [climate] Add auto_mode to thermostat fixture so HEAT_COOL is supported 2026-04-27 05:21:27 -05:00
J. Nick Koston 65b5615a31 [light] Use InitialStateHelper in DimRelativeAction integration test 2026-04-27 05:10:02 -05:00
J. Nick Koston 83f83c96a8 [light] Use InitialStateHelper in ToggleAction integration test 2026-04-27 05:09:27 -05:00
J. Nick Koston 497665f59f [climate] Use InitialStateHelper in integration test 2026-04-27 05:08:35 -05:00
J. Nick Koston a532f0adc9 [cover] Use InitialStateHelper in integration test 2026-04-27 05:08:08 -05:00
J. Nick Koston 2eac9f5121 [light] Add integration test for DimRelativeAction 2026-04-27 05:05:00 -05:00
J. Nick Koston e9ced485ea [light] Add integration test for ToggleAction 2026-04-27 05:04:28 -05:00
J. Nick Koston 66115c117a [climate] Add integration test for ControlAction 2026-04-27 05:03:57 -05:00
J. Nick Koston 3522eef8ee [cover] Add integration test for ControlAction/CoverPublishAction 2026-04-27 05:02:58 -05:00
J. Nick Koston e4f413adad [core] decouple main loop cadence from scheduler wake timing (#15792) 2026-04-21 14:48:21 +02:00
J. Nick Koston 574bdc9a00 Merge remote-tracking branch 'origin/decouple_scheduler_loop_cadence' into integration 2026-04-20 12:06:28 +02:00
J. Nick Koston 78aabf257f [core] wake_loop_threadsafe() forces a component-phase iteration
After the Phase A / Phase B split in this PR, an external producer that
called wake_loop_threadsafe() (MQTT RX, USB RX, BLE event, espnow,
camera, mWW, speakers, USB host/CDC, lwip socket, enable_loop_soon_any_context)
only got Phase A — the component phase stayed gated by loop_interval_,
so the producer's component loop() could be delayed by up to
loop_interval_ ms before draining its queued work. That breaks the
long-standing semantic of wake_loop_threadsafe().

Add a wake_request flag set by every wake_loop_* entry point and
exchange-cleared at the gate in Application::loop(). When the flag is
set, force Phase B regardless of loop_interval_.

Storage is conditional on the threading model:
  - ESPHOME_THREAD_MULTI_ATOMICS: std::atomic<uint8_t> (uint8_t, not
    bool, because GCC on Xtensa generates an indirect call for
    atomic<bool> ops — same workaround as scheduler.h)
  - ESPHOME_THREAD_SINGLE / ESPHOME_THREAD_MULTI_NO_ATOMICS: volatile
    uint8_t (8-bit aligned loads/stores are atomic on every supported
    MCU; the platform signal that follows wake_request_set provides the
    cross-thread/cross-core memory barrier)

Helpers (wake_request_set / wake_request_take) are always_inline so
IRAM_ATTR call sites stay in IRAM. Set BEFORE the platform signal so the
consumer is guaranteed to see the flag on its next gate check.

Adds an integration test that raises loop_interval_ to 2s, snapshots a
counting component's loop count, spawns a std::thread that calls
App.wake_loop_threadsafe() after 50ms, and asserts the count increments
inside a 500ms observation window. Without the fix the count would not
move for ~2s.
2026-04-20 11:52:56 +02:00
J. Nick Koston 93e99efc2d Merge branch 'dev' into decouple_scheduler_loop_cadence 2026-04-18 17:38:24 -05:00
J. Nick Koston a036a9eab3 Merge branch 'decouple_scheduler_loop_cadence' into integration 2026-04-18 17:33:39 -05:00
J. Nick Koston 7d12b984a8 [core] address review polish on main-loop decoupling
Doc and test updates from a code review of this PR:

- Correct the `tail_us == 0 on Phase A-only ticks` claim in the
  Application::loop() comment and the RuntimeStatsCollector::record_loop_active
  docstring. `loop_tail_start_us` is set to `loop_before_end_us`, and
  `loop_now_us` is sampled later, so `tail_us` on Phase A-only ticks is
  the small gate-check + record prefix — tiny but non-zero.
  (Also flagged by Copilot on application.h:623 and runtime_stats.h:45.)

- Call out ESP8266 as the floor case in the WDT_FEED_INTERVAL_MS margin
  table. Its soft WDT (~1.6 s) is the tightest margin at ~5x, so future
  changes to the constant need to preserve comfortable headroom there.

- Tighten the test lower bound at tests/integration/test_loop_interval_decoupling.py
  from `2 <= loop_delta <= 6` to `3 <= loop_delta <= 6`. Allowing 2 would
  let a >50% slowdown from the 4-in-2s nominal pass as CI jitter, which
  undermines the regression signal. 3 keeps the test honest while still
  absorbing realistic CI jitter.

- Add a second integration test
  (test_loop_interval_default_not_pulled_forward) that covers the inverse
  direction: at the default loop_interval_ with a fast scheduler item
  (5 ms — well under the old delay_time/2 = 8 ms floor), the component
  phase must still run at ~62 Hz, not the pre-fix ~128 Hz. This locks
  down the original 128 Hz → 62 Hz regression that motivated the PR.
2026-04-18 17:32:29 -05:00
J. Nick Koston ba775b7a0a Merge remote-tracking branch 'upstream/dev' into integration 2026-04-18 16:23:21 -05:00
J. Nick Koston 38d894dfe7 [ld2412] Fix flaky integration test race condition (#15833) 2026-04-18 08:17:22 -05:00
J. Nick Koston 6abb9fd815 Merge remote-tracking branch 'upstream/decouple_scheduler_loop_cadence' into integration
# Conflicts:
#	esphome/core/application.h
2026-04-18 07:12:36 -05:00
J. Nick Koston 43d98cb445 Merge remote-tracking branch 'upstream/dev' into decouple_scheduler_loop_cadence
# Conflicts:
#	esphome/core/scheduler.cpp
2026-04-17 09:33:59 -05:00
J. Nick Koston 162bd415ce Merge remote-tracking branch 'upstream/fix-delay-action-mutable-lambda' into integration 2026-04-17 08:36:08 -05:00