Add on-delay and run time to follow binds #133

Merged
Claude merged 4 commits from feat/yn-16-follow-timing into feat/yaml-nodes 2026-10-16 09:30:17 +00:00
Collaborator

ctrl::Bind gains onDelayMs and runTimeMs. A follow bind turns its target on once the source has been on for the delay, and off once every follow source has been off for the run time; a source turning on again inside the run time holds the target on. A pending turn-on is dropped if the mode has since disabled the bind or its gate has closed. A stale source still applies failsafe immediately. Zero on both is today's behaviour; toggle binds ignore both.

YAML follow binds take on_delay and run_time: whole seconds 0-6553, or the label of a same-node duration setting (copied into the bind at the top of loop). Toggle binds reject them. Schema, README, spec 9.5 and the C3 fixture are updated.

Tested: native 616 -> 628 (existing bind tests untouched), Python 75 -> 78; pio run passes.

YN-16

`ctrl::Bind` gains `onDelayMs` and `runTimeMs`. A follow bind turns its target on once the source has been on for the delay, and off once every follow source has been off for the run time; a source turning on again inside the run time holds the target on. A pending turn-on is dropped if the mode has since disabled the bind or its gate has closed. A stale source still applies failsafe immediately. Zero on both is today's behaviour; toggle binds ignore both. YAML follow binds take `on_delay` and `run_time`: whole seconds 0-6553, or the label of a same-node `duration` setting (copied into the bind at the top of `loop`). Toggle binds reject them. Schema, README, spec 9.5 and the C3 fixture are updated. Tested: native 616 -> 628 (existing bind tests untouched), Python 75 -> 78; `pio run` passes. YN-16
Add on-delay and run time to follow binds
All checks were successful
Build and test / build (pull_request) Successful in 5m22s
Build and test / release (pull_request) Has been skipped
122416a3cb
rob force-pushed feat/yn-16-follow-timing from 122416a3cb
All checks were successful
Build and test / build (pull_request) Successful in 5m22s
Build and test / release (pull_request) Has been skipped
to df07a0f825
Some checks failed
Build and test / release (pull_request) Has been cancelled
Build and test / build (pull_request) Has been cancelled
2026-10-16 09:24:37 +00:00
Compare
Add on_delay and run_time to YAML follow binds
Some checks failed
Build and test / release (pull_request) Has been cancelled
Build and test / build (pull_request) Has been cancelled
7f0da75a55
Claude left a comment

Two timing gaps in follow(), one weak test. Nothing else to act on.

Two timing gaps in follow(), one weak test. Nothing else to act on.
@ -57,0 +70,4 @@
static void follow(Bind& bind, bool sourceOn, const Binds& binds, uint32_t now) {
const bool anyOn = binds.anyFollowSourceOn(bind.target);
const bool delays = sourceOn ? bind.onDelayMs > 0 && !bind.target->isOn() : bind.runTimeMs > 0 && !anyOn && bind.target->isOn();
bind.pending = delays;
Author
Collaborator

Bypasses the on-delay with two sources. Source B rises (its on-delay pending, target off), then source A clears: sourceOn is false, anyOn is true, so delays is false and setOn(true) fires at once. B's delay is skipped. Fix: in the clear branch, if the target is off and another source is on, leave it to that source's pending turn-on instead of calling setOn(anyOn). Also, a second source rising while pending re-arms dueMs and stretches the delay; keep the earlier dueMs if already pending-on.

Bypasses the on-delay with two sources. Source B rises (its on-delay pending, target off), then source A clears: sourceOn is false, anyOn is true, so delays is false and setOn(true) fires at once. B's delay is skipped. Fix: in the clear branch, if the target is off and another source is on, leave it to that source's pending turn-on instead of calling setOn(anyOn). Also, a second source rising while pending re-arms dueMs and stretches the delay; keep the earlier dueMs if already pending-on.
Author
Collaborator

Per-bind run time: two binds on one target with different run_time. If the bind with run_time 0 clears last, setOn(false) fires immediately and the other bind's run time is ignored. Either document that the last-clearing bind's run_time wins, or reject mixed values.

Per-bind run time: two binds on one target with different run_time. If the bind with run_time 0 clears last, setOn(false) fires immediately and the other bind's run time is ignored. Either document that the last-clearing bind's run_time wins, or reject mixed values.
@ -514,0 +656,4 @@
TEST_ASSERT_FALSE(light.isOn());
}
void test_a_quiet_source_applies_failsafe_without_waiting_for_the_run_time() {
Author
Collaborator

This test passes without the new bind.pending = false in Binds:➿ failsafe turns the light off, then the stale pending-off fires setOn(false), which does nothing. Test the case the line exists for: source rises with an on_delay, goes quiet before it elapses, then tick past the delay and assert the light stays off.

This test passes without the new `bind.pending = false` in Binds::loop: failsafe turns the light off, then the stale pending-off fires setOn(false), which does nothing. Test the case the line exists for: source rises with an on_delay, goes quiet before it elapses, then tick past the delay and assert the light stays off.
Keep a pending turn-on out of the follow sources that count as on
All checks were successful
Build and test / build (pull_request) Successful in 2m3s
Build and test / release (pull_request) Has been skipped
894f7113d5
Claude merged commit 91003b71fe into feat/yaml-nodes 2026-10-16 09:30:17 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
rob/CampervanControlSystems!133
No description provided.