Send messages to named output from a custom node

Node-red currently supports sending messages to multiple outputs as an array (node.send([msg1, msg2])). It would be nice to have a way to send message to a particular output without having to keep in mind the order of the outputs. Use case:
I am having a custom node which has variable number of outputs- the number of outputs depend on user configuration. Assume that the outputs are output1, output2, output3. In my implementation I could simply do node.send([{output1:msg1}, {output2:msg2}, {output3:msg3}]) and only the outputs which are on would get the messages.

i think that you can send to only one output, just fill the other outputs with null, example:

node.send([null, msg2])

Your proposed format is already used to send multiple messages out of one port - so changing it would break every existing user. Also surely the order does matter in that the representation in the UI must be in a consistent order (which it may not be if you use an object rather than an array) so that they don’t move around with the user knowing ?

Hi Dave
You are right- my proposal would break existing users.
Would you be able to recommend a good way to solve my problem? Before sending each message, I would really prefer not to have to check which outputs are on and which order they are in.
Thanks

It would be quite a change from the current working practice but I can see why you might want named outputs instead of an output array.

I wonder if it could be an option added to the outputs tab where you could name the outputs and have a new switch to turn the send() output array to into an object?

Just not sure it would be useful enough to warrant the effort that would be required to implement and test it. You don’t normally have that many outputs - I think the most I’ve ever done is about 10 - so it isn’t generally that hard to remember the order, especially if you name them.

At the cost of adding a switch node to your flow, you can identify outputs by name rather than position without doing surgery on the guts of Node-RED. This flow illustrates the idea.

[{"id":"e8605e0f.b70bd8","type":"inject","z":"332979b5.72a646","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":100,"y":160,"wires":[["8ee48481.2b6b38"]]},{"id":"8ee48481.2b6b38","type":"function","z":"332979b5.72a646","name":"your function","func":"var msg1 = {payload:'Message 1',output:'output1'};\nvar msg2 = {payload:'Message 2',output:'output2'};\nvar msg3 = {payload:'Message 3',output:'output3'};\nnode.send([[msg1,msg2,msg3]]);\nreturn\n","outputs":1,"noerr":0,"x":250,"y":160,"wires":[["cc26d85c.8f8768"]]},{"id":"cc26d85c.8f8768","type":"switch","z":"332979b5.72a646","name":"output switch","property":"output","propertyType":"msg","rules":[{"t":"eq","v":"output1","vt":"str"},{"t":"eq","v":"output2","vt":"str"},{"t":"eq","v":"output3","vt":"str"}],"checkall":"true","repair":false,"outputs":3,"x":420,"y":160,"wires":[["a520de39.a33bb8"],["14217aa2.f1de5d"],["37d7eac2.4656fe"]]},{"id":"a520de39.a33bb8","type":"debug","z":"332979b5.72a646","name":"","active":true,"tosidebar":true,"console":false,"tostatus":true,"complete":"payload","x":610,"y":100,"wires":[]},{"id":"14217aa2.f1de5d","type":"debug","z":"332979b5.72a646","name":"","active":true,"tosidebar":true,"console":false,"tostatus":true,"complete":"payload","x":610,"y":160,"wires":[]},{"id":"37d7eac2.4656fe","type":"debug","z":"332979b5.72a646","name":"","active":true,"tosidebar":true,"console":false,"tostatus":true,"complete":"payload","x":610,"y":220,"wires":[]}]

Instead of adding the property msg.output, you could use msg.topic or msg.index and take advantage of mqtt or join nodes elsewhere in the flow. Not as elegant as your proposal, but simple.

1 Like

Hi Julian
Thanks for this. You are right that most custom nodes don’t have too many outputs- in fact the node I am writing has just 5. But its not just the order that is important. I will try to make my use case clearer with a better example:
Possible Outputs: Output1, Output2, Output3
User has turned on Output1 and Output3.
In my my custom node, i have something like:
node.send([{Output2:msg2},{Output3:msg3}])
This should send msg3 to Output3- msg2 is not sent as Output2 is not on.
The advantage is that it makes my code cleaner- I don’t have to check which outputs are on every time I send a message.
Thanks

