Skip to main content

RAK2560 WisNode Sensor Hub Payload Decoder

Sensor Hub LoRaWAN Payload and NB IoT JSON Format

Sensor Probe

The RAK1901, RAK1902, RAK1904, and RAK1906 all incorporate multiple sensors integrated into a single sensor IC.

WisBlock ModuleSensor ICSensor TypeSensor Data Values
RAK1901SHTC3Temperature and HumidityTemperature (-40° C to +125° C)
Humidity (0 to 100% RH)
RAK1902KPS22HBTemperature and Barometric PressureTemperature (-40° C to +85° C)
Pressure (260 to 1260 hPa)
RAK1904LIS3DH3-Axis Acceleration3-Axis (XYZ)
RAK1906BME680EnvironmentalTemperature (-40° C to 85° C)
Humidity (0 to 100% RH)
Pressure (300 to 1100 hPa)
Gas (0 to 500 IAQ)

The four (4) WisBlock modules will have four (4) sensor types as follows:

SensorTypeData Size
Temperature0x672
Humidity0x681
Pressure0x662
3-axis0x716

RAK Sensor Type is 1 Byte, which uses the IPSO Object ID minus 3200 in the below conversion rule:

RAK_DATA_TYPE = IPSO_OBJECT_ID - 3200
TypeIPSO IDRAK Data Type (Decimal)RAK Data Type (Hex)Data SizeData Resolution per BitSensor Hub NB IoT Json
Temperature sensor33031030x6720.1° C Signed MSB"Temperature"
Humidity sensor33041040x6810.1% Unsigned"Humidity"
Accelerometer (3-Axis)33131130x7160.001 G Signed MSB per axis"Accelerometer"
Barometer (Pressure)33151150x7320.1 hPa Unsigned MSB"Barometer"

RAKwireless Standardized Payload Decoder

On GitHub, you can find a standard version of the decoder that works with all solutions.

Sensor Probe IO

