So on reading further, I see you have a solution you are happy with - good.
If you dont mind, I will pick up a few points (in no particular order)...
I'm glad I was of some help.
Regarding this fixation on leaving source data format untouched etc, IMO, is completely moot.
Whatever comes out of the PLC/Modbus nodes IS what it is.
i.e. if its wrong for you, change it immediately after source to the format you need. So cloning / duplicating a potentially large chunk of data is pointless. Just do the necessary swap
and then consume the data as you please.
I too use PLCS on an almost daily business - of late, consuming data is one of my main jobs.
As for the "every HMI just works" comment - imagine you were developing a HMI in node-red (which BTW is perfectly achievable - see my demo in the UI-SVG node that i co-authored or search this forum for "HMI") you too would swap the incoming data if it were necessary.
To try and clarify, a HMI only "just works" because the HMI manufacturer swapped the data as required - same as you would/should.
I too have faced these things on a daily basis.
Its obvious from your considerations you are a seasoned PLC/HMI programmer. And while that will come in useful in node/node-red world, it can get in the way.
When it comes to collecting data from a PLC there are tons of considerations
- Is the data related to each other - if so, try poll it all in one block for consistency
- Is the related data points to collect bigger than the maximum poll block size of the driver?
- if yes, you need to synchronise using handshaking / flags otherwise the poll blocks will be returned with a difference of COMM TIME + PLC SCAN TIME (i.e. potentially out of step / inconsistent)
- Is the amount of data being collected (related or unrelated) littered all over the PLC?
- consider gathering it all up into a single poll-able area to minimise COMMS + ensure data sample consistency.
- etc
- etc
Lets say for arguments sake, you need to sample 1000 related values from the PLC for database logging. Now the PLC driver can only poll 200 16 bit values in one COMM poll & it takes 15ms for a complete poll cycle & the PLCs SCAN time is 5ms.
You either decide to make 5 COMM polls or the driver takes care of it under the hood. The driver wont care about consistency & will get the 5 samples required to make up 1000 values.
So you have a few choices but its likely you will move the 1000 values into a static/controlled Data area in the PLC and use a set of flags to prevent the 1000 WDs being changed until the COMM driver has done its 5 200WD polls.
Unless you are talking HUGE amounts of data and extensive post-processing, you are not gonna feel this.
Yes, nodejs is single threaded but its event loop is pretty fast.
And lets be honest, you probably arent going to poll the whole PLC data memory banks. And even if you did need to process (lets say) 65535 items - running that through a function, converting to various value formats, might be faster than you imagine - example.
BUT - there is no need to pre-process all values in an instant, every poll. I would take the values, swap if necessary (one or two buffer function calls) then only consume/convert the values needed at that particular time. This is of course far easier to state than implement
Penultimate observation / comment (my opinions - take them or leave them)...
Putting all your converted data into a single object is a bit like the "PLC way" (a memory bank) - but not ideally suited to modern parts of this evolving industry like IIoT / MQTT.
Would you be up for a challenge?
- If you dont have one, setup an MQTT broker. (mosquito is fine)
- Download MQTT explorer & get it connected to your broker
- Get your PLC and node-red talking - get an amount of data (say 1000 WDs)
- Do the buffer swap / convert each item you need converted to its desired int/in32/float format (hard coded for now is fine)
- compare the converted value to a memory store (hint use context for memory
flow.get("myLookupObject");
) - if value has changed,
- update the local memory (hint:
myLookupObject[itemName] = itemValue; flow.set("myLookupObject", myLookupObject);
node.send
a new object with a.topic
and.payload
- update the local memory (hint:
- compare the converted value to a memory store (hint use context for memory
- attach the output of this function to an MQTT out node.
What you should see - initially lots of activity as the PLC values are first read and converted to MQTT messages - then it goes quiet as no PLC data is changing. As data in the PLC changes, the MQTT Explorer picks up changes.
From here (once your data is converted from a contiguous lump of data into modern TOPIC/VALUE items in MQTT - your future opportunities suddenly expand. Want an MQTT based HMI on your smartphone - easy. Want to send Emails / Telegrams? easy.
Last words...
So, I am going to leave this here - I hope you can see while I may not have fully explained early examples I did take into consideration more than one might realise?
Happy learning.