Log: There is no context to infer the closure's argument types from

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

Anything to suggest?

In my opinion this is based on the fact that the system has ti guess which kind of type is returned. Try somsthing like

val ContactItem window = Windows.members.filter[ i | i.name.contains(room) ].head as ContactItem
1 Like

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.

2 Likes

I had this come up because I used a not yet defined group name in a lambda. After I defined the group in the .items file, everything was OK

2 Likes

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

Best, Jay

I never managed to get rid of them
It’s only a warning and the rules run

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.

3 Likes

Thanks Rich for helping me out!

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)

Best, Jay

Hi Vincent, did you get this to work? I too get the error.

my rule is:

al Number lowBatteryThreshold = 35

rule "Battery Status Check"
when
    Item gBatteries changed
then
    var String msg = ""
    var triggertDevices = gBatteries.members.filter[s|s.state <= 35]

    triggertDevices.forEach [ i |
        msg = msg + (transform("MAP", "batteries.map", i.name) + ': ' + i.state.toString) + '%\n'
        logInfo("Battery Check","Low battery at " + i.name + ": " + i.state.toString + "%")
    ]

    if (msg != "") {
     sendBroadcastNotification(msg + " of your battery remaining")
    }
end

No, not really.
I use jython now

No worries