Type Conversions

@rlkoshak took all your suggestions form post #11 and incorporated them. This time I edited the wiki as discussed.

It did not make sense to me to add this to the Number item section, as it is stated there:

Which would make it confusing to me, how we end up with a hex-value. Thus, I added it to the string section, please check whether you are OK with it and whether I captured it correctly.

Finally, if we are all OK, I am not sure how to proceed as it may cause conflicts with PR#469. Both should go into the rules documentation and #469 should come before this one here. I guess I will wait until #469 is merged and open another PR for issue #472 only after it merged.

The conversion is to go from hex to DecimalType, or at least. The article, in my mind at least, should cover conversions in both directions. We show both directions in the DateTime section.

It comes up frequently. All that being said, the String section is as good a place to put it as the Number section. We should probably include an example of parsing a Date Time String.

I’m on my phone for the next few days so can’t easily look up the the issue numbers. But I have no problems with what you say.

Ok, good points, I added some more conversions in particular hex to Number and DecimalType (and vice versa) to the wiki entry

Hey guys, short reply from me. I’m currently on a surprise vacation (invited on Thursday, flight Friday morning). I think we should try to make the article a bit more systematic, as already mentioned here. Definitely something I can work on in the next couple of day (I have my laptop with me).

The rest of the changes look great! Later guys :wink:

Really great text and discussion!

What bothered me for some time - is there a way to convert string (the name of the item) to the object, so the item object further be manipulated.

If there is no way for this, it would be great to have this clearly stated as well.

No, from a programming perspective that doesn’t make any sense. We could add a statement that one cannot do this but if we start going down the path of listing everything that one cannot do the article becomes infinite in length.

Having said that, if you do a little but of setup up front you can get the Item or if a group by name. See Design Pattern: Associated Items

Thanks, fair enough. I just thought about something like FAQ where “NO” would be said to questions of dummies, even if they do not make sense from a programming perspective.

Just wanted to mention that here for everyone to be aware, the tutorial posted here is now also available at:

http://docs.openhab.org/configuration/rules-dsl.html#conversions

If you want to add improvements or additions, please do so there!

3 Likes

I don’t know if this is relevant, but I’m trying do define a Map, like this:

var Map<GenericItem, State> LightStates = null

However this does not work, as “State cannot be resolved to a Type” Is State a Type?
If I leave the parameters off, I get a warning “Map is raw type it should be parameterized”, but it works.

The discussion here https://community.openhab.org/t/storestates-restorestates/29994/3 says that this is correct.

Not a big deal, the raw Map works, just gives an error when the rules are loaded is all.

I don’t know this definitively, but I do not think that one can use Java Interfaces as Types in the Rules DSL. This is also why you can’t do Map<Item, Boolean>. Since State is an Interface rather than a proper class I think you can’t define the Map like that.

You can’t use Item either, as Item is an openhab reserved word, which was why is was using GenericItem.

I tried:

MAP<GenericItem, Object>

to see if that would work, and I get the error "can’t map Map<Item, State> to Map<GenericItem, Object>

Doesn’t really matter, I’ll just chalk it up to “openhab weirdness”.

1 Like

Hi,
the expression:

val hours = (MyDateTimeItem.state as DateTimeType).calendar.get(Calendar::HOUR_OF_DAY)

gives an error:

The name ‘Calendar’ cannot be resolved to an item or type

it is needed:

import java.util.Calendar

I am not sure about the syntax. Look here:

In 2.2 release and beyond you need to use

(MyDateTimeItem.state as DateTimeType).getZonedDateTime.getHour
1 Like

Hi guys,

casting and type coversion is something that drives me crazy as well. Maybe you can point me to the right direction:

This is the rule that should tell me when the washinmachine is done. Took the biggest part of that from annother post (I guess it was from Thom Dietrich)

val Number Waschmaschine_MODE_OFF = 0
val Number Waschmaschine_MODE_STANDBY = 1
val Number Waschmaschine_MODE_ACTIVE = 2
val Number Waschmaschine_MODE_FINISHED = 3
val Number Waschmaschine_MODE_CREASE_PROTECTION = 4

var Number Waschmaschine_Counter = 0


rule "Waschmaschine Status"
when
    Item Steckdose_Waschmaschine_Strom changed
