OH3 rules, percentage change from previousState

Hi there

I’m trying to trigger on a change of more than X percentage from the previous state, so to do this I need both new and previous state values.

I’m using OpenHabian OH3 on a Pi 4.

I have a rule:

When
Item state changes
(both Previous State and State are empty)
Then
Run Rule (pointed to my script)

My test script is:

logInfo("testing", "Energy changed from " + TPLink_Power.previousState(true, "rrd4j").state + " to " + TPLink_Power.state.toString)

This always returns:
rrd4j does not allow querys without a begin date, unless order is descending and a single value is requested.

If I change true to false both values are always the same even though I can see from the log that they did change.

Rd4J is the only persistence service running; I didn’t configure anything so it’s just what comes out of the box.

How do I get the previous value - OR is there a way to trigger when an item has changed by XX percentage in a given direction?

Thanks!

previousState will never be reliable unless you persist everyChange (which is not usual with rrd4j). Even then I’m not sure it works at all well with rrd4j.

The rule trigger event provides some implicit variables -

newState looks useful.

previousState exists if you have a change type trigger.

What makes you think they are ‘empty’?

No, you must have a simple trigger and do any comparisons withing the body of the rule.

Thank you for your help.

Where I say Previous State and State are empty, I meant I have left them null in the Rules UI - I could have been clearer there!

So it sounds like while previousState exists if there’s a change type trigger (and I am getting a value here) it’s not going to be the right thing with rrd4j persistence.

I will test newState in case that returns something interesting but otherwise I guess I need to use a different persistence for items I want to use in rules that will depend on the new value being different by a percentage to the previous value.

What would be ‘best practice’ to achieve this? Rrd4j is working well for everything so far, so I don’t want to add more services than I need.

How about an second item just to hold the last value? On change of the monitored item I could compare the current value with the stored one and do whatever I want the rule to do, and finally update the ‘last value’ item with the current value. That looks like it’d work on paper but feels like I’m over engineering something that might already be possible more simply.

cheers

I think you misunderstand the implicit variables.

previousState is a stand alone variable, not relying on any persistence at all. It contains the previous state of the Item that triggered the rule.
By implication, it only exists if the rule was triggered by an “changed” trigger.
Usage -
logInfo("test", "prev " + previousState.toString)

newState is a stand alone variable that contains the current state of the Item that triggered the rule. The same as someItem.state, it is of use e.g.with group based triggers where you might not easily know who triggered the rule.
logInfo("test", "now " + newState.toString)

someItem.previousState() is unrelated to the above, it is a persistence method of each Item.

Thinks; this might not be the right approach, depending on what you are trying to do. What happens if you get ten 1% increases, do you care?

1 Like

That all makes perfect sense, thanks again.

I think maybe it’s because I’m calling a script from the rule rather than embedding the script IN the rule.

previousState always returns the same value in my tests but not the same string:

Energy changed from 31/01/2021, 11:52: TPLink_Power -> 2042.263 to 2042.263 W

I will move the script to the rule script editor instead.

EDIT:

Same response there. With the script contained within the rule UI script editor the output to logging is the same. previousState contains the same value as state

Could you show us what you are doing? previousState (the implicit variable) cannot be the same as the triggering Item state when you use a ‘changed’ rule trigger.
Are you using the release version of OH3.0 ?

Yes, release version of OpenHabian. Straightforward build.

Rule:



Module:

image




Script in ‘EmailSpaEnergy’ as shown above:

logInfo("testing", "Energy changed from " + SpaTPLink_Power.previousState + " to " + SpaTPLink_Power.state)




Output:

Energy changed from 31/01/2021, 11:52: SpaTPLink_Power -> 2042.263 to 2042.263 W

Oh right, it’s the redirection. The implicit variables are about what triggered the rule that you use them in i.e.the second rule in this case.

I get the same result when the script is in the rule itself though, is that the same reason?

Ah, here we go.
As advised, previousState (the implicit variable) is a stand alone variable.

logInfo("testing", "Energy changed from " + previousState + " to "

anyItem.previousState() is a persistence method and is something different.

Ah - I see what you mean now!

Perfect, that works exactly as I expect.

Thank you very much!

I’m still a bit concerned about what you are trying to achieve, rather then the mechanism.
If your sensor reports changes at say 1% intervals you will never detect a 10% change by using any kind of previousState

A spa turns its heater on periodically to maintain water temperature. The smart plug it’s connected to posts power consumption every 30 seconds which is very slightly different every time, usually by < 1 W.

When the heater comes on the power consumption jumps from c. 45 W to about 2.2kW, sometimes in two or three steps, but the first is always the largest. By looking for an large increase or decrease, I can monitor the heater activity.

I found the UI-based rule caused memory heap exceptions (or some combination of what I was doing with Math within the rule) so I moved it to a .rules file.

The key was still getting that previousState value, thanks again!

Not perfectly elegant but it works - mostly. I opted for a couple of value conditions rather than a percentage change, after a few tests, which results in more than one notification sometimes. For example here, there are two notifications because the increase was > 900 twice in a row.

00:46:32.666 [INFO ] [.openhab.core.model.script.spaEnergy] - Spa energy from 43.649 W to 1165.208 W, difference 1121
00:46:32.680 [INFO ] [.openhab.core.model.script.spaEnergy] - The spa heater turned on
00:47:02.715 [INFO ] [.openhab.core.model.script.spaEnergy] - Spa energy from 1165.208 W to 2168.106 W, difference 1002
00:47:02.729 [INFO ] [.openhab.core.model.script.spaEnergy] - The spa heater turned on
00:47:32.957 [INFO ] [.openhab.core.model.script.spaEnergy] - Spa energy from 2168.106 W to 2040.815 W, difference 127
00:48:03.166 [INFO ] [.openhab.core.model.script.spaEnergy] - Spa energy from 2040.815 W to 2039.934 W, difference 0

This is the rule:

rule "Spa Energy Change"

when
    Item SpaTPLink_Power changed
then
    var int energyDiff = Math.abs(((SpaTPLink_Power.state as Number) - (previousState as Number)).intValue)
    
    logInfo("spaEnergy", "Spa energy from " + previousState + " to " + SpaTPLink_Power.state + ", difference " + energyDiff)

    var String emailMessage = null
    
    if ((energyDiff > 1000) && ((SpaTPLink_Power.state as Number) > 900))
    {      
        emailMessage = "The spa heater turned on"    
    }
    else if ((energyDiff > 1000) && ((SpaTPLink_Power.state as Number) < 900))
    {
        emailMessage = "The spa heater turned off"        
    }

    if (emailMessage !== null)
    {
        logInfo("spaEnergy", emailMessage)
        var String messageSubject = "Spa heater update"
        var String messageBody = emailMessage
        val mailActions = getActions("mail","mail:smtp...etc")
        mailActions.sendMail.... etc
    }
end

Any tips to improve this very welcome!

1 Like