I get these messages in the log openhab.log at start up and when changing these rule files:
2018-05-18 07:08:32.976 [INFO ] [el.core.internal.ModelRepositoryImpl] - Validation issues found in configuration model 'main.rules', using it anyway:
There is no context to infer the closure's argument types from. Consider typing the arguments or put the closures into a typed context.
2018-05-18 07:08:32.988 [INFO ] [el.core.internal.ModelRepositoryImpl] - Loading model 'main.rules'
VSCode is not suggesting anything wrong.
It is only in rules where I use members.filter or allMembers.filter
Example:
rule "Battery Monitor"
when
Time cron "0 55 10 * * ?"
then
if (!Batteries.allMembers.filter( [ battery | (battery.state as Number) <= (lowBatteryThreshold) ] ).empty) {
val report = Batteries.allMembers.filter( [ (state as Number) <= (lowBatteryThreshold) ] ).sortBy( [ state as DecimalType ] ).map[ name + ": " + state.format("%d%%") ].join("\n")
val message = "Battery levels:\n\n" + report + "\n\nRegards,\n\nOur House"
sendMail("vzorglub@gmail.com", "Low battery alert !", message)
}
end
or
rule "Generic Windows Changed"
when
Member of HeatingWindows changed or
Member of Radiators changed
then
val room = triggeringItem.name.split("_").get(0)
val window = Windows.members.filter[ i | i.name.contains(room) ].head
val radiator = Radiators.members.filter [ i | i.name.contains(room) ].head
if (radiator.state == ON) {
if (window.state == OPEN) {
sendCommand(room + "_RadiatorValve", "OFF")
}
}
if (radiator.state == OFF) {
if (window.state == CLOSED) {
val offset = House_HeatingOffset.state as Number
val target = Targets.members.filter[ i | i.name.contains(room) ].head.state as Number
val ambient = AmbientTemps.members.filter[ i | i.name.contains(room) ].head.state as Number
if (ambient <= (target - (offset / 2))) {
sendCommand(room + "_RadiatorValve", "ON")
}
}
}
end
Thomas is right, at compile time (i.e. when the Rules are loaded) the Rules Engine can’t figure out what type is being used in the lambdas (everything between [ ] is a lambda). In particular, it can’t figure out what the type of battery is in the first filter in your first Rule or i isin the Windows filter in your second rule.
Adding the type to the result of head might work. If it doesn’t give a type to the items in the filter.
val window = Windows.members.filter[ ContactItem i | i.name.contains(room) ].head
I just did a grep through my Rules and I’ve see I use both over the years.
I’m trying to figure this syntax out and came across this posting . . .
This syntax works but I think the error I’m getting on a clean boot up is tied to this syntax.
if (Temperatures.members.filter(s | s.state > 89).size > 0) { // check for any temperature sensors in the house that are very high
I tried to re-write it based on the posting but it fails; any suggestions on how it should be written?
val SensorItem firesensor = Temperatures.members.filter[s | s.state].size as SensorItem
if (firesensor.state > 89) { // check for any temperature sensors in the house that are very high
What’s a SensorItem? As far as I know there is no such Item type. Is it a Number Item or a Number:Temperature Item?
And .size returns the number of entries in what the filter returns. It’s just an int, not even a Number. You can’t cast an int to SensorItem even if there were such a thing as a Sensor Item.
The “closure” part is the [ ] after the filter. The error is saying that it can’t figure out what type s is. We know that s is an Item so use filter[ GenericItem s | s.state != NULL && s.state != UNDEF && s.state > 89 ].size. Note, I added a bunch of other tests to avoid an error should any member of Temperatures be NULL or UNDEF.
I just made up the value SensorItem; wasn’t sure what/where this variable came from. All the items that report temperatures are NUMBERS.
Example below:
Number FurnaceSensor_Temp "Floor Temperature [%.2f]" (FurnaceWater, Temperatures) { channel="zwave:device:ffffffd1ffffffb2ffffffdbffffffad:node13:sensor_temperature" }
Based on that; I’m assuming your syntax will still work? Here’s what I’m proposing to use:
if (Temperatures.members.filter[ GenericItem s | s.state != NULL && s.state != UNDEF && s.state > 89 ].size > 0)