then
  if (Steckdose_Waschmaschine_Strom.state < 1) Waschmaschine_OpState.postUpdate(Waschmaschine_MODE_OFF)
  else if (Steckdose_Waschmaschine_Strom.state > 100  && Waschmaschine_OpState.state !== (Waschmaschine_MODE_CREASE_PROTECTION) || Steckdose_Waschmaschine_Strom.state > 500){
    Waschmaschine_OpState.postUpdate(Waschmaschine_MODE_ACTIVE)
  }
  if (Waschmaschine_OpState.state == (Waschmaschine_MODE_ACTIVE) && Steckdose_Waschmaschine_Strom.state < 2){
    Waschmaschine_Counter = Waschmaschine_Counter + 1
  }
  if (Steckdose_Waschmaschine_Strom.state > 1 && Steckdose_Waschmaschine_Strom.averageSince(now.minusMinutes(2)) < 2) {
    if (Waschmaschine_OpState.state == Waschmaschine_MODE_OFF) Waschmaschine_OpState.postUpdate(Waschmaschine_MODE_STANDBY)
  }
  if (Waschmaschine_Counter > 6){
    if (Waschmaschine_OpState.state == Waschmaschine_MODE_ACTIVE){
      Waschmaschine_Counter = 0
      Waschmaschine_OpState.postUpdate(Waschmaschine_MODE_CREASE_PROTECTION)
    }
  }
  if (Steckdose_Waschmaschine_Strom.averageSince(now.minusMinutes(30)) < 150){
    if (Waschmaschine_OpState.state == (Waschmaschine_MODE_CREASE_PROTECTION)) Waschmaschine_OpState.postUpdate(Waschmaschine_MODE_FINISHED)
  }
 end  

Now when loading into VSC, it throws an error like this

file: 'file:///Volumes/openHAB-share/openhab2-conf/rules/washing_machine_state.rules'
severity: 'Fehler'
message: 'Ambiguous binary operation.
The operator declarations
	operator_lessThan(Number, Number) in NumberExtensions and
	operator_lessThan(Type, Number) in NumberExtensions
both match.'
at: '25,114'
source: ''
code: 'org.eclipse.xtext.xbase.validation.IssueCodes.ambiguous_feature_call'

The script runs and alternates between states “0” and “2”, but never actually reaches “1”, “3” or “4”.

Guess the main problem is this expression here

Steckdose_Waschmaschine_Strom.averageSince(now.minusMinutes(2)) < 2)

So I have tried “xxx as Decimal”, “(xxx as Decimal).floatValue”, replaced the figure “2” with a variable of type int or type float or type number, nothing worked. What am I doing wrong?

Thanks for any hints

You’ve hit one of the weird cases.

I think the problem is the first line of the Rule.

if (Steckdose_Waschmaschine_Strom.state < 1) Waschmaschine_OpState.postUpdate(Waschmaschine_MODE_OFF)

Steckdose_Waschmaschine_Strom.state (assuming it is a Number Item) carries a DecimalType. But DecimalType is both of type Number and of type Type. So when the Rules Engine tries to run the < operator it doesn’t know which one to run, the one that takes Number, Number or it takes Type, Number.

You can fix this by telling the Rules Engine which < operation to call by casting the state to Number.

if (Steckdose_Waschmaschine_Strom.state as Number < 1) Waschmaschine_OpState.postUpdate(Waschmaschine_MODE_OFF)
1 Like

Great, why I am always that lucky…

The line you have posted is working and not mentioned by VSC. I guess the problem is exactly what you said, but I guess i’d rather need to specify the type of this expression: ‘Steckdose_Waschmaschine_Strom.averageSince(now.minusMinutes(2)’, as the comparison to ‘>2’ fails.
…and this is where I have no clue, how to do it…

First of all, do you have persistence set up?

Secondly, log out the result of the call from averageSince. If there is a problem with persistence or the data in the database then averageSince will return null and you can’t compare null with >.

Anytime you have errors or a rule doesn’t execute as expected:

  • watch the openhab.log for errors
  • watch events.log to verify the events that should trigger the Rule are happening
  • log out everything

Yes, using rrd4j

Ok, guess this I will have to check, thanks! But as the error is already stated by the editor (VSC), I’d say we should stick with the casting problem.

no errors, ‘2018-03-15 17:53:35.324 [INFO ] [el.core.internal.ModelRepositoryImpl] - Loading model ‘washing_machine_state.rules’’
No additional line (error) after that. So should be fine.

The triggers are occuring (changes in current drawn by the machine. I can see it changing in the GUI, it is logged in persistence so I can draw a chart and the values are written in events.log. The rule itself works but never enters the states I have stated above. When editing the code in VSC, it returns the lines in question with the errors I have posted. Still, the rule itself runs and returns the states “off” and “active” when the specified conditions (current drawn by the machine) are true.

What else could I log? I guess you where spot on with your first reply, it must be a casting problem. So how do I cast this expression so the rule engine understands it as a number it can compare to the value of “< 2”

Steckdose_Waschmaschine_Strom.averageSince(now.minusMinutes(2))

Is the syntax of the type correct (xyz(now.minusMinutes(2)) ?

If you log out the result you will immediately be able to see what it is that averageSince is returning. We won’t know what we can cast it to or what we need to convert it from until we know what it is.