I’m almost certainly sure it was discussed few times, but i can’t really find any straight answer.
I do have something like
var Number dimmer = 0
if(Kitchen_StripeLED.state != "NULL" && Kitchen_StripeLED.state != "UNDEF") dimmer = (Kitchen_StripeLED.state as Number).intValue
Which saves current state of the dimmer and then lighten LED up to 70%
and then under some conditions I do have
Which should return dimmer to previous state when lights go off
Which now does not work unless I change that to
So question is
Why this does not work when hKitchenDimmer contains number 20
hKitchenDimmer is defined as
but .toString saves the day
I’m sometimes bit lost when to use state and when to use state.toString
It’s a subtle issue of type. When you call
.state you get back an Object of type
sendCommand requires a
Number, or a
Command type Object. So you need to cast or convert that
State Object into one of those in order for it to work as an argument to
toString you are converting the
State to a
String. Other options could be:
MyOtherItem.sendCommand(MyItem.state as Number)
MyOtherItem.sendCommand(MyItem.state as Command) // NOTE: not all States are Commands and not all Commands are States, for example StringType is only a State, PLAY is only a Command
- `sendCommand(MyOtherItem.name, MyItem.state.toString) // NOTE: the postUpdate and sendCommand actions only supports two Strings as arguments
Number Items there is one gotcha. There is a method of
sendCommand that accepts
Number and another one that accepts
DecimalType. For some reason, when you cast the state to
DecimalType it will get confused and throw an ambiguous method call exception because a
DecimalType is also of type
Number. It doesn’t throw an exception when cast to
Number though so I always recommend avoiding casting to
Finally, one more passing comment.
dimmer is a
Number. You cast
Number which is what
dimmer is expecting. So why make the call to
intValue? All it’s going to do is convert the state to a primitive
int only to convert it back to a
Number. Not only is it redundant, at least on OH 2, forcing variables to be a certain type unnecessarily can add huge amounts of time to the loading and parsing of .rules files. I have no expectation that this would change in OH 3. So avoid forcing stuff to be a type unless necessary and definitely avoid forcing stuff to be primitives unless absolutely necessary.
There is a lot of magic that the language does to make it kinda sorta typeless. When it works it’s great (i.e. when you can just call .state and it’s able to convert the
State to what ever it needs to be in that context) but often times it can’t. For example
logInfo("Test", "Some state " + MyItem.state) works because the "Some state " is a String so the language is smart enough to coerce MyItem.state to a String by calling toString for you. However,
logInfo("Test", MyItem.state + " Some state") wont work because the first argument is a
State/Number and it’s not smart enough to realize that if the second argument is a String so you want to use the String + operator, not the Number + operator.
So use the following rules to thumb.
- By default don’t specify the type
- When it doesn’t work cast it to
Number (if you are in a calculations/comparison context) or call
- Only ever convert a Number to a primitive when necessary and do so at the last moment (e.g. in calling
now.plusSeconds((MyDelay.state as Number).intValue))
Thanks @rlkoshak as always for great explanation !
most probably some kind of leftofvers from the past when I created those rules… you know "if it ain’t broke, don’t fix it"
But I very often sadly do try to fix it for no good reason