MQTT Compact Message: Decoders

Disclaimer

The meteorological variables are reproduced from sources listed at the end of each instrument section to the best of our ability without variation of their numerical content. Corresponding hardware manufacturer should be contacted for any and all concerns regarding their definition, interpretation and precision. Our contribution is limited exclusively to the presentation of variables in the MQTT payload (ordering in the array etc.).

Barani MeteoHelix IoT Pro

The MQTT message format for LoRaWAN and Sigfox MeteoHelix weather stations for message type=1. Please note that this section documents the “standalone” MeteoHelix instrument without a cable connection to the MeteoRain device. Therefore the last 16 bits of the LoRa payload, reserved for rain information, are not parsed.

Meteo-variables

As per our general design choice, all meteorological data is contained in a JSON array. This device provides 7 meteorological variables, which can be accessed from the payload by their index, starting from zero, in this order:

  1. Average temperature
  2. Minimum temperature
  3. Maximum temperature
  4. Relative humidity
  5. Atmospheric pressure
  6. Diffuse solar radiation
  7. Peak of diffuse solar radiation

Device-specific information

Device-info data is a JSON structure providing only the battery information:

bp
Battery level as percentage.
bv
Battery level as potential in volts

Payload decoder with chirpstack signature

var pos = 0;
var bindata = "";

var ConvertBase = function (num) {
    return {
        from : function (baseFrom) {
            return {
                to : function (baseTo) {
                    return parseInt(num, baseFrom).toString(baseTo);
                }
            };
        }
    };
};

function pad(num) {
    var s = "0000000" + num;
    return s.slice(-8);
}

ConvertBase.dec2bin = function (num) {
    return pad(ConvertBase(num).from(10).to(2));
};

ConvertBase.bin2dec = function (num) {
    return ConvertBase(num).from(2).to(10);
};

function data2bits(data) {
    var binary = "";
    for(var i=0; i<data.length; i++) {
        binary += ConvertBase.dec2bin(data[i]);
    }
    return binary;
}

function bitShift(bits) {
    var num = ConvertBase.bin2dec(bindata.substr(pos, bits));
    pos += bits;
    return Number(num);
}

function precisionRound(number, precision) {
    var factor = Math.pow(10, precision);
    return Math.round(number * factor) / factor;
}

function bin2hex(b) {
    return b.match(/.{4}/g).reduce(function(acc, i) {
        return acc + parseInt(i, 2).toString(16);
    }, '');
}

function Decode(fPort, bytes) {
    var message = {};
    var sensordata = {};
    var devicedata = {};
    var linkdata = {};
    
    bindata = data2bits(bytes);
    payload = bin2hex(bindata);
    
    type =  bitShift(2);
	
    battery_index = bitShift(5);
    battery_volts = precisionRound(battery_index*0.05 + 3.0, 2);
    battery_level = precisionRound(3.22581*battery_index, 0);

    temperature = precisionRound(bitShift(11)*0.1-100, 1);
    temperature_min = precisionRound(temperature - bitShift(6)*0.1, 1);
    temperature_max = precisionRound(temperature + bitShift(6)*0.1, 1);

    humidity = precisionRound(bitShift(9)*0.2, 1);

    pressure = bitShift(14)*5+50000;

    irradiation = bitShift(10)*2;
    irr_max = irradiation + bitShift(9)*2;

    sensordata=[temperature,temperature_min,temperature_max,humidity,pressure,irradiation,irr_max]

    devicedata.bp=battery_level;
    devicedata.pv=battery_volts;

    linkdata.i = LoRaObject.rxInfo[0].mac;
    linkdata.rssi = LoRaObject.rxInfo[0].rssi;
    linkdata.snr = LoRaObject.rxInfo[0].loRaSNR;
    linkdata.f = LoRaObject.txInfo.frequency;
    linkdata.b = LoRaObject.txInfo.dataRate.bandwidth;
    linkdata.s = LoRaObject.txInfo.dataRate.spreadFactor;
    linkdata.c = LoRaObject.txInfo.codeRate;
    
    message.t = LoRaObject.time.substring(0,19);
    message.i = LoRaObject.devEUI;
    message.d = sensordata;
    message.x = linkdata;
    message.h = devicedata;
    message.p = payload;
    return message;
}

Sources

Consult the online calculator for the interpretation of variables.