Hi Michael
Thanks for your suggestion. Unfortunately this wont work for me as the custom node I am writing would be consumed by other people- I would prefer handling it in my code rather than making every user do this.
Thanks

Yes, I certainly get the benefits. My concern is more about compatibility and the amount of effort required to implement this vs. all the other things that are in the pipeline on the journey to v1.

Compatibility could be taken care of I'm sure, maybe with my suggestion above. But the effort is something else - unless someone volunteers to write the code, the test cases and the documentation.

Oh ok- totally get the effort part.
Thanks!

I guess the bit I still don’t get is how the user turns on and off these outputs. If this is logic inside your node then the runtime won’t know about it. If not where is it ? What is the mechanism for the user interaction ?

The way I have handled this sort of issue in the past is by starting my function with

msg1 = null;
msg2 = null;
msg3 = null;

Then the code runs through and sets up whichever messages are appropriate at the time and then at the end I have

return [msg1, msg2, msg3];

so only the messages that have been setup actually get sent.

2 Likes

Structuring msg’s & topics has been (and still is) something that I have difficulties with, and it appears to come up fairly frequently in support requests.
There are a number of examples, particularly in the NR user guide which help, but it would be great if support in this area could be expanded to help users self-help.
Maybe a piece of work from the community? - Mike McRoberts?

Paul

Nice use case. Building up on what our colleagues proposed above I draft a potential solution (not thoroughly tested).

This solution demands that you configure the output ports in the object “exits” and the msg to send on the object “tosend”

let exits    = {output1: "on", output2: "off",output3:"on"};
let tosend   = {output1:"msg1", output2:"msg2", output3:"msg3"};

Flow:


[{"id":"f7439f10.c4a73","type":"inject","z":"3c475e68.8db8e2","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":219,"y":178.00000286102295,"wires":[["7c986c85.69e944"]]},{"id":"7c986c85.69e944","type":"function","z":"3c475e68.8db8e2","name":"your function","func":"let exits    = {output1: \"on\", output2: \"off\",output3:\"on\"};\nlet tosend   = {output1:\"msg1\", output2:\"msg2\", output3:\"msg3\"};\nlet dis = [];\n\nlet dispatchme = Object.entries(exits).forEach(bui);\n\nfunction bui (ele) {\n    let outputx = ele[0]\n    if (ele[1] === \"on\" && outputx in tosend) {\n        dis.push({[outputx] : tosend[outputx]})} else {\n            dis.push(null);\n        }\n        \n    }\n\nnode.send(dis);\n","outputs":3,"noerr":0,"x":389,"y":178,"wires":[["93fc59cd.35e6c8"],["53642af7.477be4"],["30668395.13fa9c"]]},{"id":"30668395.13fa9c","type":"debug","z":"3c475e68.8db8e2","name":"","active":true,"tosidebar":true,"console":false,"tostatus":true,"complete":"true","x":729,"y":238,"wires":[]},{"id":"53642af7.477be4","type":"debug","z":"3c475e68.8db8e2","name":"","active":true,"tosidebar":true,"console":false,"tostatus":true,"complete":"true","x":732,"y":192,"wires":[]},{"id":"93fc59cd.35e6c8","type":"debug","z":"3c475e68.8db8e2","name":"","active":true,"tosidebar":true,"console":false,"tostatus":true,"complete":"true","x":732,"y":148,"wires":[]}]

1 Like

error

object.entries is only in node8 and beyond (well 7 but…)

2 Likes

The user turns on/off outputs in the node configuration- very much like the configuration UI in the function node


The difference from function nodes is that the outputs have names and that you can toggle them on or off