Hi,
Need help with “beautification” of the rule output.
Or pointers to that part of the documentation, as this advanced string manipulation is beyond my skills…
rule "Low battery alert"
when
Item gBatteries changed
then
if(gBatteries.state > 20) return;
val lowBatteriesList = gBatteries.members.filter[ b | b.state < 20 ].map[ name ].reduce[ list, bat | list = list + ", " + transform("MAP", "batteries.map", bat) ]
aAlert.sendCommand("The following batteries need to be replaced: " + lowBatteryList.subString(0, lowBatteryList.size-2) + ".")
end
stole it and simplified (omit using map file, plus removed some other parts)
rule "Low battery alert"
when
Time is midnight
then
if(Ephemeris.isWeekend == true)
{val lowBatteryList = gBattery.members.filter[b|b.state <= 15].map[name]
mailActions.sendMail("vanja@something.net", "openHAB Alert - Battery Low", "Low battery at: " + lowBatteryList)}
end
It’s the “other parts” that converts the list to a String, namely the reduce. If you are going to copy code it’s important to understand what it does before you change it. You can find more information on map/reduce at Design Pattern: Working with Groups in Rules
The map operation takes each element of the list, does something to it, and returns a new list with the results. The reduce takes each element of the list and combines them into a single result.
val lowBatteryList = gBattery.members.filter[b|b.state <= 15]
.map[ i | i.name + ' ' + i.state ]
.reduce[ msg, b | list = b + '\n' ]
mailActions.sendMail("vanja@something.net", "openHAB Alert - Battery Low", "Low battery at:\n" + lowBatteryList)
In JS this is simpler since we have the join operator. Note, you should always get a Thing action inside the rule that uses it. When you get the Action as a global, if the Thing isn’t online when the .rules file is read or if the thing goes offline then back online the action will fail until you reload the .rules file.
rules.when().timeOfDay("00:00")
.if(() => actions.Ephemeris.isWeekend())
.then( () =>
const bats = items.gBatteries.filter( i => i.numericState < 15)
.map(i => i.name + ' ' + i.state)
.join('\n');
actions.get("mail", "uid:of:mail:thing")
.sendMail("vanja@something.net",
"openHAB Alert - Battery Low",
"Low battery at:\n" + bats)
)
.build('Low battery alert', 'Sends an email with the list of all the low batteries.', [], 'lowBatteries');
2025-01-28 20:53:00.559 [INFO ] [el.core.internal.ModelRepositoryImpl] - Validation issues found in configura using it anyway:
Assignment to final parameter
2025-01-28 20:54:22.633 [ERROR] [internal.handler.ScriptActionHandler] - Script execution of rule with UID 'f invoke 'assignValueTo' for feature param msg in failsafe
This is why I am basically done with Rules DSL. It’s a broken language. No one should be doing new development of rules using it.
I don’t know what’s wrong unless you’ve already defined msg as a val somewhere else in this rule or as a global. The first argument to reduce is the “accumulator” and the second argument is the current element of the list.