Generic flow to save MQTT payloads to context

Do you use a function node or the core nodes to built a flow to save MQTT payloads to the flow context? I'm thinking of using one MQTT in node with a '#' (multi level) wildcard and using the last branch in the topic tree as the key for the context store (or all the ending branches?).

Can it be done in a simple way without the function node?

Why would you want to do that? Instead connect the mqtt message to wherever you need it.

Because the payload won't necessarily come in when the flow is triggered.

Please post a simple miniflow showing what you mean by that. I have many complex flows and have never had to save an mqtt value in context.

I want to have a flow compare an analog value to a target value +- a deadband value. That deadband value and target value I want to adjust via MQTT.

What node are you using for the comparison? If you use node-red-contrib-thermostat (which I recommend, you don't need to use the ramp feature) then you can feed the analogue value from your process and the target and hysteresis in (with different topics) from MQTT and will all just work. No need for context vars and much simpler.
If you are writing your own function node for the hystersis function then you can write it to expect those values with identifying topics in the same way.

This application is not a thermostat. It's going to be a kid turning 3 knobs, trying to figure out the combination. I want to light an LED for each knob when it's within range of the target (+-deadband) and be able to change the deadband and target values anytime via mqtt.

That is irrelevant if all you needed was a comparator with hysteresis, however it seems that is not what you want, you want to determine which of three ranges the value is.
Personally I would use a Join node in key/value pair mode to combine the value, deadband and target and then a function node to determine the result.

Whether I use one or the other depends on the complexity of the input vs the complexity of the output. It really doesn't matter except that it is often easier to read a single function node that several complex change nodes.

So my general rules of thumb for a function node are:

  • How difficult would this be to do in a pure flow? If it is just a couple of nodes, that's fine, if it is 10 nodes then probably not fine.
  • If I am using JSONata, how long is it taking me to puzzle over the JSONata code? If it is a few minutes then fine, otherwise use a function node!
  • Did someone already write some JavaScript that I can purloin? If so then use it!

Of course, I know JavaScript reasonably well and if you don't then your own rules might look a little different.

I tend to have a couple of MQTT output nodes around. Both connected via Link nodes. One for retained output and one for non-retained. That is simply a convenience.

2 Likes

@m_elias what has all this got to do with the subject "Generic flow to save MQTT payloads to context"?

I was trying to narrow the discussion and avoid explaining in minute detail. I admit I don't consider myself a good programmer, I'm mostly self taught learning what I need as I go but I'm trying to learn how to use the nodes available in node red without always going for the function node. Unfortunately I'm also becoming slower at learning new things.

This is just a small example of a larger scenario where flows are being triggered and doing their thing but I want to change a multitude of parameters at anytime without triggering the actual action flows, they have their own triggers. With Arduinos I use MQTT to change variables that don't trigger any action in itself but wait until their value is needed by the various processes. Is this such a foreign concept in Node-Red? I will have to study the join node to see what it does.

That is often done but often there is no need, why use a context variable when you can just use the value from mqtt when you need it?

Have a look at the cookbook example Joining Streams.

1 Like

Something like this might work for you. The Inject nodes simulate the MQTT inputs
image

[{"id":"8d73428a.b58da","type":"inject","z":"bdd7be38.d3b55","name":"Deadband 2","topic":"topics/deadband","payload":"2","payloadType":"str","repeat":"","crontab":"","once":true,"onceDelay":0.1,"x":153.5,"y":101,"wires":[["369d10e1.a0e09"]]},{"id":"7b816efe.74b4f","type":"inject","z":"bdd7be38.d3b55","name":"Target 50","topic":"topics/target","payload":"50","payloadType":"str","repeat":"","crontab":"","once":true,"onceDelay":0.1,"x":143,"y":154,"wires":[["369d10e1.a0e09"]]},{"id":"152eb7a3.c262a","type":"inject","z":"bdd7be38.d3b55","name":"Value 20","topic":"topics/value","payload":"20","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":153,"y":271,"wires":[["369d10e1.a0e09"]]},{"id":"b924b2e3.6b4958","type":"inject","z":"bdd7be38.d3b55","name":"Value 50","topic":"topics/value","payload":"50","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":156,"y":309,"wires":[["369d10e1.a0e09"]]},{"id":"5af789a0.b6c8f8","type":"inject","z":"bdd7be38.d3b55","name":"Value 60","topic":"topics/value","payload":"60","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":157,"y":345,"wires":[["369d10e1.a0e09"]]},{"id":"369d10e1.a0e09","type":"join","z":"bdd7be38.d3b55","name":"","mode":"custom","build":"object","property":"payload","propertyType":"msg","key":"topic","joiner":"\\n","joinerType":"str","accumulate":true,"timeout":"","count":"3","reduceRight":false,"reduceExp":"","reduceInit":"","reduceInitType":"","reduceFixup":"","x":356,"y":211,"wires":[["690dac8e.d2fa24"]]},{"id":"690dac8e.d2fa24","type":"function","z":"bdd7be38.d3b55","name":"Comparator","func":"if (msg.payload[\"topics/value\"] < msg.payload[\"topics/target\"] - msg.payload[\"topics/deadband\"]/2) {\n    msg.payload = \"below\"\n} else if (msg.payload[\"topics/value\"] > msg.payload[\"topics/target\"] + msg.payload[\"topics/deadband\"]/2) {\n    msg.payload = \"above\"\n} else {\n    msg.payload = \"inside\"\n}\nreturn msg;","outputs":1,"noerr":0,"x":513,"y":211,"wires":[["79b6233c.5b4af4"]]},{"id":"79b6233c.5b4af4","type":"debug","z":"bdd7be38.d3b55","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":541,"y":291,"wires":[]}]
1 Like

Looks like the join node does what I need. Thanks!

I have a different application for a join node, which needs to be duplicated for a dozen identical flows (except one branch of their mqtt topic is unique).
rootTopic/[device1:device2:etc]/cmd/#

Multiple mqtt in nodes -> join node -> function node -> mqtt out node

What's a good way to duplicate them so that if I change one flow, they all change? If I create a sub flow, it would only include the join and function nodes?

I envision I could use one flow if the join node could be setup in a two tier system. What I mean is, can it join 5 payloads from each device separately in the same join node?

If your question is not related to the subject of this thread (saving to context) then it would be better to start a new thread with an appropriate subject line.

Is it possible for me to edit my title to be more accurate to the discussion?

Yes, by using the pen alongside the title, but this thread is marked as solved. Start a new thread for a new question.

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