Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

FieldTypeValue
Headeruint80x00 on success, 0x80 if an error occurred
Pressurefloat32Pressure in Bar, ffffffff on error.
Temperaturefloat32

Temperature in °C, ffffffff on error.

Voltageuint16Voltage in mV, ffff on error

LoRaWAN JavaScript Reference Parser (All probe variants)

...

Status
colourRed
titleLoRaWAN only works with default config for MbCmd!

Code Block
languagejs
titlePressure Probe Parser
linenumberstrue
/**
 * Parser for Lobaro Pressure Probe via LoRaWAN (hybrid gateway).
 * Usable for Pressure Probe as or with Presure+Temperature Probe.
 * Works with TTN, ChirpStack, or the Lobaro Platform.
 */
function signed(val, bits) {
    // max positive value possible for signed int with bits:
    var mx = Math.pow(2, bits-1);
    if (val < mx) {
        // is positive value, just return
        return val;
    } else {
        // is negative value, convert to neg:
        return val - (2 * mx);
    }
}
function int16_BE(bytes, idx) {
    bytes = bytes.slice(idx || 0);
    return signed(bytes[0] << 8 | bytes[1] << 0, 2*8);
}
function uint16_BE(bytes, idx) {
    bytes = bytes.slice(idx || 0);
    return bytes[0] << 8 | bytes[1] << 0;
}
function uint32_BE(bytes, idx) {
    bytes = bytes.slice(idx || 0);
    return bytes[0] << 24 | bytes[1] << 16 | bytes[2] << 8 | bytes[3] << 0;
}
function float32FromInt(asInt) {
    var sign = (asInt >> 31) == 0 ? 1 : -1;
    var exponent = ((asInt >> 23) & 0xFF) - 127;
    var significand = (asInt & ~(-1 << 23));
    if (exponent === 128)
        return null;
        // return sign * ((significand) ? Number.NaN : Number.POSITIVE_INFINITY);
    if (exponent === -127) {
        if (significand === 0) return sign * 0.0;
        exponent = -126;
        significand /= (1 << 22);
    } else {
        significand = (significand | (1 << 23)) / (1 << 23);
    }
    return sign * significand * Math.pow(2, exponent);
}
function float32_BE(bytes, idx) { return float32FromInt(uint32_BE(bytes, idx)); }
  
/**
 * TTN decoder function.
 */
function Decoder(bytes, port) {
    var vals = {};
    if( port == 20 ){
        if (bytes.length==5) {
            // Pressure Probe without temperature sensor and Bridges internal Temperature
            vals["error"] = !!(bytes[0]&0x80);
            vals["pressure"] = int16_BE(bytes, 1)/1000;
            vals["temperature"] = int16_BE(bytes, 3);
        }  else if (bytes.length==7) {
            vals["error"] = !!(bytes[0]&0x80);
            vals["pressure"] = int16_BE(bytes, 1)/1000;
            vals["temperature"] = int16_BE(bytes, 3);
            vals["voltage"] = uint16_BE(bytes, 5) / 1000;
        } else if (bytes.length==9) {
            vals["error"] = !!(bytes[0]&0x80);
            // pressure in mH2O
            vals["pressure"] = float32_BE(bytes, 1);
            // temperature in Degree Celsius
            vals["temperature"] = float32_BE(bytes, 5);
        } else if (bytes.length==11) {
            vals["error"] = !!(bytes[0]&0x80);
            // pressure in mH2O
            vals["pressure"] = float32_BE(bytes, 1);
            // temperature in Degree Celsius
            vals["temperature"] = float32_BE(bytes, 5);
            vals["voltage"] = uint16_BE(bytes, 9) / 1000;
        }
    }
     
    if (port === 64 && bytes.length == 13) { // status packet
        vals["Firmware Identifier"] =  String.fromCharCode(bytes[0]) + String.fromCharCode(bytes[1]) + String.fromCharCode(bytes[2]);
        vals["FirmwareVersion"] = bytes[3] + '.' + bytes[4] + '.' + bytes[5];
        vals["status"] = bytes[6];
        vals["reboot reason"] = bytes[7];
        vals["final words"] = bytes[8];
        vals["voltage"] = uint16_BE(bytes,9)/1000.0
        vals["temperature"] =  int16_BE(bytes,11)/10.0;
    }
    return vals;
}
 
function NB_ParseModbusQuery(input){
  vals = {};
  
  for( var i = 0; i< input.d.batch.length; i++ ){
    if (input.d.batch[i].cmd == "AQMAFgAC"){
      vals["pressure"] = float32_BE(bytes(atob(input.d.batch[i].rsp)),3);
    }
    if (input.d.batch[i].cmd == "AQMAJgAC"){
      vals["temperature"] = float32_BE(bytes(atob(input.d.batch[i].rsp)),3);
    }
    
    // else: keller
    if (input.d.batch[i].cmd == "AQMAAgAC"){
      // convert to mH2O
      vals["pressure"] = float32_BE(bytes(atob(input.d.batch[i].rsp)),3)*10.197442889221;
    }
    if (input.d.batch[i].cmd == "AQMACAAC"){
      vals["temperature"] = float32_BE(bytes(atob(input.d.batch[i].rsp)),3);
    }
      // vbat
   if (input.d.batch[i].cmd == "+gQABQAB"){
      vals["vBat"] = int16_BE(bytes(atob(input.d.batch[i].rsp)),3)/1000.0;
    }
  
    // internal temperature
     if (input.d.batch[i].cmd == "+gQABAAB"){
      vals["temperatureInt"] = int16_BE(bytes(atob(input.d.batch[i].rsp)),3);
    }
  }
  
  return vals;
}
   
/**
 * TTN V3 Wrapper
 */
function decodeUplink(input) {
   return {
    data: {
      values: Decoder(input.bytes, input.fPort)
    },
    warnings: [],
    errors: []
  };
}
   
function NB_ParseDeviceQuery(input) {
  for (var key in input.d) {
      var v = input.d[key];
      switch (key) {
          case "temperature":
              v = v / 10.0;
              Device.setProperty("device.temperature", v);
              continue;
          case "vbat":
              v = v / 1000.0;
              Device.setProperty("device.voltage", v);
              continue;
      }
      Device.setProperty("device." + key, v);
  }
  return null;
}
   
function NB_ParseConfigQuery(input) {
  for (var key in input.d) {
    Device.setConfig(key, input.d[key]);
  }
    return null;
}
   
function NB_ParseStatusQuery(input) {
    NB_ParseDeviceQuery(input);
    return null;
}
   
/**
 * ChirpStack decoder function.
 */
function Decode(fPort, bytes) {
    // wrap TTN Decoder:
    return Decoder(bytes, fPort);
}
   
/**
 * Lobaro Platform decoder function.
 */
function Parse(input) {
    if (input.i && input.d) {
      // NB-IoT
      var decoded = {};
      decoded = input.d;
      decoded.address = input.i;
      decoded.fCnt = input.n;
      
      var query = input.q || "data";
      
      switch (query) {
        case "config":
          return NB_ParseConfigQuery(input);
        case "device":
          return NB_ParseDeviceQuery(input);     
        case "modbus":
          return NB_ParseModbusQuery(input);
        case "status":
          return NB_ParseStatusQuery(input);
        default:
      }
      return decoded;
    }
    
    
    var data = bytes(atob(input.data));
    var port = input.fPort;
    return Decoder(data, port);
}

...