Here is an example of detecting mqtt devices, using mqtt wildcards and context storage. This is a simplified example. You could also use announce topics to create the context array.
Hope it helps you.
[{"id":"07871d268f9a72c4","type":"inject","z":"da8a6ef0b3c9a5c8","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"tasmota/switch/room1/state","payload":"1","payloadType":"num","x":170,"y":3480,"wires":[["4ca64d529cad2e93"]]},{"id":"4ca64d529cad2e93","type":"mqtt out","z":"da8a6ef0b3c9a5c8","name":"","topic":"","qos":"","retain":"","respTopic":"","contentType":"","userProps":"","correl":"","expiry":"","broker":"e8ba3ef5.22f4a8","x":610,"y":3420,"wires":[]},{"id":"7ff9bd7510d8d085","type":"change","z":"da8a6ef0b3c9a5c8","name":"","rules":[{"t":"set","p":"topic","pt":"msg","to":"$join($split($$.topic, \"/\")[[0..2]], \"/\") & \"/state\"\t","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":440,"y":3420,"wires":[["4ca64d529cad2e93"]]},{"id":"0370b0c601ae83fd","type":"inject","z":"da8a6ef0b3c9a5c8","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"tasmota/switch/room1/state","payload":"0","payloadType":"num","x":170,"y":3520,"wires":[["4ca64d529cad2e93"]]},{"id":"c087a20355415b49","type":"inject","z":"da8a6ef0b3c9a5c8","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"tasmota/switch/room2/state","payload":"1","payloadType":"num","x":170,"y":3580,"wires":[["4ca64d529cad2e93"]]},{"id":"57540b0a07b20989","type":"inject","z":"da8a6ef0b3c9a5c8","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"tasmota/switch/room2/state","payload":"0","payloadType":"num","x":170,"y":3620,"wires":[["4ca64d529cad2e93"]]},{"id":"59d708256ccc2a06","type":"mqtt in","z":"da8a6ef0b3c9a5c8","name":"","topic":"tasmota/switch/+/command","qos":"2","datatype":"auto-detect","broker":"e8ba3ef5.22f4a8","nl":false,"rap":true,"rh":0,"inputs":0,"x":220,"y":3420,"wires":[["7ff9bd7510d8d085"]]},{"id":"ae6e48770263980c","type":"comment","z":"da8a6ef0b3c9a5c8","name":"simulaate tasmota devices, everything below here is to simulate a response from a tasmota device","info":"","x":380,"y":3380,"wires":[]},{"id":"ae903c4ca875ebf5","type":"mqtt in","z":"da8a6ef0b3c9a5c8","name":"","topic":"tasmota/switch/+/state","qos":"2","datatype":"auto-detect","broker":"e8ba3ef5.22f4a8","nl":false,"rap":true,"rh":0,"inputs":0,"x":180,"y":3260,"wires":[["9fa0c82f4c9ca881"]]},{"id":"9fa0c82f4c9ca881","type":"change","z":"da8a6ef0b3c9a5c8","name":"","rules":[{"t":"set","p":"tasmota","pt":"flow","to":"$append(\t $flowContext(\"tasmota\")[name != $$.topic][],\t [{\"name\": $$.topic, \"state\": $$.payload, \"color\": ($$.payload = 1 ? \"#00FF00\" : \"#FF0000\")}]\t)^(name)[]","tot":"jsonata"},{"t":"set","p":"payload","pt":"msg","to":"tasmota","tot":"flow"}],"action":"","property":"","from":"","to":"","reg":false,"x":420,"y":3240,"wires":[["f93c17b321065488"]]},{"id":"f93c17b321065488","type":"ui_template","z":"da8a6ef0b3c9a5c8","group":"2d4fe667.28f8ba","name":"","order":18,"width":0,"height":0,"format":"<script>\nthis.scope.action = function(obj) { return obj; }\n</script>\n\n\n<md-list>\n <md-list-item ng-repeat=\"device in msg.payload\">\n <md-button class=\"md-ink-ripple\" \n style=\"color: {{device.color}}\"\n ng-click=\"send({payload:action({name: device.name, state: device.state})})\" \n >{{device.name}} -- {{device.state}}</md-button>\n </md-list-item>\n</md-list>","storeOutMessages":false,"fwdInMessages":false,"resendOnRefresh":true,"templateScope":"local","className":"","x":580,"y":3260,"wires":[["7a453ae2374c5358"]]},{"id":"7a453ae2374c5358","type":"change","z":"da8a6ef0b3c9a5c8","name":"","rules":[{"t":"set","p":"topic","pt":"msg","to":"$join($split($$.payload.name, \"/\")[[0..2]], \"/\") & \"/command\"\t","tot":"jsonata"},{"t":"set","p":"payload","pt":"msg","to":"$$.payload.state = 1 ? 0 : 1","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":760,"y":3260,"wires":[["c7694ee5f1ba16fe"]]},{"id":"c7694ee5f1ba16fe","type":"mqtt out","z":"da8a6ef0b3c9a5c8","name":"","topic":"","qos":"","retain":"","respTopic":"","contentType":"","userProps":"","correl":"","expiry":"","broker":"e8ba3ef5.22f4a8","x":950,"y":3280,"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":""},{"id":"2d4fe667.28f8ba","type":"ui_group","name":"demo","tab":"1caa8458.b17814","order":2,"disp":true,"width":"12","collapse":false},{"id":"1caa8458.b17814","type":"ui_tab","name":"Demo","icon":"dashboard","order":1,"disabled":false,"hidden":false}]
To add devices add more inject pairs with different room names. You will have to adjust flow for your device command and status topics.