MQTT and converting C to F

I have a Generic MQTT Thing with the channel:

UID: mqtt:topic:tower:groundfloorThermostat
label: Ground Floor Thermostat
thingTypeUID: mqtt:topic
configuration: {}
bridgeUID: mqtt:systemBroker:tower
location: Ground Floor
channels:
  - id: groundfloortempIndoor
    channelTypeUID: mqtt:number
    label: Ground Floor Temp Indoor
    description: ""
    configuration:
      stateTopic: /home/hvac/groundfloor/tempIndoor
      unit: °C

the MQTT topic is being generated by a bash script I have running on a cron job on a different linux machine to pull the temperature from my daikin one plus thermostat from https://api.daikinskyport.com/ and publish each parameter to an MQTT topic.

I then bring what topics I want into channels in openHAB.

If there is a better way to do this I would be open. Its a quick and dirty bash script and this was the easiest way I knew.

Anyway, thats all working my problem is the temperature is coming in Celsius and I want to convert it to Fahrenheit. I have set the unit on the thing channel as °C but then when I view it on my locations page it shows as °C.

I have also attached the Item setup.

I have another aerotec zwave sensor that seems to be working correct. The temp is coming in as C and it displays correctly as F on my locations page.

The MQTT channel unit parameter is currently only used for outgoing payloads.

For incoming numerical, they get passed to the Item as-is, with no unit attached.
Assuming you are using a Number:Temperature type Item…
The framework will assume a “naked” number is meant to be taken as default units.
An Item may be assigned a default unit in its ‘pattern’ metadata.
If absent, for temperature types the system default unit will be assumed.

So, things you need to know - Item type, Item pattern, system locale.

If you have an incoming reading in C but want it displayed in F, you can -
Make sure the pattern or default is in F
Add a transformation to your channel that appends a string “°C” to your incoming numeric.
The framework will take care of conversion.

Thank you for the reply.

yes my items is set up as follows:

Could you point me in the direction of how to do the append string transformation?

Not really. Transformations and their use with MQTT binding are well documented, many examples. I should think this would be possible with a REGEX.

Don’t forget to look at your Item pattern metadata or system locale if you want F.

Alright, I tried regex on the incoming value transformations but that seemed to give my thing an error.

So then I tried REGEX on the linked item profile which didn’t seem to change the value however when I went into the Analyze graph for the item it seemed to be showing the graph as Fahrenheit even though the units are still Celsius.



Any ideas?

Can’t help much with secret errors.
But, do use the correct syntax as given in the notes underneath. Not REGEX(blah) but REGEX:blah

Don’t forget, none of this is any use at all unless you assign your Item a default unit of F, or ensure that your system default is F.

You don’t seem to have a clear view of what your Item state actually is,it’s worth finding out how to use API Explorer to inspect it directly without any transformations or formatting affecting what you are looking at…

By System Default is F is it good enough to check Imperial (US) under regional settings?

So this seems to work correctly for one time after I add a pattern to the item of %.1f °F

The value will correctly convert from my C value into the F value and display. However the next time I get an update from the MQTT it goes back to the C value with °F on the end.

For example the item is reading as:

{
  "link": "http://10.0.0.50:8080/rest/items/JoeMQTT_JoeTempValue",
  "state": "23.2 °C",
  "stateDescription": {
    "step": 1,
    "pattern": "%s °C",
    "readOnly": true,
    "options": []
  },
  "editable": true,
  "type": "Number:Temperature",
  "name": "JoeMQTT_JoeTempValue",
  "label": "Joe Temp Value",
  "category": "",
  "tags": [
    "Measurement",
    "Temperature"
  ],
  "groupNames": [
    "gGF"
  ]
}

Then I add the pattern onto the item meta data and its reading as:

{
  "link": "http://10.0.0.50:8080/rest/items/JoeMQTT_JoeTempValue",
  "state": "23.2 °C",
  "stateDescription": {
    "step": 1,
    "pattern": "%.1f °F",
    "readOnly": true,
    "options": []
  },
  "editable": true,
  "type": "Number:Temperature",
  "name": "JoeMQTT_JoeTempValue",
  "label": "Joe Temp Value",
  "category": "",
  "tags": [
    "Measurement",
    "Temperature"
  ],
  "groupNames": [
    "gGF"
  ]
}

However it is showing correctly in the item display on the webpage:

But then as soon as I send an update to the MQTT topic it reverts back:

