# Test for PR #11676 bug: wait_until timeout when triggered mid-component-loop # This demonstrates that App.get_loop_component_start_time() is stale when # wait_until is triggered partway through a component's loop execution esphome: name: wait-mid-loop host: api: actions: - action: test_mid_loop_timeout then: - logger.log: "=== Test: wait_until triggered mid-loop should timeout correctly ===" # Reset test state - globals.set: id: test_complete value: 'false' # Trigger the slow script that will call wait_until mid-execution - script.execute: slow_script # Wait for test to complete (should take ~300ms: 100ms delay + 200ms timeout) - wait_until: condition: lambda: return id(test_complete); timeout: 2s - if: condition: lambda: return id(test_complete); then: - logger.log: "✓ Test PASSED: wait_until timed out correctly" else: - logger.log: "✗ Test FAILED: wait_until did not complete properly" logger: level: DEBUG globals: - id: test_complete type: bool restore_value: false initial_value: 'false' - id: test_condition type: bool restore_value: false initial_value: 'false' - id: timeout_start_time type: uint32_t restore_value: false initial_value: '0' - id: timeout_end_time type: uint32_t restore_value: false initial_value: '0' script: # This script simulates a component that takes time during its execution # When wait_until is triggered mid-script, the loop_component_start_time # will be stale (from when the script's component loop started) - id: slow_script then: - logger.log: "Script: Starting, about to do some work..." # Simulate component doing work for 100ms # This represents time spent in a component's loop() before triggering wait_until - delay: 100ms - logger.log: "Script: 100ms elapsed, now starting wait_until with 200ms timeout" - lambda: |- // Record when timeout starts id(timeout_start_time) = millis(); id(test_condition) = false; # At this point: # - Script component's loop started 100ms ago # - App.loop_component_start_time_ = time from 100ms ago (stale!) # - wait_until will capture millis() NOW (fresh) # - BUG: loop() will use stale loop_component_start_time, causing immediate timeout - wait_until: condition: lambda: return id(test_condition); timeout: 200ms - lambda: |- // Record when timeout completes id(timeout_end_time) = millis(); uint32_t elapsed = id(timeout_end_time) - id(timeout_start_time); ESP_LOGD("TEST", "wait_until completed after %u ms (expected ~200ms)", elapsed); // Check if timeout took approximately correct time // Should be ~200ms, not <50ms (immediate timeout) if (elapsed >= 150 && elapsed <= 250) { ESP_LOGD("TEST", "✓ Timeout duration correct: %u ms", elapsed); id(test_complete) = true; } else { ESP_LOGE("TEST", "✗ Timeout duration WRONG: %u ms (expected 150-250ms)", elapsed); if (elapsed < 50) { ESP_LOGE("TEST", " → Likely BUG: Immediate timeout due to stale loop_component_start_time"); } id(test_complete) = false; }