Make my rule files shorter --> working with groups

Hi,
i have some rules which are written multiple times for similar items. I want to have one rule which does the job for all items in one group.

Here are my rule files:

rule "Xiaomi Temp 1 Status Changed"
when
		Item Xiaomi_Temp_1 received update
then
		var SimpleDateFormat df = new SimpleDateFormat( "dd.MM., HH:mm" )
		var String timestamp = df.format( new Date() )
		Xiaomi_Temp_1_komplett.postUpdate(String::format("%.1f", (Xiaomi_Temp_1.state as DecimalType).floatValue()) + " °C / " + String::format("%.0f", (Xiaomi_Humidity_1.state as DecimalType).floatValue()) + " % (" + timestamp + ")")
end


rule "Xiaomi Temp 2 Status Changed"
when
		Item Xiaomi_Temp_2 received update
then
		var SimpleDateFormat df = new SimpleDateFormat( "dd.MM., HH:mm" ) 
		var String timestamp = df.format( new Date() )
		Xiaomi_Temp_2_komplett.postUpdate(String::format("%.1f", (Xiaomi_Temp_2.state as DecimalType).floatValue()) + " °C / " + String::format("%.0f", (Xiaomi_Humidity_2.state as DecimalType).floatValue()) + " % (" + timestamp + ")")
end


and so on...

How can i do this in one single rule? Can someone help me?

I aready have this kind of rule running for my lighting, but i can´t change this to work with the rules above…

And here are the second rules, same problem, i want them in one single rule:


rule "Xiaomi Temp 1 time since"
	when
		Time cron "0 * * * * ?"
	then
		var Number lastthingy1 = (Xiaomi_Temp_1_last_connection.state as DateTimeType).calendar.timeInMillis
		var Number myminutes1 = ((now.millis - lastthingy1) / 60000)
		Xiaomi_Temp_1_time_since.postUpdate(myminutes1)
end


rule "Xiaomi Temp 2 time since"
when
		Time cron "0 * * * * ?"
then
		var Number lastthingy2 = (Xiaomi_Temp_2_last_connection.state as DateTimeType).calendar.timeInMillis
		var Number myminutes2 = ((now.millis - lastthingy2) / 60000)
		Xiaomi_Temp_2_time_since.postUpdate(myminutes2)
end

and so on...

So the rule is just posting a Sring combining the temp and humidity reading, correct? So it is probably safe to assume that it doesn’t matter if this Item gets updated lots of times even if there is no change. I make this assumption because it makes the rule a whole lot easier.

Put all the Items into two Groups, one for Temp and one for Humidity. I’m assuming your current naming scheme remains consistent.

rule "Xiaomi Temp changed"
when
    Item Xiaomi_Temps received update
then
    val SimpleDateFormat df = new SimpleDateFormat( "dd.MM., HH:mm")
    val String timestamp = df.format(new Date())

    Xiaomi_Temps.members.forEach[temp |
        val humidity = Xiaomi_Humidities.findFirst[hum | hum.name == temp.name.replace("Temp", "Humidity")]
        postUpdate(temp.name+"_komplett", String::format("%.1f", (temp.state as DecimalType).floatValue()) + " °C / " + 
                                          String::format("%.0f", (humidity.state as DecimalType).floatValue()) + " % (" + 
                                          timestamp + ")")
    ]
end

Any time any Item in Xiaomi_Temps receives an update the rule triggers and the String Item gets updated for all the Temp Items. The String Items will get a lot of redundant updates but that is a small price to pay for the vastly simpler Rule.

For the second set of rules, we have the same approach.

Put the last_connection Items into a Group.

rule "Update Xiaomi Temp time since"
when
    Time cron "0 * * * * ?"
then
    Xiaomi_Temp_Last_Connections.members.forEach[ lastTime as DateTimeType |
        val lastMillis = lastTime.calendar.timeInMillis
        val mins = (now.millis - lastMillis) / 60000
        val split = lastTime.split("_") // so we can reconstruct the time_since Item name
        postUpdate(split.get(0)+"_"+split.get(1)+"_"+split.get(2)+"_time_since", mins)
    ]
