So I have a string item that represents the application currently running on my WebOS TV. I want to change the lighting to ‘movie mode’ when I switch to certain app, which works fine as long as there are no special characters in the app name. Once there are, however, I can’t figure out how to trigger a rule based on that.
Example:
rule "Movie mode"
when
Channel “zwave:device:875776fc:node9:event” triggered OFF_stick2 or
Item TV_Application changed to netflix or
Item TV_Application changed to amazon or
Item TV_Application changed to com.itkey.plexclient
then
etc.
Netflix and Amazon work just fine, but the ‘com.itkey.plexclient’ doesn’t work, if I leave the string as it is above, the rule file doesn’t compile: mismatched input ‘.’ expecting ‘then’. Same when I try to escape the points: mismatched input ‘’ expecting ‘then’
When I put it between single or double quotes: “com.itkey.plexclient” or ‘com.itkey.plexclient’, the rule compiles, but never triggers.
How the hell do I escape and/or write a string literal in a ‘when’ condition for a String item ? Can’t find anything about it in the documentation.
Also, how do I define a function so I can re-use bits of code. E.g. I want to ignore some rules if I already changed the lights manually without having to copy-paste the same bit of code all over the place.
A few remarks
It will be much easier to read code if you use proper formatting. The top row offers varies code fences that will do all the formatting for you, please use them.
I am surprised that your rule triggers at all… Items are objects that carry state (and other info) that needs to be converted to make it useable; starting reading here: http://docs.openhab.org/configuration/rules-dsl.html#manipulating-item-states
if your state of TV_Application is really a string, this may work:
rule "Movie mode"
when
Channel “zwave:device:875776fc:node9:event” triggered OFF_stick2 or
Item TV_Application changed
then
if (TV_Application.state.toString == "com.itkey.plexclient"){ //dostuff }
Of course you could also use case statements and rather than add them to the rule trigger, just check them in the file. Note that above the rule triggers for any changes of TV_Application, which gives flexibility in the rule.
Alternatively, if the value of TV_Application does not matter as long as there is any application active you may not need a case statement of figure out what exactly the application is.
Scripts aren’t functions. I want to do something like
boolean areAllLightsOff () {
return light1.state == OFF
&& light2.state == OFF
&& light3.state == OFF //etc.
}
and then be able to use it in my rules
rule "automatically turn on living room lights at dusk"
when
Channel "astro:sun:civilTwilight" triggered START
then
if(areAllLightsOff()) {
// turn on some lights in the living room
}
end
Now I have to keep repeating blocks of code all over the place,
There is no need to convert state to string, as it is done implicitly.
I could check it in the ‘then’ clause, which is exactly what I’m doing now, but that is kind of ugly and requires me to duplicate rules. The rule would trigger on the button press (Channel “zwave:device:875776fc:node9:event” triggered OFF_stick2), but then it wouldn’t match the if condition and not run. I need this rule to run when EITHER a physical button is pressed OR the TV’s application changes to a specific value). As far as I can tell there is no way to determine which condition exactly triggered the rule so I can’t know in the then clause wether or not to check the TV_Application.state.
If it helps, in my suggestion above, you rule would trigger on ANY changes of TV_Application
you could then just check this item for the desired value(s) in the rule.
But for me this discussion is getting difficult as you have not posted any item definition and from your subsequent posts I am now confused what your problem is. Maybe if you post the whole story the discussion may be easier.
Finally, typically the escape character is “\”, while I have no experience nor did I see this anywhere in the forum maybe it helps if you write “\.” instead of full stops in your original post.
Humm. My own experience is with OH1 where Item SomeStringItem changed to “blah”
was both working and understandable.
This year old post suggests that got broken in OH2
Obviously that’s no good, as it’s not going to work for strings with e.g. spaces or keywords like “or”. This is a regression in OH2
I thought it had been fixed in OH2, but nope, see outstanding issue.
I guess every OH2 user is using the workaround, trigger on changed only and then do the analysis within the rule body with if()
Maybe if you post the whole story the discussion may be easier.
I have a couple of lights in my living room with z-wave modules. I also have 2 2-paddle switches on the wall. I made some modifications to the ZWave binding so that it sends channel triggers for zwave basic set commands. I have defined a couple of ‘scenes’, such as ‘TV’. ‘Movie’, etc. These scenes can be either triggered by pressing one of the buttons on the wall, or they trigger automatically when certain events happen, such as starting the Netflix app on my TV.
My problem is that I have to keep several copies of each rule, because there is no way to have multiple ‘when’ conditions like this, and no way to define functions and re-use code that way.
Take for example this rule:
rule "TV mode"
when
Channel "zwave:device:875776fc:node9:event" triggered ON_stick2 or
Item TV_Power changed to ON
then
logInfo("Woonkamer","Switching to TV lighting plan")
// change lights, etc.
end
I have to keep a copy of this rule because I can’t match on the event string:
rule "TV mode 2"
when
Item TV_Application changed or
Item denonmarantz_avr_6011_input changed
then
if(TV_Application.state == "com.webos.app.hdmi2" && denonmarantz_avr_6011_input.state == "SAT/CBL") {
logInfo("Woonkamer","Switching to TV lighting plan")
Due to the ‘if’ construction, this won’t do anything when I press the button to switch to this mode, because in that case the TV and AVR may not be in the right mode. So now I have to keep two copies of the rule, for different triggers, and try to keep them in sync. This is doable now, with just a few rules and lights, but as I add z-wave modules to more rooms in the coming months it will grow in complexity and become a PITA to keep everything in sync. It’s just bad practice (DRY).
I haven’t read the full thread but your example should be implemented as a Group.
boolean areAllLightsOff () {
return light1.state == OFF
&& light2.state == OFF
&& light3.state == OFF //etc.
}
should be
Group:Switch:OR(ON,OFF) allLights
and your Rule just needs:
if(allLights.state == OFF) {
// turn on some lighs in the living room
}
No function/lambda needed, at least in this one case. Further more, you can now use all your lights turning off as an event to trigger a Rule now.
Or you can trigger a single rule for all the the combination of events that would occur to change the lights and turn on/off the lights as necessary based on the current state using if/else or switch statements.
Or you can separate the state calculation from the lights changing so you have a rule or rules to calculate whether the particular scene you want should be ON and then a separate rule that sets the lights based on the result of the Scene calculation.
Unless I missed something, rossko57 provided a link for how to implement just such a function.
As lipp indicates, you haven’t posted enough of your code yet to do a full analysis. But there is more than one way to make your rules generic and easier to maintain than relying solely on the rule triggers.