[SOLVED] Question on the sendCommand()

So i recently started working with openHAB and i stumbled about this, when trying to shorten my code, while writing rules.
There are switches for my digital inputs and i wrote this rule to write the “value” of the triggered switch into a dummy variable to show it in the UI. The dummies are more or less for testing purposes right now, so don’t bother about the concept.
The switches are named like this: dOut*_switch
The dummies like: dOut*
And i went with the following implementation, which works fine for me:

rule "rulename"
when
        Member of dOut_switch received update
then    
        if(triggeringItem.state == ON){
                if(triggeringItem.name == "dOut1_switch"){dOut1.sendCommand(1)}
                else if(triggeringItem.name == "dOut2_switch"){dOut2.sendCommand(1)}
                else if(triggeringItem.name == "dOut3_switch"){dOut3.sendCommand(1)}
                else if(triggeringItem.name == "dOut4_switch"){dOut4.sendCommand(1)}
                else if(triggeringItem.name == "dOut5_switch"){dOut5.sendCommand(1)}
                else if(triggeringItem.name == "dOut6_switch"){dOut6.sendCommand(1)}
        }
        else if(triggeringItem.state == OFF){
                if(triggeringItem.name == "dOut1_switch"){dOut1.sendCommand(0)}
                else if(triggeringItem.name == "dOut2_switch"){dOut2.sendCommand(0)}
                else if(triggeringItem.name == "dOut3_switch"){dOut3.sendCommand(0)}
                else if(triggeringItem.name == "dOut4_switch"){dOut4.sendCommand(0)}
                else if(triggeringItem.name == "dOut5_switch"){dOut5.sendCommand(0)}
                else if(triggeringItem.name == "dOut6_switch"){dOut6.sendCommand(0)}
        }
end

So then i wondered if i could cut the code be giving the sendCommand a modified String as a reference to the Item.
I thought about sth like this:

rule "rulename"
when
        Member of dOut_switch received update
then    
        if(triggeringItem.state == ON){
               sendCommand(triggeringItem.name.replaceAll("_switch", ""), 1)
        }
        else if(triggeringItem.state == OFF){
               sendCommand(triggeringItem.name.replaceAll("_switch", ""), 0)
        }
end

However the sendCommand cant handle this, because it seems it can only take the actual Item as an input.

So my question is, is there a way to reference to items, by using their names as strings?
Or do I have to work around that by using an array for example.

Thanks for your thoughts in advance!

triggeringItem.name.split("_").get(0).toString

Isn’t that going to create the exact same output as triggeringItem.name.replaceAll("_switch", “”)?

If I put this as input for sendCommand, sth like this
sendCommand(triggeringItem.name.split("_").get(0).toString, value)
it won’t make a difference, won’t it?

Or am i missing sth here?

I think that is essentially true. A workaround is to put your set of Items into a group. Rule can then search the group by name string to select an Item for action.
Outlined here

Ah! Ok, thanks!

I guess, I can figure sth out this way.

From the docs :

Event Bus Actions

sendCommand(String itemName, String commandString): Sends the given command to the specified Item to the event bus.

The action take an item name as a string
Did you try my suggestion?

1 Like

You can also try your way with a toString at the end

triggeringItem.name.replaceAll("_switch", “”).toString

Yes, I know that it’s supposed to do that, but I can’t get it to work this way.
I did try your suggestion, but the result was still the same.
And I think the “.toString” won’t be needed here, because there should be an automatic string conversion.
For example, i can do the “cutting” either way and send the result to a StringItem.

String testString "blabla" and so on

-------------------------------------------------

testString.sendCommand(triggeringItem.name.split("_").get(0).toString)
//works as well as
testString.sendCommand(triggeringItem.name.split("_").get(0))
//same goes for the .replaceAll()-variant

Fine you know better

So I got it to work as intended!

rule "rulename"
when
        Member of dOut_switch received update
then
        if(triggeringItem.state == ON)
                 {sendCommand(dOut.members.findFirst[don |don.name == triggeringItem.name.replaceAll("_switch", "")], 1)
        }
        else if(triggeringItem.state == OFF){
                 sendCommand(dOut.members.findFirst[doff | doff.name == triggeringItem.name.replaceAll("_switch", "")], 0)
        }
end

@vzorglub and @rossko57 thank you again for your help, you two saved my day

And I just tries toString with your code and it works. I have been doing this for three years now and instead of arguing you could have taken my first answer and saved yourself 2 hours.

The string conversion never was my problem at all, I couldnt get sendCommand() to trigger on a string.

