Writing motion pistons with webCoRE Pt1 and Task Cancellation Policy

This example reviews several motion piston options and discusses the ups and downs of each one.

As most of us know, in home automation, events happen (be they sensors, or time based), and automations react to these events to complete some function.

Let's look at a simple automation, that turns on a switch based on motion:

Few notes:

  • this piston uses a single trigger comparison (changes) to turn on a light

  • this piston is incomplete, in that it will turn on a light, but the light is not automatically turned off.

  • How does 'changes' work?

    • When webCoRE initializes a piston (after you edit/save a piston or resume it), it does a dummy run through - primarily to initialize current variable and device states the piston is using.

    • When the piston runs based on an event, how does changes work?

      • because webcore has previous values cached, when a 'changes' comparison executes webcore can compare the previous run's value to the value now to determine if 'changes' is true or false

      • This is why it is important that trigger comparisons that track values/state are crossed on each execution

  • this piston could have been written using condition comparison like is and if there are no other triggers in the piston it would operate similar to the trigger comparison changes because of webCoRE's automatic subscriptions to condition comparisons if there are no trigger comparisons.


So here is a piston to deal with on and off:

In this case, once the motion ends, the light will be turned off in 2 minutes (so long as no other motion occurs)

  • This piston can receive 2 events motion:active and motion:inactive (the lightning bolts show event subscriptions) that drive execution

    • It can also receive a wakeup from its wait request when the piston requests a wait .

so how does this execute:

  1. Let's assume the starting state is the bulb is off, and the motion is inactive

Execution 1

  1. A motion event occurs, so the wakeup event is motion:active, and the piston begins execution with the $currentEvent being motion with a value of active

  2. the if at line 18 evaluates to TRUE as the motion did change to active because of this event/execution

    1. The statements ('task' as it is an action) at line 21 execute and turn on the light
  1. The piston continues execution with the if at line 27, which evaluates to FALSE (because the event was motion:active)

  2. the piston exits as it ran to the end

Result: motion happened and we turned on the light.


Execution 2

At some point, the motion ends, and the wakeup event is motion:inactive. The delay for this event depends on the settings of the motion device being used. Some report quickly and others may have a delay before reporting no more motion (this is the device in question, not webCoRE)

  1. A motion event occurs, so the wakeup event is motion:inactive, and the piston begins execution with the $currentEvent being motion with a value of inactive

  2. the if at line 18 evaluates to FALSE as the motion did NOT change to active

  1. The piston continues execution with the if at line 27, which evaluates to TRUE (because the event was motion:inactive)

    1. The tasks at line 30 execute

    2. The wait statement causes the piston to pause for 2 minutes asking to resume right after the wait

    3. the piston now exits, with a timer to resume at line 34 (after the wait) in 2 minutes

Result - we are waiting for 2 minutes (or until something else happens)


Execution 3

After 2 minutes the timer fires, and resumes the piston at line 34 (it resumed with most of the state of when it requested the wakeup)

  1. the off command is sent

  2. the piston continues execution to the end and exits (because there are no more statements to run)

Result: Light is turned off


There is an alternate execution 3A that could have occurred:

During the 2 minute wait, another motion:active event occurs

  1. This will start the piston from the top, with the event motion:active (very much like Execution 1 )

  2. the if at line 18 evaluates to TRUE as the motion did change to active because of this event/execution

    1. The task at line 21 execute and turn on the light. (webCoRE by default will see the light is already on so it will optimize the on command)
  1. The piston continues execution with the if at line 27, which evaluates to FALSE (because the event was motion:active)

    • webCoRE will notice it had the timer running for the wait (from an earlier run) that was controlled by this if statement (line 27), and it will cancel this timer because this if statement evaluated FALSE (where when the timer was set, it was TRUE). (the condition changed state, so it cancelled the timer ( wait ) controlled by this if statement)

    • This cancel is controlled by Task Cancellation Policy (which can be found in the IDE if you select the if statement, and the gear icon) Cancel tasks on condition state change is the default

  2. the piston exits as it ran to the end

Result: Light is on, just like after Execution 1


later a motion:inactive occurs, and things operate like Execution 2

So the default of Task Cancellation policy in this case did exactly what we wanted.


Possible problems with this piston:

  • What if I turn on the light manually (and I need it on because I'm working but not moving a lot)?

    • odds are the motion sensor noticed you doing this (and may have beat you to it)
    • when the motion stops, the light is going to go off
  • What if I don't want the light so bright at night?

See the next tip for piston solutions for this.


References:

https://wiki.webcore.co/Task_Cancellation_Policy

6 Likes

Reserved for updates

Download the Hubitat app