openhab / openhab-addons

Add-ons for openHAB
https://www.openhab.org/
Eclipse Public License 2.0
1.9k stars 3.59k forks source link

[mqtt] Binding doesn't work with Units Of Measurement #6751

Closed PascalTurbo closed 2 years ago

PascalTurbo commented 4 years ago

When trying to add a channel to an Item with Unit of measurement, like for example Number:Temperature, MQTT Binding isn't able to process this item and throws an exception:

2020-01-03 10:17:25.033 [ERROR] [nal.common.AbstractInvocationHandler] - An error occurred while calling method 'ThingHandler.handleCommand()' on 'org.openhab.binding.mqtt.generic.internal.handler.GenericMQTTThingHandler@172b164': null
java.lang.NumberFormatException: null
        at java.math.BigDecimal.<init>(BigDecimal.java:494) ~[?:1.8.0_65]
        at java.math.BigDecimal.<init>(BigDecimal.java:383) ~[?:1.8.0_65]
        at java.math.BigDecimal.<init>(BigDecimal.java:806) ~[?:1.8.0_65]
        at org.openhab.binding.mqtt.generic.values.NumberValue.update(NumberValue.java:91) ~[?:?]
        at org.openhab.binding.mqtt.generic.ChannelState.publishValue(ChannelState.java:333) ~[?:?]
        at org.openhab.binding.mqtt.generic.AbstractMQTTThingHandler.handleCommand(AbstractMQTTThingHandler.java:128) ~[?:?]
        at sun.reflect.GeneratedMethodAccessor36.invoke(Unknown Source) ~[?:?]
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_65]
        at java.lang.reflect.Method.invoke(Method.java:497) ~[?:1.8.0_65]
        at org.eclipse.smarthome.core.internal.common.AbstractInvocationHandler.invokeDirect(AbstractInvocationHandler.java:152) [bundleFile:?]
         at org.eclipse.smarthome.core.internal.common.InvocationHandlerSync.invoke(InvocationHandlerSync.java:59) [bundleFile:?]
        at com.sun.proxy.$Proxy29896.handleCommand(Unknown Source) [?:?]
        at org.eclipse.smarthome.core.thing.internal.profiles.ProfileCallbackImpl.handleCommand(ProfileCallbackImpl.java:74) [bundleFile:?]
         at org.eclipse.smarthome.core.thing.internal.profiles.SystemFollowProfile.onStateUpdateFromItem(SystemFollowProfile.java:60) [bundleFile:?]
         at sun.reflect.GeneratedMethodAccessor35.invoke(Unknown Source) ~[?:?]
         at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_65]
         at java.lang.reflect.Method.invoke(Method.java:497) ~[?:1.8.0_65]
         at org.eclipse.smarthome.core.internal.common.AbstractInvocationHandler.invokeDirect(AbstractInvocationHandler.java:152) [bundleFile:?]
         at org.eclipse.smarthome.core.internal.common.Invocation.call(Invocation.java:52) [bundleFile:?]
         at java.util.concurrent.FutureTask.run(FutureTask.java:266) [?:1.8.0_65]
         at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [?:1.8.0_65]
         at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [?:1.8.0_65]
         at java.lang.Thread.run(Thread.java:745) [?:1.8.0_65]
J-N-K commented 4 years ago

One could discuss if throwing the exception (instead of rejecting the command) is a bug but supporting UoM is difficult and not supported at the moment.

PascalTurbo commented 4 years ago

At least there should be an entry in the documentation, that Units Of Measurement are not supported by the binding. Also if the missing support is a known issue, rejecting the command and writing a WARN Log message instead of an exception will be more user friendly.

jochen314 commented 4 years ago

