OH 5.1.1 how to iterate things in Rules DSL

As part of updating to OH 5.1.1 I found that I have a couple dozen instances of the error:

DSL model 'home.rules' has errors, therefore ignoring it: There is no context to infer the closure's argument types from. Consider typing the arguments or put the closures into a typed context.
- Unloading DSL model 'home.rules'

I have found and fixed most of these where I added a type name to places where was using ‘findFirst’ and ‘forEach’ to iterate items in a group. However, I have one case which I cannot fix. I have the lambda below for checking if a thing is ONLINE based on the “Thing ID”. The code uses a ‘forEach’ and I believe needs to specify the type within the braces, but specifying ‘Thing’ as the type is not accepted and I don’t know what else to try. The 7th line in the code block below is the problem. Can anyone suggest a way to implement this that works in OH 5.1.1 and later?

val Functions$Function1<String,Boolean> isThingOnline = [ String in_thingUID |
    var Boolean returnval = false
    var foundThing = false

    // Check if the device is on-line
    val allthings = ScriptServiceUtil.getInstance.thingRegistry.getAll()
    allthings.forEach [thing |
        // Now get the UID for the device
        val thingUID = thing.getUID().toString()
        if (thingUID == in_thingUID) {
            foundThing = true
            val statusInfo = thing.getStatusInfo()
            val thingStatus = statusInfo.getStatus().toString()
            if (thingStatus == "ONLINE") {
                logWarn("isThingOnline", "Thing " + thingUID + " is ONLINE")
                returnval = true
            }
            else {
                logWarn("isThingOnline", "Thing " + thingUID + " is NOT ONLINE")
                returnval = false
            }
        }
    ]
    if (foundThing == false) {
        logWarn("isThingOnline", "Thing " + in_thingUID + " was not found")
    }
    return returnval
]

Thanks!

I ran into similar problems like this and Grok was able to assist with correction. Give the suggestions here a try ?

Thanks for the reply. I’ve been continuing to look at my rules file and discovered that I was wrong to call out my lambda function in my first post because that wasn’t the problem. I was actually using [group].members.filter in one of my rules and I had missed fixing these to add the type. Once I fixed those the error went away without changing lambda for checking if the thing was ONLINE.

I think I’ve got it working now. By the way, the alternative approach I was going to try to iterate all of the things for my ONLINE checker looked like this:

val Functions$Function1<String,Boolean> isThingOnline = [ String in_thingUID |
    var Boolean returnval = false
    var foundThing = false

    // Check if the device is on-line
    val allthings = ScriptServiceUtil.getInstance.thingRegistry.getAll()
    val Integer numThings = allthings.length
    var Integer thingIdx = 0
    while (thingIdx < numThings) {
        val thing = allthings.get(thingIdx)
        val thingUID = thing.getUID().toString()
        if (thingUID == in_thingUID) {
            foundThing = true
            val statusInfo = thing.getStatusInfo()
            val thingStatus = statusInfo.getStatus().toString()
            if (thingStatus == "ONLINE") {
                logWarn("isThingOnline", "Thing " + thingUID + " is ONLINE")
                returnval = true
            }
            else {
                logWarn("isThingOnline", "Thing " + thingUID + " is NOT ONLINE")
                returnval = false
            }
        }
        thingIdx++
    }
    if (foundThing == false) {
        logWarn("isThingOnline", "Thing " + in_thingUID + " was not found")
    }
    return returnval
]

But I didn’t need it.

That is way more complex than it needs to be.

val isThingOnline = [ String in_thingUID |
    val thing = ScriptServiceUtil.getInstance.thingRegistry.get(new ThingUID(in_thingUID));
    var returnVal = false

    if(thing === null) {
        logWarn("isThingOnline", "Thing " + in_thingUID + " was not found")
    }
    else {
        returnVal = thing.statusInfo.status == ThingStatus.ONLINE
        var status = if (returnVal) "ONLINE" else "NOT ONLINE"
        logWarn("isThingOnline", "Thing " + in_thingUID + " " + status)
    }
]

You might need to import ThingUID and ThingStatus.

2 Likes

Sometimes after var and val types must be provided, sometimes not, sometimes they are ignored, and I do not know when the types are required and when they are ignored. For

val Functions$Function1<String,Boolean> isThingOnline = [ String in_thingUID |

there is more concise syntax:

val (String)=>Boolean isThingOnline = [ String in_thingUID |

It is described at https://eclipse.dev/Xtext/documentation/305_xbase.html#xbase-types-function-types and at https://eclipse.dev/Xtext/xtend/documentation/203_xtend_expressions.html#closure-types.