TypeIPSO IDRAK Data Type (Decimal)RAK Data Type (HEX)Data SizeData Resolution per BitSensor Hub NB IoT Json
Digital Input320000x001(ON/OFF)"Digital-Input"
Digital Output320110x011(ON / OFF)"Digital-Output"
Analog Input320220x0220.01mA(V), Min: 0.0, MAX: 655.35"Analog-Input"
Nitrogen3216160x1021mg/Kg, Min: 0, MAX: 65535"NITROGEN"
Phosphorus3217170x1121mg/Kg, Min: 0, MAX: 65535"PHOSPHORUS"
Potassium3218180x1221mg/Kg, Min: 0, MAX: 65535"POTASSIUM"
Salinity3219190x1321mg/L, Min: 0, MAX: 65535"SALINITY"
Dissolved oxygen (DO)3220200x1420.01mg/L, Min: 0.0, MAX: 655.35"Dissolved-Oxygen"
Oxidation Reduction Potential (ORP)3221210x1520.1mv sign"ORP"
Chemical Oxygen Demand (COD)3222220x1621mg/L, Min: 0, MAX: 65535"COD"
Turbidity3223230x1721NTU, Min: 0, MAX: 65535"Turbidity"
NO33224240x1820.1ppm, Min: 0.0, MAX: 6553.5"NO3"
NH4+3225250x1920.01ppm, Min: 0.0, MAX: 655.35"NH4PULS"
Biochemical oxygen demand (BOD)3226260x1A21mg/L, Min: 0, MAX: 65535"BOD"
Illuminance33011010x6541Lux, Min: 0, MAX:4294967295"Illuminance"
Presence33021020x661(Yes/No)"Presence"
Temperature33031030x6720.1°C, Min: -3276.8, MAX:3276.7"Temperature"
Humidity Sensor Soil Humidity SCD30 humidity33041040x6811%RH Unsigned"Humidity"
Air Quality Index33051050x6921 Unsigned MSB 1, Min: 0, MAX: 65535"GAS"
Humidity33121120x7020.1%, Min: 0.0, MAX:100.0"High-Precise-Humidity"
Accelerometer (3-Axis)33131130x7160.001 G Signed MSB per axis"Accelerometer"
Pressure33151150x7320.1hPa, Min: 0.0, MAX: 6553.5"Barometer"
Battery Level (Battery Voltage)33161160x7420.01V, Min: 0.0, MAX: 655.35"BatteryValue"
Precipitation33171170x7721mm/h, Min: 0, MAX: 65535"Precipitation"
Percentage33201200x7811%, Min: 0, Max:100"Percentage"
CO2 concentration33251250x7D21ppm, Min: 0, MAX: 65535"CO2"
EC33921920xC020.001mS/cm, Min: 0.0, Max:65.535"EC"
EC33271270x7F40.001uS/cm, Min: 0.0, Max:4294967.295"High-Precision-EC"
Distance33301300x8240.001 m"Distance"
RAK Device Serial Number1260x7E33 bytes Serial number in MSB "SSN""Serial Number"
VOC33381380x8A21, Min: 0, MAX: 65535"VOC"
Wind Speed33461460x9220.01m/s, Min: 0.0, MAX: 655.35"GustWindSpeed"
Strikes33471470x9321, Min: 0, MAX: 65535"Strikes"
Capacity33841840xB811%RH, Min: 0, MAX: 100"Capacity"
DC Current33851850xB920.01A, Min: -327.68, MAX: 327.67"DC_Current"
DC Voltage33861860xBA20.01V, Min: 0.0, MAX: 655.35"DC_Voltage"
Moisture33881880xBC20.1%, Min:0.0, Max:100.0"Moisture"
Wind Speed33901900xBE20.01m/s, Min: 0.0, MAX: 655.35"Wind-Speed"
Wind Direction (0o - North)33911910xBF21o , in 0~359o"Wind-Direction"
pH33931930xC120.01, Min: 0.0, MAX: 655.35"High_Precision_PH"
Normal Precision pH33941940xC220.1 pH"PH"
Pyranometer33951950xC321 unsigned MSB (W/m2)"PYRANOMETER"
PM1034272270xE321ug/m3, Min: 0, MAX: 65535"PM10"
PM2.534282280xE421ug/m3, Min: 0, MAX: 65535"PM2.5"
Noise34332330xE920.1dB, Min: 0.0, MAX: 6553.5"Noise"
Orientation34292290xE520.1°, Min: -90.0, MAX: 90.0"ORIENTATION"
Raw Data in Binary (Modbus ADU)34412410xF1/TLV format binary raw data for Modbus, RS232 or other specific data format "BinaryRaw" (NBIOT Json Mode)
Binary2byte34432430xF32Modbus content"Raw2byte"
Binary4byte34242240xF44Modbus content"Raw4byte"
Generic Float (IEEE754)34452450xF54"Float"
Generic Integer (32bit)34462460xF64Min: -2147483648, Max: 2147483647"Int32"
Generic Unsigned Integer (32bit)34472470xF74Min: 0, Max: 4294967295"uInt32"
Raw Data in Binary34482480xF8/TLV format binary raw data "BinaryTLV" (NBIOT Json Mode)"BinaryTLV"

RK900-09 Weather Station Sample Payload Decoder

Click to view the Payload Decoder code
function Decoder(bytes, port) {  
var decoded = {};
var str = bin2HexStr(bytes);
var i = 0;
while (i < str.length) {
var channelId = parseShort(str.slice(i, i + 4), 16);
var value = parseShort(str.slice(i + 4, i + 8), 16);
i += 8;
switch (channelId) {
case 0x01BE:
decoded.wind_speed = value / 100;
break;
case 0x02BF:
decoded.wind_direction = value;
break;
case 0x0367:
decoded.temperature = value / 10.0;
break;
case 0x0470:
decoded.humidity = value / 10.0;
break;
case 0x0573:
decoded.pressure = value / 10.0;
break;
default:
break;
}
}

try {
decoded.lorawan_rssi = (port && port.metadata && port.metadata.rssi) || 0;
decoded.lorawan_snr = (port && port.metadata && port.metadata.snr) || 0;
decoded.lorawan_datarate = (port && port.metadata && port.metadata.data_rate) || '';
} catch (e) {
console.log('Failed to read gateway metadata');
}

return decoded;
}

