MQTT 2.5.0-S1549-1 binding reports Exception with formatBeforePublish

Hi,

I switched to the Snapshot version 2.5.0~S1549-1 (Build #1549) and experience the following issue with the MQTT binding.

If I set the value of an item (i.e. I_KG_Heizraum_LueftungStufe), the binding reports the following exception:

==> /var/log/openhab2/events.log <==
2019-03-07 23:30:03.645 [vent.ItemStateChangedEvent] - I_KG_Heizraum_LueftungStufe changed from 1 to 2
==> /var/log/openhab2/openhab.log <==
2019-03-07 23:30:03.655 [TRACE] [.MqttChannelStateDescriptionProvider] - Providing state description for channel mqtt:homie300:mosquitto:heatingpi:ventilation#level
2019-03-07 23:30:03.663 [TRACE] [.MqttChannelStateDescriptionProvider] - Providing state description for channel mqtt:homie300:mosquitto:heatingpi:ventilation#level
2019-03-07 23:30:03.657 [DEBUG] [eneric.internal.generic.ChannelState] - Format pattern incorrect for mqtt:homie300:mosquitto:heatingpi:ventilation#level
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.openhab.binding.mqtt.generic.internal.generic.ChannelState.publishValue(ChannelState.java:332) [214:org.openhab.binding.mqtt.generic:2.5.0.201903042328]
	at org.openhab.binding.mqtt.generic.internal.handler.AbstractMQTTThingHandler.handleCommand(AbstractMQTTThingHandler.java:123) [214:org.openhab.binding.mqtt.generic:2.5.0.201903042328]
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:?]
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:?]
	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) [134:org.openhab.core:2.5.0.201903021530]
	at org.eclipse.smarthome.core.internal.common.InvocationHandlerSync.invoke(InvocationHandlerSync.java:59) [134:org.openhab.core:2.5.0.201903021530]
	at com.sun.proxy.$Proxy141.handleCommand(Unknown Source) [214:org.openhab.binding.mqtt.generic:2.5.0.201903042328]
	at org.eclipse.smarthome.core.thing.internal.profiles.ProfileCallbackImpl.handleCommand(ProfileCallbackImpl.java:75) [184:org.openhab.core.thing:2.5.0.201903021532]
	at org.eclipse.smarthome.core.thing.internal.profiles.SystemDefaultProfile.onCommandFromItem(SystemDefaultProfile.java:49) [184:org.openhab.core.thing:2.5.0.201903021532]
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:?]
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:?]
	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) [134:org.openhab.core:2.5.0.201903021530]
	at org.eclipse.smarthome.core.internal.common.Invocation.call(Invocation.java:53) [134:org.openhab.core:2.5.0.201903021530]
	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) [?:?]

Interestingly, the new value (in this case 2) is transported cleanly via the MQTT channel to my device. So, the functionality itself works like expected…

Here’s my configuration.
Excerpt of items:

Number I_KG_Heizraum_LueftungStufe "Lüftung Stufe [%d]" (KG, KG_Heizraum) { channel="mqtt:homie300:mosquitto:heatingpi:ventilation#level", autoupdate="true" }

Excerpt of sitemap:

Setpoint item=I_KG_Heizraum_LueftungStufe minValue=1 maxValue=4 step=1

The lines of code, this exception comes from seems to be:

            // Formatter: Applied before the channel state value is published to the MQTT broker.
            if (config.formatBeforePublish.length() > 0) {
                try (Formatter formatter = new Formatter()) {
                    Formatter format = formatter.format(config.formatBeforePublish, mqttCommandValue);
                    mqttCommandValue = format.toString();
                } catch (IllegalFormatException e) {
                    logger.debug("Format pattern incorrect for {}", channelUID, e);
                }
            }

in file \org\openhab\binding\mqtt\generic\internal\generic\ChannelState.java

All help pages that I found that describe how to use the formatBeforePublish feature seem to be written for the MQTT 1.x binding, where you have an item definition like

mqtt=">[mosquitto:heatpump/set:command:*:DEFAULT)],<[mosquitto:heatpump/state1:state:*:DEFAULT]

However, first, I don’t know how to translate that to the “channel=…” notation of MQTT 2.x and how to insert the formatting there, and second I wonder why the exception is raised because documentation says that formatting before publishing is optional (which is also suggested by this if condition in the code fragment above).

Can you please:
a) explain me how to use formatting before publishing for the MQTT 2.x binding
b) fix the code such that a missing formatting does not lead to an exception

Thanks and regards,
Stefan D.

You forgot the Thing (and channel) configuration. Format pattern can be set in the channel definition.

Hi Udo,

right, sorry that I forgot.
I created the things via PaperUI.
These are the relevant parts from the jsondb:

  "mqtt:homie300:mosquitto:heatingpi": {
    "class": "org.eclipse.smarthome.core.thing.internal.ThingImpl",
    "value": {
      "label": "T_KG_Heizraum_heatingpi",
      "bridgeUID": {
        "segments": [
          "mqtt",
          "broker",
          "mosquitto"
        ]
      },
      "channels": [
...
        {
          "acceptedItemType": "Number",
          "kind": "STATE",
          "uid": {
            "segments": [
              "mqtt",
              "homie300",
              "mosquitto",
              "heatingpi",
              "ventilation#level"
            ]
          },
          "channelTypeUID": {
            "segments": [
              "mqtt",
              "homie_heatingpi_ventilation_level"
            ]
          },
          "label": "Ventilation level",
          "configuration": {
            "properties": {
              "format": "0:9999",
              "name": "Ventilation level",
              "retained": "true",
              "settable": "true",
              "unit": "",
              "datatype": "integer_"
            }
          },
          "properties": {},
          "defaultTags": []
        },
...
      ],
      "configuration": {
        "properties": {
          "deviceid": "heatingpi",
          "basetopic": "homie"
        }
      },
      "properties": {
        "homieversion": "3.0.1"
      },
      "uid": {
        "segments": [
          "mqtt",
          "homie300",
          "mosquitto",
          "heatingpi"
        ]
      },
      "thingTypeUID": {
        "segments": [
          "mqtt",
          "homie300"
        ]
      }
    }

Don’t know where or how to specify a formatting here (probably not via PaperUI?).

Regards,
stedon81

The exception is correct. It is a limitation of the implementation, it works only on string/text channels, not on number channels. Those would need to be converted to a string first, before being fed into the formatter.

I do not see “formatBeforePublish” set in your “configuration->properties” of homie_heatingpi_ventilation_level. So I do wonder why you get that exception in the first place.