Writing motion pistons Pt 2

In a previous tip, we explored motion pistons

We were left with some problems in the last piston of that tip:

  • 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?

Here is a piston to deal with these issues and review of its operation:


This piston can receive events for:

  • motion:active and motion:inactive

  • switch:on and switch:off

  • wakeup (time) events when the piston requests a wait

Few things to notice:

  • there is only 1 motion device in use, and one bulb/switch in use. This is important for this particular piston as less devices means less different states and events the piston deals with.

How it works

  • when the piston turns on the light due to motion, it sets the local variable programatic to TRUE

    • this is how the piston knows if it should later turn off the light (vs. someone else turned it on, so they should turn it off)
  • The piston has to see events for the light coming on / off, so it can determine if this piston turned it on (and therefore should turn it off) vs. something turned it on and this piston should leave it alone until it is turned off.

When the light is off, the piston resets state (the variable programatic) so it can turn the light on if motion occurs later

This piston relies on the variable programatic holding its value across runs (which it does so long as you do not set a value to it in the define section)

Some complexity to watch:

  • if the piston is changed to have multiple motion sensors (ie a or b goes active), or has multiple bulb/switches to turn on/off and monitor:

    • at one level, this is easy to add by using device variables for motionDevices and switchDevices.

      • however :there are now more events/states coming into the piston (to evaluate)

        • the if statements have to be adjusted for any changes to active for motion and all are inactive. (changes is a trigger; is/are are condition comparisions)

        • the switch check statements (line 24, 47 above) have to be adjusted to all are off (notice this needs to be a condition comparison (for line 47), not a trigger; as multiple changes events CANNOT occur at the same time)

          • this can cause you to need to create a separate trigger aggregation for the switch devices (per other tips on trigger aggregation) or move entirely to condition comparisons

So here is a piston that deals with multiple devices, and also displaying piston state accurately to what it is or is not controlling

Do notice

  • This piston is only using condition comparisons, and relies on webCoRE subscribing to condition comparison devices if there are no trigger comparisons.

So what is going on?

  • the first 2 if statements (lines 28, 51) are dealing with correctly noting if things are manually being operated so that the state is displayed correctly

    • it is complicated in that there could be multiple switch events and motion events that occur in sequential order to complete an on or off operation

    • Because we may be monitoring two or more lights/switches and two or more motion sensors, it means when we turn on or turn off the lights there will be multiple events coming back to this piston - (light 1 going on, light 2 going on, ... or light 1 going off, light2 going off...) as well as multiple motion:active and motion:inactive events. These could confuse the piston logic for state tracking so the offPending variable is there to ensure accurate operation.

  • the 3rd if (line 61) is dealing with turning off the lights

  • the 4th if (line 76) is dealing with turning on the lights


Reserved for future

Download the Hubitat app