Convert upper and lower bytes to float

  • Platform information:
    • Hardware: 4690k, 32gb, spinning rust
    • OS: Debian Buster Docker
    • Java Runtime Environment: whatever comes with docker latest
    • openHAB version: latest
  • Issue of the topic: Trouble combining bytes into float

For some reason the manufacter likes to supply json which split each upper and lower byte into separate fields.

Here is an example of the atrocity I am dealing with:

{"nodenr": 23,
"ch_temp_lsb": 219,
"ch_temp_msb": 21,
"tap_temp_lsb": 181,
"tap_temp_msb": 18,
"ch_pressure_lsb": 126,
"ch_pressure_msb": 0,
"room_temp_1_lsb": 235,
"room_temp_1_msb": 8,
"room_temp_set_1_lsb": 164,
"room_temp_set_1_msb": 6,
"room_temp_2_lsb": 255,
"room_temp_2_msb": 127,
"room_temp_set_2_lsb": 255,
"room_temp_set_2_msb": 127,
"displ_code": 126,
"IO": 0,
"serial_year": 14,
"serial_month": 12,
"serial_line": 15,
"serial_sn1": 1,
"serial_sn2": 69,
"serial_sn3": 51 ,
"room_set_ovr_1_msb": 6,
"room_set_ovr_1_lsb": 64,
"room_set_ovr_2_msb": 0,
"room_set_ovr_2_lsb": 0,
"rf_message_rssi": 33,
"rfstatus_cntr": 0}

All of these values are floats and as of such I would like to recombine the separate fields into their corresponding value. Below is what I have so far the most important part being the rules section.

Currently my output by rules is the following:

2020-06-20 10:42:04.346 [INFO ] [el.script.>>> HeatingDescription <<<] - 95c
2020-06-20 10:42:04.347 [INFO ] [el.script.>>> HeatingDescription <<<] - 2396
2020-06-20 10:42:04.348 [INFO ] [el.script.>>> HeatingDescription <<<] - 0
2020-06-20 10:42:04.349 [INFO ] [el.script.>>> HeatingDescription <<<] - 0

The javascript on the webplatform responsible for converting this mess achieves it
through the following: (jsondata.room_temp_1_lsb + jsondata.room_temp_1_msb*256) / 100

Items:

Number temperature_lsb { http="<[http://192.168.3.254/data.json:30000:REGEX(.*?\"room_temp_1_lsb\": (.*?),.*)]" }
Number temperature_msb { http="<[http://192.168.3.254/data.json:30000:REGEX(.*?\"room_temp_1_msb\": (.*?),.*)]" }
String temperature

Sitemap

sitemap default label="My home automation" {
Frame label="Demo" {
    Text item=temperature_lsb label="Living Room [%.1f °C]" icon="temperature"
    Text item=temperature_msb label="Living Room [%.1f °C]" icon="temperature"
    Text item=temperature label="Living Room [%s]" icon="temperature"
}
Frame label="Chart" {
    Chart item=temperature_lsb label="Temperature chart" refresh=10000 period=h
    Chart item=temperature_msb label="Temperature chart" refresh=10000 period=h
}
}

Rules

import java.math.BigDecimal
import org.openhab.core.library.types.*

rule "LivingRoomCombine"
when
   Item temperature_lsb received update or
   Item temperature_msb received update or
   System started
then
    val int default_int = 0
    val String hex_lsb = if (temperature_lsb.state instanceof DecimalType) Integer.toHexString((temperature_lsb.state as DecimalType).intValue) else Integer.toHexString(default_int)
    val String hex_msb = if (temperature_msb.state instanceof DecimalType) Integer.toHexString((temperature_msb.state as DecimalType).intValue) else Integer.toHexString(default_int)
val String hex = String::format("%s%s", hex_msb, hex_lsb)
    logInfo(">>> HeatingDescription <<<", hex)

val DecimalType hex_int = new DecimalType(Integer.parseInt(hex, 16))
    logInfo(">>> HeatingDescription <<<", String::format("%1$.0f", hex_int.toBigDecimal))
    val Float hex_float = Float.intBitsToFloat(hex_int.intValue)
    val DecimalType hex_deci = new DecimalType(hex_float)
    logInfo(">>> HeatingDescription <<<", String::format("%1$.0f", hex_float))
    logInfo(">>> HeatingDescription <<<", String::format("%1$.0f", hex_deci.toBigDecimal))

val BigDecimal temperature_lsb_t = if (temperature_lsb.state instanceof DecimalType) (temperature_lsb.state as DecimalType).toBigDecimal else new BigDecimal(0)
val BigDecimal temperature_msb_t = if (temperature_msb.state instanceof DecimalType) (temperature_msb.state as DecimalType).toBigDecimal else new BigDecimal(0)
var String formattedString = String::format("%1$.0f°C / %2$.0f°C", temperature_lsb_t, temperature_msb_t)
temperature.postUpdate(new StringType(formattedString))
end

Services

# timeout in milliseconds for the http requests (optional, defaults to 5000)
#timeout=

# the interval in milliseconds when to find new refresh candidates
# (optional, defaults to 1000)
#granularity=

# whether to substitute the current time or state value into the URL
# (optional, defaults to true)
#format=

# configuration of the first cache item
thermostat.url=http://192.168.3.254/roomthermostat.htm?heater=0
thermostat.updateInterval=5000

I fixed it using the following rule:

import java.math.BigDecimal
import org.openhab.core.library.types.*

rule "LivingRoomCombine"
when
    Item ch_temperature_lr_lsb received update or
    Item ch_temperature_lr_msb received update or
    System started
then
    val BigDecimal temperature_lsb_t = if (ch_temperature_lr_lsb.state instanceof DecimalType) (ch_temperature_lr_lsb.state as DecimalType).toBigDecimal else new BigDecimal(0)
    val BigDecimal temperature_msb_t = if (ch_temperature_lr_msb.state instanceof DecimalType) (ch_temperature_lr_msb.state as DecimalType).toBigDecimal else new BigDecimal(0)
    val BigDecimal temperature_t = new DecimalType(((temperature_lsb_t.doubleValue) + (temperature_msb_t.doubleValue*256.0))/100.0).toBigDecimal
    var String formattedString = String::format("%2.2f", temperature_t)
    ch_temperature_lr.postUpdate(new StringType(formattedString))
end

You don’t need the org.openhab.core import, and these can mess you up sometimes, best to remove that one.

All references to org.openhab.* in imports and class references should be removed. All of these classes are automatically included and have moved.