A TTN decoder by manufacturer can be found here.

Contact Barani Design for further information about the instrument.

Barani MeteoWind (2022 models)

The MQTT message format for LoRaWAN and Sigfox MeteoWindIoT Pro wind transmitter, valid for MeteoWind IoT units with 2022 production dates.

Meteo-variables

As per our general design choice, all meteorological data is contained in a JSON array. This device provides 8 meteorological variables. The variables can be accessed from the payload by their index, starting from zero, in this order:

  1. average wind speed for the 10 minute interval
  2. gust value per WMO (maximum rolling 3 second average wind speed)
  3. minimum rolling 3 second average wind speed.
  4. wind speed standard deviation.
  5. mean (average) wind direction for the 10 minute interval.
  6. wind direction corresponding to the gust value (item 1.)
  7. wind direction standard deviation
  8. elapsed time in multiple of seconds after start of logging interval, time resolution = 5 sec.

Device-specific information

Device-info data is a JSON structure with the following fields:

v
Vector/Scalar value of wind speed & direction, Scalar=0(default),Vector=1.
a
Alarm sent? This value indicates whether alarm was activated during the current time interval: alarm was not sent during the last logging interval=0 (default), at least one alarm was sent during the last logging interval =1.
bp
Battery level as percentage.
bv
Battery level as potential in volts

Payload decoder with chirpstack signature

var pos = 0;
var bindata = "";

var ConvertBase = function (num) {
    return {
        from : function (baseFrom) {
            return {
                to : function (baseTo) {
                    return parseInt(num, baseFrom).toString(baseTo);
                }
            };
        }
    };
};

function pad(num) {
    var s = "0000000" + num;
    return s.slice(-8);
}

ConvertBase.dec2bin = function (num) {
    return pad(ConvertBase(num).from(10).to(2));
};

ConvertBase.bin2dec = function (num) {
    return ConvertBase(num).from(2).to(10);
};

function data2bits(data) {
    var binary = "";
    for(var i=0; i<data.length; i++) {
        binary += ConvertBase.dec2bin(data[i]);
    }
    return binary;
}

function bitShift(bits) {
    var num = ConvertBase.bin2dec(bindata.substr(pos, bits));
    pos += bits;
    return Number(num);
}

function precisionRound(number, precision) {
    var factor = Math.pow(10, precision);
    return Math.round(number * factor) / factor;
}

function bin2hex(b) {
    return b.match(/.{4}/g).reduce(function(acc, i) {
        return acc + parseInt(i, 2).toString(16);
    }, '');
}

function Decode(fPort, bytes) {
    var message = {};
    var sensordata = {};
    var devicedata = {};
    var linkdata = {};
    
    bindata = data2bits(bytes);
    payload = bin2hex(bindata);

    index = bitShift(8);
    battery_index = bitShift(3);
    
    battery_volts = precisionRound(0.2*battery_index + 3.0, 1)
    battery_level = precisionRound(14.286*battery_index, 0)

    wind_avg = precisionRound(bitShift(9)*0.1, 1);
    wind_max = precisionRound(wind_avg + bitShift(9)*0.1, 1);
    wind_min = precisionRound(wind_avg - bitShift(9)*0.1, 1);
    wind_dev = precisionRound(bitShift(8)*0.1, 1);

    dir_avg = precisionRound(bitShift(9), 1);
    dir_max = precisionRound(bitShift(9), 1);
    dir_dev = precisionRound(bitShift(7), 1);
    gust_time = precisionRound(bitShift(7)*5, 1);
    vector = bitShift(1);
    alarm = bitShift(1);
    
    sensordata=[wind_avg,wind_max,wind_min,wind_dev,dir_avg,dir_max,dir_dev,gust_time];

    devicedata.bp=battery_level;
    devicedata.bv=battery_volts;
    devicedata.a=alarm;
    devicedata.v=vector;
    

    linkdata.i = LoRaObject.rxInfo[0].mac;
    linkdata.rssi = LoRaObject.rxInfo[0].rssi;
    linkdata.snr = LoRaObject.rxInfo[0].loRaSNR;
    
    linkdata.f = LoRaObject.txInfo.frequency;
    linkdata.b = LoRaObject.txInfo.dataRate.bandwidth;
    linkdata.s = LoRaObject.txInfo.dataRate.spreadFactor;
    linkdata.c = LoRaObject.txInfo.codeRate;

    message.t = LoRaObject.time;
    message.i = LoRaObject.devEUI;
    message.d = sensordata;
    message.x = linkdata;
    message.h = devicedata; 
    message.p = payload;

    return message;
}

