Type Conversions

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.

I can’t even log it :joy: as the editor does not accept the expression as any kind of number…
Bummr…
It throws Messages like “cannot convert from Decimal to String”, or “cannot convert from Number to decimal”…and so on. When I do NOTHING to the string, it still shows the first error. So no idea how to log it

logInfo("Waschmaschine Strom Durchschnittswert",(Steckdose_Waschmaschine_Strom.averageSince(now.minusMinutes(2))))
nope

logInfo("Waschmaschine Strom Durchschnittswert",(Steckdose_Waschmaschine_Strom.averageSince))
nope

logInfo("Waschmaschine Strom Durchschnittswert",(Steckdose_Waschmaschine_Strom.averageSince as Decimal)
nope

logInfo("Waschmaschine Strom Durchschnittswert",(Steckdose_Waschmaschine_Strom.averageSince as Number)
nope

logInfo("Waschmaschine Strom Durchschnittswert",(Steckdose_Waschmaschine_Strom.averageSince as Number).floatValue
nope

logInfo("Waschmaschine Strom Durchschnittswert",(Steckdose_Waschmaschine_Strom.averageSince as Decimal).floatValue
nope

…(don’t look at the brackets too close, I have just written the different expressions from the top of my head)

Edit: THIS I love the most:

logInfo("Waschmaschine Strom Durchschnittswert",(Steckdose_Waschmaschine_Strom.averageSince as DecimalType))

returns the error

file: 'file:///Volumes/openHAB-share/openhab2-conf/rules/washing_machine_state.rules'
severity: 'Warnung'
message: 'Unnecessary cast from DecimalType to DecimalType'
at: '18,98'
source: ''
code: 'org.eclipse.xtext.xbase.validation.IssueCodes.obsolete_cast'

So if I do nothing, it’s wrong. If I cast decimal to decimal it’s redundant. Ok, now there’s a complete clusterf** in my mind…

Ok, I guess I let that sit where it ist for today and give it a fresh try on the weekend.

Ignore the editor for now. Just because the editor marks it as wrong does not mean it won’t run (necessarily). If you save the file and openhab.log doesn’t spit out a syntax error log statement the Rule will run.

Bingo. So averageSince is returning a DecimalType.

So you should be able to log:

logInfo("Waschmaschine Strom Durchschnittswert", Steckdose_Waschmaschine_Strom.averageSince(now.minusMinutes(2)).toString)

I think I mentioned in the original posting above that OH is not good at converting numbers to strings.

That is just a warning. The code will still run.

Since it is returning a DecimalType and I already explained why DecimalType is a problem, the same solution I recommended for the first line will apply here as well.

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

Please be aware that it’s

logInfo(String,String)

where the first string is the logger name, and the second string is the logged message.
The log line is like

2016-06-04 16:28:39.482 [INFO] [me.model.script.loggername] Log Message

and you could switch the logging ON and OFF by using

log:set DEBUG|INFO|WARN|ERROR|OFF org.eclipse.smarthome.model.script.loggername

Edit: It seems to work now.

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

//#########################################################################//
//Waschmaschine Status anhand des aktuellen Stromverbrauches setzen                               //
//Wenn Status Fertig, dann Telegram senden                                                                            //
//#########################################################################//

rule "Waschmaschine Status"
when
    Item Steckdose_Waschmaschine_Strom changed
then
  logInfo("WaMa Strom Durchschnitt 30 min", Steckdose_Waschmaschine_Strom.averageSince(now.minusMinutes(30)).toString)
  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)) as Number) < 50) {
    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)) as Number) < 150){
    if (Waschmaschine_OpState.state == (Waschmaschine_MODE_CREASE_PROTECTION)) Waschmaschine_OpState.postUpdate(Waschmaschine_MODE_FINISHED)
  }
 end  

Thanks a lot for your help and patience !

Hm, seems the problem is only solved partially…this doesn’t look to me like an average being calculated?

2018-03-18 17:07:07.447 [INFO ] [cript.WaMa Strom Durchschnitt 30 min] - 280.96
2018-03-18 17:07:12.612 [INFO ] [cript.WaMa Strom Durchschnitt 30 min] - 0.0
2018-03-18 17:07:14.311 [INFO ] [cript.WaMa Strom Durchschnitt 30 min] - 786.56000000000
2018-03-18 17:07:15.984 [INFO ] [cript.WaMa Strom Durchschnitt 30 min] - 505.92
2018-03-18 17:07:27.923 [INFO ] [cript.WaMa Strom Durchschnitt 30 min] - 0.0
2018-03-18 17:07:29.589 [INFO ] [cript.WaMa Strom Durchschnitt 30 min] - 421.76
2018-03-18 17:07:41.401 [INFO ] [cript.WaMa Strom Durchschnitt 30 min] - 0.0
2018-03-18 17:07:44.780 [INFO ] [cript.WaMa Strom Durchschnitt 30 min] - 561.92
2018-03-18 17:07:56.701 [INFO ] [cript.WaMa Strom Durchschnitt 30 min] - 0.0
2018-03-18 17:07:58.381 [INFO ] [cript.WaMa Strom Durchschnitt 30 min] - 646.72
2018-03-18 17:08:00.065 [INFO ] [cript.WaMa Strom Durchschnitt 30 min] - 392.960000000000
2018-03-18 17:08:10.277 [INFO ] [cript.WaMa Strom Durchschnitt 30 min] - 0.0
2018-03-18 17:08:13.642 [INFO ] [cript.WaMa Strom Durchschnitt 30 min] - 421.76
2018-03-18 17:08:25.525 [INFO ] [cript.WaMa Strom Durchschnitt 30 min] - 0.0
2018-03-18 17:08:27.212 [INFO ] [cript.WaMa Strom Durchschnitt 30 min] - 843.52
2018-03-18 17:08:28.890 [INFO ] [cript.WaMa Strom Durchschnitt 30 min] - 449.92
2018-03-18 17:08:40.781 [INFO ] [cript.WaMa Strom Durchschnitt 30 min] - 0.0
2018-03-18 17:08:42.481 [INFO ] [cript.WaMa Strom Durchschnitt 30 min] - 533.76
2018-03-18 17:08:54.383 [INFO ] [cript.WaMa Strom Durchschnitt 30 min] - 0.0
2018-03-18 17:08:56.063 [INFO ] [cript.WaMa Strom Durchschnitt 30 min] - 252.96
2018-03-18 17:08:57.762 [INFO ] [cript.WaMa Strom Durchschnitt 30 min] - 561.92
2018-03-18 17:09:09.670 [INFO ] [cript.WaMa Strom Durchschnitt 30 min] - 0.0
2018-03-18 17:09:11.329 [INFO ] [cript.WaMa Strom Durchschnitt 30 min] - 674.5600000000001
2018-03-18 17:09:13.035 [INFO ] [cript.WaMa Strom Durchschnitt 30 min] - 392.960000000000
2018-03-18 17:09:23.240 [INFO ] [cript.WaMa Strom Durchschnitt 30 min] - 0.0

Seems the averageSince is not really processed…instead it returns the current value which is pointless :frowning:

(ok, so this isn’t about the casting anymore)

If you can check the database to see what is being saved. The problem could be a bunch of places so we need to start narrowing it down.

Hm, as the Graph is being drawn, I’d would need a hint where and how to check the rr4dj files please?

The graph is a good indication that things are working. You can user the OH REST API to do some a queries against the db directly.