MQTT 2.0 - Error Updating Integer types using Homie Convention

I am running into an error updating integer types in the new MQTT 2.0 binding with a device using the homie convention. I have no problems with string types.

Rule looks like this:

rule "Track Time Changed"
when
    Item ChromecastStatusCurrentTime changed
then
    val trackPosition = (ChromecastStatusCurrentTime.state as DecimalType).intValue
    logInfo("Nuvo", "Sending new track position {}", trackPosition)
    //Nuvo_Source_5_Track_Position.sendCommand(new Integer(trackPosition))
    Nuvo_Source_5_Track_Position.sendCommand(50)
end

note I simplified it to just send 50, in case my conversion was an issue.

Item is defined like this:

Number                 Nuvo_Source_5_Track_Position      {channel="mqtt:homie300:mosquitto:nuvo:source5#position"}

I see the following in the log when an update happens:

2019-01-12 13:34:33.943 [DEBUG] [eneric.internal.generic.ChannelState] - Format pattern incorrect for mqtt:homie300:mosquitto:nuvo:source5#position

java.util.IllegalFormatConversionException: d != java.lang.String

	at java.util.Formatter$FormatSpecifier.failConversion(Formatter.java:4302) ~[?:?]

	at java.util.Formatter$FormatSpecifier.printInteger(Formatter.java:2793) ~[?:?]

	at java.util.Formatter$FormatSpecifier.print(Formatter.java:2747) ~[?:?]

	at java.util.Formatter.format(Formatter.java:2520) ~[?:?]

	at java.util.Formatter.format(Formatter.java:2455) ~[?:?]

	at org.eclipse.smarthome.binding.mqtt.generic.internal.generic.ChannelState.publishValue(ChannelState.java:312) [230:org.eclipse.smarthome.binding.mqtt.generic:0.10.0.oh240]

	at org.eclipse.smarthome.binding.mqtt.generic.internal.handler.AbstractMQTTThingHandler.handleCommand(AbstractMQTTThingHandler.java:119) [230:org.eclipse.smarthome.binding.mqtt.generic:0.10.0.oh240]

	at sun.reflect.GeneratedMethodAccessor121.invoke(Unknown Source) ~[?:?]

	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?]

	at java.lang.reflect.Method.invoke(Method.java:498) ~[?:?]

	at org.eclipse.smarthome.core.internal.common.AbstractInvocationHandler.invokeDirect(AbstractInvocationHandler.java:153) [102:org.eclipse.smarthome.core:0.10.0.oh240]

	at org.eclipse.smarthome.core.internal.common.InvocationHandlerSync.invoke(InvocationHandlerSync.java:59) [102:org.eclipse.smarthome.core:0.10.0.oh240]

	at com.sun.proxy.$Proxy222.handleCommand(Unknown Source) [230:org.eclipse.smarthome.binding.mqtt.generic:0.10.0.oh240]

	at org.eclipse.smarthome.core.thing.internal.profiles.ProfileCallbackImpl.handleCommand(ProfileCallbackImpl.java:75) [109:org.eclipse.smarthome.core.thing:0.10.0.oh240]

	at org.eclipse.smarthome.core.thing.internal.profiles.SystemDefaultProfile.onCommandFromItem(SystemDefaultProfile.java:49) [109:org.eclipse.smarthome.core.thing:0.10.0.oh240]

	at sun.reflect.GeneratedMethodAccessor120.invoke(Unknown Source) ~[?:?]

	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?]

	at java.lang.reflect.Method.invoke(Method.java:498) ~[?:?]

	at org.eclipse.smarthome.core.internal.common.AbstractInvocationHandler.invokeDirect(AbstractInvocationHandler.java:153) [102:org.eclipse.smarthome.core:0.10.0.oh240]

	at org.eclipse.smarthome.core.internal.common.Invocation.call(Invocation.java:53) [102:org.eclipse.smarthome.core:0.10.0.oh240]

	at java.util.concurrent.FutureTask.run(FutureTask.java:266) [?:?]

	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [?:?]

	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [?:?]

	at java.lang.Thread.run(Thread.java:748) [?:?]

