Updating the UI widgets on an alternative way?

Is there an alternative way to update the UI widgets?
I read values from multiple sensors, and use a switch node to route the msgs to the corresponding UI element.
It looks cool but feels bad.

1 Like

Depends on how you're doing it. I'm assuming you're using a function? If so, you can eliminate the switch node by setting up your function with the outputs instead. In all cases though (outside of custom coding/scripting pages), this is how Node-Red is setup to work so it's going to look like a giant ladder.

If you're using a function, go into your function to the setup tab. Set it for the number of outputs you have on your switch node. Then in your function code, instead of just returning message, return an array. Looks like this:

return([...]);

The position in the array corresponds with the output connection on your function. There's two ways of doing this. The first way allows you to update a single output. Suppose I only needed to modify output 3 with the msg.payload. It would look like this:

return([null,null,msg,null,null...]);

The null's keep that output from updating anything so those widgets are left alone. The second way is to have a single return with multiple messages, say if you're processing all your sensor readings at the same time:

return([msg1,msg2,msg3,msg4...]);

It will look just as clunky as your switch block, but it eliminates the switch block and makes it so your code can route the message instead of adjusting the block every time.

Good luck.

1 Like

Thank you for your answer!
Looks like then i will stay with the switch node, maybe use multiple of it.

I'm stuck at this point.

If you have multiple sensors, why not connect them to the GUI they control directly?

Ok, you may be using MQTT but.....

Things are always a trade off how you get things done.

Suggestion - if the above is true:
Have multiple MQTT IN nodes rather than one and the switch.
More nodes, but easier to see what is happening.

You may need to show more of what is happening upstream where the message come in your flow also.

1 Like

I like this answer too. It's easy to pair MQTT with sensors
IF
the MQTT nodes output the data in the way that the GUI nodes understand. Some sensors use simple registers and need some preprocessing to become human readable, which can be done in the MQTT environment but is not guaranteed to occur. A layout like this would make it much easier to track pairings and whatnot in the flow, but the data needs to be pre-processed in transit so it can be routed directly to the GUI components and displayed.

The second thing to take into account is there are a lot of pairings taking place. Most systems shouldn't feel the overhead of constant data retrieval. But would the components of this system make it possible for constant queries? Or is it better for a single query and response? For instance, you can retrieve multiple PIDs using the OBD2 protocol on your car. If you send a single query, you can get a single response. This can cover all the PIDs you can possibly check. But there is a ton of traffic overhead and your refresh rate can suffer drastically. Or, you can group all the queries into one, suffer a long transmit and retrieval and pull all your data at once where it can be processed locally while retrieving the next refresh. The traffic overhead decreases significantly and your refresh rate actually goes up, even though you're pulling a ton of data. It also synchronizes the data in a snapshot vs. being out of sync, which may be a factor as well.

Not knowing the setup, individual MQTT nodes would organize everything significantly better and make it possible to have copy/paste simplicity for new sensor groups as they're added. But without knowing the specifics of the setup, one may have to account for the worst before implementing a change like that.

(Not exactly directed at you, but to clarify something)

If that is true then you SHOULD (imo) have an MQTT node per display node, and between them you have a node that specifically does what is needed to make the data GUI node understandable.

Having a generic MQTT IN node and it handles ALL messages and then passes all the messages to some node that handles all the different types of messages and formats them into GUI READABLE messages and spits them out and then you go into a SWITCH node is making something easy more complicated.

If/when you have a new sensor that gives another style of formatted message you have to go in and make the node able to deal with that, and then add another condition to the switch node.

Rather you have individual MQTT IN nodes connected to a function node (for example) that processes THAT message and then is connected to the GUI node: adding another sensor is easy.

All you do is put another MQTT IN node, another function node and connect it to the GUI node.

Yes: It takes up a bit more screen real estate but it can easily be put into a block (square/rectangular) area and it is neat.

Yes, exactly what I was meaning. Having it split out like that would be ideal and should be the method employed when doing a lot of repetitive structures. And it kinda looks pretty, like a big, multi-cylinder engine where everything is purring in tune.

My only qualm was the communications overhead. If the system can handle the queries (like most should be able to), it should be just like you described. If not, adjustments may need to be made, but that's a rare case which I only bring up because I've run into it.

But yes, total agreement with what you said otherwise.

If the Mqtt nodes all use the same config ( which they should if talking to the same broker) then there is no/minuscule difference between having one Mqtt node and a big switch (as you have) or multiple Mqtt in nodes. As they all share the same connection it’s more down to which you find easiest to understand in 6 months when you come back to “fix”/update it.

Oh I hate doing that long time from now code review. I always fail it...

I always find some new way of doing stuff in the mean time and come back to the original trying to figure out how it works. And sometimes I can't...

I surprise myself sometimes... :laughing:

But from where I am seeing things:

We don't know what is happening between the sensor (and it's output) and the switch node.

This has never been resolved on how it is done. (Or why)

Agreed: If there is little work done between the input and the GUI, fair enough.

Thank you all the answers.

Looks like i'am currently heading to the other direction. Previously i had this repeating structure for each sensor i had. But it's grow too large for my taste and decided to change the whole process to a loop.

Here is the brief summary of the process:
Reading flow:

  • the data is received by a Modbus-Flex-Sequencer node every minute (it gets the sensors data (unitid, address...) from a database on startup or when i press a button).
  • every reading is passed to a function node through a switch node for a little data manipulation (divide by 10 or 100, and some other expressions)
  • after that the value is saved to a global variable like { id: ... , value: ...}
  • after the last sensor is read the next flow is "activated"

UI_update flow:

  • in this flow i loop through the global variables which contain the last measured values, and save them to a Database, update an SVG node, and update the widgets.


