Rule: How to convert two bytes to signed integer?

I am receiving data via MQTT in the form of a beacon.

The data I want to extract is contained in 4 bytes, two of those bytes form a signed Short (16 bits).

I have successfully extracted the data into an array of bytes, but I am having a hard time reconstructing the original signed Short from the two bytes. Ultimatly it doesn’t matter if its an integer, as long as its the right value! I will be converting it to a float later on anyway.

Here is what I have so far:

rule "Parse MCThings 111BA Beacon Data"
    Item MCThings111BABeacon changed
    if (MCThings111BABeacon.state instanceof StringType) {
        var value = MCThings111BABeacon.state as StringType
        var valueLength = value.toString.length() as Integer
        val byte[] bytes = value.toString.getBytes("UTF-8")
        val StringBuilder sb = new StringBuilder
        val StringBuilder sb1 = new StringBuilder
        bytes.forEach[b | sb1.append(String::format("%02X", b) + ":")]

        logInfo("error", "Beacon Bytes:  " + sb1.toString)
        logInfo("error", "bytes[6] = " + bytes.get(6).toString)

        var byte beacontype = bytes.get(1)

        if(beacontype == 0xBF) {
            var byte datatype = bytes.get(6)
            //this is where the short is extracted
            var int temp1 = bytes.get(7) & 0xFF
            temp1 = (temp1 << 8) & 0xFF00
            var int temp2 = bytes.get(8) & 0xFF
            var Short temp3 = (temp1).bitwiseOr(temp2)
            var int i_temp = temp3

            //get fractional part
            var temp6 = 0.0 + (bytes.get(9) & 0xFF)
            var f_temp = temp6 / 100
            //add integer and fractional part
            var temp = i_temp+f_temp
            if(datatype == 1) sb.append("Uptime ")
            else if (datatype == 2) sb.append("Battery ")
            else if (datatype == 3) sb.append("Temp ")
            else if (datatype == 4) sb.append("Ext Temp ")
            else if (datatype == 5) sb.append("Humidity ")
            else if (datatype == 6) sb.append("Dewpoint ")
            else if (datatype == 7) sb.append("Pressure ")
            else if (datatype == 8) sb.append("Altitude ")

            sb.append(temp.toString + " ")

        sb.append(String::format("%02X", bytes.get(6)) + ":")
        sb.append(String::format("%02X", bytes.get(7)) + ":")
        sb.append(String::format("%02X", bytes.get(8)) + ":")
        sb.append(String::format("%02X", bytes.get(9)))
        logInfo("error", "Decoded Bytes:  " + sb.toString)
        postUpdate(MCThings111BABeaconDecoded, sb.toString)


The problem is with the section “//this is where the short is extracted” as most of the time it works, but sometimes i get weird numbers (like -17 instead of 881)

Here is an example:
17:09:49.987 [INFO ] [org.openhab.model.script.error:53 ] - bytes[6] = 1 17:09:49.990 [INFO ] [org.openhab.model.script.error:53 ] - Decoded Bytes: Uptime -17.65000000 01:04:EF:BF 17:09:59.987 [INFO ] [org.openhab.model.script.error:53 ] - Beacon Bytes: EF:BF:BD:11:01:00:02:0B:7E:00:EF:BF:BD:2E:13:01:00:00:00:00:00: 17:09:59.988 [INFO ] [org.openhab.model.script.error:53 ] - bytes[6] = 2 17:09:59.992 [INFO ] [org.openhab.model.script.error:53 ] - Decoded Bytes: Battery 2942.00000000 02:0B:7E:00
Here uptime should be 1201 (not -17) if you decode 04:EF you get 1263 (not -17) (the BF should be 00 but I think that’s another issue).
Battery is 0B:7E which decodes correctly as 2942.

I think it’s because it’s a signed short in 2’s compliment, and in openhab Bytes are signed. I’m having a hard time using Short’s and Bytes in openhab (which is why there is so much conversion experimentation in my test rule). I cant get bitwiseAnd to work (I don’t think it works with Bytes) which is why I’m using &0xFF to try to preserve the bit order.

Theoretically all I need to do is

var Short temp3 = (bytes.get(7) << 8).bitwiseOr(bytes.get(8))

but obviously that doesn’t work. I also can’t access the bytes using a construct such as bytes[7] or bytes[8] as I thought would work.

Anyone have any suggestions on how to do this seemingly simple task?


Have you tried to use a ByteBuffer and the b he Short method?