{
  "link": "http://10.0.0.50:8080/rest/items/JoeMQTT_JoeTempValue",
  "state": "18.2 °F",
  "stateDescription": {
    "step": 1,
    "pattern": "%.1f °F",
    "readOnly": true,
    "options": []
  },
  "editable": true,
  "type": "Number:Temperature",
  "name": "JoeMQTT_JoeTempValue",
  "label": "Joe Temp Value",
  "category": "",
  "tags": [
    "Measurement",
    "Temperature"
  ],
  "groupNames": [
    "gGF"
  ]
}

Not sure what else to try. My guess is something wrong with my channel configuration with the REGEX but not sure how to troubleshoot.

I don’t want to jinx it but I think I got it. I had to bring the MQTT topic in as a String instead of a Number, do the REGEX to append the °C, then link it to an Item that is a Number:Temperature.

I’m having the same issue on OH3.1.0 - Release Build. I don’t understand why such a simple feature is so hard to implement, it was pretty straight forward in OH2.

@rossko57 Doesn’t using a transformation on the channel to add a “°C” defeat the purpose of using the Unit of Measure field? According to the documentation, isn’t that exactly what it’s for?

The unit is used for representing the value in the GUI as well as for converting incoming values (like from ‘°F’ to ‘°C’). Examples: “°C”, “°F”

Could this be a bug?

In my case, I have a Nodemcu running tasmota with a DHT11 temp sensor. The nodemcu is sending MQTT messages to OH3.1.

My regional settings is as follows:

The MQTT payload is:

{
  "Time": "2021-11-16T20:16:32",
  "Switch5": "OFF",
  "Switch6": "OFF",
  "ANALOG": {
    "Range": 367
  },
  "DHT11": {
    "Temperature": 28,
    "Humidity": 53,
    "DewPoint": 17.5
  },
  "TempUnit": "C"
}

The channel for the MQTT Generic thing is:

UID: mqtt:topic:myMQTTBroker:2ef896ee53
label: AC Sensor
thingTypeUID: mqtt:topic
configuration:
  payloadNotAvailable: Offline
  availabilityTopic: tele/AC_Sensor/LWT
  payloadAvailable: Online
bridgeUID: mqtt:broker:myMQTTBroker
location: Garage
channels:
  - id: dht11_temperature
    channelTypeUID: mqtt:number
    label: AC Sensor - DHT11 Temperature
    description: ""
    configuration:
      unit: °C
      qos: 0
      stateTopic: tele/AC_Sensor/SENSOR
      transformationPattern: JSONPATH:$.DHT11.Temperature

The item config is as follows:

The item stateDescription metadata is as follows:

So after configuring this, it works on the current value as shown:

However, after the item gets an update, it reverts to Celcius showing the F measurement unit:

The same thing happens in the sitemap and in the pages.

BTW, if I remove the metamask stateDescription, it works as expected in the sitemap:

This should be pretty easy to replicate with a MQTT client.

You’re expecting openHAB to somehow guess what units some random number ought to be tagged with? Not going to happen, who’d want unpredictable guesses.
But you can tell it (by appending °C). Or, you can let it make an assumption based on your locale.

You would expect (and so would I) that this channel setting is right place to declare to openHAB.

but in the current release that does not work, it’s only for outbound.
Work in progress

So for now that means that unless you do something about it, a “plain” number is passed from your JSON to the Item. The Item is type Number:Temperature, and so demands some or unit or other. Faced with no clue, the framework looks to your Item pattern, finds a clue “°F”, and uses that for the assumed units of the number that was passed.

In your case however, the original unit is hidden elsewhere in your JSON.
You could write a JS transformation that parses the whole JSON (i.e. this is to use instead of JSONPATH) and extracts both the numeric and the C clue and throws in a needed degree symbol to present complete data to the Item in the form of “28 °C”.
Really, that’s what you should be doing when the device provides hints, rather than make assumptions.

You’d still have to make an assumption about humidity units.

Rossko, thanks for your detailed explanation.

Two more questions:

  1. Why does it work the first time the item gets configured with the metadata and then after the item gets an update it breaks? (as shown above)

  2. Why does this configuration work properly with sitemaps as shown above? Here’s my working sitemap.cfg snippet:
    Default item=ACSensor_ACSensorDHT11Temperature label="Garage AC Sensor [%.0f °F]"

It seems as some parts of the OH3 is using the UoM but other parts of the code does not. This is why I was thinking it could be a bug?

Thanks!

Just FYI, I found the answer to question1 above here: MQTT Binding and Units of Measurement - #6 by rossko57

Which configuration?
What’s crucial in explaining headaches is to see what your Item state really is at the given moment, using API explorer. You can’t take MainUI display at face value .

