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"
when
Item MCThings111BABeacon changed
then
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)
}
end
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?
Thanks,