Groov View Radio Buttons Using Node-RED

Radio buttons is a topic that has come up several times in the forum, with one post providing a solution using OptoScript, so I thought I’d share a way I found to do it using Node-RED and groov View:

Here I have two flows, one using PAC Control tables with check boxes on the left, and another using groov View data stores with toggle buttons on the right. Of course you can use either gadget with either method.
The flows for both are pretty stragith forward, here is the one for PAC Control:

And if you prefer to use groov Data Store tables rather than PAC Control tables you can do that as well by using dynamic settings to write a groov table with a single write node:

The main logic centers around the fact that as long as only one button is on, we only need to track which was the “last button” to be pressed, then turn that button off every time a new one is pressed. For groov View data stores we just need to send a write object for each button, whereas for PAC Control tables we can use an entire array each time.
Here are the two flows:

PAC Control tables (Remember to change the PAC read and write nodes from buttons[] to whatever your integer table is called.)

[{"id":"fe567ef4.5f17e","type":"function","z":"e02f10b4.235de","name":"radio buttons","func":"mySize = msg.payload.length;\nlast_button = context.get('last_button');\nif (typeof last_button == 'undefined') last_button = -1;\n\nfor(i = 0; i < mySize; i++) {\n    if(msg.payload[i] == 1 && i != last_button) {        // if this button is on, and it wasn't before...\n        context.set('last_button', i);      // save the current button index as the new \"last\" button to be pressed\n        \n        write_values = new Array(mySize).fill(0);   // toggle all others off except this one.\n        write_values[i] = 1;\n        return { payload : write_values };\n    }\n}","outputs":1,"noerr":0,"x":590,"y":1720,"wires":[["f76a5e0.6c15fa"]]},{"id":"d38406a6.0363d8","type":"rbe","z":"e02f10b4.235de","name":"","func":"rbe","gap":"","start":"","inout":"out","property":"payload","x":450,"y":1720,"wires":[["fe567ef4.5f17e"]]},{"id":"e807498b.c246b8","type":"inject","z":"e02f10b4.235de","name":"0.5 s","topic":"","payload":"","payloadType":"date","repeat":".5","crontab":"","once":false,"onceDelay":0.1,"x":190,"y":1720,"wires":[["8cc5a67.9545058"]]},{"id":"8cc5a67.9545058","type":"pac-read","z":"e02f10b4.235de","device":"","dataType":"int32-table","tagName":"buttons","tableStartIndex":"","tableLength":"","value":"","valueType":"msg.payload","topic":"","topicType":"none","name":"","x":320,"y":1720,"wires":[["d38406a6.0363d8"]]},{"id":"f76a5e0.6c15fa","type":"pac-write","z":"e02f10b4.235de","device":"","dataType":"int32-table","tagName":"buttons","tableStartIndex":"","value":"","valueType":"msg.payload","name":"","x":740,"y":1720,"wires":[[]]}]

groov Data Store tables (Remember to go into the function node and change dynamic_buttons to whatever your table is called.)

[{"id":"5f9551dd.b1a3b","type":"inject","z":"e02f10b4.235de","name":"0.5 s","topic":"","payload":"","payloadType":"date","repeat":".5","crontab":"","once":false,"onceDelay":0.1,"x":210,"y":1540,"wires":[["fcbcdab9.3f07c8"]]},{"id":"fcbcdab9.3f07c8","type":"groov-read-ds","z":"e02f10b4.235de","dataStore":"","tagName":"dynamic_buttons","tableStartIndex":"","tableLength":"10","value":"","valueType":"msg.payload","topic":"","topicType":"none","name":"read","x":330,"y":1540,"wires":[["f93b8cb4.2b716"]]},{"id":"f93b8cb4.2b716","type":"rbe","z":"e02f10b4.235de","name":"","func":"rbe","gap":"","start":"","inout":"out","property":"payload","x":450,"y":1540,"wires":[["bddead70.f6145"]]},{"id":"bddead70.f6145","type":"function","z":"e02f10b4.235de","name":"radio buttons","func":"mySize = msg.payload.length;\nlast_button = context.get('last_button');\nif (typeof last_button == 'undefined') last_button = -1;\n\nfor(i = 0; i < mySize; i++) {\n    if(msg.payload[i] && i != last_button) {    // if this button is on, and it wasn't before...\n        \n        context.set('last_button', i);      // save the current button index as the new \"last\" button to be pressed\n\n        \n        if(last_button == -1) {             // if this is running for the first time,\n            for(a = 0; a < mySize; a++) {   // toggle all others off except this new button:\n                node.send({ payload : {\n                    tagName         : 'dynamic_buttons',\n                    tableStartIndex : a,\n                    values          : (a == i) ? true : false // false for everything but >i<\n                }});\n            }\n        }\n        \n        \n        else {                      // otherwise just turn the last active button off, leave the rest alone.\n            return { payload : {\n                tagName         : 'dynamic_buttons',\n                tableStartIndex : last_button,\n                values          : false\n            }}\n        }\n    }\n}","outputs":1,"noerr":0,"x":590,"y":1540,"wires":[["8ebb9f95.2e7c7"]]},{"id":"8ebb9f95.2e7c7","type":"groov-write-ds","z":"e02f10b4.235de","dataStore":"","tagName":"","tableStartIndex":"","value":"payload.values","valueType":"msg","name":"output","x":730,"y":1540,"wires":[[]]}]

If you find some way to modify this code for your own projects please post it below, or feel free to drop any questions about how to get this working.

And as always, happy coding!