sendCommand() Documentation

Actual documentation for this particular feature is lacking . You will have to look at the code.

However, an IndexOutOfBoundsException, at least in my experience, points to something else being a problem.

Yes I suppose that is what I am after. I don’t know where to find this code (or in what file name it resides). A quick grep in the OpenHAB directory only reveal a rules_library.xml that has this command. I don’t think that is it…

I was able to resolve my issues. [itemName].sendCommand(“string input”) is what I used and no out of bound errors reappeared. Although for whatever reasons I get errors every know and then that destination Item failed to receive the command. Anyway I now send the command x3 to mitigate this problem.

I can’t say I’ve ever seen nor heard of such a problem, and it is a little alarming. I would recommend setting your logs to Debug, capture a case where you see that error, and open an issue on github. You should not be seeing this behavior.

Linked here from another thread. I have to admit (due to my lack of understanding of coding) to be completely confused by this. Particularly the second paragraph where it says the sendCommand([itemName], [command]) is not able to accept numbers. I use this format for a dimmer and it accepts numbers fine.

Would it be possible to show an example where sendCommand([itemName], [command]) would not work but MyItem.sendCommand([command]) would?

It is not a problem with numbers in general, it is a problem with primitives.

It is exceptionally difficult to explain this to non-programmers because it gets into certain programming concepts for which there is no easily available metaphor or simile in real life to use as a basis of explanation.

Pictures drawn on a white board would help a lot too.

So I’m going to have to resort to “because I said so”. But I’ll give it a try.

In Java and the Rules DSL there are two basic types, Objects and Primitives. Whenever you see a type after a var or a val that starts with an uppercase letter (e.g. val String, var Number, etc.) you are dealing with an Object. If it starts with a lowercase letter (e.g. var int, val boolean, etc.) you are dealing with a primitive. If you do not specify the type you can usually assume that it is an Object.

The big difference for this discussion between Objects and Primitives is that Objects have methods where Primitives do not.

In Java and the Rules DSL there is a concept of Inheritance. This only applies to Objects. Inheritance allows one to take an existing Object type, called a Class, and add to it to make it into something different. This something difference becomes a Child of the original Class. The top level base Class for all Objects in Java and the Rules DSL is called Object. The Child can be treated as if it were the parent because everything the parent can do the child can do too.

In addition to some other useful things, Object implements a method called toString. And since Object is the parent of all Objects, that means all Classes also implement a toString method.

But primitives do not inherit from Object. They don’t inherit from anything and they don’t have any methods at all which includes toString.

So, because all Objects have a toString method, the language allows one to use an Object in a place where a String is required and the language is smart enough to say “Hey, that’s an Object but I need a String so I’ll call toString because I know all Objects have a toString method.” But when you have a Primitive there is no toString method so almost all of the time the language has no idea how to convert the primitive value to a String.

Now we need to look at the sendCommand Action. This Action only supports two arguments: String, String. This is because the action needs to be completely generic and work for all Item types.

There is also a sendCommand method on the Items. In this case the sendCommand method is defined by the class for that Item which allows the class to create sendCommand methods that take different types of data. For example, the NumberItem class would have sendCommand(int), sendCommand(long), sendCommand(float), sendCommand(double), sendCommand(Number), sendCommand(DecimalType), and sendCommand(String) methods. Each of these separate methods can be individually written to handle all of these different types of Objects and primitives unlike the Action which can only handle Strings.

So if I have a Number Item named MyItem:

val DecimalType zero = 0 // Object DecimalType
val Number one = 1       // Object Number
val two = 2              // When a type isn't provided for numerical values the Object BigDecimal is used
val int three = 3        // Primitive int
val String four = "4"    // Object String

sendCommand(MyItem, zero)  // Success: MyItem.toString and zero.toString is called to get the String values
sendCommand(MyItem, one)   // Success: MyItem.toString and one.toString is called to get the String values
sendCommand(MyItem, two)   // Success: MyItem.toString and two.toString is called to get the String values
sendCommand(MyItem, three) // Failure: three is a primitive and has no toString method
sendCommand(MyItem, four)  // Success: MyItem.toString is called and four is already a String

