0

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.

  • If the data was IEC-61131 PLC structure, you could use the following library in Node.js to convert between data: https://www.npmjs.com/package/iec-61131-3 However as the boolean seems to be 2 bytes instead of standard one this won't work as-is. So basically I'm just adding this comment as a future reference if it helps someone. – Quirzo Jan 26 '23 at 06:45

1 Answers1

0

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 
}
LuxuryWaffles
  • 1,518
  • 4
  • 27
  • 50
  • If the actual data set is a single MQTT topic containing multiple structures and arrays etc. etc. etc., your PLC will need to publish a huge chunk of data for just one tweak to a Boolean. The power of MQTT is its RBE (Report By Exception) capabilities. But if it's basically a huge structure that contains various pieces that are constantly changing, represented as a single MQTT topic, you gain no leverage of RBE capabilities, on the Publisher and especially on the Subscriber(s) side. – franji1 Jan 23 '23 at 22:12