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).
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.
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.
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.
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”.
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?
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)
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…
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
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”
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 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…
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.
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