Event "frequency" trigger


#1

1) Give a description of the problem
I’m trying to create a piston that will send me a notification when my toddler wakes up from her nap. The trigger will be both sound and motion detection from the nursery wyze cam pushing a momentary button tile via IFTTT. The issue is that I only want the alert sent if the button has been pressed X times in the last X timeframe. This is to prevent false alerts when she makes the occasional noise or repositions herself in her sleep. I only want the alert when a consistent number of events (button presses) are registered within a short time frame, say 10 minutes.

2) What is the expected behaviour?
I haven’t tried the piston yet because I couldn’t figure out how to configure the trigger. I’m also wondering if folks have a better idea of how to do this or know any limitations to wyze came motion cool-down periods or lag time to ST that might cause problems.

Thanks!


How to make a piston fire only if switch is not already on
#2

Perhaps something like:

integer movements;

If button is pressed                                          <--trigger from IFTTT
    set variable movements=movements+1
end if
if movements is greater than 5 then                <--condition count > x
   Send message
   set variable movements=0
end if
every 15 minutes                                             <--trigger to reset counter
    set variable movements=0
end every

#3

Brilliant. I’ll try this. I’m sure there will need to be a lot of parameter tuning to deal with motion detection cool-downs and the threshold of my toddler’s “awake state” (can she be a device too?)


#4

The counting and the limiting alerts is fairly simple…

I think the real challenge will be in determining at what point to reset the count.


IE: Let’s assume for a moment that it resets every fifteen minutes, with a > 5 count alert…

A total of 10 triggers may be ignored if they happen while straddling the 15 minute mark.
(IE: 5 could happens at the 14 min mark, and 5 happen a minute later, with no alert sent until the 11th)

To truly capture 6 events within a 15 minute window, I think you’d need rolling variables, and a whole slew of code. (IE: each event would need to calculate how long ago the previous sixth event happened)

Alternatively, if you would be OK with occasionally 10 triggers NOT sending an alert, then @guxdude’s suggestion will save you a lot of frustrations, LOL


Edited my numbers to better reflect the example


#5

I use the same logic for our laundry dryer since I don’t have a power meter on the line. I just count how many times my vibration sensor triggers in a set amount of time and just reset the counter after so many minutes.


#6

How about this?

integer movements;
datetime firstMovement

If button changes to pressed                                          <--trigger from IFTTT
    set variable movements=movements+1
    if movements is equal to 1                                           <--condition for first movement
        or
       ($now-firstMovement)/60000 is greater then 15       <--condition for too much time elapsed
    then
         set variable firstMovement=$now
         set variable movements=1
    end if
end if
if movements is greater than 5 then                <--condition count > x
   Send message
   set variable movements=0
end if

#7

I like where you are going with this @guxdude, but there are still holes in that logic.

Take this example:

  • 12:00 = 1st trigger (Set time)
  • 12:12 = 2nd trigger (count=2)
  • 12:13 = 3rd trigger (count=3)
  • 12:14 = 4th trigger (count=4)
  • 12:15 = 5th trigger (count=5)
  • 12:16 = 6th trigger (past time, set count to 1 & Set new time)
  • 12:17 = 7th trigger (this is the 6th trigger in 5 minutes, but no alert will be sent because the count is only 2)

In other words:
The 6th trigger needs to check the time of the 1st trigger
The 7th trigger needs to check the time of the 2nd trigger
The 8th trigger needs to check the time of the 3rd trigger
etc


#8

Ahh. Very good. Yes, without a sliding window, it still won’t hold up against all cases. In fact this second logic may be worse as you would expect sporadic movement.

EDIT: Use of a datetime list should work but you would have to shift the values each time there was a new movement. As always, doable but with increasing complexity.


#9

Yes… If the logic was “greater than 5” for an alert, then we’d need to keep at least 6 dateTime variables. (the previous 5 triggers, plus the current one) Shifting them over once each execution, and letting the oldest data drop off.

With this method, we’d only have to compare {time1} with {time6} at each event.


Unfortunately, it’s not a very dynamic approach though.

If you later decided to switch to “greater than 8”,
then new lines of code would have to be added for each extra count.


#10

I think it could be made flexible. I would think you could define numberOfMovements=X and then store numberOfMovements+1 values and always compare item 0 with item numberOfMovements.


#11

Everything… *grunt* … can be made…*groan* … flexible… LOL


All jokes aside, there would still need to be an extra variable created for each time stored though…

(unless you just made extra at time of creation)


#12

Here is what I was talking about. You can change the variables for the number of events and time limit and it should trigger appropriately. I didn’t have a push button so used a simulated switch and had to turn it off but should work in any situation. It is little off in that it requires n+1 events within the time limit to go off but that could easily be fixed.


#13

Ahh yes… Using an array… but then you have the other issue with removing extraneous elements later. That is not such a pleasant experience here in webCORE.

Do you know any tricks for this?
(IE: going from an 8 array down to a 5, and clearing 5, 6 and 7)


#14

Yes, that is a pain in webcore. No tricks other than what I saw you mention about editing the variable. A pain. Hopefully you know what you want when you get started but, in reality, you can always ignore the extra values. Not pretty but it will work just fine.(webcore won’t look if you don’t. haha)


#15

Maybe ignoring the bogus data is the best way… I think your loop will ignore the higher numbers if you reduce the number of events. Of course, (playing devil’s advocate), if you later decide to increase to a higher number, then those ancient numbers will come rolling back in for the next X events…

… but I guess that is nitpicking now, LOL

There might not be one perfect solution…
(as is most things innovative)
… but man, what an journey!


#16

A quick press of the test but will always initialize however many values you need.


#17

OK, I am tracking with you…

  • Edit piston
  • Set it to a high number
  • Save the piston
  • Press Test to clear
  • Edit piston again
  • Set to correct number
  • Save piston
  • Back in business

How true… :sunglasses:


#18

Should have mentioned, I did come across one shortcut. Perhaps others already know this but it was pretty simple to reset the lists by taking a snapshot, deleting the piston and then adding it back in with the recover code. That was quick!

One other lesson from this quick project: you can’t do any math in the ‘list index’ field. I had to create the variable ii=$index+1 for the loop shifting the values. Maybe there is a way to do it but I couldn’t get webcore to interpret ‘$index+1’ but I could assign that to ii and use ii for the list index.


#19

Yeah, this one drove me crazy last year… It only likes [#] in this slot.