Session, dashboard concurrent use

I know there has been a few posts on multi users in dashboard, but my problem is not exactly the same (I hope).

Let's say I have a bunch of sensors, all send the same data structure. I want to create a dashboard tab, where data from a sensor is displayed.

I want to use the same dashboard tab to display data from sensor 1, but if I open it in another browser tab, I want to see sensor 2.

So far what I understood that I can place a ui-control and it will give me messages when a user opens my tab. And I guess I can keep this information in the context and store which socketid is viewing which sensor. And before I refresh the data on the UI I can pick which sensor's data to show. Would this result in the same dashboard showing different information on the same tab?

Also, would it be possible for me to pass the sensor ID in the dashboard URL? Like http://<ip>:1880/ui/#!/2?sensorid=2
Is there a req.param for the dashboard URL request?


Note that the sessionid can change quite easily. It only takes a temporary disconnection for it to change and this can happen if the user leaves the PC for a while or on some other network interruption.

Also note that you would probably need to use some front-end custom code in a ui_template to be able to differentiate things.

Really, uibuilder is better at handling these things as it already has filters you can use for page names, client ids and browser tab ids. all of which are more stable.

OK, I have modest experience with ui-builder. Although I don't think I used client id and browser id information before. How can I access that?

If you look at the connect control msg when a client connects, you should see that it reports the page name, client id and tab id.

If you include one or more of those in a msg to send to uibuilder in, for example msg._uib.clientId or msg._ui.clientId, any connected clients will check those and will only accept the msg if the property matches.

Can you elaborate on this? I created a test uibuilder node, and I am sending data in with msg._uid.clientId with a client id of my connected client and also with some random client id. All of them are being processed by the uibuilder (message shows up on the template page). Do you mean that in uibuilder.onChange I should validate if the value of msg._uid.clientId matches with the current client ID? How do I get the client ID in the index.js?

_uib not _uid

Sorry, typo, I used _uib:

This is one of the inject node that matches the clientID I got from uibuilder and the other inject node users some random different _uib. And I can see both messages on the UI.

Apologies for the delay.

I've just tested this and I got the expected result, a message containing the correct clientId gets through and a different clientId does not.

tabId filtering also works as expected.


OK, as we discussed on the other topic, this could be down to the fact that I am still on version 5.1.1, since I seem to have done the same from your screenshot above.

Ah, I missed that. The filters were added in v6.5

OK, since the last post, I did upgrade to the latest version but it is still not working:

The clientId you can see on the screen is clearly a bogus ID, but the message is still shown in the uibuilder. So I am still missing something.

I'll try to check it out tomorrow.

Just tested again.

Opened up the same page in 2 different browsers, found their clientIds and set up two inputs sent direct to the uibuilder node.

With the other input having the other clientId. Each browser window only shows the message for the correct client.

Can you share the HTML you are using?

Sorry, you are right. I started this example with 5.x.x uibuilder, and the HTML must have been creaed with that example. I deleted the uibuilder node, recreated it and it works fine now.

1 Like

I extended the logic beyond the simple inject nodes, so Node-Red registers all clients that are connected to it can tag the traffic to the correctionding session id. But what I noticed, that I open the same uibuilder page on multiple tabs in Chrome, or separate Chrome windows, the clientid is always the same. I though those would differ for each instance. Or is that the _socketid?

Sorry, I probably made it more complex than maybe it needed to be. But I wanted to be able to identify a "person" reasonably accurately without having to do a lot of complex stuff. So I decided that a "client" is any tab on the same browser until that browser restarts (or clears cookies).

If you want to identify a single tab, you can use the tabId for that.

You can, of course, identify the page instead or as well as. And you should be able to combine them.

While the _socketId identifies a specific connection (an individual tab in our case), it is not really very reliable because it changes if the user reloads the page or if the connection is temporarily lost (e.g. a network blip or the browser tab or PC going to sleep). So I generally recommend avoiding it in most cases.

BTW, in a future release, it will probably be possible for 1 client id, tab id, and/or page name to talk to another via Node-RED just by knowing the appropriate Id. I'm still playing around with Socket.IO's rooms features to see what is actually feasible and sensible to do.

For me even thet tabid are the same if I duplicate the window in Chrome.
Actually, I would not mind the _socketid as long as I can also pass it to the msg._uib parameter, or something similar. Also just a question, I assume if I assume msg._uib and pass that through uib-element that is still fine.

Ah, I didn't know that! If you navigate to the same page with a new tab, you get a new id but if you duplicate it you get the same tab id. :frowning:

All you need for that is to have msg._socket (not msg._uib._socket) in the msg you try to send to the uibuilder node. In that case, it will automatically only go to the appropriate client.

Let me leave my example here. Still does not seem to work with _socket.
There is a "Client Collection" function node which logs which client has which socket id, and link it to the ?device=test1 or ?device=test2 in the URL parameter.
Based on this, the "Router" function node adds msg._socket to the outgoing message before sending it through the uib-element. I checked the message leaving uib-element, and each has the correct _socket id. But still each message Chrome instance gets the message. I must be missing something simple.