end

Both rules above use Design Pattern: Associated Items

Again, we trade lots of redundant updates to Items for a vastly simpler rule.

Thanks, i will try this.

I think it doesn´t matter, if there are lots of redundant updates.


EDIT:

For the second rule i get a warning and i think the rule isn´t doing anything…

2017-12-13 08:42:33.757 [WARN ] [el.core.internal.ModelRepositoryImpl] - Configuration model 'temperatur_anzeigen.rules' has errors, therefore ignoring it: [162,59]: no viable alternative at input '|'

The new group is defined like this:

Group Xiaomi_Temp_Last_Connections

I had errors some time ago with this kind of groups in design-pattern-rules, i had to define it in another way. Could this be the same problem? But last time it was a group which stores simple on-off switches, no datetime items?

The complete rule-file isn´t firing any more when the second rule is active.


And from the first rule i get this:

2017-12-13 12:59:48.092 [INFO ] [el.core.internal.ModelRepositoryImpl] - Validation issues found in configuration model 'temperatur_anzeigen.rules', using it anyway:
There is no context to infer the closure's argument types from. Consider typing the arguments or put the closures into a typed context.

Rule isn´t working.

But rest of the rules in the rule file work, while only the first rule is active. Whitz second rule active, none of the rules inside the rules-file worked.

As the error says, it is ignoring the rule.

There is a syntax error somewhere in the file at or around line 162, character 59. That isn’t a warning, it is an error. I’m not sure why it is only logged as a warning.

It has nothing to do with your Group definition.

Not having your full .rules file it is hard to say.

The quickest way to solve problems like this is to load your config into ESHD or, if you are on a recent snapshot, loaded into VSCode. It has to be a recent build to get the syntax checking.

The second one is also an error, but at least it isn’t ignoring the whole file. It can’t determine the type of something, maybe temp in the forEach? Again, the quickest way to solve this is using ESHD or VSCode.

I´m on snapshot #1068 and have VSCode 0.3.5 installed. How can i get syntax checking?

I don´t want to upgrade openhab snapshot because of the errors which are in the newer builds, i will wait till they are solved.

Line 162 was the second rule you told me, the line with “forEach”. Sign 59 was at the end of the line with the “|”.

You may need a more recent snapshot. Once you do there is an user option to fill out in VSCode to point to the language server hosted on OH.

Change the forEach to

Xiaomi_Temp_Last_Connections.members.forEach[ DateTimeItem lastTime |
    val lastMillis = (lastTime.state as DateTimeType).calendar.timeInMillis

I had two errors, lastTime is a DateTimeItem not DateTimeType, and I can’t do the as there and have to set the type like above.

With this changes, i get the following error every minute and rule isn´t working.

2017-12-14 08:40:00.002 [ERROR] [ntime.internal.engine.ExecuteRuleJob] - Error during the execution of rule Update Xiaomi Temp time since: The name '<XFeatureCallImplCustom>.split(<XStringLiteralImpl>)' cannot be resolved to an item or type.

EDIT1:
Could it be because of using "" and not '’ in the split-command?

EDIT2:
No, it was not, same error. But in my old rules with split i have used ’ instead of ".

EDIT3:
I made a loginfo for the the state of “val lastTime” and i get this: 2017-12-14T09:04:05.096+0100

So i think splitting with “_” will not give the right values back.

Now i upgraded to latest oh snapshot.

Here are the errors from the syntax checker:

Do i need the imports of:

import org.openhab.model.script.actions.functions
import java.util.Date
import java.text.SimpleDateFormat

?

Here is the rule with the line numbers:

You should not have to import anything from org.openhab.

It’s a stupid typo.

val split = lastTime.name.split('_')

Thanks, now i don´t get an error fopr this line. But i get a new error from the line below…

Sign 82 is the last variable in the line (mins)

With this the error is gone, hope it works now:

mins.toString
postUpdate(split.get(0)+"_"+split.get(1)+"_"+split.get(2)+"_time_since", mins.toString)
1 Like