I am not sure, if I understand the problem correctly. Let's see: UoM are working for status values, right? I have my temperature and humidity sensor set up like this without problems. The problem described here is about sending values to such a channel, right? Now, what is the value, you try to send? It is a number channel, so the natural value to send is a BigDecimal. But the stacktrace shows, a string is beeing send. And as it is not converted to a BigDecimal, I assume, that the string is the value plus uom, like 18 °C. First: Where does that string come from? Can it be converted to just the number at the origin already?

If we need to do it in NumberValue, then the convertion from String to BigDecimal should be done using tec.uom.se.quantity.Quantities.getQuantity(CharSequence), right? We could then even try to convert to the 'correct' UoM.

Rossko57 commented 4 years ago

Comment: bindings that support UoM do so because they can discover from the devices themselves that some data both represents, say, a temperature and what units it comes in. Generic MQTT cannot support that approach (though maybe Homie could) No discovery, no auto UoM. Seems wise.

But you as the user might well know that device X data Z does represent a QuantityType, e.g. if it sends 18.0 it always means 18.0mph or whatever.

Strikes me that what is needed is a channel profile that allows you to interface a binding regular number channel with an OH QuantityType Item. Such a utility would allow any generic bindings to interface with UoM. Also missing at the moment is how to specify uhh, "command profile" for OHQT->binding

jochen314 commented 4 years ago

@PascalTurbo Can you check, if #6763 solves your problems?

mjcumming commented 4 years ago

Homie does have UOM. However, the MQTT Homie binding handles a percentage UOM in a non intuitive way. Homie properties that are a percent only accept values between 0 and 1. Most would expect a percent value range to be 0-100.

@Rossko57 in theory that is what Homie should accomplish. But it needs more work.

openhab-bot commented 3 years ago

This issue has been mentioned on openHAB Community. There might be relevant details there:

https://community.openhab.org/t/mqtt-automatic-quantitytype-conversion-kwh-wh-does-not-work/101417/4

ccutrer commented 3 years ago

Homie does have UOM. However, the MQTT Homie binding handles a percentage UOM in a non intuitive way. Homie properties that are a percent only accept values between 0 and 1. Most would expect a percent value range to be 0-100.

@Rossko57 in theory that is what Homie should accomplish. But it needs more work.

I have a Homie property defined as:

homie/anthem-avr/avr/front-panel-brightness/$name => front_panel_brightness
homie/anthem-avr/avr/front-panel-brightness/$datatype => integer
homie/anthem-avr/avr/front-panel-brightness/$format => 0:100
homie/anthem-avr/avr/front-panel-brightness/$settable => true
homie/anthem-avr/avr/front-panel-brightness/$unit => %
homie/anthem-avr/avr/front-panel-brightness => 25

This shows up as a Dimmer channel in the UI, and is linked to a Dimmer item, and everything works just fine. I also have a similar one that is a $datatype => float, but otherwise defined the same (0:100 range, Dimmer in OpenHAB) that also works the same. Are you trying to link to a Number item instead? I did that once, and noticed that the commands were coming through as say 0.25 on the MQTT side. But I don't see anything that says Homie properties that are a percent only accept values between 0 and 1. The spec says (https://homieiot.github.io/specification/#percent) Percentage values are not restricted to 0-100, which would imply 0-100 would still be the "normal" range?

Rossko57 commented 3 years ago

But I don't see anything that says Homie properties that are a percent only accept values between 0 and 1.

I think it is the openHAB side that has the problem. If you pass a number with no unit to a Number:Dimensionless type (as usually used for %) it is accepted as a valid Quantity, but expressed as a NN:1 ratio. 70% becomes 0.7 The user can give an Item a default unit by setting metadata 'pattern' and giving a unit, something like%d %% How the Homie binding interacts with default units I could not say,maybe someone will test.

The percentType used in Dimmer Item or channel types is not the same as the Quantity Type used in Number:Dimensionless Items or channels.

openhab-bot commented 3 years ago

This issue has been mentioned on openHAB Community. There might be relevant details there:

https://community.openhab.org/t/mqtt-binding-and-units-of-measurement/127026/3