Hello Rule specialists,
how can I do string manipulation on item names within rules? Heres my example:
I have rollershutters and window contacts. A rule triggers a whole group of rollershuttes to go down.
In case the window is still open, I’d like to NOT close the rollershutter.
OH rules do not work like Bash. In OH 1 you cannot get the state of an item if all you have us it’s String name.
Easiest approach is to put the windows in a group and make the names similar to their corresponding rollershutter. In your rule do a foreach on the rollershutter group and then a filter on the windows group for the window that has the name that corresponds to the rollershuter. Something like:
rollershutters.members.foreach (rs |
val windowName = // generate matching win name
if(windows.members.filtet(w | w.name == windowName).head.state != OPEN)
rs.sendCommand(CLOSED) // or what ever command you send)
I typed this on my phone so there are almost certainly errors in the above.
I think this is the tricky part I’m trying to get my head around. You said that the devices should be named similar. How is that meant? Can you give an example for that? I was under the impression that my names are already similar.
Also would you mind explaining what your if clause does? You’re looking through the group of window contacts, if it matches the generated window name and checks for its state, right?
I think then my question is really how to generate the “val windowName”.
Thanks much
Sorry for my terse previous reply. I was typing it on my phone while trying to keep a toddler entertained. It is probably a miracle that it makes any kind of sense at all.
So I assumed that you had more than one window/rollershutter pair so you would want to make sure to name your items so you can easily split the name of the rollershutter apart and easily recreate the name of the corresponding window. For example:
Items:
Group gWindows
Group gRollershutters
String eg_esszimmer-fenster-1 "Esszimmer Fenster 1 [MAP(contact3.map):%s]" (gWindows)
Rollershutter eg_esszimmer-rolladen-1 "Rolladen Essz. 1 [%d %%]" (gRollershutters)
String eg_esszimmer-fenster-2 "Esszimmer Fenster 2 [MAP(contact3.map):%s]" (gWindows)
Rollershutter eg_esszimmer-rolladen-2 "Rolladen Essz. 2 [%d %%]" (gRollershutters)
// any more pairs
Note that I added two groups and added the items to those groups so we can get at them in the rule.
That is correct. The gWindows.members.filter(w | w.name == windowName).head (NOTE the correction from “filtet” to “filter” and I renamed the group name to match the name I used above) creates a List that is populated with all of the members that match windowName and grabs the first one. Since all Items must have a unique name there should only be one and if there are none (i.e. the “.head” returns null) you have an error in generating windowName or in your Items file.
The .state gets the current state of the item and we are comparing that to OPEN and only evaluating to true and sending the command to close the rollershutter if the window is not OPEN.
Assuming you named your Items following some pattern like my example above, you can have a character that separates the first part of the name (the parts of the name that are shared between the window and the rollershutter, in the above the “eg_esszimmer”) from the part that tells you whether it is a window or rollershutter (in the above the “fenster” and “rolladen”) and the part that identifies the unique pair (in the above the “1” and “2”). I used a “-” to separate these parts.
So I would use the String.split method and use the parts to reconstruct the window name.
val nameParts = rs.name.split("-") // returns an array with three elements
val windowName = nameParts[0] + "-fenster-" + nameParts[2]
So the full code would be (with changes to names as listed above):
Hey Rich,
sorry for getting back so late on this. I know the problem with toddlers. I do have two of them over here. Thats also the reason why I have less time for my own hobbies like Openhab
I want to thank for for such a detailed, well explained answer to my problem. The string.split helped me a lot and was the missing piece in my puzzle.
Thanks much, and really appreciate your help!
Seb
Thanks a lot for your quick reply. Yes, that was it. And for all others who wondering about still existing errors:
“namedParts[0]” etc. does not work. You have to use “nameParts.get(0)” instead.
I read this in another post from you Rich - thanks a lot for your valuable posts in this forum that helped me a lot already!
Unfortunately, it seems to me a lot of guesswork and trial and error to figure out the syntax and possibilities of DSL. I would love to have a good and up-to-date documentation for this (not only me…).
For example: How do I even know that the .split() command exists without this forum?
The easiest is to use VSCode with the openHAB Extension. When you type
val nameParts = rs.
VSCode will give you a list of all the possible valid ways to complete the statement. Use the up and down arrows to scroll throgh the list or narrow the list down by start typing the name of a method.
It does take a bit of work understanding how the language works and knowing what you are dealing with. The Rules Domain Specific Langauge (DSL) is its own language (see the first link) that is based on the Xtext language and closely resembles the Xtend language (see the second link) which makes available all the core classes from the Java language (see the third link).
Rich,you suggested me to use VS-Code too, which I do, and it is not showing me this list of possible statements! I installed the openhab-extension in VSC by clicking Ctr+Shift+X, typing ‘openhab’ and click install and reload.
VS-Code gives me suggestions for already used vars or Items, but it is giving me a list only of vars or Items that I have already used in the same file, and even the once that are miss-spelled. From what I read about VS-Code installation for openhab, all configuration is optional and the deaults are with all the trick built in.
Should the suggestion-lists work with the current version of the openhab-extension? (I’m using 0.3.5) and the current version of VSC? (Version 1.20.0, Shell 1.7.9, Renderer 58.0.3029.110, Node 7.9.0, Architecture x64)
And should I do more configuration?
My OH-configfiles are on RaspberryPi with samba-share. My VSC runs on windows laptop.
rule “Rolladen Wohnzimmer schliessen”
when
Item EG_wz_switch_3_long received update OFF
then
gH_Rolladen_wz_switch.members.forEach[rs|
val nameParts = rs.name.split("")
val windowName = nameParts.get(0) + "" + nameParts.get(1) + “fk” + nameParts.get(3)
logInfo (“Fensterkontakt der offen is:”, +windowName)
if(gH_Contact_global.members.filter [fk | fk.name == windowName].head.state != OPEN){
postUpdate(rs,DOWN)
}]
end
I think, it is somehow in relation, that items comes not as a string value therefore the full rules does not fly (i.e. logInfo also do not appear in the log).
Any suggestions, what I could do to improve as I am not a real programmer? I understand, what the code intend to do basically (more or less), but I get really fast to my limit.