“Group.members.findFirst[i | i.name == triggeringItem.name…” is what i was looking for, so i can get a reference to the item i want to write to.
And I didn’t meant to lecture you or sth, maybe we had a little misunderstanding there.
Sorry for that and thank you again

Have nice day and an even better weekend

I think the bigger point here is:

  1. You should be able to use the String name of the Item with the sendCommand Action
  2. If you can’t then either you are doing something wrong or there is a bug that needs to be fixed
  3. The Rules DSL is actually pretty bad at knowing when and how to convert objects to Strings

Given this, Vincent’s solution is actually the true solution. You found a workaround, but it is an unnecessary work around.

That’s the point I don’t get. And again, I didn’t mean to lecture anybody. I just wanted to understand the problem after all… I feel like I did sth wrong there, but i can’t figure out what exactly and it’s driving me crazy.

I’m really sorry for asking this again. But where exactly is the difference between

triggeringItem.name.split("_").get(0).toString

and

triggeringItem.name.replaceAll("_switch", 0).toString

And why can i send the output of either of those commands to a StringItem without the .toString-conversion?
Is there a conversion in the .name or does sendCommand do that, or am I missing sth else completly?

I did try it, i implemented Vincents way like this:

rule "rulename"
when
        Member of dOut_switch received update
then
        if(triggeringItem.state == ON){sendCommand(triggeringItem.name.split("_").get(0).toString, 1)}
        else if(triggeringItem.state == OFF){sendCommand(triggeringItem.name.split("_").get(0).toString, 0)}
end

But the dummies won’t receive the command.

So at this point the only possible way for me is, that i did a mistake there on the code, maybe any of you can help me figuring out what i did wrong here.

Sorry for getting on your nerves, and thank you for your responses.

In the second line you are replacing a string with a nomuber. Won’t work.
Do:

triggeringItem.name.replaceAll("_switch", "").toString

That should be the same as the first one. The advantage of the first one is that you don’t have “_switch” hard coded so if you decide to change the name of your items but keep the same naming structure, you won’t need to change your code.

The toString ensures that a string is “outputed”. Xtend doesn’t do that automatically in every fonction.

Your rule should work as it is. What are the dOut# items. Switches, numbers…?

Sometimes my brain works in mysterious ways, or hardly at all…

I deleted the wrong part of the code when copying it…

triggeringItem.name.replaceAll("_switch", "").toString

Is what i meant. Sorry about that.

Ok, that’s acutally a very good point. Then I really should switch to your version and save my self some work in the future.

dOut*items are numbers.

Let’s add some logging to see what’s happening:

rule "rulename"
when
        Member of dOut_switch received update
then
    logInfo("STATE", triggeringItem.state.toString)
    if(triggeringItem.state == ON) {
        logInfo("STATE ON", triggeringItem.name.split("_").get(0).toString)
        sendCommand(triggeringItem.name.split("_").get(0).toString, 1)
    } else if(triggeringItem.state == OFF) {
        logInfo("STATE OFF", triggeringItem.name.split("_").get(0).toString)
        sendCommand(triggeringItem.name.split("_").get(0).toString, 0)}
    }
end

Run that and let’s see openhab.log

2018-06-18 12:40:20.209 [INFO ] [eclipse.smarthome.model.script.STATE] - ON
2018-06-18 12:40:20.230 [INFO ] [ipse.smarthome.model.script.STATE ON] - dOut1
2018-06-18 12:40:20.240 [ERROR] [ntime.internal.engine.RuleEngineImpl] - Rule 'rulename': An error occurred during the script execution: Could not invoke method: org.eclipse.smarthome.model.script.actions.BusEvent.sendCommand(java.lang.String,java.lang.String) on instance: null

sendCommand(String, String)

rule "rulename"
when
        Member of dOut_switch received update
then
    logInfo("STATE", triggeringItem.state.toString)
    if(triggeringItem.state == ON) {
        logInfo("STATE ON", triggeringItem.name.split("_").get(0).toString)
        sendCommand(triggeringItem.name.split("_").get(0).toString, "1")
    } else if(triggeringItem.state == OFF) {
        logInfo("STATE OFF", triggeringItem.name.split("_").get(0).toString)
        sendCommand(triggeringItem.name.split("_").get(0).toString, "0")
    }
end

Yup that works, for sure it does…

So the sendCommand() will take the itemname and the value as a string. gotti

And the method I did first, only works because the reference is an acutal item/object?
like:
sendCommand(string, string)
sendCommand(object, value)
?
But they shouldn’t get mixed up