function bin2HexStr(bytesArr) {
var str = '';
for (var i = 0; i < bytesArr.length; i++) {
var tmp = (bytesArr[i] & 0xff).toString(16);
if (tmp.length == 1) {
tmp = '0' + tmp;
}
str += tmp;
}
return str;
}

// convert string to short integer
function parseShort(str, base) {
var n = parseInt(str, base);
return (n << 16) >> 16;
}

// convert string to triple bytes integer
function parseTriple(str, base) {
var n = parseInt(str, base);
return (n << 8) >> 8;
}
Data Interpretation
Sensor Data UnitID (Channel)TypeData
Serial Number1 Byte1 Byte3 Bytes
Wind Speed1 Byte1 Byte2 Bytes
Wind Direction1 Byte1 Byte2 Bytes
Temperature1 Byte1 Byte2 Bytes
Humidity1 Byte1 Byte2 Bytes
Air Pressure1 Byte1 Byte2 Bytes

With the defined data, here's how to interpret the payload received data:

RK900-09 Weather Station Data Sample

Payload (hex) received data: 007E006F07 01BE0000 02BF0000 036700C6 047002E7 05732719

Sensor Data UnitID (Channel)TypeData
Serial Number007e006f07
Wind Speed01be0000
Wind Direction02bf0000
Temperature036700c6
Humidity047002e7
Air Pressure05732719

Convert the sensor data from hexadecimal to decimal:

  • Serial Number: 007e
  • Data: 006f07
SN: 006f07
  • Wind Speed: 01be
  • Data: 0000
0000 (hex) = 0 (dec)
0 x 0.01 (conversion factor) = 0 m/s
  • Wind Direction: 02bf
  • Data: 0000
0000 (hex) = 0 (dec)
0 x 1 (conversion factor) = 0°
  • Temperature: 0367
  • Data: 00C6
00C6 (hex) = 198 (dec)
198 x 0.1 (conversion factor) = 19.8° C
  • Humidity: 0470
  • Data: 02E7
02E7 (hex) = 743 (dec)
743 x 0.1 (conversion factor) = 74.3%RH
  • Air Pressure: 0573
  • Data: 2719
2719 (hex) = 10009 (dec)
10009 x 0.1 (conversion factor) = 1000.9 hPa

RAK9154 Solar Battery Sample Payload Decoder

RAK IPSO Sensor type definition in JSON

  • Filename: snsr_type_def.json
