[SOLVED] Rule with string item and receivedCommand not working

I have seen examples of rules like:

rule "test"
    Item PhoneCallState received command
    if(receivedCommand == ON) {
      // do stuff }

but if the item is not a switch, but string item…

rule "Test Call State"
    Item TestCallState received command
    if(receivedCommand == OFFHOOK) {
2023-09-13 19:33:49.411 [ERROR] [internal.handler.ScriptActionHandler] - Script execution of rule with UID 'scenes-14' failed: The name 'OFFHOOK' cannot be resolved to an item or type; line 172, column 27, length 7 in scenes

also tried to add ‘’, like ‘OFFHOOK’
same error.
if I check the event log

2023-09-13 19:33:34.922 [INFO ] [openhab.event.ItemCommandEvent      ] - Item 'TestCallState' received command OFFHOOK
2023-09-13 19:33:34.924 [INFO ] [openhab.event.ItemStateUpdatedEvent ] - Item 'TestCallState' updated to OFFHOOK
2023-09-13 19:33:34.925 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'TestCallState' changed from IDLE to OFFHOOK
2023-09-13 19:33:45.060 [INFO ] [openhab.event.ItemCommandEvent      ] - Item 'TestCallState' received command IDLE
2023-09-13 19:33:45.061 [INFO ] [openhab.event.ItemStateUpdatedEvent ] - Item 'TestCallState' updated to IDLE
2023-09-13 19:33:45.062 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'TestCallState' changed from OFFHOOK to IDLE

Is this not working by design or?

I had 2 separate rules where I explicity defined
When Item bla changed from IDLE to OFFHOOK
and this works
So I wanted to make single fancy rule with receivedCommand and failed.



thanks, this kind of, intermittently works, with a 5-10seconds delay. clearly there is some issue with this receivedCommand thing, so going back to working setup, where the command is executed exactly when the phone is in call

edit: after some more testing, this started to work reliably. thanks

if(receivedCommand == "OFFHOOK")

tried that as well…

Could you paste your whole rule?

What’s intermittent exactly? The event should fire as soon as the item received a command.

Unless, your openhab is laggy / slow? Check the cpu usage.

is your item read only? Could you post your item definition?
And your log is not consistent with your rule. You send a command to item Mute, not item TestCallState.

yes, when phone is in call, i send a command to mute music (those are different items)

here is the final working rule

rule "Vanja Call State"
    Item XinezCallState received command
    if(receivedCommand.equals("OFFHOOK") || receivedCommand.equals("RINGING") && Vanja.state == ON && Mute.state == OFF) {
      Mute.sendCommand(ON) }
    if(receivedCommand.equals("IDLE") && Vanja.state == ON && Mute.state == ON) {

I am lost. .This is your rule and what exactly is not working?
I still cannot match your rule to the error message.

no, this is the working rule, issue is solved.
non working rule is in the first post: …(if(receivedCommand == OFFHOOK)…
thanks for the help

Just to clearly outline what the original problem is.

Some Item types have enumerated states or commands. For example, a Switch Item can only have ON, OFF, NULL, and UNDEF as a state.

Other Item types have arbitrary states or commands. For example, a Number Item can be any natural number. A String can be any String.

Some Items can have arbitrary(ish) states but also accept enumerated commands. For example Dimmer and Color have a range of possible states but can also accept the following enumerated commands ON, OFF, INCREASE, DECREASE.

When referring to enumerated states and commands, you do not use quotes. When referring to non-enumerated states and commands, you may need to cast the state (e.g. receivedCommand as Number == 6) or, in the case of String just make sure what you are comparing to is a String (e.g. receivedCommand == “OFFHOOK”).

All that was wrong with your original code was you didn’t put “OFFHOOK” into quotes.

I already tried with “” and ‘’ before posting here and it didn’t work (but it didnt throw any errors as well), however .equals(“”) that someone suggested works…

In that case, like with a number, you have to tell Rules DSL that it’s a String. The easiest way to do that is to either swap the arguments as it’s the type of the first argument that dictates the type of equals performed:

"OFFHOOK" == receivedCommand

or convert receivedCommand to a String

receivedCommand.toString() == "OFFHOOK"

Obviously using .equals works also.

I’m surprised in this particular case that Rules DSL didn’t convert receivedCommand to a String automatically. :person_shrugging: That’s Rules DSL for you.

so you redid all your rules with blockly? I just cannot comprehend how is this appealing for people like you (developers) :slight_smile:

No, I write all my rules in JavaScript with a personal library as well as a public library that I maintain for the community. Most of my complicated rules have been turned into rule templates for anyone to review, learn from, or just install and use.

In actuality, I rewrote all my rules in Jython years ago (around OH 2.3 I think). When Jython support was late to coming to OH 3 I rewrote them again in Nashorn Java Script. Finally, when I was able to convince the JS Scripting add-on developers to add some features to the add-on to make it more friendly to UI rules writers I updated my rules to JS Scripting. I’ve never used Blockly for anything beyond what I’ve done to help users on the forum.

But, having said that, yes, I’d prefer Blockly over Rules DSL at this point. It is more complete (Rules DSL cannot access Item metadata, call another rule, etc.), it’s typing is less half-assed and consistent, and it supports common programming concepts like real functions, external libraries, etc.

When it was a choice between Rules DSL and one of the JSR223 languages, yes, I was an advocate for Rules DSL, especially for new users who are not already programmers. However, now that we have better support for third party languages with the helper libraries coming with the add-on and we have a more beginner friendly yet more complete coding environment with Blockly, I can’t recommend Rules DSL for anything but legacy.

For reference, here is how I would write your rule as a UI rule using JS Scripting

configuration: {}
  - id: "1"
      itemName: XinezCallState
      state: OFF
    type: core.ItemCommandTrigger
  - inputs: {}
    id: "3"
      itemName: Vanja
      state: ON
      operator: =
    type: core.ItemStateCondition
  - inputs: {}
    id: "3"
    label: Update call state
    description: Sets Mute to ON or OFF based on call state and presence
      type: application/javascript
      script: >
        if(["OFFHOOK", "RINGING"].contains(event.receivedCommand.toString())) {

        else if(events.receivedCommand.toString() == "IDLE") {

    type: script.ScriptAction

This uses the “But only if…” clause in UI rules so the rule only runs if Vanja is ON, making it so we don’t have to check for that in the script action. I also reordered the checks to simplify the if conditions and reduce duplicated code.

Note, all you would “code” in the above is the script action. The rest gets created when you create the rule.

Given the simplicity of this rule I might choose between a number of different representations in a .js file.

JSRule which will be closer to what you are used to in Rules DSL:

  name: "Vanja Call State",
  description: "Mutes based on call status",
  triggers: [triggers.ItemCommandTrigger('XinezCallState')],
  execute: (event) => {
    if(items.Vanja.state != "ON") return;

    if(["OFFHOOK", "RINGING"].contains(event.receivedCommand.toString()) {
    else if(event.receivedCommand.toString() == "IDLE") {
  tags: [],
  id: "vanja-call-state"

Or using rule builder:

     .then((event) => {
       if(["OFFHOOK", "RINGING"].contains(event.receivedCommand.toString()) {
       else if(event.receivedCommand.toString() == "IDLE") {
    .build("Vanja Call State", "Mutes based on call status", [], "vanja-call-state");

Or it could be simpler if we break it into two rules:

     .if((event) => ["OFFHOOK", "RINGING"].contains(event.receivedCommand.toString()))
     .build("Vanja Mute Call State", "Mutes based on OFFHOOK and RINGING", [], "vanja-call-state-mute");

     .if((event) => "IDLE" == event.receivedCommand.toString())
     .build("Vanja Unmute Call State", "Unmutes based on IDLE", [], "vanja-call-state-unmute");

Note, all of these examples are just typed in. They almost certainly contain typos and may not work as written. I don’t write rules in text files so I’m making some assumptions on how things work, particularly with the rule builder examples.

Also checkout JRuby

Your rule above can be rewritten in JRuby like this:

rule "Vanja Call State" do
  received_command XinezCallState 
  only_if { Vanja.on? }
  run do |event|
    if ["OFFHOOK", "RINGING"].include?(event.command) 
    elsif event.command == "IDLE"


rule "Vanja Call State" do
  received_command XinezCallState 
  only_if { Vanja.on? }
  run do |event|
    case event.command
    when "OFFHOOK", "RINGING" then Mute.ensure.off
    when "IDLE" then Mute.ensure.on

Or if you can change the logic a bit and send Mute ON when the state is anything but OFFHOOK/RINGING, you can simplify it even more because Item.command takes a boolean that translates truthy to ON and falsey to OFF.

rule "Vanja Call State" do
  received_command XinezCallState 
  only_if { Vanja.on? }
  run { |event| Mute.ensure.command !["OFFHOOK", "RINGING"].include?(event.command) }

thanks for all the examples guys, so there is 4 different ways of writing/processing rules other then DSL…or at least 4, maybe more :slight_smile:
it’s nice that OH became so versatile and flexible, but at the same time confuses me as a user (same story as - should I use habpanel, main ui, basic ui…)

If I were to decide to rewrite all my 88 rules, how to decide what style to pick? I like all of them, and from looking at the examples here I don’t care which one I pick, as long as it gives me some longevity and does not get deprecated any time soon.

So in first example you created a rule using the “official” new rule UI, added some stuff by mouse clicking, then add action, run script - ECMA script ? and then wrote the part after "script: "

In second example, you simply create .js file somewhere (script folder?) and start writing? Given you have JavaScript Scripting addon/binding installed, it will just run.
I like this approach best I guess because it mostly resembles to DSL way of doing things (nostalgia or practicality I dont know…)

In third example, rule builder? what is it? do I have it :slight_smile: or its some addon from marketplace

Looking into JRuby, so install the addon, and use it in the same way as ECMA script, within “official” rule builder, select run script → JRuby
Is there a way to create the whole thing (rule) in say JRuby rather then creating rule in gui, defining triggers by clicking, and then add script…

this is exactly what I would like to avoid :slight_smile:
long story short, as explained here, rule engine in OH3 used Nashorn to execute the rules, now in OH4 it uses Graal, so you should convert all your rules…

It sounds like you prefer file-based rules as opposed to UI based rules.

Both JS and JRuby support file-based rules.

In terms of longevity, nobody can give any guarantees. However, JSScripting is more popular, more people use it, and more importantly, @rlkoshak uses it, and he’s the most active and the most helpful around the forums. So there’s a definite advantage to using JSScripting. It is also being used by Blockly so it will be the one getting the highest priority.

JRuby is more niche, and it came to the scene later than JS, so it has a lot fewer users, but it is also being maintained and continually improved.

There are more, Groovy and Java Rule are options that come with OH. The Smarthome/J marketplace has a Java Scripting add-on. And of course there are external rules services like Node Red and HABApp.

You don’t have to rewrite your rules. But I would suggest exploring your options with new development until you find one you like. Then decide whether it’s worth rewriting your rules or leaving them be.

They already work so you’ve already worked past the issues that can crop up with Rules DSL.

That would be the normal way of doing it. This is covered in the Getting Started Tutorial.

But in truth, I hand coded the YAML above based on an existing rule I have.

See the docs for the JS Scripting add-on. The where and how is covered there in far more detail than I can here off the top of my head. This goes for all of the language options including jRuby. For the external rules services see their docs.

Assuming it’s syntactically and logically correct.

It’s a optional way to create rules in JS Scripting. It’s covered in the add-on docs.

You can:

  • not use MainUI to manage your rules and write all your rules in text files
  • click on the “Code” tab and fill out the YAML manually
  • write the rule as JSON and post it to the REST API

There are some advantages to using UI rules.

  • they can be edited from anywhere you can access MainUI
  • you can use more than one rules language within the same rule
  • you have access to Scenes and Rule Templates

Since we haven’t really been talking about Blockly at all in the first place, you are avoiding that entirely anyway. Needing to open and resave your Script Actions and Script Conditions is specific to Blockly and only Blockly. It does not impact any other language, whether managed through the UI or text file based.

And that’s all you have to do to convert your rules, open them and resave them. It’s not like you have to rewrite them.

There is always going to be some work you will have to do when moving between major OH versions.

I’d add that because Blockly uses it, there is another path to follow to learn it. You can build the code in Blockly and then look to see what JS it generated from the blocks to learn how to write JS code yourself.

I’d say the only rules language to avoid right now is Jython. It’s future is somewhat in doubt due to lack of activity on the upstream libraries. It’s also based on a years past end of life version of Python. If Python is your thing, definitely look into HABApp.

Beyond that, experiment. Try them all out and see which one fits you best.