[Fixed] Problem with sendMiosAction in OH2

Hre is the rule:

import org.openhab.core.library.types.*
import org.openhab.model.script.actions.*
import org.joda.time.*
import java.util.regex.Matcher
import java.util.regex.Pattern

rule "Synthèse vocale"
when
    Item TTSCommand received command
then
    logInfo("TTS","TTSCommand=" + TTSCommand.state.toString)
    
    var params = TTSCommand.state.toString.split(",")
    var String room = params.get(0)
    var String command = params.get(1)
    logInfo("TTS","room=" + room + " command=" + command)
    var item = SonosSalonId
    if (room == "salon") {
        item = SonosSalonId
    }
    else if (room == "chambre") {
        item = SonosChambreId
    }
    else {
        item = null
    }
    if (command == "heure") {
        var int heure = now.getHourOfDay
        var int minute = now.getMinuteOfHour
        var String msg
        if (heure == 0) {
            msg = String::format("Il est minuit %d.", minute)
        }
        else if (heure == 1) {
            msg = String::format("Il est une heure %d.", minute)
        }
        else {
            msg = String::format("Il est %1$d heures %2$d.", heure, minute)
        }
        try {
            msg = msg.encode("UTF-8")
        }
        catch (Exception e) {
        }
        sendMiosAction(item, "Sonos/Say", newArrayList('Text' -> msg, 'Language' -> 'fr', 'GroupZones' -> 'Current', 'Volume' -> 50))
    }
end

SonosSalonId and SonosChambreId are two of my items in my items file.
I get this error:

21:47:30.508 [ERROR] [.script.engine.ScriptExecutionThread] - Error during the execution of rule 'Synthèse vocale': Cannot resolve proxy: java:/Objects/org.openhab.core.items.Item#org.openhab.core.items.Item

What could be wrong ?

I think the problem is in fact the call to sendMiosAction.

This rule works:

rule "Synthèse vocale"
when
    Item TTSCommand received command
then
    logInfo("TTS","TTSCommand=" + TTSCommand.state.toString)
    
    var params = TTSCommand.state.toString.split(",")
    var String room = params.get(0)
    var String command = params.get(1)
    logInfo("TTS","room=" + room + " command=" + command)
    if (command == "heure") {
        var int heure = now.getHourOfDay
        var int minute = now.getMinuteOfHour
        var String msg
        if (heure == 0) {
            msg = String::format("Il est minuit %d.", minute)
        }
        else if (heure == 1) {
            msg = String::format("Il est une heure %d.", minute)
        }
        else {
            msg = String::format("Il est %1$d heures %2$d.", heure, minute)
        }
        try {
            msg = msg.encode("UTF-8")
        }
        catch (Exception e) {
        }
        logInfo("TTS","msg=" + msg)
    }
end

If I add the call to sendMiosAction, I get the error:

rule "Synthèse vocale"
when
    Item TTSCommand received command
then
    logInfo("TTS","TTSCommand=" + TTSCommand.state.toString)
    
    var params = TTSCommand.state.toString.split(",")
    var String room = params.get(0)
    var String command = params.get(1)
    logInfo("TTS","room=" + room + " command=" + command)
    if (command == "heure") {
        var int heure = now.getHourOfDay
        var int minute = now.getMinuteOfHour
        var String msg
        if (heure == 0) {
            msg = String::format("Il est minuit %d.", minute)
        }
        else if (heure == 1) {
            msg = String::format("Il est une heure %d.", minute)
        }
        else {
            msg = String::format("Il est %1$d heures %2$d.", heure, minute)
        }
        try {
            msg = msg.encode("UTF-8")
        }
        catch (Exception e) {
        }
        logInfo("TTS","msg=" + msg)
        sendMiosAction(SonosChambreId, "Sonos/Say", newArrayList('Text' -> msg, 'Language' -> 'fr', 'GroupZones' -> 'Current', 'Volume' -> 50))
    }
end

@lolodomo,
This turns out to be quite interesting.

The OH 1.x MiOS Action is implemented using two calls akin to:

sendMiosAction(<Item>, <String>)
sendMiosAction(<Item>, <String>, List<Pairs>)

So it’s expecting to be called with an openHAB 1.x Item as a parameter.