Click to view the Payload Decoder code
{
"7e": {
"name": "SSN",
"resolution" : 1,
"length": 3,
"unit": ""
},
"14": {
"name": "Dissolved-Oxygen",
"resolution" : 0.01,
"length": 2,
"unit": "mg/L"
},
"15": {
"name": "Oxidation Reduction Potential",
"resolution" : 0.1,
"length": 2,
"unit": "mV",
"sign": "-1000~+1000mv"
},
"67": {
"name": "Temperature",
"resolution" : 0.1,
"length": 2,
"unit": "°C"
},

"68": {
"name": "Humidity",
"resolution" : 1,
"length": 1,
"unit": "%"
},
"73": {
"name": "Barmoeter",
"resolution" : 0.1,
"length": 2,
"unit": "hPA"
},
"71": {
"name": "A",
"resolution" : 0.001,
"length": 6,
"unit": "G"
},
"be": {
"name": "Wind-Speed",
"resolution" : 0.01,
"length": 2,
"unit": "m/s"
},
"bf": {
"name": "Wind-Direction",
"resolution" : 1,
"length": 2,
"unit": "°"
},
"65": {
"name": "Illuminance",
"resolution" : 1,
"length": 4,
"unit": "lux"
},
"70": {
"name": "High-Precise-Humidity",
"resolution" : 0.1,
"length": 2,
"unit": "%"
},
"c1": {
"name": "High_Precision_pH",
"resolution" : 0.01,
"length": 2,
"unit": "pH"
},
"c2": {
"name": "pH",
"resolution" : 0.1,
"length": 2,
"unit": ""
},
"c3": {
"name": "Pyranometer",
"resolution" : 1,
"length": 2,
"unit": "W/m2"
},
"c0": {
"name": "EC",
"resolution" : 0.001,
"length": 2,
"unit": "mS/cm"
},
"7f": {
"name": "High-Precision-EC",
"resolution" : 0.001,
"length": 4,
"unit": "us/cm"
},
"13": {
"name": "Salt",
"resolution" : 1,
"length": 2,
"unit": "mg/L"
},
"b8": {
"name": "Capacity",
"resolution" : 1,
"length": 1,
"unit": "%"
},
"b9": {
"name": "Current",
"resolution" : 0.01,
"length": 2,
"unit": "A"
},
"ba": {
"name": "Voltage",
"resolution" : 0.01,
"length": 2,
"unit": "V"
},
"10": {
"name": "Nitrogen",
"resolution" : 1,
"length": 2,
"unit": "mg/kg"
},
"11": {
"name": "phosphorus",
"resolution" : 1,
"length": 2,
"unit": "mg/kg"
},
"12": {
"name": "potassium",
"resolution" : 1,
"length": 2,
"unit": "mg/kg"
},
"77": {
"name": "Dummy",
"resolution" : 1,
"length": 4,
"unit": "qq"
},
"7d": {
"name": "CO2",
"resolution" : 1,
"length": 2,
"unit": "ppm"
},
"82": {
"name": "Distance",
"resolution" : 0.001,
"length": 2,
"unit": "m"
},
"e5": {
"name": "ORIENTATION",
"resolution" : 0.1,
"length": 2,
"unit": "°",
"sign": "–90° to 90°"
},
"e9": {
"name": "Noise",
"resolution" : 0.1,
"length": 2,
"unit": "dB"
},
"f1": {
"name": "RS485",
"resolution" : 1,
"length": 1,
"unit": ""
},
"f2": {
"name": "BINARY",
"resolution" : 1,
"length": 2,
"unit": ""
},
"02": {
"name": "AIC",
"resolution" : 0.01,
"length": 2,
"unit": ""
},
"03": {
"name": "AIV",
"resolution" : 0.01,
"length": 2,
"unit": ""
}
}

Decoder in Python

Click to view the Payload Decoder code
import re, json 

data='007e00280c15ba04f116b9000017b8641867011819f300401af30001'
pattern = re.compile('.{2}')
handle_data = re.findall(pattern, data)

snsr_id_index = 0
ssn = ''
value = ''


def twos_complement_hex(hex_str):
decimal_num = int(hex_str, 16)
twos_complement = (decimal_num + (1 << (len(hex_str) * 4))) % (1 << (len(hex_str) * 4))
return twos_complement # Return the integer value


with open('snsr_type_def.json', 'r', encoding='UTF-8') as f:
unit_dict = json.load(f)

while (snsr_id_index+1) < len(handle_data):
ipso_index = snsr_id_index+1

if handle_data[ipso_index] not in unit_dict.keys():
pass
elif (len(handle_data[ipso_index-1:]) -
(2+unit_dict[handle_data[ipso_index]]['length']) ) < 0:
pass
else:
inner_dict = unit_dict[handle_data[ipso_index]]
name = inner_dict['name']
resolution = inner_dict['resolution']
unit = inner_dict['unit']
data_index = ipso_index+1
sensor_id_type = ''.join(i for i in handle_data[data_index-2:
data_index])
if name == 'RS485':
inner_dict['length'] = len(handle_data[data_index:])
hex_data = ''.join(i for i in handle_data[data_index:
data_index+inner_dict['length']])
dec_data = ''
if name == 'SSN':
dec_data = hex_data
ssn = hex_data
elif name == 'RS485':
dec_data = hex_data
elif name == 'A':
for A in range(3):
dec_data +=
'%s,'%round(twos_complement_hex(hex_data[A*4:(A+1)*4])*resolution,2)
dec_data = dec_data[0:-1]
else:
dec_data = round(twos_complement_hex(hex_data)*resolution,
len(str(resolution ))-1)
value += '%s: %s%s, ' %(name, dec_data, unit)
snsr_id_index += (1+inner_dict['length'])

