Rule help to trigger if value repeats a certain number of times

This one is a little tricky. I think the Latch design pattern would be the best approach. This looks like what you are trying to do. There are a couple of ways to implement this. I would probably use a timer.

var Timer colourtimer = null

rule "really changed?"
when
    Item Esp_Colour changed
then
    if(colourtimer == null || colourtimer.hasTerminated) {
        sendNotification("my_email", "New colour = " + Esp_Colour.state.toString)
        colourtimer = createTimer(now.plusMinutes(20), [|
            colourtimer = null
        ])
    }        
end

Theory of operation: If there is a currently running colourtimer, simply ignore all incoming color changes for 20 minutes. Otherwise send a notification and start colourtimer. The alert will be sent on the first change of the Esp_colour and ignore any other changes for the next 20 minutes. After the 20 minutes the assumption is the temp will have stabilized and still be the same color. The existence of the colourtimer is acting as a latch.

This isn’t quite what you are asking for but it is the simplest approach I can think of.

[Edit] Removed a Persistence based rule which upon review would not have worked.

The major error in your existing rule is that you set NewColour to Esp_Colour.state.toString and then immediately compare Esp_Colour.state.toString to NewColour. That condition will ALWAYS return true so that is why the else never executes. I think what you really want to do is define NewColour as a global var and only change it inside the if clause, not before. But even then this comparison is redundant because you already know that Esp_Colour has changed because of the rule trigger so there really is no need for NewColour or the if/else at all. The very fact that you are running the rule tells you the colour has changed.

But, since the rule only executes when the colour changes what you would really need to do is reschedule the Timer in the rule every time the colour changes. This will cause the timer to only go off after the colour has remained the same for 20 minutes. So here is a third approach using a Timer.

var Timer colourtimer = null

rule "really changed?"
when
    Item Esp_Colour changed
then
    if(colourtimer == null || coulourtimer.hasTerminated){
        colourtimer = createTimer(now.plusMinutes(20), [|
            sendNotification("my_email" , "New colour = " +Esp_Colour.state)
        ])
    }
    else {
        colourtimer.reschedule(now.plusMinutes(20))
    }
end

I would not use a counter to solve this because you have no guarantee how many times it will switch between one color and the next while it is at that transitional area.

Yet another approach would be to set a buffer range when changing the color of the light to avoid the rapid flapping. That would eliminate the bouncing entirely and is probably the “correct” solution. Your rule that sets Esp_Colour would look something like:

    var Number difference = (OutsideTemp.state as DecimalType) - (InsideTemp.state as DecimalType)
    var String newColour = Esp_Colour.state.toString
    switch(newColour){
        case "blue": { // current state is blue
            if(difference >= -1.5) newColour = "green"
        }
        case "green": { // current state is green
            if(difference <= -2) newColour = "blue"
            else if(difference >= 2) newColour = "orange"
        }
        case "orange": { // current state is orange
          if(difference <= 1.5) newColour = "green"
          else if(difference >= 5) newColour = "red"
        }
        case "red": { // current state is red
            if(difference <= 4.5) newColour = "orange"
        }
    }
    if(Esp_Colour.state.toString != newColour) EspColour.sendCommand(newColour)

Theory of Operation: There is a half a degree (assuming degrees C given your spelling of “colour”) buffer between colors. So, for example, if the temperature is going up it will transition from “blue” to “green” when the difference in temperatures is -1.5. But if the temperature is dropping, it will only transition from “green” to “blue” when the difference is -2. As long as the temperature fluctuations are less than half a degree it won’t cause the colour to keep changing and there is need for the rules above at all. Furthermore, this will enforce the state transitions between the colours (i.e. it can’t jump from blue to orange without going through a green state first).

You may need to experiment with how big or small you can make the buffer to avoid the bouncing. Just make the buffer larger than the typical jump you see between temperature readings and this should work.

This has been fun to think about. I need to turn these into more Design Patterns.

2 Likes