Extending existing parser

Hi,

Is it possible to extend a parser that is already implemented in one of the connectors?
One of our sensors is nearly identical to one of the existing, available in the connectors list. However, there’s a small difference in the amount of data being transmissed - the new one sends several values instead of only one.
It would be really helpful to just modify the existing parser instead of implementing everything from the scratch.

Hi @fssolution,

What device’s connector in specific are you looking for? I need to check if the connector is public, if so I can send you.

Hi @guilhermeco,

It’s Axioma Water Meter Qalcosonic W1

Hi @fssolution,

The connector is public, I will be sending you the code below:

/* This is an generic payload parser example.
** The code find the payload variable and parse it if exists.
**
** IMPORTANT: In most case, you will only need to edit the parsePayload function.
**
** Testing:
** You can do manual tests to this parse by using the Device Emulatitudeor. Copy and Paste the following code:
** [{ variable: 'payload', value: '5d35a00e30293500005D34B630e7290000b800b900b800b800b800b900b800b800b800b800b800b800b900b900b9009' }, { variable: 'port', value: 100 }];
**
** The ignore_vars variable in this code should be used to ignore variables
** from the device that you don't want.
*/
// Add ignorable variables in this array.
const ignore_vars = [];
/**
 * This is the main function to parse the payload. Everything else doesn't require your attention.
 * @param {String} payload_raw
 * @returns {Object} containing key and value to TagoIO
 */

function statusMsg(status) {
  let msg;
  switch (status) {
    case 8:
      msg = 'Erro permanente'
      break;
    case 16:
      msg = 'Erro temporário'
      break;
    case 32:
      msg = 'Vazamento'
      break;
    case 160:
      msg = 'Queimado'
      break;
    case 96:
      msg = 'Fluxo negativo'
      break;
    case 128:
      msg = 'Congelado'
      break;
    default:
      msg = 'Bateria Fraca'
      break;
  }
  return msg;
}