snsr_id_index += 1

print(value)
Data Interpretation
Data UnitID (Channel)TypeData
Serial Number1 Byte1 Byte3 Bytes
Battery Voltage1 Byte1 Byte2 Bytes
Battery Current1 Byte1 Byte2 Bytes
Battery SOC (State of charge)1 Byte1 Byte1 Byte
Battery Temperature1 Byte1 Byte2 Bytes
Battery Error1 Byte1 Byte2 Bytes
Battery FW Version1 Byte1 Byte2 Bytes

With the defined data, here's how to interpret the payload received data:

RAK9154 Solar Battery Data Sample

Payload (hex) received data: 007e 00280c 15ba04f1 16b90000 17b864 18 670118 19 f30040 1af30001

Data UnitID (Channel)TypeData
Serial Number007e00280C
Battery Voltage15ba04F1
Battery Current16b90000
Battery SOC17b864
Battery Temperature18670118
Battery Error19f30040
Battery FW Version1af30001

Convert the sensor data from hexadecimal to decimal:

  • Serial Number: 007e
  • Data: 00280c
SN: 00280C
  • Battery Voltage: 15ba
  • Data: 04f1
04F1 (hex) = 1265 (dec)
1265 x 0.01 (conversion factor) = 12.65 V
  • Battery Current: 16b9
  • Data: 0000
0000 (hex) = 0 (dec)
0 x 0.01 (conversion factor) = 0 A
  • Battery SOC: 17b8
  • Data: 64
64 (hex) = 100 (dec)
100 x 0.01 (conversion factor) = 1.00 = 100%
  • Battery Temperature: 1867
  • Data: 0118
0118 (hex) = 280 (dec)
280 x 0.1 (conversion factor) = 28.0° C
  • Battery Error: 19f3
  • Data: 0040
Battery Error = no error
  • Battery FW Version: 1af3
  • Data: 0001
Battery FW Version = v00.01

RAK200-03 Pyranometer Sample Payload Decoder

Click to view the Payload Decoder code
function Decoder(bytes, port) {
var decoded = {};
var str = bin2HexStr(bytes);
var i = 0;
while (i < str.length) {
var channelId = parseShort(str.slice(i, i + 4), 16);
var value = parseShort(str.slice(i + 4, i + 8), 16);
i += 8;
switch (channelId) {
case 0x01C3:
decoded.pyranometer = value;
break;
default:
break;
}
}

try {
decoded.lorawan_rssi = (port && port.metadata && port.metadata.rssi) || 0;
decoded.lorawan_snr = (port && port.metadata && port.metadata.snr) || 0;
decoded.lorawan_datarate = (port && port.metadata && port.metadata.data_rate) || '';
} catch (e) {
console.log('Failed to read gateway metadata');
}

return decoded;
}

function bin2HexStr(bytesArr) {
var str = '';
for (var i = 0; i < bytesArr.length; i++) {
var tmp = (bytesArr[i] & 0xff).toString(16);
if (tmp.length == 1) {
tmp = '0' + tmp;
}
str += tmp;
}
return str;
}

// convert string to short integer
function parseShort(str, base) {
var n = parseInt(str, base);
return (n << 16) >> 16;
}

// convert string to triple bytes integer
function parseTriple(str, base) {
var n = parseInt(str, base);
return (n << 8) >> 8;
} var n = parseInt(str, base);
return (n << 8) >> 8;
Data Interpretation
Sensor Data UnitID (Channel)TypeData
Serial Number1 Byte1 Byte3 Bytes
Pyranometer1 Byte1 Byte2 Bytes

With the defined data, here's how to interpret the payload received data:

RK200-03 Solar Pyranometer Data Sample

Payload (hex) received data: 007e 006f03 01c3 0000

Sensor Data UnitID (Channel)TypeData
Serial Number007e006f03
Pyranometer01c30000

Convert the sensor data from hexadecimal to decimal:

  • Serial Number: 007e
  • Data: 006f07
SN: 006f03
  • Pyranometer: 01c3
  • Data: 0000
0000 (hex) = 0 (dec)
0 x 1 (conversion factor) = 0 W/m2