Escaping string in 'when' clause

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.

You can write a script and then call it from your rule.

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,

You’ll want reusable functions? Magic word in OH is 'lambda’

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

As far as I can tell, what I’m doing is supposed to work, as per: https://docs.openhab.org/configuration/rules-dsl.html#event-based-triggers

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.

I’m not at all convinced about that. The docs reference “no quotes needed” is really about cases like

when
    Item SomeSwitchType changed to ON

The conventional way to trigger from string type Item

when
    Item SomeStringType changed to "TVon"

You should at least try that way (all string triggers)

A year ago, string from/to triggers were not working well in OH2, so beware if you use an elderly version.

You should at least try that way (all string triggers)

That doesn’t work at all.

You are right, my bad, sorry.

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.