How to parameterise MQTTin Topic text

I'm completely new to Node Red but have managed to get a nice UI up and running, it's been fun putting that together.

I'm using the MQTTin / MQTTout nodes for several topics and I am trying to make the topic name configurable, so something like {{payload}}/Device/Status so that the first entry can become the device's hostname for example, ideally set by a simple to use node that the user can fill in.

But so far I've only found that the topic text is taken as a string and not interpreted, hence, is there a way for this to take it from a global variable?

Thanks!

You mean something like this the $$.payload could be replace with a context var also

[{"id":"07fd89d3a89d5cb3","type":"inject","z":"452103ea51141731","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"test/test/test","payload":"","payloadType":"date","x":130,"y":140,"wires":[["95368512da4f5279"]]},{"id":"95368512da4f5279","type":"mqtt out","z":"452103ea51141731","name":"","topic":"","qos":"","retain":"","respTopic":"","contentType":"","userProps":"","correl":"","expiry":"","broker":"e8ba3ef5.22f4a8","x":350,"y":160,"wires":[]},{"id":"f52d1e2878827bdc","type":"inject","z":"452103ea51141731","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"test2/test/test","payload":"","payloadType":"date","x":130,"y":180,"wires":[["95368512da4f5279"]]},{"id":"df567f7c7501d44e","type":"inject","z":"452103ea51141731","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"test","payloadType":"str","x":70,"y":220,"wires":[["ae543ad4c4b9690c"]]},{"id":"709f55f05c659b1e","type":"inject","z":"452103ea51141731","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"test2","payloadType":"str","x":70,"y":280,"wires":[["ae543ad4c4b9690c"]]},{"id":"ae543ad4c4b9690c","type":"change","z":"452103ea51141731","name":"","rules":[{"t":"set","p":"action","pt":"msg","to":"subscribe","tot":"str"},{"t":"set","p":"topic","pt":"msg","to":"$$.payload & \"/test/test\"","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":240,"y":220,"wires":[["74813aa1ea7888c5"]]},{"id":"74813aa1ea7888c5","type":"mqtt in","z":"452103ea51141731","name":"","topic":"","qos":"2","datatype":"json","broker":"e8ba3ef5.22f4a8","nl":false,"rap":true,"rh":0,"inputs":1,"x":410,"y":220,"wires":[["a57e807943da422f"]]},{"id":"a57e807943da422f","type":"debug","z":"452103ea51141731","name":"debug 94","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":660,"y":180,"wires":[]},{"id":"e8ba3ef5.22f4a8","type":"mqtt-broker","name":"testb","broker":"192.168.1.25","port":"1883","clientid":"node-red-test","autoConnect":true,"usetls":false,"compatmode":false,"protocolVersion":"4","keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"0","birthRetain":"false","birthPayload":"","birthMsg":{},"closeTopic":"","closeQos":"0","closePayload":"","closeMsg":{},"willTopic":"","willQos":"0","willPayload":"","willMsg":{},"userProps":"","sessionExpiry":""}]

requires node-red v 2.1+ I believe.

Amazing. Hadn't realised this is what the dynamic option does. Thank you!

What would be the recommended way to have a user set this $$.payload value? I'm hoping it would be a one-time edit somewhere in the flow tab, so it can be shared among several MQTT in/out nodes in the same tab without looking like you're editing code? I found with inject you still have to nudge it manually for it work. Sorry for the newbie question.

You could probably try a subflow, but as i don't fully understand your usage it's a guess

[{"id":"012a21f27496b183","type":"subflow","name":"paramater topic mqtt","info":"","category":"","in":[{"x":40,"y":80,"wires":[{"id":"3eafc95185d6bf84"}]}],"out":[{"x":500,"y":80,"wires":[{"id":"d380135b44b2f19c","port":0}]}],"env":[{"name":"sub_string","type":"str","value":"test","ui":{"type":"input","opts":{"types":["str"]}}}],"meta":{},"color":"#DDAA99"},{"id":"3eafc95185d6bf84","type":"change","z":"012a21f27496b183","name":"","rules":[{"t":"set","p":"action","pt":"msg","to":"subscribe","tot":"str"},{"t":"set","p":"topic","pt":"msg","to":"$env(\"sub_string\") & \"/test/test\"","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":200,"y":80,"wires":[["d380135b44b2f19c"]]},{"id":"d380135b44b2f19c","type":"mqtt in","z":"012a21f27496b183","name":"","topic":"","qos":"2","datatype":"json","broker":"e8ba3ef5.22f4a8","nl":false,"rap":true,"rh":0,"inputs":1,"x":370,"y":80,"wires":[[]]},{"id":"617cb6f309785c01","type":"inject","z":"012a21f27496b183","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":true,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":110,"y":20,"wires":[["3eafc95185d6bf84"]]},{"id":"5fa7aaa8f52552e3","type":"inject","z":"452103ea51141731","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"test/test/test","payload":"","payloadType":"date","x":230,"y":1040,"wires":[["f9a4e5387ed440e6"]]},{"id":"f9a4e5387ed440e6","type":"mqtt out","z":"452103ea51141731","name":"","topic":"","qos":"","retain":"","respTopic":"","contentType":"","userProps":"","correl":"","expiry":"","broker":"e8ba3ef5.22f4a8","x":450,"y":1060,"wires":[]},{"id":"5e4cf4f5280179cc","type":"inject","z":"452103ea51141731","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"test2/test/test","payload":"","payloadType":"date","x":230,"y":1080,"wires":[["f9a4e5387ed440e6"]]},{"id":"240682b39f36608f","type":"subflow:012a21f27496b183","z":"452103ea51141731","name":"","env":[{"name":"sub_string","value":"test2","type":"str"}],"x":453.00000762939453,"y":1119.0000734329224,"wires":[["0dfc13eeaa228c49"]]},{"id":"0dfc13eeaa228c49","type":"debug","z":"452103ea51141731","name":"debug 94","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":753.0000076293945,"y":1079.0000734329224,"wires":[]},{"id":"e8ba3ef5.22f4a8","type":"mqtt-broker","name":"testb","broker":"192.168.1.25","port":"1883","clientid":"node-red-test","autoConnect":true,"usetls":false,"compatmode":false,"protocolVersion":"4","keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"0","birthRetain":"false","birthPayload":"","birthMsg":{},"closeTopic":"","closeQos":"0","closePayload":"","closeMsg":{},"willTopic":"","willQos":"0","willPayload":"","willMsg":{},"userProps":"","sessionExpiry":""}]

The user would then enter the subscription parameter in the subflow config.

[edit] added inject to initialise after deploy.

I got that working on the subscribe side, as I found I could also set the inject to fire once on start-up so I don't have to manually trigger it, and once subscribed, the node continues to receive data. But on the publish side, it looks like you have to send the topic name each time you want to send a payload, and I guess there's no way of putting a global variable or such into the topic label of the MQTTout node.

My goal is to enable other users to configure this flow as simply as possible by setting the hostname to use in the topic string.

Still guessing as you show no examples.

You can feed a topic in to the mqtt out node. So you can save the prefix as a global, then use a function or change node to prefix the topics. I have prefixed them in the inject nodes in this example.
Just set the prefix

[{"id":"6a302d09687e4d68","type":"subflow","name":"set mqtt sub paramater","info":"","category":"","in":[],"out":[{"x":580,"y":20,"wires":[{"id":"d070c746cc388a55","port":0}]}],"env":[{"name":"sub_string","type":"str","value":"please set","ui":{"label":{"en-US":"mqtt prefix"},"type":"input","opts":{"types":["str"]}}}],"meta":{},"color":"#DDAA99","status":{"x":600,"y":100,"wires":[{"id":"d070c746cc388a55","port":1}]}},{"id":"04904b5d1eed1e6d","type":"inject","z":"6a302d09687e4d68","name":"","props":[{"p":"payload"}],"repeat":"","crontab":"","once":true,"onceDelay":"0.1","topic":"","payload":"","payloadType":"date","x":170,"y":20,"wires":[["d070c746cc388a55"]]},{"id":"d070c746cc388a55","type":"function","z":"6a302d09687e4d68","name":"function 11","func":"let param = env.get(\"sub_string\") || \"please set\";\nmsg = [{topic: param},{status:{text: param}}];\nglobal.set(\"mqtt_prefix\", param)\nreturn msg;","outputs":2,"noerr":0,"initialize":"","finalize":"","libs":[],"x":370,"y":40,"wires":[[],[]]},{"id":"01cd665373cb4cef","type":"subflow","name":"Subflow 1","info":"","category":"","in":[{"x":40,"y":80,"wires":[{"id":"fefb4c0d6c852023"}]}],"out":[{"x":340,"y":80,"wires":[{"id":"fefb4c0d6c852023","port":0}]}],"env":[{"name":"topic","type":"str","value":"/test/test","ui":{"label":{"en-US":"Enter Topic"},"type":"input","opts":{"types":["str"]}}}],"meta":{},"color":"#DDAA99","status":{"x":340,"y":160,"wires":[{"id":"fefb4c0d6c852023","port":1}]}},{"id":"fefb4c0d6c852023","type":"function","z":"01cd665373cb4cef","name":"function 12","func":"const topic = env.get(\"topic\") || \"/test/test\";\nconst mqtt_sub = context.get(\"topic\");\nconst new_mqtt_sub = msg.topic;\nmsg.topic = mqtt_sub + topic;\nmsg.action = \"unsubscribe\";\nnode.send(msg)\nmsg.topic = new_mqtt_sub + topic;\ncontext.set(\"topic\", new_mqtt_sub);\nmsg.action = \"subscribe\";\nreturn [msg,{status: {text: msg.topic}}];","outputs":2,"noerr":0,"initialize":"","finalize":"","libs":[],"x":190,"y":80,"wires":[[],[]]},{"id":"618f6119970f3c65","type":"link in","z":"452103ea51141731","name":"link in 1","links":["5f71c25083234615"],"x":225,"y":1140,"wires":[["584f086f99bb4386"]]},{"id":"584f086f99bb4386","type":"subflow:01cd665373cb4cef","z":"452103ea51141731","name":"/test/test","x":340,"y":1140,"wires":[["8c4b454db7df7149"]]},{"id":"8c4b454db7df7149","type":"mqtt in","z":"452103ea51141731","name":"","topic":"","qos":"2","datatype":"auto-detect","broker":"e8ba3ef5.22f4a8","nl":false,"rap":true,"rh":0,"inputs":1,"x":490,"y":1140,"wires":[["0dfc13eeaa228c49"]]},{"id":"0dfc13eeaa228c49","type":"debug","z":"452103ea51141731","name":"debug 94","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":720,"y":1140,"wires":[]},{"id":"e36c75a1b2dfc890","type":"link in","z":"452103ea51141731","name":"link in 2","links":["5f71c25083234615"],"x":235,"y":1200,"wires":[["ed37061f517a0348"]]},{"id":"ed37061f517a0348","type":"subflow:01cd665373cb4cef","z":"452103ea51141731","name":"/test/test1","env":[{"name":"topic","value":"/test/test1","type":"str"}],"x":350,"y":1200,"wires":[["d34256616ff69f7c"]]},{"id":"d34256616ff69f7c","type":"mqtt in","z":"452103ea51141731","name":"","topic":"","qos":"2","datatype":"auto-detect","broker":"e8ba3ef5.22f4a8","nl":false,"rap":true,"rh":0,"inputs":1,"x":490,"y":1200,"wires":[["a3f09deb8fdd24db"]]},{"id":"a3f09deb8fdd24db","type":"debug","z":"452103ea51141731","name":"debug 95","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":740,"y":1200,"wires":[]},{"id":"964d78d4fdf8fbe4","type":"subflow:6a302d09687e4d68","z":"452103ea51141731","name":"Enter prefix","env":[{"name":"sub_string","value":"test2","type":"str"}],"x":210,"y":1080,"wires":[["5f71c25083234615"]]},{"id":"5f71c25083234615","type":"link out","z":"452103ea51141731","name":"link out 1","mode":"link","links":["e36c75a1b2dfc890","618f6119970f3c65"],"x":395,"y":1080,"wires":[]},{"id":"5fa7aaa8f52552e3","type":"inject","z":"452103ea51141731","name":"test/test","props":[{"p":"payload"},{"p":"topic","v":"$globalContext(\"mqtt_prefix\") & \"/test/test\"","vt":"jsonata"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":300,"y":1300,"wires":[["f9a4e5387ed440e6"]]},{"id":"81b4ddae6445d6fa","type":"inject","z":"452103ea51141731","name":"test/test1","props":[{"p":"payload"},{"p":"topic","v":"$globalContext(\"mqtt_prefix\") & \"/test/test1\"","vt":"jsonata"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":300,"y":1360,"wires":[["f9a4e5387ed440e6"]]},{"id":"f9a4e5387ed440e6","type":"mqtt out","z":"452103ea51141731","name":"","topic":"","qos":"","retain":"","respTopic":"","contentType":"","userProps":"","correl":"","expiry":"","broker":"e8ba3ef5.22f4a8","x":690,"y":1340,"wires":[]},{"id":"e8ba3ef5.22f4a8","type":"mqtt-broker","name":"testb","broker":"192.168.1.25","port":"1883","clientid":"node-red-test","autoConnect":true,"usetls":false,"compatmode":false,"protocolVersion":"4","keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"0","birthRetain":"false","birthPayload":"","birthMsg":{},"closeTopic":"","closeQos":"0","closePayload":"","closeMsg":{},"willTopic":"","willQos":"0","willPayload":"","willMsg":{},"userProps":"","sessionExpiry":""}]

[edit] added status messages to subflows.

Thank you so much for your help, I got it working! Below is what I did:

[{"id":"d592b0e207eb67bb","type":"inject","z":"85a351b7396c63e7","name":"Hostname","props":[{"p":"payload"}],"repeat":"","crontab":"","once":true,"onceDelay":0.1,"topic":"","payload":"raspberrypi0w","payloadType":"str","x":490,"y":460,"wires":[["94098272486a3a8d","5ce6e303daa16c23","0b075e1af2ca2bc4","fde9d2e379c5c901"]]}]

(I just learnt I have to select 'compact' mode to export the JSON onto 1 line, didn't dare post it otherwise :slight_smile: - I hope I pasted it correctly )

So, I now have an inject node that the user would modify before use to set their device host name, and then with your example method I create the 2 subscribe topics (e.g. hostname/RedReactor/Service') but also set a global hostname variable that is picked up by the output configuration node so that multiple sliders can simply publish their command, merged onto 1 output node.

Happy to know if there's a better way! (for example, I'll need to see what happens if you have multiple devices, can you have each with their own UI tab, but would the global hostname variable create a conflict?)

As a final update, I found that to be able to run multiple instances of this flow I had to move the global variables into flow variables, and have completed my first release of the Red Reactor battery monitoring dashboard, see picture here https://www.theredreactor.com/wp-content/uploads/2022/10/RR_NodeRED-UI-Screenshot.jpg

Thanks for pointing me in the right direction. I love Node-RED!

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