function parsePayload(payload_raw, port) {
  try {
    const bytes = Buffer.from(payload_raw, 'hex');

    const data = [];

    if (port === 100) {
      const time = new Date(bytes.readUInt32LE(0) * 1000);
      const status_code = parseInt(payload_raw.substr(8, 2), 16);

      data.push({ variable: 'status_code', value: status_code, time, metadata: { msg: statusMsg(status_code) } });

      const current_volume = bytes.readUInt32LE(5) * 0.001;
      data.push({ variable: 'volume', value: current_volume, unit: 'm3', time });

      const volume_at_log_datetime = new Date(bytes.readUInt32LE(9) * 1000);

      let volume_history;
      /* const log_volume_delta_1 = bytes.readUInt16LE(13) * 0.001;
      data.push({ variable: 'volume', value: log_volume_delta_1, unit: 'm3', time: moment(volume_at_log_datetime).add(1, 'hour').toDate() });
      volume_history = log_volume_delta_1;

      const log_volume_delta_2 = bytes.readUInt16LE(19) * 0.001;
      volume_history = volume_history + log_volume_delta_2;
      data.push({ variable: 'volume', value: Number((volume_history).toFixed(3)), unit: 'm3', time: moment(volume_at_log_datetime).add(2, 'hours').toDate() });

      const log_volume_delta_3 = bytes.readUInt16LE(21) * 0.001;
      volume_history = volume_history + log_volume_delta_3;
      data.push({ variable: 'volume', value: Number((volume_history).toFixed(3)), unit: 'm3', time: moment(volume_at_log_datetime).add(3, 'hours').toDate() });

      const log_volume_delta_4 = bytes.readUInt16LE(23) * 0.001;
      volume_history = volume_history + log_volume_delta_4;
      data.push({ variable: 'volume', value: Number((volume_history).toFixed(3)) , unit: 'm3', time: moment(volume_at_log_datetime).add(4, 'hours').toDate() });


      const log_volume_delta_5 = bytes.readUInt16LE(25) * 0.001;
      volume_history = volume_history + log_volume_delta_5;
      data.push({ variable: 'volume', value: Number((volume_history).toFixed(3)), unit: 'm3', time: moment(volume_at_log_datetime).add(5, 'hours').toDate() });

      const log_volume_delta_6 = bytes.readUInt16LE(27) * 0.001;
      volume_history = volume_history + log_volume_delta_6;
      data.push({ variable: 'volume', value: Number((volume_history).toFixed(3)), unit: 'm3', time: moment(volume_at_log_datetime).add(6, 'hours').toDate() });

      const log_volume_delta_7 = bytes.readUInt16LE(29) * 0.001;
      volume_history = volume_history + log_volume_delta_7;
      data.push({ variable: 'volume', value: Number((volume_history).toFixed(3)), unit: 'm3', time: moment(volume_at_log_datetime).add(7, 'hours').toDate() });

      const log_volume_delta_8 = bytes.readUInt16LE(31) * 0.001;
      volume_history = volume_history + log_volume_delta_8;
      data.push({ variable: 'volume', value: Number((volume_history).toFixed(3)), unit: 'm3', time: moment(volume_at_log_datetime).add(8, 'hours').toDate() });

      const log_volume_delta_9 = bytes.readUInt16LE(33) * 0.001;
      volume_history = volume_history + log_volume_delta_9;
      data.push({ variable: 'volume', value: Number((volume_history).toFixed(3)), unit: 'm3', time: moment(volume_at_log_datetime).add(9, 'hours').toDate() });

      const log_volume_delta_10 = bytes.readUInt16LE(35) * 0.001;
      volume_history = volume_history + log_volume_delta_10;
      data.push({ variable: 'volume', value: Number((volume_history).toFixed(3)), unit: 'm3', time: moment(volume_at_log_datetime).add(10, 'hours').toDate() });

      const log_volume_delta_11 = bytes.readUInt16LE(37) * 0.001;
      volume_history = volume_history + log_volume_delta_11;
      data.push({ variable: 'volume', value: Number((volume_history).toFixed(3)), unit: 'm3', time: moment(volume_at_log_datetime).add(11, 'hours').toDate() });

      const log_volume_delta_12 = bytes.readUInt16LE(39) * 0.001;
      volume_history = volume_history + log_volume_delta_12;
      data.push({ variable: 'volume', value: Number((volume_history).toFixed(3)), unit: 'm3', time: moment(volume_at_log_datetime).add(12, 'hours').toDate() });

      const log_volume_delta_13 = bytes.readUInt16LE(41) * 0.001;
      volume_history = volume_history + log_volume_delta_13;
      data.push({ variable: 'volume', value: Number((volume_history).toFixed(3)), unit: 'm3', time: moment(volume_at_log_datetime).add(13, 'hours').toDate() });

      const log_volume_delta_14 = bytes.readUInt16LE(43) * 0.001;
      volume_history = volume_history + log_volume_delta_14;
      data.push({ variable: 'volume', value: Number((volume_history).toFixed(3)), unit: 'm3', time: moment(volume_at_log_datetime).add(14, 'hours').toDate() });

      const log_volume_delta_15 = bytes.readUInt16LE(45) * 0.001;
      volume_history = volume_history + log_volume_delta_15;
      data.push({ variable: 'volume', value: Number((volume_history).toFixed(3)), unit: 'm3', time: moment(volume_at_log_datetime).add(15, 'hours').toDate() }); */

      return data;
    }

    if (port === 103) {
      const time = new Date(bytes.readUInt32LE(0) * 1000);
      const status_code = parseInt(payload_raw.substr(8, 2), 16);
      data.push({ variable: 'status_code', value: status_code, time, metadata: { msg: statusMsg(status_code) } });
    }
    return data;
  } catch (e) {
    return [{ variable: 'parse_error', value: e.message }];
  }
}

// let payload = [{ variable: 'payload', value: '297dcb6010ff120000909eca60ff120000000000000000000000000000000000000000000000000000000000000000' }, { variable: 'port', value: 103 }];
// Remove unwanted variables.

// Payload is an environment variable. Is where what is being inserted to your device comes in.
// Payload always is an array of objects. [ { variable, value...}, {variable, value...} ...]
const payload_raw = payload.find(x => x.variable === 'payload_raw' || x.variable === 'payload' || x.variable === 'data');
const port = payload.find(x => x.variable === 'port' || x.variable === 'fport');

if (payload_raw && port) {
  // Get a unique serie for the incoming data.
  const { value, time } = payload_raw;
  let { serie } = payload_raw;
  serie = new Date().getTime();

  // Parse the payload_raw to JSON format (it comes in a String format)
  if (value) {
    payload = payload.concat(parsePayload(value.replace(/ /g, ''), Number(port.value))).map(x => ({ ...x, serie }));
  }
  const vars_to_keep = ['hardware_status', 'port', 'payload', 'time', 'encrypted_payload', 'gateway', 'volume', 'gps_location', 'parse_error', 'gps_alt', 'freq', 'status_code'];
  payload = payload.filter(x => vars_to_keep.includes(x.variable));
  if (Number(port.value) === 0 || Number(port.value) === 101) {
    payload = [];
  }
}

// console.log(payload);

-Guilherme

1 Like

Thank you very much @guilhermeco!