Number changes to trigger rule

  • Platform information:
    • Hardware: RPi 3
    • OS: Raspbian
    • Java Runtime Environment:
    • openHAB version: 2.5.2

Hi,

Apologies in advance as I think this is probably a very obvious one, but I can’t get this to work.
I have two very simple rules that should trigger when the rain volume collected by a weather station changes (open weather binding) to indicate that’s it’s either started to rain, or stopped raining.

The actual Item value changes when it should (I have this persisting to a db each time it changes and I see this getting updated as expected) but the rules don’t fire when I would expect them to.There are no errors in the logs.

If I alter the rule such that is triggered by :-

    Item localCurrentRainVolume changed

instead of:-

    Item localCurrentRainVolume changed from 0

then the rule fires (but I then can’t tell if it’s just started, or stopped raining, as the change could be from some non-zero value to another non-zero value)

Any thoughts? Is there an obvious synax error?
Thanks
Steve

Thing:-

Bridge openweathermap:weather-api:api "OpenWeatherMap Account" [apikey="<MY-KEY>", refreshInterval=30, language="en"] {
    Thing weather-and-forecast local "Local Weather And Forecast" [location="51.348850,-0.512330", forecastHours=0, forecastDays=7]
}

Item:-

Number:Length localCurrentRainVolume "Current rain volume [%.1f %unit%]" <rain> { channel="openweathermap:weather-and-forecast:api:local:current#rain" }

Rules:-

// If it's started to rain and it's at a humane time, tell us
rule "rain started warning"
when
    Item localCurrentRainVolume changed from 0
then
    logInfo("org.openhab","localCurrentRainVolume changed from 0")
    // if we're in
    if ( Life360_IsSomeoneHome.state == ON ) {
        // Is it a humane time? (9:00am to 22:30)
        if( now.millis >= now.withTimeAtStartOfDay.plusHours(9).millis && now.millis < now.withTimeAtStartOfDay.plusHours(22).plusMinutes(30).millis) { 
            // It's started to rain!
            Echo_BigLounge_TTS.sendCommand("It's just started to rain!")
            Echo_Kitchen_TTS.sendCommand("It's just started to rain!")
            Echo_Bedroom_TTS.sendCommand("It's just started to rain!")
            sendBroadcastNotification("It's just started to rain at home")
        }
    }
end

// If it's started to rain and it's at a humane time, tell us
rule "rain stopped warning"
when
    Item localCurrentRainVolume changed to 0
then
    logInfo("org.openhab","localCurrentRainVolume changed to 0")
    // if we're in
    if ( Life360_IsSomeoneHome.state == ON ) {
        // Is it a humane time? (9:00am to 22:30)
        if( now.millis >= now.withTimeAtStartOfDay.plusHours(9).millis && now.millis < now.withTimeAtStartOfDay.plusHours(22).plusMinutes(30).millis) { 
            Echo_BigLounge_TTS.sendCommand("It's just stopped raining")
            Echo_Kitchen_TTS.sendCommand("It's just stopped raining")
            Echo_Bedroom_TTS.sendCommand("It's just stopped raining")
            sendBroadcastNotification("It's just stopped raining at home")
        }
    }
end

If you are persisiting, you can put the logic into the rule. Let it fire when something changes and the comapre the current item’s state to it’s previous one with a case select statement?

You may find that your Item is not 0 but 0.0
Number Items are a little strange in rules; you cannot set a Number to be solely integer or decimal, they’re sort of Schrodiinger and both at the same time.

Who cares, until it comes to equality testing.
The strange part is that if( 0 == 0.0 ) is not true. Those numbers have the same mathematical weight but are not identical.
Usually you can work around it by forcing integer or decimal types. Or by use of < > comparisons which work exactly as expected ( 1 > 0 , 1 > 0.0 are both true).

But you don’t get those choices for the to and from parts of a rules changed trigger. They’re strict equality.

What I would do …
Trigger the rule from any/every change, then make the decision in code.
You don’t need persistence to find out what the state was before; every rule triggered by changed has available a magic inherent variable, previoustate
So in your case you could use if(previousState < 0.001) or something like, which would also take care of any nearly-zero conditions if you wanted.

If it must be zero, cast the type;
if( (previousState as Number).intValue == 0 )

Thank you. That’s really helpful. I had considered that 0.0 may not be 0 but figured that would be very odd behaviour. However, your detailed response is really useful and has hopefully put me on the right track

Regards
Steve

It’s inherited weirdness from Number in openHAB internally using BigDecimal java type - which holds 0 and 0.0 in different ways. The equality function isn’t smart enough to figure it out. The flexibility of Number is great in many other ways, but this part is the non-obvious cost.

Of course if you know your binding always supplies 0.0 you can just use that in the trigger from :smiley:

The state of localCurrentRainVolume is a QuantityType, so this would never trigger…

A QuantityType will never equal just 0, but QuantityType (u"0 in") in scripted automation or “0 | in” in the DSL. So, you’d need to use something like this for the trigger (you could change the unit)…

Item localCurrentRainVolume changed from "0 in"

You could remove the state from the trigger and still tell whether the rain was coming or going by checking previousState.

2 Likes

Wow. Gets even more complicated! Is there documentation anywhere I could read up On that covers the details above? (Sorry if it’s somewhere obvious)

https://www.openhab.org/docs/concepts/units-of-measurement.html

https://www.openhab.org/docs/configuration/rules-dsl.html

Many thanks!

1 Like