MyItem.sendCommand(one)    // Success: MyItem.sendCommand(Number is called
MyItem.sendCommand(two)    // Success: MyItem.sendCommand(Number) is called
MyItem.sendCommand(three)  // Success: MyItem.sendCommand(int) is called
MyItem.sendCommand(four)   // Success: MyItem.sendCommand(String) is called

You will notice that I skipped over zero above. This is because there is what I am increasingly considering to be a bug in OH. This is beyond the scope of your question and might confuse you more but it also might help further explain. This is also only an issue with Number Items. What will happen is zero will also fail when using the MyItem.sendCommand. This goes back a few paragraphs.

Remember back when I talked about inheritance. Well, DecimalType is a child of Number. This means DecimalType can be treated as if it were a Number, to include casting it to a Number (e.g. MyItem.state as Number). You will notice above there is both a MyItem.sendCommand(DecimalType) and a MyItem.sendCommand(Number) method. So when you call MyItem.sendCommand(zero) the language gets confused. It doesn’t know whether you mean to call MyItem.sendCommand(DecimalType) or MyItem.sendCommand(Number). You will see an error in the logs that says something like “Ambiguous method call”.

12 Likes

Ok Dad!

Seriously though, thank you for the great write up. Not going to lie, I was thoroughly confused by the time I got halfway through the the post but as you say, that is a factor of my limited knowledge of programming. Since I don’t know the basics like the difference between a Number and Integer data point it’s really tough to reach the higher concepts.

Still, it’s a great starting point for research. I’m always willing to learn and this is a great jumping off point.

If I could bother you for just one concrete example of when sendCommand(Item, XX) would not work, be it a switch, thermostat, or whatever. I get the point that “Objects” would work but “Primitives” would not but it would be nice to see at least one real world example.

The big thing you need to watch out for is when using a type that starts with a lower case: int, long, float, double, boolean.

If you have one of those then the call will fail, as illustrated in the “three” example above.

val int three = 3

sendCommand(MyItem, three)

The above will fail.

You will pretty much only see this problem when working with Number and Dimmer Items (or other Items that take numerical states, I don’t use them all so don’t know off the top of my head).

BTW, I smile every time I see Mr. Bean’s face on your postings. :slight_smile:

Hey Rich, now that you spend a few minutes to write all of this down here, please select the important paragraphs and drop them in the documentation. You can also create an issue with the text, if you don’t want to bother with PR creation.

Being completely honest I also never know which to choose and bet on copy&paste from a similar rule of mine. Not really ideal…

@RHINESEL I feel exactly the same way :smiley:

Issue created: https://github.com/openhab/openhab-docs/issues/185

It will be a bit before I can get to it but at least it is captured.

I’ve a TON of these sorts of postings scattered about. I always planned on compiling them into a series of articles , if for no other reason then I can link to them instead of retyping them every time.

I haven’t used any rules that call a var yet so that’s why I guess I’ve never run into an issue.

And thanks, Mr. Bean always makes me smile too!

Next time you are about to answer a question, add it to the FAQs and refer the user there. Deal!?

Sure, though most of my answers are kind of like Software Programming 101 for Dummies type explanations. Is the FAQ appropriate for those?

I’ll spend some time to migrate and rewrite some I’ve already written there. We can find a more appropriate home for them if it becomes a problem.

We could create a second FAQ for common Rule problems… ?

That could work well. Lets wait and see. I’ll make a Rules section in the FAQ and if it gets too long or unwieldy we can move it to its own FAQ or come up with an alternative format.

I’m blind and cannot find the faq. Would you please give me a link?

There you go :wink:

Thanks! I don’t know, how I could not find it.
:hushed:

1 Like

Just +1-ing the ‘Rikoshak is world’s best OH rule explainer and should definitely integrate all these articles in a wiki’.

Or maybe you should start a blog, I think you even risk making money out of it.

Seriously, every time I have an issue I google it and one of your responses comes up. Kudos.

Theoretically, they will all become merged with the docs. But time is in short supply right now so…