[{"id":"ddf27e1052787ad5","type":"debug","z":"b4d7bc8a9540f906","name":"debug 72","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1040,"y":120,"wires":[]},{"id":"e181aa0641a3733f","type":"debug","z":"b4d7bc8a9540f906","name":"debug 73","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1040,"y":260,"wires":[]},{"id":"c545de0744ed3c75","type":"function","z":"b4d7bc8a9540f906","name":"Test 1","func":"let number = Math.floor(Math.random()*100);\nmsg.topic = \"test1\";\nmsg.payload = number;\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":310,"y":220,"wires":[["9e9cbe1ba459dfc1"]]},{"id":"bb23d9df851b734e","type":"inject","z":"b4d7bc8a9540f906","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"},{"p":"_uib","v":"{\"clientId\": \"eqQ9-YhGOxeAtcv2Etc5i\" }","vt":"json"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"test","payload":"OK","payloadType":"str","x":470,"y":340,"wires":[["958d1f8c4fc837f6"]]},{"id":"01512afde4d3dcf2","type":"inject","z":"b4d7bc8a9540f906","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"},{"p":"_uib","v":"{\"clientId\": \"fdfdfdfdfdffsfsd\" }","vt":"json"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"test","payload":"Not OK","payloadType":"str","x":490,"y":380,"wires":[["958d1f8c4fc837f6"]]},{"id":"958d1f8c4fc837f6","type":"uibuilder","z":"b4d7bc8a9540f906","name":"","topic":"","url":"uitest","okToGo":true,"fwdInMessages":false,"allowScripts":false,"allowStyles":false,"copyIndex":true,"templateFolder":"blank","extTemplate":"","showfolder":false,"reload":false,"sourceFolder":"src","deployedVersion":"6.8.2","showMsgUib":false,"title":"","descr":"","x":780,"y":220,"wires":[["ddf27e1052787ad5"],["e181aa0641a3733f","3bb6fe2cc8712d87"]]},{"id":"08a6f1d386d371a7","type":"inject","z":"b4d7bc8a9540f906","name":"Toggle Visible Msgs","props":[{"p":"_uib","v":"{\"command\":\"showMsg\"}","vt":"json"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":510,"y":420,"wires":[["958d1f8c4fc837f6"]]},{"id":"3bb6fe2cc8712d87","type":"function","z":"b4d7bc8a9540f906","name":"Client collection","func":"let clientlist = flow.get(\"clientlist\");\nif (clientlist === undefined) {\n    clientlist = {};\n}\n\nif (msg.uibuilderCtrl === \"client connect\") {\n    if (msg.urlParams.device !== undefined) {\n        clientlist[msg.urlParams.device] = msg._socketId;\n    }\n    // return because the URL is missing the device parameter\n    delete msg.uibuilderCtrl;\n    return msg;\n}\nif (msg.uibuilderCtrl === \"client disconnect\") {\n    delete clientlist[msg.urlParams.device];\n}\nflow.set(\"clientlist\", clientlist);","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1060,"y":320,"wires":[["e6824a35d4e387b0"]]},{"id":"f9de99c97f05389e","type":"inject","z":"b4d7bc8a9540f906","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"1","crontab":"","once":true,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":130,"y":180,"wires":[["c545de0744ed3c75","b3f3614223dfa819"]]},{"id":"b3f3614223dfa819","type":"function","z":"b4d7bc8a9540f906","name":"Test 2","func":"let number = Math.floor(Math.random()*100+100);\nmsg.topic = \"test2\";\nmsg.payload = number;\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":310,"y":260,"wires":[["9e9cbe1ba459dfc1"]]},{"id":"9e9cbe1ba459dfc1","type":"function","z":"b4d7bc8a9540f906","name":"Router","func":"let clientlist = flow.get(\"clientlist\");\nif (clientlist === undefined) {\n    return;\n}\n\nif (clientlist[msg.topic] !== undefined) {\n    msg._socket = clientlist[msg.topic];\n    return msg;\n}\n\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":470,"y":240,"wires":[["30674faded2349bf"]]},{"id":"30674faded2349bf","type":"uib-element","z":"b4d7bc8a9540f906","name":"","topic":"","elementtype":"html","parent":"#more","parentSource":"","parentSourceType":"str","elementid":"more","elementId":"","elementIdSourceType":"str","heading":"","headingSourceType":"str","headingLevel":"h2","data":"payload","dataSourceType":"msg","position":"last","positionSourceType":"str","passthrough":false,"confData":{},"x":1050,"y":460,"wires":[["958d1f8c4fc837f6","f1923e4c384ac61a"]]},{"id":"e6824a35d4e387b0","type":"change","z":"b4d7bc8a9540f906","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"<p>Missing device parameter in the payload</p>","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":810,"y":460,"wires":[["30674faded2349bf"]]},{"id":"f1923e4c384ac61a","type":"debug","z":"b4d7bc8a9540f906","name":"debug 81","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1230,"y":500,"wires":[]}]

test1 and test2 just random numbers, but test2 is always >100, test1 <100. Therefore I expect the window to show different numbers.

Had a quick play with that flow last night. I was a bit too tired to make full sense of it. However, I think you have a small logic error which is causing the issue. But I need to go through step by step to work it out.