Sources

Consult the online calculator for the interpretation of variables.

A TTN decoder by manufacturer can be found here.

Contact Barani Design for further information about the instrument.

Barani MeteoRain IoT Pro (standalone)

The MQTT message format for LoRaWAN MeteoRain automatic wireless rain gauge. Please note that this section documents the “standalone” MeteoRain instrument without a cable connection to the MeteoHelix.

Meteo-variables

As per our general design choice, all meteorological data is contained in a JSON array. This array provides 3 meteorological variables. The variables can be accessed from the payload by their index, starting from zero, in this order:

  1. Rain clicks (revolving counter)
  2. Time interval (min time interval between successive pulses). It is sent as 182/time (in seconds).
  3. Rain intensity correction to rain clicks (revolving counter)

To compute the rainfall from the tick and the correction, two last entries are required. The formula is the following:

Device-specific information

Device-info data is a JSON structure with the following fields:

f
Frost alert (0/1)
h
Heater on (0/1)
bp
Battery level as percentage.
bv
Battery level as potential in volts

Payload decoder with chirpstack signature

var pos = 0;
var bindata = "";

var ConvertBase = function (num) {
    return {
        from : function (baseFrom) {
            return {
                to : function (baseTo) {
                    return parseInt(num, baseFrom).toString(baseTo);
                }
            };
        }
    };
};

function pad(num) {
    var s = "0000000" + num;
    return s.slice(-8);
}

ConvertBase.dec2bin = function (num) {
    return pad(ConvertBase(num).from(10).to(2));
};

ConvertBase.bin2dec = function (num) {
    return ConvertBase(num).from(2).to(10);
};

function data2bits(data) {
    var binary = "";
    for(var i=0; i<data.length; i++) {
        binary += ConvertBase.dec2bin(data[i]);
    }
    return binary;
}

function bitShift(bits) {
    var num = ConvertBase.bin2dec(bindata.substr(pos, bits));
    pos += bits;
    return Number(num);
}

function precisionRound(number, precision) {
    var factor = Math.pow(10, precision);
    return Math.round(number * factor) / factor;
}

function bin2hex(b) {
    return b.match(/.{4}/g).reduce(function(acc, i) {
        return acc + parseInt(i, 2).toString(16);
    }, '');
}

function Decode(fPort, bytes)
{
    var message = {};
    var sensordata = {};
    var devicedata = {};
    var linkdata = {};
    var rx = {};
    var tx = {};
    var battery_index = 0;
    
    bindata = data2bits(bytes);
    payload = bin2hex(bindata);

    counter =  bitShift(8);

    battery_index = precisionRound(bitShift(5), 0);
    battery_volts = precisionRound(battery_index*0.05 + 3.0, 2);
    battery_level = precisionRound(3.22581*battery_index, 0);

    rain_tick = bitShift(12);
    rain_time = bitShift(8);
   
    frost_alert = 1 - bitShift(1);
    heater_on = bitShift(1);
    correction = precisionRound(bitShift(12)*0.01,2);

    sensordata=[rain_tick,rain_time,correction];

    devicedata.bp=battery_level;
    devicedata.bv=battery_volts;
    devicedata.f=frost_alert;
    devicedata.h=heater_on;

    linkdata.i = LoRaObject.rxInfo[0].mac;
    linkdata.rssi = LoRaObject.rxInfo[0].rssi;
    linkdata.snr = LoRaObject.rxInfo[0].loRaSNR;
    
    linkdata.f = LoRaObject.txInfo.frequency;
    linkdata.b = LoRaObject.txInfo.dataRate.bandwidth;
    linkdata.s = LoRaObject.txInfo.dataRate.spreadFactor;
    linkdata.c = LoRaObject.txInfo.codeRate;

    message.t = LoRaObject.time.substring(0,19);
    message.i = LoRaObject.devEUI;
    message.d = sensordata;
    message.x = linkdata;
    message.h = devicedata;
    message.p = payload;
    return message;
}

Sources

Consult the online calculator for the interpretation of variables.

A TTN decoder by manufacturer can be found here.

Contact Barani Design for further information about the instrument.