Recommended way to extend or compose nodes

I want to extend or compose nodes to provide a simple user experience for people using them. There appear to be several ways to do it and I'm looking for advice to help prevent me from choosing the wrong one.

I would like to create nodes that use other nodes and abstract them into a single node. For example, a sensor node would use the MQTT In node to receive data but do some work on the data before passing it along to the output. Another would use the Modbus-Read node and do some work on that data before passing it along to the output.

Ideally these would appear in the workspace as a single node with 1 output and a some properties to configure them. For example there would be a property to specify which topic the MQTT In node should subscribe to. In addition to MQTT In, it would use a Change node to modify the data and a Filter node to only let some messages pass through.

The options I'm aware of are:

  • Subflows: Appears in the editor as a single node but I don't seen a way to add properties or edit the properties in the subnodes of a subflow instance. I can't edit the topic in the MQTT In node and if I edit it the subflow template then it changes for all instances of that subflow.
  • Groups: Very flexible and lets me edit all the properties of the grouped nodes but it appears in the workspace as multiple nodes so it's messy to look at and work with when there are lot of these groups.
  • Custom Node: Appears as a single node and I can create the properties I want but I don't know if there is a way to use other nodes in a custom node. I don't want to implement the MQTT and Modbus protocols myself, I want to use the built-in nodes that already do that.

Of these options, I only know Groups will work. I just don't the way it looks in the workspace because I have to look at all the implementation details of each instance instead of a single, abstract node for each sensor.

Does anyone have a recommendation on which method is best for my application?

You can define groups in some remote area in your flow (or even in a different tab) and then represent each group by a single link-call node.

A subflow can have properties that are configured individually for each instance. The properties can be used as values in nodes in the subflow. See Subflows : Node-RED.

The properties appear as environment variables inside the subflow. See here for how to use env vars.

1 Like

Awesome, thanks! I learned something new about both. I think subflows with environment variables are probably the way to go.

Nice summary of options. We went with subflows as well. It gives us the possibility to have custom fitted versions of nodes. For example we use http node extended with retry options for faulty networks / connections and drop-down list to select access token for remote service. One downside with it is it is hard to distribute among node red instances.

1 Like

It is possible (though I have not tried it for some time) to package a subflow as a node which you can then make available to the node red instances. It is a somewhat manual operation though.

2 Likes

Just take in account that a subflow is actually a 'macro', i.e. if you have 10 instances of a subflow which contains 10 nodes, this sums up to 100 node instances, and this can grow exponentially with nested subflows, and cause load-time & performance issues. Also, there are some limitations in subflow behavior & memory access.
In contrast, a group is like a 'subroutine', instantiated once for all the callers.

Can you expand on that please?

In our case these are security alarm sensors so there are usually at most 20 of them, maybe 50 in extreme cases. I don't think it will use too much memory.

It would be neat if there were a way to create a custom node that contains other nodes though, instantiating and managing them through code instead of the GUI.

1 Like

That is effectively what you get if you package a subflow as a node.

1 Like

Some quick examples (of the top of my head):

  • The subflow maintains private flow and env contexts. For addressing variables from the containing flow, you need to specify $parent before the variable name. In case of nested subflows you have to know your depth level ($parent.$parent... etc.), which becomes messy and impacts the reusability.
  • You cannot jump into a subflow from a link-out or link-call
1 Like

I solved the depth level by declaring the $parent env in all subflows (all the way up to the top flow) :smiley: Works for shared env variables like log file.