Per your example above, it uses a model that’s similar to sendCommand(), and you get something like:

sendMiosAction(SonosChambreId, "Sonos/Say", ...)

With Rules executing under openHAB 2.x, we’re working with ESH Item instead, which is a wholly different beast (different Java package/Interface) and, as a result it doesn’t find a signature match and fails with the error you’re seeing above.

In theory, there are a few options to address the problem but, in practice, most of these run into other issues:

OPTION A: Overload the static methods in the MiOS Action declaration to include “String-based” parameter variants.
Users moving to OH2.x would convert from using the Item, to using the name-of-the-Item when making the calls.

sendMiosAction(SonosChambreId, ...)

becomes

sendMiosAction("SonosChambreId", ...)
  • ISSUE: In practice, this doesn’t work. The runtime appears to have a problem matching the String-only version or the presence of the (OH1) Item-based one confuses it, so it fails with a different type of error.
  • ISSUE: It’s not consistent with the commonly used internal method sendCommand(<Item>) - although it has both variants.

OPTION B: Wrap the incoming parameters with OH Compat 1.x equivalents (for Item)
so the method-matching logic will find the OH 1.x Action implementation correctly.
I’m not clear on how this part of the code works today, so this may be more complex than I’d imagine, but it would provide for the best overall compatibility.

  • ISSUE: Given there are only a handful of Bindings that use Structured type parameters, this may be overkill.

OPTION C: Overload the static methods in the MiOS Action declaration to include variants with ESH Item.
Similar to option (A)

  • ISSUE: This would likely have the reverse problem of dragging ESH dependencies into the OH1 Binding that might cause it not to resolve correctly in an OH 1.x environment (existing users break, in theory)
  • ISSUE: It has the same issue with overloading that OPTION A had.

OPTION D: Cutover to using String-based static methods for the implementation, and not use Item parameters.

  • ISSUE: Backwards compatibility would be broken for existing rules, and users would have to cutover “all at once” since, due to OPTION A issues, there couldn’t be an easy overlap version that lets them migrate.

Each has it’s own set of issues and some, like the Overloading scenarios.

At this point I’m tempted to break compatibility (OPTION 4) but, IMHO, this doesn’t provide a very natural scripting experience in openHAB.

@watou, It looks like you’re using Item class in the parameters of your Action Bindings for Nest and EcoBee. Can you confirm that you’re successfully exercising OH 2 Rules using these via the Compat layer? Maybe there’s something else I’m missing.

Your analysis makes perfect sense and I have no contrary evidence.

If the compat1x layer can be made to match the current method signatures of the ecobee and mios actions if the org.eclipse.smarthome version doesn’t match (B), that would be the most compatible for users. Otherwise those two action bundles might just be changed to look up itemNames in the ItemRegistry (D), because that’s the easiest change to make to existing rules. I will follow your and @Kai’s lead on how to adapt the ecobee action service if needed.

The compat layer actually does not have a chance to hook into the parameters of a call for transforming them - the classes are registered as they are. So I doubt that option B is easily feasible.

A way to not break the rules for existing users might be to offer both methods (one with openhab-Item, and once with Strin parameters). OH 1.x users could continue to use the Item version, while OH2 users would have to use the String version (temporarily, until a ported version of the bindings is available :slight_smile: ).

Yup, that’s OPTION A in the list above. I tried that, and it looks like the Method resolver has issues with this. I vaguely remember these existing in openHAB 1.x (originally I was trying to mimic sendCommand(..) syntax)

In my pre-compat version, the MiOS Action exposes something like:

sendMiosAction(<Item>, <String>)
sendMiosAction(<Item>, <String>, List<Pairs>)

so I augmented this with the String variants to get:

sendMiosAction(<Item>, <String>)
sendMiosAction(<Item>, <String>, List<Pairs>)
sendMiosAction(<String>, <String>)
sendMiosAction(<String>, <String>, List<Pairs>)

and then I’d use an OH 2 RuleDef like:

import java.util.List

rule "Test sendMiosAction"
when
    Time cron "0/10 * * * * ?"
then
    var List y = newArrayList('newLoadlevelTarget' -> 0)
    sendMiosAction("GuestBedroom2LightsId", "HaDevice1/TiggleState", y)