I suspect you’re noticing that the format data in a sitemap in a sitemap widget config is never used to influence Item state back at the server, it’s purely for display in that widget.

What makes you think that, which parts?

Sorry, I was referring to the configuration I showed on my first post. Understanding the whole thing about UoM on incoming MQTT messages, while that configuration does not work with Label Cards in OH3 pages, it does work fine with sitemaps.

Meaning, if I use default values creating the MQTT thing and the temperature item, the sitemap converts the temperature to F appropriately, without using any transform scripts to add a C to the temperature value received from MQTT.

We know the MQTT binding currently has a deficiency about incoming units. If you don’t do anything about that, results can be unexpected.

Ok, so following your advice above, I used ExtendsClass website to test the transformation below:
REGEX Transformation:
REGEX:s/.*("Temperature":)(.*),("H.*).*/"$2 °C"/g

MQTT Incoming Message:
{"Time":"2021-11-17T17:08:39","Switch5":"OFF","Switch6":"OFF","ANALOG":{"Range":366},"DHT11":{"Temperature":27.6,"Humidity":49.0,"DewPoint":15.9},"TempUnit":"C"}

But I get the following warning on the logs:
[WARN ] [ab.binding.mqtt.generic.ChannelState] - Incoming payload '"26.9 °C"' not supported by type 'NumberValue'

if I remove the double-quotes, then the item shows UNDEF as the value.

Link to a String type Item (as well) for testing, then you can see what you are doing.

OK, so for those who will run into this, here’s the config to get this to work.

  1. Go to Settings\Regional Settings. Click Show Advanced. Under Measurement System, select either “Metric” or “Imperial(US)”. When using “Metric”, OH3 will assume that raw data temperature will be received in Celsius. Using “Imperial (US)” will default to Fahrenheit. For this example, Imperial (US) is used.

  2. Create a String channel, not a number channel:

UID: mqtt:topic:myMQTTBroker:2ef896ee53
label: AC Sensor
thingTypeUID: mqtt:topic
configuration:
  payloadNotAvailable: Offline
  availabilityTopic: tele/AC_Sensor/LWT
  payloadAvailable: Online
bridgeUID: mqtt:broker:myMQTTBroker
location: Garage
channels:
  - id: dht11_temperature
    channelTypeUID: mqtt:string
    label: AC Sensor - DHT11 Temperature
    description: ""
    configuration:
      qos: 0
      stateTopic: tele/AC_Sensor/SENSOR
      transformationPattern: <insert some transformation patter here>

Use a transformation pattern that results in “[number or decimal] °C” or “[number or decimal] °F” without the double quotes ("). So, if you get the temperature in C, the transformation result should be “[number or decimal] °C”. Note: Notice the use of the Degree symbol (°) and a white space between the value and the temperature unit.

Example MQTT Message:

{“Time”:“2021-11-17T20:16:32”,“Switch5”:“OFF”,“Switch6”:“OFF”,“ANALOG”:{“Range”:366},“DHT11”:{“Temperature”:28.0,“Humidity”:50.0,“DewPoint”:16.6},“TempUnit”:“C”}

Transformation pattern:
REGEX:s/\{(.*)("Temperature":)(.*),"H.*("TempUnit":)"(.*)"\}/$3 °C/g

In this example, we get the raw temperature data in Celsius, so the result should be “28.0 °C” without the double quotes ("). Notice, that the MQTT message also includes the temperature unit, so we could use the following transformation pattern to use the right temperature unit automatically:
REGEX:s/\{(.*)("Temperature":)(.*),"H.*("TempUnit":)"(.*)"\}/$3 °$5/g

NOTE: For troubleshooting, link a String item to the channel and you should see the right temperature string as the item state.

  1. Link/Create an Item:
  • Type = Number:Temperature
  • Semantic Class = Measurement
  • Semantic Property = Temperature

At this point, the item state should show the temperature unformatted.

  • If your Measurement System is set to “Metric”, whether you receive temperature data in Celsius or Fahrenheit, the item state should be in Celsius. (OH converts it in the background when necessary).
  • If your Measurement System is set to “Imperial (US)”, whether you receive temperature data in Celsius or Fahrenheit, the item state should be in Fahrenheit. (OH converts it in the background when necessary).
  1. To format the state with the desired temperature unit, add a State Description metadata to the item. Under Pattern use “%.1f °F” or “%.1f °C” without the double quotes. In this examples, we want to convert the temperature from Celsius to Fahrenheit:

The final configuration of the item should look something similar to this:

1 Like