Hidden configuration node keep track of values in associated child nodes

Hi all,
For a node I am modifying I have one or more hidden configuration nodes (let's call these parent nodes A,B,C...). To start, assume there are no parent nodes configured yet. A child node (child node 1) is dragged from the palette onto the editor panel and as part of it's configuration it needs to configure a parent node, which then opens the parent node's configuration panel, where various options are selected as needed. Clicking 'Done' creates parent node A, with which child node 1 is now associated and after selecting various child node options clicking 'Done' then completes the process. We now have child node A1 associated with parent node A (all very similar to say the serial node or mqtt node).

Dragging another child node from the palette onto the editor (child node 2) and opening its configuration shows parent node A, which can be selected, or another parent node can be created. For simplicity's sake, we'll assume child node 2 also uses parent node A. We can keep doing this and create a set of say child nodes A1-A8 all associated with parent node A. So far, nothing new under the sun and in my case this all works.

However, depending on the type of parent node created, up to 8 or 16 child nodes can be associated with it. Each of parent node A's child nodes must have one of it's parameters (say X) be unique from the other child nodes. So X of child A1, must be different from X of child A2, etc. No two child nodes A1-A8 can have the same value for X

X is selected from a drop-down of values ranging from 0 thru 7. What I would like to achieve is keeping track of the already selected values for X in previous child nodes and disabling those values when a new child node is created. I already know how to disable options in a selection list, so that is not the issue. What is the issue is how to keep track of previously selected X-values, preferably without reverting to the runtime, so that a bunch of child nodes can be created without clicking deploy. I don't actually need to know which child node has a selected X-value, just that an X-value can no longer be selected.

I'm thinking that parent node A could have a hidden attribute, where it keeps an array of previously selected values. When a new child is created and associated with A, it could use that array to disable selection of already selected X-values. But how does parent A get the X-value selected in child A1, and subsequently, how does child A2 get the array of X-values from parent A?

Thanks
Joe

Hi Joe,
to solve this challenge, I'd put the child node & the parent node in one module & declare a module scoped object to keep track of the subscriptions. Each child and each parent will be able to have access to this bookkeeping object & act on it. As a hint: The RPI-GPIO nodes do something similar to ensure that a dedicated PIN is only used once...

Greetings, Ralph

@ralphwetzel ,
thanks for the quick come-back. I took a quick look at the pi-gpio code and your suggestion might just work. Parent and child nodes are already in one module. I'll have to spend some time going through the gpio code carefully, to figure out exactly what it does and how it works, which might take me a little while to see if that it will indeed work in my setup.

Thanks for the hint. If it does it work, I'll circle back to you,
Joe

@ralphwetzel , your hint was very apt. In my case I am creating a custom node to use a family of i2c port expander chips, so pin numbers and pinsInUse, etc made a lot of sense.

However, unlike the GPIO nodes, I do not need to get information from the RPi regarding used nodes, etc. By using a hidden configuration node to define the port expander chip, everything stays within the Node-Red environment, which makes things kind of easier.

So in my case Node-Red does most of the work for me. For a hidden configuration (parent) node, an object exists RED.nodes.node($('#node-input-chip').val()) (the id refers to the html of the child node that links it with the parent). This object has as one of its properties a list of all the child node ids with relevant properties for each such as which pin is selected by the child. By simply running through all the users, all the pins selected by other child nodes can be found and disabled in the pin number dropdown list so that they cannot be selected again e.g.

var chipStuff = RED.nodes.node($('#node-input-chip').val());
for (var i=0; i<chipStuff.users.length;i++) {
	if (chipStuff.users[i].id == nodeID) {
	    console.log("Release block of pin number" + chipStuff.users[i].bitNum);
	    $('#node-input-bitNum option[value='+chipStuff.users[i].bitNum+']').removeAttr('disabled');
    } else {
	    console.log("Block selection of pin number" + chipStuff.users[i].bitNum);
	    $('#node-input-bitNum option[value='+chipStuff.users[i].bitNum+']').attr("disabled","disabled").css("background","#a6bbdf");
	}
}

where nodeID equals the id of the child node. When an existing child node is double clicked to open its properties dialog, its pinNumber (bitNum) is enabled, so that if it is changed, its original pinNumber becomes available for selection by other nodes. If an existing child node is associated with a different parent node, that new parent node's used pins are not available for selection.

This all works a charm, although some finessing still needs to be done, e.g. if a new child node is dragged onto the editor pane its selected pin defaults to 0, whether that pin is already in use or not. On opening the dropdown list it becomes clear that pin 0 (if already used) is not available. Trying to figure out how to make the default the first available not-disabled pin is one of things I still need to figure out.

Anyway, thanks again,
Joe

The default property - unfortunately - doesn't accept a function to manipulate the initial value. It yet supports a validate function. You could check if the selected pin (which defaults to 0) is ok; if not (returning false), the node will be flagged with the red triangle indicating a wrong / missing configuration.

Can't the onEditPrepare function detect that the parameter is not yet set (is undefined) and then create a sensible default based on whatever thing you need ? (you may also need to fetch the list of already used resources to do this)

Yes it can and it now does. The parameter defaulted to 0 as I mentioned. In the onEditPrepare function I have included a line of jQuery that finds the first available unused pin and sets the select option to that value. It just took a lot of Googling and trial & error to eventually find the correct jQuery statement:

$('#node-input-bitNum').find("option:not(:disabled):eq(0)").attr('selected',true);

It works beautifully. Still need to do some testing, e.g. to see what happens if all pins are used and a new child node is dragged onto the editing pane. Should be easy enough to catch, as I have all the data available: total number of pins available, which of those are used, etc. Just ran out of time yesterday...

1 Like