end

But the resolver chokes on it, because it’s still attempting to resolve the OH 1.x Item references, even though they’re not used in my Rule.

The specific error is:

2016-01-30 12:41:00.007 [ERROR] [.m.r.r.i.engine.ExecuteRuleJob:62   ] - Error during the execution of rule Test sendMiosActionjava.lang.IllegalStateException: Cannot resolve proxy: java:/Objects/org.openhab.core.items.Item#org.openhab.core.items.Item
	at org.eclipse.xtext.common.types.util.JavaReflectAccess.getRawType(JavaReflectAccess.java:108)
	at org.eclipse.xtext.common.types.util.JavaReflectAccess.getRawType(JavaReflectAccess.java:150)
	at org.eclipse.xtext.common.types.util.JavaReflectAccess.getParamTypes(JavaReflectAccess.java:144)
	at org.eclipse.xtext.common.types.util.JavaReflectAccess.getMethod(JavaReflectAccess.java:76)
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.invokeOperation(XbaseInterpreter.java:1063)
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.invokeOperation(XbaseInterpreter.java:1059)
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._invokeFeature(XbaseInterpreter.java:1045)
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter.invokeFeature(XbaseInterpreter.java:990)
	at org.eclipse.smarthome.model.script.interpreter.ScriptInterpreter.invokeFeature(ScriptInterpreter.java:112)
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:900)
	at org.eclipse.xtext.xbase.interpreter.impl.XbaseInterpreter._doEvaluate(XbaseInterpreter.java:863)

That’ll be a while. I have similar progressive discovery issues that Chris has (although not quite as bad). When devices appear in MiOS/Vera, they’re often not fully formed, and “bits” of them can come along at a later stage. For most, this is quick, but when proxying Z-Wave Battery devices this process can take some time to become complete.

During the process/cycle, there’s no notion that it’s ready/finished so they could get new properties, new children/channels, etc… more or less at any time :frowning:

Ok, thanks for the details, I probably should have read the topic in detail from the start :slightly_smiling:

Maybe a workaround for this: If you register two action services through OSGi, the one with methods using items could declare a dependency on a service that only exists in openHAB 1 and thus wouldn’t be activated on openHAB 2.
The other service could then have the String version and be activated on any runtime. Do you think that might work?

Maybe. The trick is working out how to build that under the existing framework (so we remain single-source etc, but with multiple build-targets - one specifically to handle OH 2.x compatibility)

That said, I think it’s easier for Rule authors to understand calls of the form…

sendCommand(MyItem, ON)
sendMiosAction(MyItem, ...)

or perhaps this:

MyItem.sendCommand(ON)
MyItem.sendMiosAction(...)

than this mixed-syntax model that’s likely to confuse folks more:

sendCommand(MyItem, ON)
sendMiosAction("MyItem")

Did you test MyItem.SendMiosAction(…) ?
If it works, that could be enough.

@lolodomo,
That’s this long-standing issue, which any Action binding that works on Items would have:

I may have another way to do it. It looks like the method overload doesn’t have issues if one of the methods is using Object like this:

sendMiosAction(<Object>, <String>)
sendMiosAction(<Object>, <String>, List<Pairs>)
sendMiosAction(<String>, <String>)
sendMiosAction(<String>, <String>, List<Pairs>)

Then, internally, I just need to dynamically invoke getName() to end up with the String handle I already pass off to the MiOS Binding. It may not work as cleanly with the Nest/EcoBee bindings but it’ll handle this case.

I’ll need to try it out, and ensure it doesn’t break OH 1.x (etc)

@lolodomo,
I filed this for tracking:

I have a version locally that works correctly with OH 2.x, so I just need to validate that it doesn’t break anything in OH 1.x, and then submit the PR.

Thanks for the testing, it’s been extremely helpful!

@lolodomo,
PR 3931 filed and out for peer review:

I ran it both under openHAB 2.x (via IDE) and in my Production 1.8.x build and it’s working fine. If you want to try out an early version, you can build it from the PR, or pull it from my Box account:

@guessed: thank you so much for finding a solution so quickly.
I will test tomorrow morning.

1 Like

@guessed: bravo, I can confirm that it is working correctly with my rules when I use your jar file.