Convert data from an MQTT buffer to a pre-defined structure in JavaScript

198 Views Asked by At

I have PLC (like a microcontroller) which is publishing data over MQTT.

I am currently receiving the data from the PLC with a script (JS) that subscribes to the same topic that the PLC is publishing to. The data is coming in as a buffer, which is cool, but I’d like to put the data into a structure so that it’s easier to use. Here is my JavaScript:

const mqtt = require('mqtt')

const client  = mqtt.connect('mqtt://127.0.0.1')

client.on('connect', function () {

     client.subscribe('potatoes', function (err) {

          if (!err) {

              client.publish('potatoes', 'If you get this message, you’re subscribed')

          }

     })

})

client.on('message', function (topic, message) {

     console.log(message)

}

The data that the PLC is sending as bytes originates as a structure. The PLC: --first, converts the structure to an array of bytes --second, publishes the array of bytes over MQTT Note: The data that I’m actually sending has multiple structs which contain arrays of structures and so forth, but for simplicity’s sake, let’s assume it’s just sending this:

Struct Member Type Length In Bytes from MQTT
Running Boolean 2
Faulted Boolean 2
InPosition Boolean 2
ActualPosition Long Real (64bit float) 8
TargetPosition Long Real (64bit float) 8
Mode Integer (16bit signed integer) 2
SubMode Unsigned Short Integer (8bits) 2

(Don’t ask me why the Booleans use 16 bits (2-bytes), but they do.)

The question is, how can I put that data into a structure so that it looks the same as the data structure in the PLC. As an example, I’d like to be able to attach the boolean 'myStruct.Faulted' to a red indicator on my web page so that a user can see the status of a motor, for example.

I've managed to make a function that takes in a buffer and returns a struct:

function bufferToStruct(buffer) {
  const struct = {};
  struct.Running = buffer[0] !== 0;
  struct.Faulted = buffer[2] !== 0;
  //and so on for each member
  return struct;
}

but this is quite a tedious process for large, complicated structs. I was hoping that I could have a 'for each' loop to go through each member in the struct and copy the data from the buffer (provided that the function knew the byte size of each member of the struct)

Any ideas?

Note, the ideal may have been to get the PLC to convert the data to JSON and send it over MQTT as JSON so that it comes with the structure at the outset, but unfortunately, the PLC is very limited with what it can do which makes this not particularly easy.

1

There are 1 best solutions below

1
On

Maybe making an data struct to hold the length and looping through it can help with the hardcoding:

const mqttByteLengthArray = [
    { structMember: "Running", length: 2}, 
    { structMember: "Faulted", length: 2},
    { structMember: "InPosition", length: 2},
    { structMember: "ActualPosition", length: 8},
    { structMember: "TargetPosition", length: 8},
    { structMember: "Mode", length: 2},
    { structMember: "SubMode", length: 2}
]

const buffer = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24];

const results = {};

mqttByteLengthArray.reduce((a, c) => {results[c.structMember] = buffer[a]; return (a + c.length)}, 0)

console.log(results);

results will give output of an object based on the structMember and the position of the buffer based on the summation of the past length,

output:

{ 
  Running: 0,
  Faulted: 2,
  InPosition: 4,
  ActualPosition: 6,
  TargetPosition: 14,
  Mode: 22,
  SubMode: 24 
}