Variable (var) does not update

Hi Guys,
I have the following problem:
I have created a variable (var) across all rules. It will not be updated. Only once if I save the rules file. After that, the value stays that way.
What could be the problem?

Here is the code …

import org.joda.time.*
import org.openhab.core.library.types.*

var t__Dusk         = (astro_Sonnenuntergang.state as DateTimeType).zonedDateTime.toInstant.toEpochMilli //<---this dosn't update. Keep the value all the time

rule "Rollläden herunterfahren"
when
    Channel 'astro:sun:local:civilDusk#event' triggered END or
    Time cron "0 30 21 * * ?" or
    Time cron "0 0 21 * * ?"
then
    
    if(now.getHourOfDay == 21 && now.getMinuteOfHour == 0)
    {
      //do something
    }
    else if(now.getHourOfDay == 21 && now.getMinuteOfHour == 30 )
    {
      //do something
    }
    else if(t__Dusk <= now().millis)
    {       
      //do something
    }

end

THX

I guess that variables outside rules are only loaded once when the .rules file is loaded (it’s a constant). To solve this, you need to put the variable inside your rules (if you use it more than once) or use item.state instead. Note that if you decide to put the variable inside of your rule and you don’t let your code update the value, then you can use val instead of var.

import org.joda.time.*
import org.openhab.core.library.types.*

rule "Rollläden herunterfahren"
when
    Channel 'astro:sun:local:civilDusk#event' triggered END or
    Time cron "0 30 21 * * ?" or
    Time cron "0 0 21 * * ?"
then
    val t__Dusk = (astro_Sonnenuntergang.state as DateTimeType).zonedDateTime.toInstant.toEpochMilli

    if(now.getHourOfDay == 21 && now.getMinuteOfHour == 0)
    {
      //do something
    }
    else if(now.getHourOfDay == 21 && now.getMinuteOfHour == 30 )
    {
      //do something
    }
    else if(t__Dusk <= now().millis)
    {       
      //do something
    }

end

or

import org.joda.time.*
import org.openhab.core.library.types.*

rule "Rollläden herunterfahren"
when
    Channel 'astro:sun:local:civilDusk#event' triggered END or
    Time cron "0 30 21 * * ?" or
    Time cron "0 0 21 * * ?"
then
    if(now.getHourOfDay == 21 && now.getMinuteOfHour == 0)
    {
      //do something
    }
    else if(now.getHourOfDay == 21 && now.getMinuteOfHour == 30 )
    {
      //do something
    }
    else if((astro_Sonnenuntergang.state as DateTimeType).zonedDateTime.toInstant.toEpochMilli <= now().millis)
    {       
      //do something
    }

end
1 Like

But the variable is not global then?
Or can I then use in other rules?

The variable is global (to this one rule file)

The evaluation is only carried out once, as the rule file loads, and the result assigned to the variable at that time.

If you need to re-evalute later, then you have to re-evaluate.

Var x = 2 + 2

X contains 4, not “2+2”

1 Like

Just to provide a few observations and reiteration of what everyone else has said.

You are using OH 2. Those imports are not required and in fact should be removed.

As has been described, that line only gets evaluated when the .rules file loads. As astro_Sonnenuntergang changes, t__Dusk remains the same. Beyond that, putting this into a global variable doesn’t really buy you much at all beyond a few keystrokes. Why not replace

else if(t__Dusk <= now.millis)

with

else if(new DateTime(astro_Sonnenuntergang.state.toString).isBefore(now))

It’s not that much longer or harder to understand and it eliminates the need for the global variable.

Or, if you care about time periods like this in more than one Rule, consider using Design Pattern: Time Of Day. Then all of your Rules that care about the time can look like:

rule "Rollläden herunterfahren"
when
    Item vTimeOfDay changed to DUSK or // starts at civil dusk
    Item vTimeOfDay changed to EVENING or // starts at 21:00
    Item vTimeOfDay change to NIGHT // starts at 21:30
then

    switch(vTimeOfDay.state.toString) {
        case "EVENING": {
            // do something
        }
        case "NIGHT": {
            // do something
        }
        case "DUSK": {
            // do something
        }
    }    
end

Then if you change when you want stuff to happen you only need to adjust it in one Rule instead of a bunch. And there is no need for the global variable. And you can even start to do even more interesting stuff.

Yes I would like to use it in several rules.
I have solved it now …

    var Number st__vorDusk 	   = 0
    var Number st__nachDawn    = 0
    var Number t__Dusk         = 0
rule "Update Variable"
when
	Time cron "0 0 0 * * ?"
then
	st__nachDawn 	= now.isAfter((astro_Sonnenaufgang.state as DateTimeType).zonedDateTime.toInstant.toEpochMilli)
	st__vorDusk 	= now.isBefore((astro_Sonnenuntergang.state as DateTimeType).zonedDateTime.toInstant.toEpochMilli)
	t__Dusk         = (astro_Sonnenuntergang.state as DateTimeType).zonedDateTime.toInstant.toEpochMilli
end

and now I can use the variables in each rule.

THX at all for your help

That won’t work because astro doesn’t recalculate the new times until at least 30 seconds after midnight. Your variables will be set to the previous day’s times.

And yet you ignored the alternative and many would consider better approaches to do instead of global variables?

You do realize that once again, that will only get evaluated at the time of your midnight rule run? (“now” wil be midnight plus a tiny bit) And the variable will stay as it is until the next midnight.

In fact, I noticed this morning.
I will now update it directly in Rules.
THX for your help