Item unit conversion (Temperature)

Hello Everyone,

I’m currently setting up mqtt with openhab and, in spite of trying quite a few things, am stuck now. The transfer of data/numbers into openhab via mqtt works fine, that’s not the issue, it’s the correct unit or the conversion from Celsius to Fahrenheit.

The MQTT binding does not support UoM, so the temperatures transmitted here are numbers (in Celsius, but I want Fahrenheit) without a unit. Accordingly, the channel is a number-channel, and not number:temperature. So using UoM and just defining the item as a number:temperature in Fahrenheit does not work. Neither does setting °C as “Unit of Measurement” in the mqtt-channel. I always get the untransformed celsius-value.

So I thought of the idea of a small conversion js-script. That works when used in a rule, so I know it is correct. Now I could use dummy-items and read the value from the mqtt-item and write it to the real item in a rule, but as I intend to do that with a number of items, I thought there must be a better way.

The “Javascript Transformation Services” https://www.openhab.org/addons/transformations/javascript/ and “Transformation Services” https://www.openhab.org/docs/configuration/transformations.html pages list two different formats for doing conversions within an item definition:

Number Livingroom_Temperature_F "Temperature [JS(convert-C-to-F.js):%.1f °F]"

and

String <itemName> { channel="<channelUID>"[profile="transform:JS", function="<filename>", sourceFormat="<valueFormat>"]}

although I’m not sure the latter one works with numbers.

Anyway, neither of those work, the corresponding item does not get updated even when a new mqtt-message for that topic arrives.

Any ideas on where I’m in the wrong direction here?

Thanks

I do the transformation within the thing definition itself. Assuming your JavaScript is all correct and saved in the correct location, you’d just need to add the following to your temperature channel:

transformationPattern="JS:convert-C-to-F.js"

To fully understand what’s going on we’d need to see your things, items and JavaScript…

Edit: …and of course ensure that the JavaScript transformation service is actually installed

By way of explanation -

Number Livingroom_Temperature_F "Temperature [JS(convert-C-to-F.js):%.1f °F]"

This is not supposed to ‘work’ the way you want it. Use of [transformation] in this context is purely about display - the actual Item state is transformed for display in e.g. BasicUI but item state remains unaltered.

String <itemName> { channel="<channelUID>"[profile="transform:JS", function="<filename>", sourceFormat="<valueFormat>"]}

As you suspect, the transform profile does not work with Number or any non-String type Items.
I think that that is a deficiency that really limits its usefulness.

I’ve not tired it yet, but as of 2.5.4 I think the binding appears to support UoM.

It doesn’t. Profiles only work with String Items unfortunately.

Thanks, guys!

@hafniumzinc was spot on, that was the answer. I really don’t know why I didn’t realize that the transformation had to be done at thing-level. I use PaperUI for things (and files for items), so it’s a bit hard to post the thing, but I inserted the JS in the “incoming value transformations” field and that works. I read about people putting transformation scripts there to dissect a jsonpath topic message, but somehow failed to see that I could put my unit conversion script here.

@rlkoshak, I do have version 2.5.6, and tried putting “°C” in the “Unit of Measurement”, but I think that as in mqtt there are only “number” channels, but not “number:temperature” ones (like my zwave sensors supply with the zwave binding), I suppose that’s the reason why it does not work.

I currently don’t have shell access to the box as I’m on my office computer, but will post the js-script I use (just 3 lines, basically) tonight for completion’s sake.

1 Like

yes, please do as I just hooked a DHT22 to a Pi and sending OpenHAB the data via mqtt and it is Celsius and I’m in US of A and need Fahrenheit to make sense for me

which would be???

That depends on how you installed openHAB. It must live in the transform folder within the configuration folder. My configuration folder is at /etc/openhab2/…

Edit: fat fingers!

It’s called “transform” (without an “s”) but it should already be present in any openhab installation. But yes, it is in the configuration folder along with the folders for items, things, rules, etc. Any new file in there needs to made readable by the openhab user.

1 Like

I do exactly the same, but do the conversion earlier in the shell script that reads out the DHT and calls mosquitto_pub to publish the value to the broker. But you can certainly do the conversion in openhab, no difference, really.

Here’s the js-script. Pretty simple. One could probably condense it into less lines, but whatever.

(function(i) {
var f = i * 9/5 + 32;
return f;
})(input)

1 Like

I am also having a problem converting a plain old number (23.47) from MQTT to °F. I have also tried unit=“°F” and unit=“°C” to see if it would do anything too.

Number	GarageHallway_Temperature	"Garage Hallway Temp Sensor [%.1f *F]"<temperature>	(gZigbee2MQTT, gTempSensor,)			{ channel="mqtt:topic:GarageHallwaySensors:temperature" }
Type number : temperature 	"Temperature"			[ stateTopic= "zigbee2mqtt/GarageHallwaySensors/temperature", transformationPattern="JS:convert-C-to-F.js"]

Only ever return the given number with a °F at the end (23.47°F) using the same JS as above

(function(i) {
var f = i * 9/5 + 32;
return f;
})(input)

Any ideas why this is not converting, on OH2.5.12?

Your Item is just a Number, there won’t be any conversions. Did you mean to use a Number:Temperature?

Who returns what where? Can we see your events.log detailing Item state? Or are you talking display in some UI?

So the topic is zigbee2mqtt/GarageHallwaySensors/temperature

Whenever it updates it just has a plain old number. So I just want to convert the plain text number (the censor reports in Celsius) 23.47 to the corresponding *F plain text number.

So the mqtt thing “temperature” should take the plain text number and use the JS script to convert it to the corresponding *F temperature and the new item state should be the transformed conversion correct ? On my phone I can send the logs later

Alright, if you keep your Item as a plain Number it should work as-is.
You do have to install the JS transform add-on.

It’s a feature of transforms that everything gets passed in and out as strings, so if you want to treat the input as a number in javascript it is best to parse it first.
parseFloat(i)

You won’t get any *F in your Item state,but you should get *F in your display, from [%.1f *F]

Hmm, I have it working as a Number:Temperature item. I also get the temperature in C from zigbee2mqtt into openhab and transform that into a Fahrenheit temperature including the unit:

Item:

Number:Temperature Sensor_Multi_Zigbee_03_Temperature "Zigbee 03 Temperature [%.1f °F]" <temperature> (temperature) {channel="mqtt:topic:home:Zigbee_Sensor_03:temperature" }

Thing:

    Thing topic Zigbee_Sensor_03 "Sensor_Zigbee_03" {
    Channels:
        Type number : temperature "Temperature"     [ stateTopic="zigbee/Zigbee_Sensor_03/temperature", transformationPattern="JS:ctof2.js" ]
    }

Transformation:

(function(i) {
  var f = i * 9/5 + 32;
  return f;
})(input)

Yes, that’s an alternative approach. The channel can post a plain number to the Item but now it’s assumed to be a temperature, so units must get added on as well. When it comes without units, a default is assumed, which is derived from the [%.1f °F] of your Item.

1 Like