Global (file wide) variables in Rules DSL

I have a rule:

rule "TimeOfDayRule"
when
    System started or
    Time cron "0 0 * ? * * *"
then
    if (now.getHourOfDay() >= 00 && now.getHourOfDay() < 06){
		myTimeOfDayMode.postUpdate("Night")
	}
	if (now.getHourOfDay() >= 06 && now.getHourOfDay() < 09){
		myTimeOfDayMode.postUpdate("Morning")
	}
	if (now.getHourOfDay() >= 09 && now.getHourOfDay() < 16){
		myTimeOfDayMode.postUpdate("Daytime")
	}
	if (now.getHourOfDay() >= 16 && now.getHourOfDay() < 23){
		myTimeOfDayMode.postUpdate("Evening")
	}
	if (now.getHourOfDay() >= 23 && now.getHourOfDay() < 24){
		myTimeOfDayMode.postUpdate("Night")
	}
end

item file

String myTimeOfDayMode "My time of Day" <none> (gHome)

Various rules use this string value. I have another rules file in which at the top I’ve placed a file wide variable. Roughly typed in example here (untested)

var TOD = myTimeOfDayMode.state.asString

I’m away from computer right now, but ignoring syntax errors (it runs) further down the rules file

if (TOD == "Night") {
   // do stuff
}

the rule worked with the variable inside the code block but as a global (file wide) variable, I’m guessing, it doesn’t pull a new value every time the rule runs? maybe only sets the variable the first time the rules file is loaded?

If so how do I do this? Without having to have the same item having it’s value checked in 6 or 8 places in one rules file

As it’s outside of a rule, this global variable gets evaluated once only as the rule file loads. It won’t do what you want.

Why wouldn’t you want to do that? There are overheads accessing an Item, but six or eight times is not a lot.

I guess because DRY (don’t repeat yourself) rossko57

Have you seen Design Pattern: Time Of Day

If not, can this be helpful in general?

Yes, in fact the rule at the top of my post is copied from a post of mine in that thread

Basically @rossko57 already answered your question, but to make it more explicit:
If you want var TOD = myTimeOfDayMode.state.toString to be evaluated each time any of the rules in the file gets triggered, you should have that definition as the first part of the then of each rule.

That doesn’t have anything to do with DRY by the way, because in a lot of programming languages this will work the way you are now experiencing.

That’s really a misapplication of DRY. Even if this worked, which it doesn’t as already explained, the global variables only gets evaluated when the .rules file gets loaded, why would you create a new variable to store a value that you can access directly?

The whole point of the vTimeOfDay Item is so that it’s state gets checked in 6 or 8 places instead of having to perform the same calculation in 6 or 8 places. Putting the state of vTimeOfDay into a global variable doesn’t prevent you from repeating yourself, it just adds an extra step or redirection.

DRY applies to calculations and code that does the same thing over and over. It doesn’t apply when all that code does is access a value.

2 Likes

Or to put it another way, accessing an Item instead of a variable isn’t repeating anything.

There are valid reasons to capture an Item state into a variable - you might want to preserve it during the execution of a rule for example.

But otherwise it’s make-work. If defining the variable worked the way you wanted it to, it would still have to the same retrieve-process work as if you specified the Item directly.

ok… ya’ll don’t have to pile on… yeeshhh
I’m a noob trying to learn

1 Like

I’m missing something. I’ve copied the rule “TimeofDayRule” and created a string myTimeOfDayMode in my item file but I still getting a rule error. I suspect I’m not initializing it correctly. What am I missing?

Post the error Tony and we’ll have a look
Most likely, as you say, the item is unitialized and currently undef or null
Use the REST api to check current state.

The error is not very helpful.

2019-05-04 07:42:11.899 [WARN ] [el.core.internal.ModelRepositoryImpl] - Configuration model ‘delarosa.rules’ has errors, therefore ignoring it: [30,1]: no viable alternative at input ‘rule’

no no, that helps, you have a syntax error somewhere in the code. At line 30 is where it runs a foul but the error could be several lines prior. You are missing a curly bracket (one of these { }) somewhere me thinks. Do you write your code in an editor? If not check out VS code
Check all your curly brackets and parenthsis to make sure they have a matching close curly bracket or parethesis

This is my first rule. Right before the rule is var definitions and an import timer statement that has been working

post up the whole rule and we’ll getting working
the mistake is with in the rule

I think your post is not getting the typical amount of new user help from the rest of the forum regulars because this is an older thread that got discussed and basically was resolved.

Thanks Andrew. Will do when I gat home. About 45 mins

1 Like

the rule is failing at ‘rule’
which is the start of your rule
does it have an ‘end’ ?
in other words does the rule have

rule "myrule"
when
	Item myitem changed
then
     // do some stuff
end

You were right. It was an error before the rule. I was reading about defining variables and I entered a new

var String myDayofWeek =

right before the rule

var String myDayofWeek =

rule "TimeOfDayRule"
when
    System started or
    Time cron "0 0 * ? * * *"
then
    if (now.getHourOfDay() >= 00 && now.getHourOfDay() < 06){
		myTimeOfDayMode.postUpdate("Night")
	}
	if (now.getHourOfDay() >= 06 && now.getHourOfDay() < 09){
		myTimeOfDayMode.postUpdate("Morning")
	}
	if (now.getHourOfDay() >= 09 && now.getHourOfDay() < 16){
		myTimeOfDayMode.postUpdate("Daytime")
	}
	if (now.getHourOfDay() >= 16 && now.getHourOfDay() < 23){
		myTimeOfDayMode.postUpdate("Evening")
	}
	if (now.getHourOfDay() >= 23 && now.getHourOfDay() < 24){
		myTimeOfDayMode.postUpdate("Night")
	}
end

I deleted that entry and I no longer have that error but my other rule is still not working. The following turns on the stereo when my wife arrives but only during the daytime. Using logInfo, I verify that the presence rule was triggered but not the If statement.

rule "Turn on stereo when Conchita comes home"
when
	//Item PresenceCellConnie changed
	Item PresenceCellTony changed
then
	logInfo("Test", "Entering Presence rule!")	
	if (myTimeOfDayMode == "Daytime") {
	val String CurrentTime = String::format( "%1$tm%1$td ", new java.util.Date )
	if (PresenceCellConnie.state == ON){
		sendTelegram("TelegramBots", CurrentTime+"Welcome Back Conchita!")		
    	sendHttpPostRequest(URLCRXN560,xmlheader,PowerOn)
		Thread::sleep(750)
		sendHttpPostRequest(URLCRXN560,xmlheader,VolLvlPM)
		sendHttpPostRequest(URLCRXN560,xmlheader,TunerSel)
		//sendHttpPostRequest(URLCRXN560,xmlheader,FMPreset)
		}
	else {
		sendHttpPostRequest(URLCRXN560,xmlheader,PowerOff)
	}}
	logInfo("Test", "Exiting Presence rule!")	
end

How do I find out the current value of myTimeOfDayMode

What kind of thing is it? Seeing as you postUpdate to it an earlier rule, I’ll guess it is an Item. Is it a String type Item? That’s a complex object with name, label, etc. properties, but you’ll be interested in the state. Is it a String type Item?

if (myTimeOfDayMode.state == "Daytime") {