No problems.

But what you are showing me just now is very different to what I understood you were doing.

All the best.

Interesting layout. I can understand somewhat of what you're doing, though there are a couple of nodes that I'm not familiar with, though none of them really affect what you're asking. There's not a lot you can do to optimize your nodes, as it's already somewhat simplified. But only somewhat.

I'm curious what's going on in your four output function controlling everything. Is there a necessity for that to be in the middle of it all? Is it performing some kind of pre-calculation or routing setup that your other nodes need?

If I were to reorganize the layout, I would have link-in/link-out nodes heavily in use. I would have a link-out node attached to your MODBUS sequencer that links to individual functions attached to associated gauge sets. Regardless of how you're getting info from MODBUS (one big pull or several small individual), you can setup the functions between the link-ins and your gauges to pull out the register information it needs. That way the gauges only get what they need. It also makes it scalable since you can easily add more registers in your MODBUS query and add in the functions and gauges to display the data. That should clean up your gauge set to several ladder rungs and it should trim out your four block function as well.

Two other things. What is your enumeration loop doing? And why do you have two inputs to the SVG graphics node? If anything, I would have the SVG tied to one function node so you didn't have multiple inputs fighting over control. Pass in any relevant data to a gate-keeper function and allow it to make the changes necessary based on what comes in.

Yeah, some stuff is just being picky, but there's a fair bit of efficiency you could gain just in control and simplicity. If I'm off about my guesses, let me know and I can adjust. But that's my impressions from what you've shown.

Thank you for your answer, this is my first ever project in Node-red and good to have some feedback on it.

Well as you asked i realized that i should cut it into 4 pieces. It is mostly just formatting my data, the measured values are stored in a global variable as key:value pairs, the enumeration node loops through that variable.
In the function node the first msg is send back to the enumeration node without modification (it needed to continue the looping i guess).
The second msg is formatted for the SVG picture to update the corresponding text on it.
The third msg is an SQL string which saves the measured value in the database.
And the forth msg is just the key and the value headed to my enormous Switch node showed in my original post.

It is because i update the SVG file with values from the database, right away as someone open the UI page. If i don't do that the SVG picture doesn't shows any values until a new measurement (which is triggered minutely).

1 Like

Now I log on here today and I get the other screenshot you put in your post (it didn't show up yesterday). I see a lot that could be cleaned up and simplified in your stuff and it would make your project so much simpler.

Here is a similar flow I created a while ago doing a similar thing to what you're doing. On the left are all my triggers for the various registers I'm trying to read over MODBUS. These are simple inject nodes that trigger the message periodically for the MODBUS node. The nice thing about doing it this way is you can set the timing, the MODBUS query AND the topic all in the same node. The benefit to doing it this way is you can easily pick each query back out again on the other end to parse and split however you want since you can separate messages by topic (i.e. sensor, location, etc.). No need to try and split up the message by whatever deliminator you're choosing. I'm not sure why the connection to a database to get your register list, as you would already have each register accounted for due to the displays you've setup. So the list of registers is preset already. Why not eliminate the excess database queries and just set the MODBUS queries in hard code?

Next on my list is the actual MODBUS Flex-getter node (name blocked out for company purposes). This does the heavy MODBUS lifting, as you already know. The data comes out of that with:

  1. The original query
  2. The result
  3. The topic
  4. Any other pertinent information from the MODBUS node.

This can all be parsed by my function node next to it based on topic. If topic, then do certain action and return result on channel X (looks like return([null,null,msg,null]) or something like that). Each action in the function manipulates the data so it can be displayed in the connected displays. I can even add a function after the function (for simplicity in job description) that will manage a single display doing a specialized task like tracking an average over a period of time displayed on a previous graph.

There's no need to send a list of registers in a single query to the MODBUS Flex-getter node as it will process individual messages in the order received. So you can send a mess and it will process them in order. That could eliminate everything prior to your initial MODBUS node. Also, if you want a manual refresh, use a UI button on your page with your displays. No need to have your editor window open just to get an update.

Second, if you separate out all your messages by topic, you can eliminate your switch function, your preprocess functions, your save-to-global function (why are you using a global?) and your isLast. That whole block would become individual functions tied to the displays. Each function responds ONLY to the topic meant for it (if certain topic, then do this thing), though all functions get all messages. Use a link-out on your MODBUS node and a link-in on each function for cleanliness. If you want to store all the values in a database, add another link-in to a function that either stores the register values directly or pre-processes all of them and then stores them.

Other things you may want to look at, look up and learn context.get() and context.set(), especially on your startup tab in your function. These can be very handy to use in functions as they make variables persistent so you can reference old data much more easily. That may eliminate your need for globals or database queries to get past data or lists. It may also eliminate your need for an enumeration loop as your function(s) will now be able to hold variables while running and give you something to reference to be able to immediately pull information for your SVG node (i.e. your new and only SVG controlling function holds past data and replaces it with new data whenever it comes in, making quick reference to old data possible as well as reacting to new data when available). You'll find the more you condense and simplify your functions, the less you'll need outside of them. Persistence is one thing Node-Red doesn't do easily without a few nodes, but can be done very simply in JavaScript using context.get() and context.set().

If you're not actually recording data for data-retention purposes (i.e. looking at what stuff was like 45 days ago), you may find that you eliminate the need for your database and several other nodes all at once while simplifying your code immensely.

Oh yeah, I should say these are all suggestions and not me telling you what to do with your stuff. Take or leave what you will. But, hopefully something helps!

Thank you for your detailed answer, it was very useful for me to see how someone else would solve a similar problem. I will consider many of your suggestions.

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.