Temperature unit conversion inside the handler

Hello,

As I’m developing my addon for an HVAC system, I have declared channels for various temperature related elements: current, setpoint, min, max…
They all are very similar, the current temperature being declared like this:

	<channel-type id="temperature">
		<item-type>Number:Temperature</item-type>
		<label>@text/channel-type.airzone.zone.temperature.label</label>
		<category>Temperature</category>
		<tags>
			<tag>Measurement</tag>
			<tag>Temperature</tag>
		</tags>
		<state pattern="%.1f °C" readOnly="true" />
	</channel-type>

Whenever I receive a new temperature reading from the device, I use updateState with this:

newState = new DecimalType(zone.getRoomTemp());

This works just fine as I do receive a Celsius reading from the system I have.
However, the API documentation clearly defines a boolean value in its responses that indicates which unit is used: °C or °F

What I would thus like to do is to send the proper value via updateState either converted by the thing handler code, or with a format pattern that is adjusted to match the unit declared by the device itself.

Converting the value to °C in the thing handler is quite straightforward, the formula is well known, but I would very much like to avoid repeating it inside my own code. Is there a set of utility functions that offer that conversion? If yes, is it available for both OH3 and OH4?

Thanks for any suggestion.

If you specify the type in the xml as a quantity type, like you did. You should use new QuantityType instead of DecimalType . QuantityType also expects the unit. Thus if the data is celcius use that and if farenheit use that. The framework will also the conversion if the user wants a specific unit. So you don’t have to do the conversion yourself.

Somehow, I was under the impression that QuantityType is only available under OH4 but looking around in other plugins, I see it has been available way longer as some plugins have been using it since 2020.

Thanks for the suggestion.

Units of measurement/Quantity Types have been around since before OH 3. I think they were introduced in the 2.2, 2.3 time range so they’ve been around a long time.

What’s changed in OH 4 is that the end user has much more control over what units get applied to their Items.

The general order of precedence for pre-OH 4.0 was:

  1. units in the State Description Pattern
  2. units of the Item as delivered by the binding
  3. system default units for that UoM (e.g. if it was a Number:Length and no other units are provided, meters is assumed if SI is selected for default or feet is the default if imperial units are selected).

But it gets complicated because bindings can stealthily set the state description pattern for you and that setting didn’t show up. There was even a bug where the binding set units took precedence over the units set by the user by overriding the State Description pattern. Plain old Number Items could end up with a QuantityType state. The State Description pattern could be overridden by the end user (once that bug is fixed) but that didn’t change the actual state carried by the Item meaning that the value persisted may be different units from what the State Description says. The problem there is that the State Description was the only hint to Persistence to tell it what units to restoreOnStartup leading to a missmatch.

Overall it was a nightmare to use and to support.

In OH 4 the order of precedence is now:

  1. the unit defined in the unit Item metadata
  2. the unit in the QuantityType posted to the Item
  3. the system default

If you send a QuantityType to a plain old Number Item, the unit is stripped and the State will be a DecimalType.

If you send a DecimalType to a Number:X Item, the unit will be derived based on the order of precedence above.

If the unit metadata is defined and the binding posts a QuantityType with a different unit, OH will convert it to the user’s unit so the Item’s state will always be in the user defined units. This means restoreOnStartup and the REST API users can trust that the units are correct.

Only end users can set the unit metadata and that unit is the one used to control the State of the Item.

The State Description pattern now only changes how the Item appears in the UIs and is no longer used to make decisions like what unit a value restored from persistence is in or how to handle a number posted without units.

As a result, what unit gets applied to the Item’s state is fully controllable by the end users, as it should be. Conversions from what the binding publishes when necessary are handled automatically. And you can choose different units for the Item to hold from what is shown in the UI if needed. I believe bindings can also offer State Description metadata still but they cannot offer unit metadata.

If a user chooses not to use UoM, they can define their Items as Number and have them stripped. If they want to use units even if the binding doesn’t offer one, they can define the unit metadata

Thanks for the detailed explanation, it makes for a clearer picture.