2019-01-12 13:34:33.949 [DEBUG] [nal.handler.AbstractMQTTThingHandler] - Successfully published value 50 to topic homie/nuvo/source5/position

Looking at the code, it seems to indicate that it is trying to convert a number placeholder in a format with a string value… The value does actually get published, after the exception.

@David_Graeff Is this working as designed, or is this an issue?

mqtt:homie300:mosquitto:nuvo:source5#position

Is that a number channel?

Yep

rule "Track Time Changed"
when
    Item ChromecastStatusCurrentTime changed
then
    val Number trackPosition = (ChromecastStatusCurrentTime.state as DecimalType).intValue
    logInfo("Nuvo", "Sending new track position {}", trackPosition)
    Nuvo_Source_5_Track_Position.sendCommand(trackPosition)
    //Nuvo_Source_5_Track_Position.sendCommand(50)
end
1 Like

No change when explicitly setting the val to be a number.

    Nuvo_Source_5_Track_Position.sendCommand(trackPosition.toString)

Tried that one before… no dice. :slight_smile:

What does the logInfo say?

 [INFO ] [.eclipse.smarthome.model.script.Nuvo] - Sending new track position 42

Question:
Does it work with:

    Nuvo_Source_5_Track_Position.sendCommand(50)

Nope. Same exception. It works, in that it sends the message. But it throws the exception every time.

Ok, well, it seems like a bug.
Report it to:

@vzorglub - thanks for the help.

@David_Graeff - Do you agree this is a defect and should be submitted?

I agree that the error message should be a better one instead of showing the exception stack trace.

You have changed the formatter parameter from “%s” to something else apparently, I have no other explanation.
The formatter takes an input and does what ever the “format” arguments tells him to do. And “%s” basically says, make a string out of everything. And that works in Java via the implicit .toString() method on every object.

There is an automated test suite that checks publish/receive of string and number channels and that test suite almost guarantees that this functionality works and no developer can break it on accident.

I have not modified the formatter.

It appears to me that “%d” is specified as the formatter in the code:

Maybe I am looking in the wrong place, but I only see test for float and boolean? https://github.com/eclipse/smarthome/blob/master/extensions/binding/org.eclipse.smarthome.binding.mqtt.generic.test/src/test/java/org/eclipse/smarthome/binding/mqtt/generic/HomieImplementationTests.java

I am not sure why the automated tests would fail, since the exception is swallowed:

I think that should be made an explicit exception, especially for the test suite to correctly fail if a formatter string is incorrect.

And yes, for integers it is correct to use the “%d” formatter, I guess. But why on earth is it failing here.

It is failing because the format is of type “%d” which means: “I only accept integers”, and on line 304 the value is being stored in a String which is then passed to the format command.

Nah, the input is always a string. The formatter pattern “%d” should be more like “output an integer”. Otherwise the entire formatter API wouldn’t make sense.

I don’t think that is correct

public class MyClass {
    public static void main(String args[]) {
       java.util.Formatter formatter = new java.util.Formatter();
       System.out.println(formatter.format("%d",5));
       System.out.println("=============");
       System.out.println(formatter.format("%d",Integer.toString(5)));
    }
}
5
=============

Exception in thread "main" java.util.IllegalFormatConversionException: d != java.lang.String
	at java.base/java.util.Formatter$FormatSpecifier.failConversion(Formatter.java:4421)
	at java.base/java.util.Formatter$FormatSpecifier.printInteger(Formatter.java:2936)
	at java.base/java.util.Formatter$FormatSpecifier.print(Formatter.java:2890)
	at java.base/java.util.Formatter.format(Formatter.java:2671)
	at java.base/java.util.Formatter.format(Formatter.java:2607)
	at MyClass.main(MyClass.java:6)
Command exited with non-zero status 1

A large part of what the formatter does is convert objects into string representations of those objects.

Oh. So I had a full black-out while coding that piece of the binding and actually need a parse-and-output like API, that complies to what I have written in the binding documentation.