Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updating an SVG element (via input node) is not persistent #55

Closed
maartenlambrecht opened this issue Apr 9, 2020 · 29 comments
Closed

Comments

@maartenlambrecht
Copy link

The example to update an SVG element through the input node (described here ) works good. But when I reload the node-red dashboard some time later, the SVG image resets to the default one (without the changes).

Is there any possibility to make these updates persistent?

@bartbutenaers
Copy link
Owner

Hi Maarten,
this is a coincidence...
We got a similar question today on the Node-RED forum.
As you can read here, I have responded that I think it is not possible/advised/ ...
But I could be mistaken!
Since I would like to have opinions from other users about this, it would be nice if you could join our discussion there and give your feedback. Or start a new discussion if you like (and please mention myself and @Steve-Mcl to make sure to get our attention).
Thanks !
Bart

@Steve-Mcl
Copy link
Collaborator

Hi Maarten,

My stance on this is that it can be achieved in node-red already & is far easier than making the node remember all state.

I'm not saying no at this time but unless myself or Bart have a lightbulb moment, it isnt going to happen soon.

In the mean time...
You should persist your own state (use flow or global context if necessary) & re-draw you SVG animations on dashboard connection. You can achieve this by using the "ui_control" node (to detect the dashboard pages has opened) and send your state updates to the SVG node.

If Bart or I come up with something, we will feedback.

@maartenlambrecht
Copy link
Author

Thank you for your answers.
I made a simple custom solution using two function nodes.

The only thing to do is give each msg that wants to change the SVG a msg.id.
Every msg that wants to change the SVG, will be stored in a global variable with its msg.id as key.
A msg with a new msg.id will be stored in a new key. A msg with a used msg.id will overwrite the last command.

All input to the SVG node goes first through this function node:
global.set("SVG_state.list."+msg.id, msg); return msg;

An ui control node triggers every reload of the dashboard and activates this function node, which is linked to the SVG node:
var temp = global.get("SVG_state.list"); Object.entries(temp).forEach(([key, val]) => node.send(val));

I hope this code will help others to 'save the state of the SVG'.

@bartbutenaers
Copy link
Owner

bartbutenaers commented Apr 10, 2020 via email

@maartenlambrecht
Copy link
Author

Hi Bart

My use case:
I have a SVG map of my home with lamps, switches and doors on it, which change color when they light, open/close. The sensor nodes send a MQTT message only on change.
When I open the dashboard on my phone, it loads the initial state of the map with everything in gray, even if there were already some lights put on.

I will stick with my solution since it works, but a server side DOM looks like a great solution!

On reboot, the SVG image resets again indeed. But as this does not happen that often, it is not a big problem for me.

Thanks for your reply and keep up the good work!

@Alloc86
Copy link

Alloc86 commented Nov 11, 2022

Just for reference, as this was the first thread talking about the issue when I was looking on how to get my floorplan be up-to-date when opening the dashboard:
[{"id":"7a1c92b47194d180","type":"ui_ui_control","z":"3c9598291d178446","name":"","events":"all","x":1160,"y":340,"wires":[["903fefce41c33f8c","7a8eb1c1c0eba7bd"]]},{"id":"d7c4ab76cef0c7b0","type":"function","z":"3c9598291d178446","name":"DataReplayStore","func":"if (msg.topic == \"replay\") {\n var temp = context.get(\"messages\");\n Object.entries(temp).forEach(([, val]) => {\n node.send(val)\n });\n\n return;\n}\n\nif (msg.hasOwnProperty(\"id\")\n && typeof msg.id === \"string\"\n && msg.id.length > 0\n && /^[a-zA-Z0-9_]+$/.test(msg.id)) {\n context.set(\"messages.\" + msg.id, msg);\n} else {\n node.warn (\"Msg has no string ID or empty string or contains non alpha-numeric characters:\");\n node.warn (msg);\n}\nreturn msg;\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1310,"y":460,"wires":[["2754dbd92226a03f","e3be2a5bb596f73e"]]},{"id":"7a8eb1c1c0eba7bd","type":"function","z":"3c9598291d178446","name":"ReplayOnConnect","func":"var svgTabName = \"Diagnose\";\nvar replayOnConnect = false;\n\nif (msg.payload != \"connect\" && msg.payload != \"change\") {\n return;\n}\n\nif (msg.payload == \"connect\" && !replayOnConnect) {\n return;\n}\n\nif (msg.payload == \"change\" && msg.name != svgTabName) {\n return;\n}\n\nmsg.topic = \"replay\";\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1350,"y":340,"wires":[["d7c4ab76cef0c7b0"]]}]

SvgReplay

All inputs to SVG go through the replay function node and must have a top level property "id" (alpha-numeric only, only additional character allowed right now is underscore, can easily be changed in the regex in the node). The ReplayOnConnect node needs to know the dashboard tab the SVG is on and will then issue the replay whenever that tab is opened.

@bartbutenaers
Copy link
Owner

Hi @Alloc86,
Thanks for sharing your solution!!
Hopefully others can benefit from it.
Bart

@doit4fun
Copy link

Alloc86 had a wonderful solution to the SVG not keeping content after tab chaging.
His solution works fine but the problem is when you use context.set("...") it will clear the memory of the context on the next Deploy (not happens when other node is modified).
So to prevent this to happen I used global.set(...) and global.get(...) . In this way the information is saved in the global project context memory and on the next deploy... the context memory will not be cleared.
For persistent info after node-red Server is shutdown...maybe mysql should be used

@ninaaa11
Copy link

Hello, unfortunately I have the problem with SVG.

The values ​​are not saved when I describe it with this function:

`var temperature = msg.payload;
msg.payload = [{
"command": "update_text",
"selector": "#Betriebsart",
"textContent": temperature
}]

return msg;

Warn:
"Msg has no string ID or empty string or contains non alpha-numeric characters:"

and

{"elementId":"Pumpe_ON","selector":"#Pumpe_ON","event":{"type":"click","pageX":354,"pageY":258,"screenX":354,"screenY":342,"clientX":354,"clientY":258,"svgX":-242,"svgY":67,"bbox":[338,265,380,222]},"payload":[{"command":"update_text","selector":"#Betriebsart","textContent":"AUTO"}],"_msgid":"e2b239a5d8d23b99","socketid":"MzQZHxDyjvDs21TqAAAh"}`

@Alloc86
Copy link

Alloc86 commented Oct 12, 2023

I assume you are talking about my code from #55 (comment) ?
You need to have an 'id' field in the message sent to the node that is unique to the what you are updating.

@ninaaa11
Copy link

That's exactly how it is! Unfortunately, I have no idea how to integrate it into this function. I'm just a copier and a Google searcher

☺️

@ninaaa11
Copy link

I can't find it, does anyone have an example or a link where it is described, please

@Alloc86
Copy link

Alloc86 commented Oct 13, 2023

One example from my setup of a function node that feeds the data:

var svgId = "AzPresence";

msg.id = svgId;
msg.payload = {
    "command": "update_attribute",
    "selector": "#" + svgId + " > g",
    "attributeName": "class",
    "attributeValue": msg.payload ? "on" : "off"
};

return msg;

As it's really specific to your setup and use case this won't be anything you'd copy paste but shows how such a message can be set up.

@bartbutenaers
Copy link
Owner

Hi @ninaaa11,
Sorry for the delay. Quite busy...
Was the feedback from @Alloc86 sufficient to solve your problem? If not can you please share a small simpliefied version of your flow that I can quickly use to reproduce your issue.
Bart

@ninaaa11
Copy link

ninaaa11 commented Oct 15, 2023

Hello,

Thank you for asking.
Unfortunately I didn't have any success and the last comment couldn't help me either.

I tried to keep it small here, to understand the result it had to be this big.

For you professionals it will probably be amateurish, but I'll try what I can and get what I can from Google .-)

@bartbutenaers
Copy link
Owner

@ninaaa11,

I get this when I import your flow:

image

You can't expect me to install all your dependencies, and spend my time to figure out how all your flows work.
Like I asked above: " share a small simpliefied version of your flow that I can quickly use to reproduce your issue.".
I only need an inject node (that Injects the message that causes your problem) and the SVG node (with a simplified svg).

@ninaaa11
Copy link

I won't even try

[ { "id": "d566a75c6044914d", "type": "tab", "label": "1_1_2_PUFER", "disabled": false, "info": "", "env": [] }, { "id": "e2b227538981e36d", "type": "group", "z": "d566a75c6044914d", "style": { "stroke": "#999999", "stroke-opacity": "1", "fill": "none", "fill-opacity": "1", "label": true, "label-position": "nw", "color": "#a4a4a4" }, "nodes": [ "09ec2e88ca7f63e0" ], "x": 1894, "y": 619, "w": 272, "h": 82 }, { "id": "8ff802424563ca49", "type": "function", "z": "d566a75c6044914d", "name": "Puffer_unten_Temp", "func": "const color1 = [0, 0, 255]; // blude\nconst color2 = [255, 0, 0]; // red\n\nvar temperature = msg.payload;\nvar factor = msg.payload/ 50;\n\nvar red = Math.round(color1[0] + factor * (color2[0] - color1[0]));\nvar green = Math.round(color1[1] + factor * (color2[1] - color1[1]));\nvar blue = Math.round(color1[2] + factor * (color2[2] - color1[2]));\n\nvar interpolatedColor = \"rgb(\" + red + \",\" + green + \",\" + blue + \")\"; \n\nmsg.payload= [{\n \"command\": \"update_text\",\n \"selector\": \"#unten_temp\",\n \"textContent\": temperature + \"°C\"\n},{\n \"command\": \"update_attribute\",\n \"selector\": \"#unten_temp\",\n \"attributeName\": \"fill\",\n \"attributeValue\": interpolatedColor\n}]\n\nreturn msg;\n", "outputs": 1, "timeout": "", "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 1150, "y": 480, "wires": [ [ "69efd453a072bc07" ] ] }, { "id": "09ec2e88ca7f63e0", "type": "ui_svg_graphics", "z": "d566a75c6044914d", "g": "e2b227538981e36d", "group": "a31dba0162f486f6", "order": 3, "width": 25, "height": 7, "svgString": "<svg version=\"1.1\" id=\"svg9\" width=\"1200\" height=\"400\" viewBox=\"0 0 200 400\" sodipodi:docname=\"ggg.svg\" inkscape:version=\"1.1.2 (b8e25be833, 2022-02-05)\" xmlns:inkscape=\"http://www.inkscape.org/namespaces/inkscape\" xmlns:sodipodi=\"http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns=\"http://www.w3.org/2000/svg\" preserveAspectRatio=\"xMidYMid meet\">\n <defs id=\"defs13\"/>\n <sodipodi:namedview id=\"namedview11\" pagecolor=\"#ffffff\" bordercolor=\"#666666\" borderopacity=\"1.0\" inkscape:pageshadow=\"2\" inkscape:pageopacity=\"0.0\" inkscape:pagecheckerboard=\"0\" showgrid=\"false\" inkscape:zoom=\"1.380626\" inkscape:cx=\"430.60177\" inkscape:cy=\"201.72009\" inkscape:window-width=\"1920\" inkscape:window-height=\"1003\" inkscape:window-x=\"-9\" inkscape:window-y=\"-9\" inkscape:window-maximized=\"1\" inkscape:current-layer=\"g15\" inkscape:snap-text-baseline=\"true\"/>\n <g inkscape:groupmode=\"layer\" inkscape:label=\"Image\" id=\"g15\">\n\n \n\n <g id=\"e1_group\" transform=\"matrix(1, 0, 0, 1, -266.424, -426.045)\">\n \n \n \n \n </g>\n \n\n \n\n \n\n \n\n\n\n\n\n\n \n\n \n\n\n <text xml:space=\"preserve\" style=\"font-size:15px;line-height:1.25;font-family:AngsanaUPC;-inkscape-font-specification:'AngsanaUPC, Normal';font-variant-ligatures:none;font-weight:bold\" x=\"464.8024\" y=\"37.301922\" id=\"text29880\" transform=\"matrix(0.979061, 0, 0, 1.02636, -232.391, 110.967)\">\n \n </text>\n <text xml:space=\"preserve\" style=\"font-size:12px;line-height:1.25;font-family:AngsanaUPC;-inkscape-font-specification:'AngsanaUPC, Normal';font-variant-ligatures:none;font-weight:bold\" x=\"461.85541\" y=\"314.00134\" id=\"text29880-8\" transform=\"matrix(1, 0, 0, 1, -229.879, -113.903)\">\n \n </text>\n <text xml:space=\"preserve\" style=\"font-size:12px;line-height:1.25;font-family:AngsanaUPC;-inkscape-font-specification:'AngsanaUPC, Normal';font-variant-ligatures:none;font-weight:bold\" x=\"466.453\" y=\"110.05737\" id=\"text29880-2\" transform=\"matrix(1, 0, 0, 1, -229.879, -113.903)\">\n \n </text>\n\n\n\n \n\n </g>\n\n <rect id=\"svgEditorBackground\" x=\"-2.8972366\" y=\"18.832037\" width=\"200\" height=\"400\" style=\"fill:none;stroke:none\"/>\n <defs id=\"defs13\"/>\n <sodipodi:namedview id=\"namedview11\" pagecolor=\"#ffffff\" bordercolor=\"#666666\" borderopacity=\"1.0\" inkscape:pageshadow=\"2\" inkscape:pageopacity=\"0.0\" inkscape:pagecheckerboard=\"0\" showgrid=\"false\" inkscape:zoom=\"0.690313\" inkscape:cx=\"412.13189\" inkscape:cy=\"288.99934\" inkscape:window-width=\"1920\" inkscape:window-height=\"1003\" inkscape:window-x=\"-9\" inkscape:window-y=\"-9\" inkscape:window-maximized=\"1\" inkscape:current-layer=\"g15\" inkscape:snap-text-baseline=\"true\"/>\n <g inkscape:groupmode=\"layer\" inkscape:label=\"Image\" id=\"g15\">\n\n\n\n\n\n </g>\n \n\n \n <text id=\"unten_temp\" x=\"582.828\" y=\"-293.764\" fill=\"#0000ff\" font-size=\"25px\" text-anchor=\"middle\" alignment-baseline=\"middle\" font-weight=\"bold\" transform=\"matrix(1, 0, 0, 1, -306.011, 688.537)\">0°C</text>\n <text id=\"Betriebsart\" x=\"-189.14552\" y=\"34.20179\" fill=\"#0000ff\" font-size=\"13.4989px\" text-anchor=\"middle\" alignment-baseline=\"middle\" font-weight=\"bold\" transform=\"matrix(1.25936, 0, 0, 0.794051, 118.807, 446.427)\" style=\"stroke-width:0.539955\"/>\n\n <g id=\"_Task_PathTriangleDigitTask\"/>\n \n \n \n\n <rect id=\"svgEditorBackground\" x=\"-2.8972366\" y=\"18.832037\" width=\"200\" height=\"400\" style=\"fill:none;stroke:none\"/>\n <defs id=\"defs13\"/>\n <sodipodi:namedview id=\"namedview11\" pagecolor=\"#ffffff\" bordercolor=\"#666666\" borderopacity=\"1.0\" inkscape:pageshadow=\"2\" inkscape:pageopacity=\"0.0\" inkscape:pagecheckerboard=\"0\" showgrid=\"false\" inkscape:zoom=\"0.690313\" inkscape:cx=\"412.13189\" inkscape:cy=\"288.99934\" inkscape:window-width=\"1920\" inkscape:window-height=\"1003\" inkscape:window-x=\"-9\" inkscape:window-y=\"-9\" inkscape:window-maximized=\"1\" inkscape:current-layer=\"g15\" inkscape:snap-text-baseline=\"true\"/>\n <g inkscape:groupmode=\"layer\" inkscape:label=\"Image\" id=\"g15\">\n\n\n\n \n\n\n\n </g>\n <text id=\"mitte_temp\" x=\"29.3446\" y=\"115.829\" fill=\"#0000ff\" font-size=\"25px\" text-anchor=\"middle\" alignment-baseline=\"middle\" font-weight=\"bold\" transform=\"matrix(1, 0, 0, 1, 246.711, 102.307)\"/>\n \n \n \n \n\n <g id=\"_Task_PathTriangleDigitTask\"/>\n\n\n\n <text id=\"e3_text\" x=\"-162.546\" y=\"-84.6876\" fill=\"#0000ff\" font-size=\"13.4989px\" text-anchor=\"middle\" alignment-baseline=\"middle\" font-weight=\"bold\" transform=\"matrix(1.25936, 0, 0, 0.794051, 118.807, 446.427)\" style=\"stroke-width:0.539955\"/>\n \n \n \n \n \n \n\n\n\n <defs>\n <linearGradient id=\"three-color-gradient\" x1=\"0\" x2=\"0\" y1=\"0\" y2=\"100%\">\n <stop offset=\"0%\" stop-color=\"{{msg.top}}\"/>\n <stop offset=\"50%\" stop-color=\"{{msg.middle}}\"/>\n <stop offset=\"100%\" stop-color=\"{{msg.bottom}}\"/>\n </linearGradient>\n </defs>\n \n \n</svg>", "clickableShapes": [ { "targetId": "#Pumpe_ON", "action": "click", "payload": "Podna", "payloadType": "str", "topic": "Podna" }, { "targetId": "#e4_ON", "action": "click", "payload": "Boiler", "payloadType": "str", "topic": "Boiler" }, { "targetId": "#e6_ON", "action": "click", "payload": "RL", "payloadType": "str", "topic": "RL" } ], "javascriptHandlers": [], "smilAnimations": [], "bindings": [], "showCoordinates": false, "autoFormatAfterEdit": false, "showBrowserErrors": false, "showBrowserEvents": false, "enableJsDebugging": false, "sendMsgWhenLoaded": false, "noClickWhenDblClick": false, "outputField": "payload", "editorUrl": "//drawsvg.org/drawsvg.html", "directory": "", "panning": "disabled", "zooming": "disabled", "panOnlyWhenZoomed": false, "doubleClickZoomEnabled": false, "mouseWheelZoomEnabled": false, "dblClickZoomPercentage": 150, "cssString": "div.ui-svg svg{\n color: var(--nr-dashboard-widgetColor);\n fill: currentColor !important;\n}\ndiv.ui-svg path {\n fill: inherit;\n}", "name": "1_1_2_ZIMA_PUFFER", "x": 2030, "y": 660, "wires": [ [] ] }, { "id": "ca973ec3b32341fa", "type": "ui_ui_control", "z": "d566a75c6044914d", "name": "", "events": "all", "x": 1540, "y": 80, "wires": [ [ "69d7a3dfd354127d" ] ] }, { "id": "69efd453a072bc07", "type": "function", "z": "d566a75c6044914d", "name": "DataReplayStore", "func": "if (msg.topic == \"replay\") {\n var temp = global.get(\"messages\");\n Object.entries(temp).forEach(([, val]) => {\n node.send(val)\n });\n\n return;\n}\n\nif (msg.hasOwnProperty(\"id\")\n && typeof msg.id === \"string\"\n && msg.id.length > 0\n && /^[a-zA-Z0-9_]+$/.test(msg.id)) {\n global.set(\"messages.\" + msg.id, msg);\n} else {\n node.warn (\"Msg has no string ID or empty string or contains non alpha-numeric characters:\");\n node.warn (msg);\n}\nreturn msg;\n", "outputs": 1, "timeout": "", "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 1690, "y": 220, "wires": [ [ "09ec2e88ca7f63e0" ] ] }, { "id": "69d7a3dfd354127d", "type": "function", "z": "d566a75c6044914d", "name": "ReplayOnConnect", "func": "var svgTabName = \"Diagnose\";\nvar replayOnConnect = false;\n\nif (msg.payload != \"connect\" && msg.payload != \"change\") {\n return;\n}\n\nif (msg.payload == \"connect\" && !replayOnConnect) {\n return;\n}\n\nif (msg.payload == \"change\" && msg.name != svgTabName) {\n return;\n}\n\nmsg.topic = \"replay\";\nreturn msg;", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 1750, "y": 80, "wires": [ [ "69efd453a072bc07" ] ] }, { "id": "150478d941e6aac7", "type": "ui_slider", "z": "d566a75c6044914d", "name": "", "label": "slider", "tooltip": "", "group": "a31dba0162f486f6", "order": 2, "width": 0, "height": 0, "passthru": true, "outs": "all", "topic": "topic", "topicType": "msg", "min": 0, "max": 10, "step": 1, "className": "", "x": 910, "y": 480, "wires": [ [ "8ff802424563ca49" ] ] }, { "id": "048168c9abcb9667", "type": "ui_spacer", "z": "d566a75c6044914d", "name": "spacer", "group": "a31dba0162f486f6", "order": 2, "width": 24, "height": 1 }, { "id": "f160f067a11f1c46", "type": "ui_spacer", "z": "d566a75c6044914d", "name": "spacer", "group": "2aa7443d78773c9f", "order": 2, "width": 24, "height": 1 }, { "id": "e2700e672118aefe", "type": "ui_spacer", "z": "d566a75c6044914d", "name": "spacer", "group": "a234de8bd1725107", "order": 2, "width": 24, "height": 1 }, { "id": "ea9541d086a667c7", "type": "ui_spacer", "z": "d566a75c6044914d", "name": "spacer", "group": "074866acbfbfcfee", "order": 2, "width": 24, "height": 1 }, { "id": "51ef62b910c9e01b", "type": "ui_spacer", "z": "d566a75c6044914d", "name": "spacer", "group": "3f8ed00ad470a59f", "order": 2, "width": 24, "height": 1 }, { "id": "a31dba0162f486f6", "type": "ui_group", "name": "ZIMA", "tab": "01469c1d4f16bbe6", "order": 1, "disp": true, "width": "25", "collapse": false, "className": "" }, { "id": "2aa7443d78773c9f", "type": "ui_group", "name": "RUCNO", "tab": "ba15d3a36829b7d1", "order": 1, "disp": true, "width": 25, "collapse": false, "className": "" }, { "id": "a234de8bd1725107", "type": "ui_group", "name": "LJETO", "tab": "17f34213e1613b31", "order": 1, "disp": true, "width": 25, "collapse": false, "className": "" }, { "id": "074866acbfbfcfee", "type": "ui_group", "name": "STANDBY", "tab": "52b3f99db16fa78e", "order": 1, "disp": true, "width": 25, "collapse": false, "className": "" }, { "id": "3f8ed00ad470a59f", "type": "ui_group", "name": "HLADJENJE", "tab": "a294c9c86cffb25f", "order": 1, "disp": true, "width": 25, "collapse": false, "className": "" }, { "id": "01469c1d4f16bbe6", "type": "ui_tab", "name": "1_1_2_PUFFER", "icon": "dashboard", "order": 4, "disabled": false, "hidden": false }, { "id": "ba15d3a36829b7d1", "type": "ui_tab", "name": "1_2_2_PUFFER", "icon": "dashboard", "order": 9, "disabled": false, "hidden": true }, { "id": "17f34213e1613b31", "type": "ui_tab", "name": "1_3_2_PUFFER", "icon": "dashboard", "order": 14, "disabled": false, "hidden": true }, { "id": "52b3f99db16fa78e", "type": "ui_tab", "name": "1_4_2_PUFFER", "icon": "dashboard", "order": 19, "disabled": false, "hidden": true }, { "id": "a294c9c86cffb25f", "type": "ui_tab", "name": "1_6_2_PUFFER", "icon": "dashboard", "order": 24, "disabled": false, "hidden": true } ]

@bartbutenaers
Copy link
Owner

@Alloc86,
It would be nice if you could jump in here, because I am not familiar with your solution...

I have done this:

  1. Imported the last (simplified) flow from @ninaaa11.

  2. Moved the slider in the dashboard

  3. Then I arrive in the DataReplayStore function, and indeed I see that the message contains no id field (which is expected by this function):

    image

Do you have any idea where this id comes from, and what it should contain? Perhaps my ui-svg node generates it (in other cases), by I can't remember at the moment...

Thanks!!

@Alloc86
Copy link

Alloc86 commented Oct 16, 2023

The id has to be assigned manually by whatever the source of the data is. For example I get most of my data from KNX nodes, so e.g. when the presence detector for my working room sends a status update I assign the id "AzPresence" to that message.
So if it the data is coming from a non-custom source (I often have my own functions anyway so I can set the ID in there) you could add e.g. a change node to set the ID like this:
image
Note that you would do either one of the two options, not both!

@ninaaa11
Copy link

Hello, yes the slider in the dashboard is now saved but the value in the svg is not.

@ninaaa11
Copy link

ninaaa11 commented Nov 6, 2023

Could anyone help with this please

Does my example work for you?

@bartbutenaers
Copy link
Owner

@ninaaa11,

Your flow above did not set an id, so we got an error in the DataReplayStore Function node.
I assume you have now set the id somehow (e.g. via the Change node like @Alloc86 proposed)? Or did you do it another way perhaps?
Can you update your (simplied) flow above, so the id is set.
Then I ''might' be able to reproduce your issue.

@ninaaa11
Copy link

ninaaa11 commented Nov 9, 2023

Hi,

[ { "id": "d566a75c6044914d", "type": "tab", "label": "1_1_2_PUFER", "disabled": false, "info": "", "env": [] }, { "id": "e2b227538981e36d", "type": "group", "z": "d566a75c6044914d", "style": { "stroke": "#999999", "stroke-opacity": "1", "fill": "none", "fill-opacity": "1", "label": true, "label-position": "nw", "color": "#a4a4a4" }, "nodes": [ "09ec2e88ca7f63e0" ], "x": 1894, "y": 619, "w": 272, "h": 82 }, { "id": "8ff802424563ca49", "type": "function", "z": "d566a75c6044914d", "name": "Puffer_unten_Temp", "func": "\n\nvar temperature = msg.payload;\nvar factor = msg.payload/ 50;\n\n\n\nmsg.payload= [{\n \"command\": \"update_text\",\n \"selector\": \"#unten_temp\",\n \"textContent\": temperature + \"°C\"\n}]\n\nreturn msg;\n", "outputs": 1, "timeout": "", "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 1150, "y": 480, "wires": [ [ "d02c0dc3238275ef" ] ] }, { "id": "09ec2e88ca7f63e0", "type": "ui_svg_graphics", "z": "d566a75c6044914d", "g": "e2b227538981e36d", "group": "a31dba0162f486f6", "order": 3, "width": 25, "height": 7, "svgString": "<svg version=\"1.1\" id=\"svg9\" width=\"1200\" height=\"400\" viewBox=\"0 0 200 400\" sodipodi:docname=\"ggg.svg\" inkscape:version=\"1.1.2 (b8e25be833, 2022-02-05)\" xmlns:inkscape=\"http://www.inkscape.org/namespaces/inkscape\" xmlns:sodipodi=\"http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns=\"http://www.w3.org/2000/svg\" preserveAspectRatio=\"xMidYMid meet\">\n <defs id=\"defs13\"/>\n <sodipodi:namedview id=\"namedview11\" pagecolor=\"#ffffff\" bordercolor=\"#666666\" borderopacity=\"1.0\" inkscape:pageshadow=\"2\" inkscape:pageopacity=\"0.0\" inkscape:pagecheckerboard=\"0\" showgrid=\"false\" inkscape:zoom=\"1.380626\" inkscape:cx=\"430.60177\" inkscape:cy=\"201.72009\" inkscape:window-width=\"1920\" inkscape:window-height=\"1003\" inkscape:window-x=\"-9\" inkscape:window-y=\"-9\" inkscape:window-maximized=\"1\" inkscape:current-layer=\"g15\" inkscape:snap-text-baseline=\"true\"/>\n <g inkscape:groupmode=\"layer\" inkscape:label=\"Image\" id=\"g15\">\n\n \n\n <g id=\"e1_group\" transform=\"matrix(1, 0, 0, 1, -266.424, -426.045)\">\n \n \n \n \n </g>\n \n\n \n\n \n\n \n\n\n\n\n\n\n \n\n \n\n\n <text xml:space=\"preserve\" style=\"font-size:15px;line-height:1.25;font-family:AngsanaUPC;-inkscape-font-specification:'AngsanaUPC, Normal';font-variant-ligatures:none;font-weight:bold\" x=\"464.8024\" y=\"37.301922\" id=\"text29880\" transform=\"matrix(0.979061, 0, 0, 1.02636, -232.391, 110.967)\">\n \n </text>\n <text xml:space=\"preserve\" style=\"font-size:12px;line-height:1.25;font-family:AngsanaUPC;-inkscape-font-specification:'AngsanaUPC, Normal';font-variant-ligatures:none;font-weight:bold\" x=\"461.85541\" y=\"314.00134\" id=\"text29880-8\" transform=\"matrix(1, 0, 0, 1, -229.879, -113.903)\">\n \n </text>\n <text xml:space=\"preserve\" style=\"font-size:12px;line-height:1.25;font-family:AngsanaUPC;-inkscape-font-specification:'AngsanaUPC, Normal';font-variant-ligatures:none;font-weight:bold\" x=\"466.453\" y=\"110.05737\" id=\"text29880-2\" transform=\"matrix(1, 0, 0, 1, -229.879, -113.903)\">\n \n </text>\n\n\n\n \n\n </g>\n\n <rect id=\"svgEditorBackground\" x=\"-2.8972366\" y=\"18.832037\" width=\"200\" height=\"400\" style=\"fill:none;stroke:none\"/>\n <defs id=\"defs13\"/>\n <sodipodi:namedview id=\"namedview11\" pagecolor=\"#ffffff\" bordercolor=\"#666666\" borderopacity=\"1.0\" inkscape:pageshadow=\"2\" inkscape:pageopacity=\"0.0\" inkscape:pagecheckerboard=\"0\" showgrid=\"false\" inkscape:zoom=\"0.690313\" inkscape:cx=\"412.13189\" inkscape:cy=\"288.99934\" inkscape:window-width=\"1920\" inkscape:window-height=\"1003\" inkscape:window-x=\"-9\" inkscape:window-y=\"-9\" inkscape:window-maximized=\"1\" inkscape:current-layer=\"g15\" inkscape:snap-text-baseline=\"true\"/>\n <g inkscape:groupmode=\"layer\" inkscape:label=\"Image\" id=\"g15\">\n\n\n\n\n\n </g>\n \n\n \n <text id=\"unten_temp\" x=\"598.055\" y=\"-462.778\" fill=\"#0000ff\" font-size=\"25px\" text-anchor=\"middle\" alignment-baseline=\"middle\" font-weight=\"bold\" transform=\"matrix(1, 0, 0, 1, -306.011, 688.537)\">0°C</text>\n <text id=\"Betriebsart\" x=\"-189.14552\" y=\"34.20179\" fill=\"#0000ff\" font-size=\"13.4989px\" text-anchor=\"middle\" alignment-baseline=\"middle\" font-weight=\"bold\" transform=\"matrix(1.25936, 0, 0, 0.794051, 118.807, 446.427)\" style=\"stroke-width:0.539955\"/>\n\n <g id=\"_Task_PathTriangleDigitTask\"/>\n \n \n \n\n <rect id=\"svgEditorBackground\" x=\"-2.8972366\" y=\"18.832037\" width=\"200\" height=\"400\" style=\"fill:none;stroke:none\"/>\n <defs id=\"defs13\"/>\n <sodipodi:namedview id=\"namedview11\" pagecolor=\"#ffffff\" bordercolor=\"#666666\" borderopacity=\"1.0\" inkscape:pageshadow=\"2\" inkscape:pageopacity=\"0.0\" inkscape:pagecheckerboard=\"0\" showgrid=\"false\" inkscape:zoom=\"0.690313\" inkscape:cx=\"412.13189\" inkscape:cy=\"288.99934\" inkscape:window-width=\"1920\" inkscape:window-height=\"1003\" inkscape:window-x=\"-9\" inkscape:window-y=\"-9\" inkscape:window-maximized=\"1\" inkscape:current-layer=\"g15\" inkscape:snap-text-baseline=\"true\"/>\n <g inkscape:groupmode=\"layer\" inkscape:label=\"Image\" id=\"g15\">\n\n\n\n \n\n\n\n </g>\n <text id=\"mitte_temp\" x=\"29.3446\" y=\"115.829\" fill=\"#0000ff\" font-size=\"25px\" text-anchor=\"middle\" alignment-baseline=\"middle\" font-weight=\"bold\" transform=\"matrix(1, 0, 0, 1, 246.711, 102.307)\"/>\n \n \n \n \n\n <g id=\"_Task_PathTriangleDigitTask\"/>\n\n\n\n <text id=\"e3_text\" x=\"-162.546\" y=\"-84.6876\" fill=\"#0000ff\" font-size=\"13.4989px\" text-anchor=\"middle\" alignment-baseline=\"middle\" font-weight=\"bold\" transform=\"matrix(1.25936, 0, 0, 0.794051, 118.807, 446.427)\" style=\"stroke-width:0.539955\"/>\n \n \n \n \n \n \n\n\n\n <defs>\n <linearGradient id=\"three-color-gradient\" x1=\"0\" x2=\"0\" y1=\"0\" y2=\"100%\">\n <stop offset=\"0%\" stop-color=\"{{msg.top}}\"/>\n <stop offset=\"50%\" stop-color=\"{{msg.middle}}\"/>\n <stop offset=\"100%\" stop-color=\"{{msg.bottom}}\"/>\n </linearGradient>\n </defs>\n \n \n</svg>", "clickableShapes": [ { "targetId": "#Pumpe_ON", "action": "click", "payload": "Podna", "payloadType": "str", "topic": "Podna" }, { "targetId": "#e4_ON", "action": "click", "payload": "Boiler", "payloadType": "str", "topic": "Boiler" }, { "targetId": "#e6_ON", "action": "click", "payload": "RL", "payloadType": "str", "topic": "RL" } ], "javascriptHandlers": [], "smilAnimations": [], "bindings": [], "showCoordinates": false, "autoFormatAfterEdit": false, "showBrowserErrors": false, "showBrowserEvents": false, "enableJsDebugging": false, "sendMsgWhenLoaded": false, "noClickWhenDblClick": false, "outputField": "payload", "editorUrl": "//drawsvg.org/drawsvg.html", "directory": "", "panning": "disabled", "zooming": "disabled", "panOnlyWhenZoomed": false, "doubleClickZoomEnabled": false, "mouseWheelZoomEnabled": false, "dblClickZoomPercentage": 150, "cssString": "div.ui-svg svg{\n color: var(--nr-dashboard-widgetColor);\n fill: currentColor !important;\n}\ndiv.ui-svg path {\n fill: inherit;\n}", "name": "1_1_2_ZIMA_PUFFER", "x": 2030, "y": 660, "wires": [ [] ] }, { "id": "150478d941e6aac7", "type": "ui_slider", "z": "d566a75c6044914d", "name": "", "label": "slider", "tooltip": "", "group": "a31dba0162f486f6", "order": 2, "width": 0, "height": 0, "passthru": true, "outs": "all", "topic": "topic", "topicType": "msg", "min": 0, "max": 10, "step": 1, "className": "", "x": 910, "y": 480, "wires": [ [ "8ff802424563ca49" ] ] }, { "id": "7a1c92b47194d180", "type": "ui_ui_control", "z": "d566a75c6044914d", "name": "", "events": "all", "x": 1420, "y": 360, "wires": [ [ "7a8eb1c1c0eba7bd" ] ] }, { "id": "d7c4ab76cef0c7b0", "type": "function", "z": "d566a75c6044914d", "name": "DataReplayStore", "func": "if (msg.topic == \"replay\") {\n var temp = global.get(\"messages\");\n Object.entries(temp).forEach(([, val]) => {\n node.send(val)\n });\n\n return;\n}\n\nif (msg.hasOwnProperty(\"id\")\n && typeof msg.id === \"string\"\n && msg.id.length > 0\n && /^[a-zA-Z0-9_]+$/.test(msg.id)) {\n global.set(\"messages.\" + msg.id, msg);\n} else {\n node.warn (\"Msg has no string ID or empty string or contains non alpha-numeric characters:\");\n node.warn (msg);\n}\nreturn msg;\n", "outputs": 1, "timeout": "", "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 1570, "y": 480, "wires": [ [ "09ec2e88ca7f63e0" ] ] }, { "id": "7a8eb1c1c0eba7bd", "type": "function", "z": "d566a75c6044914d", "name": "ReplayOnConnect", "func": "var svgTabName = \"Diagnose\";\nvar replayOnConnect = false;\n\nif (msg.payload != \"connect\" && msg.payload != \"change\") {\n return;\n}\n\nif (msg.payload == \"connect\" && !replayOnConnect) {\n return;\n}\n\nif (msg.payload == \"change\" && msg.name != svgTabName) {\n return;\n}\n\nmsg.topic = \"replay\";\nreturn msg;", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 1610, "y": 360, "wires": [ [ "d7c4ab76cef0c7b0" ] ] }, { "id": "d02c0dc3238275ef", "type": "change", "z": "d566a75c6044914d", "name": "", "rules": [ { "t": "set", "p": "id", "pt": "msg", "to": "myId", "tot": "msg" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 1330, "y": 580, "wires": [ [ "d7c4ab76cef0c7b0" ] ] }, { "id": "a31dba0162f486f6", "type": "ui_group", "name": "ZIMA", "tab": "01469c1d4f16bbe6", "order": 1, "disp": true, "width": "25", "collapse": false, "className": "" }, { "id": "01469c1d4f16bbe6", "type": "ui_tab", "name": "1_1_2_PUFFER", "icon": "dashboard", "order": 4, "disabled": false, "hidden": false } ]

@bartbutenaers
Copy link
Owner

Hi @ninaaa11,

It doesn't happen, but I have to admit I can't get it working. The replayed message looks very good to me: it has the correct socketId, has the correct id, has the correct payload. Then the dashboard framework passes it to socket.io but it never arrives at the client. I have no clue how this can happen...

@bartbutenaers
Copy link
Owner

@ninaaa11,

I got a short moment of illumination...

When you refresh your browser screen, a new client session is started. As a result the Node-RED dashboard framework will start a new socketid for that session (to communicate via socket.io with that session).

The replayed message contains the old socket id, so when you resend it then socket.io has no idea what to do with the message. Because the client session for that old obsolete socketId is not active anymore, the message will be ignored.

The fix was simply to copy the socket id from the input message (i.e. the 'connect' message arriving from the ui-control node) to the replayed message:

image

Hopefully this flow works better for you:

[{"id":"a6873dd18b204117","type":"function","z":"74259cf82ee7a8a3","name":"Puffer_unten_Temp","func":"\n\nvar temperature = msg.payload;\nvar factor = msg.payload/ 50;\n\n\n\nmsg.payload= [{\n    \"command\": \"update_text\",\n    \"selector\": \"#unten_temp\",\n    \"textContent\": temperature + \"°C\"\n}]\n\nmsg.id = \"temp_sensor\"\n\nreturn msg;\n","outputs":1,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[],"x":390,"y":40,"wires":[["9dcbece6bc200ab2"]]},{"id":"999b1ef205adfb1b","type":"ui_svg_graphics","z":"74259cf82ee7a8a3","g":"3c1370244a486c1b","group":"a31dba0162f486f6","order":3,"width":25,"height":7,"svgString":"<svg version=\"1.1\" id=\"svg9\" width=\"1200\" height=\"400\" viewBox=\"0 0 200 400\" sodipodi:docname=\"ggg.svg\" inkscape:version=\"1.1.2 (b8e25be833, 2022-02-05)\" xmlns:inkscape=\"http://www.inkscape.org/namespaces/inkscape\" xmlns:sodipodi=\"http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns=\"http://www.w3.org/2000/svg\" preserveAspectRatio=\"xMidYMid meet\">\n    <defs id=\"defs13\"/>\n    <sodipodi:namedview id=\"namedview11\" pagecolor=\"#ffffff\" bordercolor=\"#666666\" borderopacity=\"1.0\" inkscape:pageshadow=\"2\" inkscape:pageopacity=\"0.0\" inkscape:pagecheckerboard=\"0\" showgrid=\"false\" inkscape:zoom=\"1.380626\" inkscape:cx=\"430.60177\" inkscape:cy=\"201.72009\" inkscape:window-width=\"1920\" inkscape:window-height=\"1003\" inkscape:window-x=\"-9\" inkscape:window-y=\"-9\" inkscape:window-maximized=\"1\" inkscape:current-layer=\"g15\" inkscape:snap-text-baseline=\"true\"/>\n    <g inkscape:groupmode=\"layer\" inkscape:label=\"Image\" id=\"g15\">\n\n        \n\n        <g id=\"e1_group\" transform=\"matrix(1, 0, 0, 1, -266.424, -426.045)\">\n            \n            \n            \n            \n        </g>\n        \n\n        \n\n        \n\n        \n\n\n\n\n\n\n        \n\n        \n\n\n        <text xml:space=\"preserve\" style=\"font-size:15px;line-height:1.25;font-family:AngsanaUPC;-inkscape-font-specification:'AngsanaUPC, Normal';font-variant-ligatures:none;font-weight:bold\" x=\"464.8024\" y=\"37.301922\" id=\"text29880\" transform=\"matrix(0.979061, 0, 0, 1.02636, -232.391, 110.967)\">\n            \n        </text>\n        <text xml:space=\"preserve\" style=\"font-size:12px;line-height:1.25;font-family:AngsanaUPC;-inkscape-font-specification:'AngsanaUPC, Normal';font-variant-ligatures:none;font-weight:bold\" x=\"461.85541\" y=\"314.00134\" id=\"text29880-8\" transform=\"matrix(1, 0, 0, 1, -229.879, -113.903)\">\n            \n        </text>\n        <text xml:space=\"preserve\" style=\"font-size:12px;line-height:1.25;font-family:AngsanaUPC;-inkscape-font-specification:'AngsanaUPC, Normal';font-variant-ligatures:none;font-weight:bold\" x=\"466.453\" y=\"110.05737\" id=\"text29880-2\" transform=\"matrix(1, 0, 0, 1, -229.879, -113.903)\">\n            \n        </text>\n\n\n\n        \n\n    </g>\n\n    <rect id=\"svgEditorBackground\" x=\"-2.8972366\" y=\"18.832037\" width=\"200\" height=\"400\" style=\"fill:none;stroke:none\"/>\n    <defs id=\"defs13\"/>\n    <sodipodi:namedview id=\"namedview11\" pagecolor=\"#ffffff\" bordercolor=\"#666666\" borderopacity=\"1.0\" inkscape:pageshadow=\"2\" inkscape:pageopacity=\"0.0\" inkscape:pagecheckerboard=\"0\" showgrid=\"false\" inkscape:zoom=\"0.690313\" inkscape:cx=\"412.13189\" inkscape:cy=\"288.99934\" inkscape:window-width=\"1920\" inkscape:window-height=\"1003\" inkscape:window-x=\"-9\" inkscape:window-y=\"-9\" inkscape:window-maximized=\"1\" inkscape:current-layer=\"g15\" inkscape:snap-text-baseline=\"true\"/>\n    <g inkscape:groupmode=\"layer\" inkscape:label=\"Image\" id=\"g15\">\n\n\n\n\n\n    </g>\n    \n\n    \n    <text id=\"unten_temp\" x=\"598.055\" y=\"-462.778\" fill=\"#0000ff\" font-size=\"25px\" text-anchor=\"middle\" alignment-baseline=\"middle\" font-weight=\"bold\" transform=\"matrix(1, 0, 0, 1, -306.011, 688.537)\">0°C</text>\n    <text id=\"Betriebsart\" x=\"-189.14552\" y=\"34.20179\" fill=\"#0000ff\" font-size=\"13.4989px\" text-anchor=\"middle\" alignment-baseline=\"middle\" font-weight=\"bold\" transform=\"matrix(1.25936, 0, 0, 0.794051, 118.807, 446.427)\" style=\"stroke-width:0.539955\"/>\n\n    <g id=\"_Task_PathTriangleDigitTask\"/>\n    \n    \n    \n\n    <rect id=\"svgEditorBackground\" x=\"-2.8972366\" y=\"18.832037\" width=\"200\" height=\"400\" style=\"fill:none;stroke:none\"/>\n    <defs id=\"defs13\"/>\n    <sodipodi:namedview id=\"namedview11\" pagecolor=\"#ffffff\" bordercolor=\"#666666\" borderopacity=\"1.0\" inkscape:pageshadow=\"2\" inkscape:pageopacity=\"0.0\" inkscape:pagecheckerboard=\"0\" showgrid=\"false\" inkscape:zoom=\"0.690313\" inkscape:cx=\"412.13189\" inkscape:cy=\"288.99934\" inkscape:window-width=\"1920\" inkscape:window-height=\"1003\" inkscape:window-x=\"-9\" inkscape:window-y=\"-9\" inkscape:window-maximized=\"1\" inkscape:current-layer=\"g15\" inkscape:snap-text-baseline=\"true\"/>\n    <g inkscape:groupmode=\"layer\" inkscape:label=\"Image\" id=\"g15\">\n\n\n\n        \n\n\n\n    </g>\n    <text id=\"mitte_temp\" x=\"29.3446\" y=\"115.829\" fill=\"#0000ff\" font-size=\"25px\" text-anchor=\"middle\" alignment-baseline=\"middle\" font-weight=\"bold\" transform=\"matrix(1, 0, 0, 1, 246.711, 102.307)\"/>\n    \n    \n    \n    \n\n    <g id=\"_Task_PathTriangleDigitTask\"/>\n\n\n\n    <text id=\"e3_text\" x=\"-162.546\" y=\"-84.6876\" fill=\"#0000ff\" font-size=\"13.4989px\" text-anchor=\"middle\" alignment-baseline=\"middle\" font-weight=\"bold\" transform=\"matrix(1.25936, 0, 0, 0.794051, 118.807, 446.427)\" style=\"stroke-width:0.539955\"/>\n    \n    \n    \n    \n    \n    \n\n\n\n    <defs>\n        <linearGradient id=\"three-color-gradient\" x1=\"0\" x2=\"0\" y1=\"0\" y2=\"100%\">\n            <stop offset=\"0%\" stop-color=\"{{msg.top}}\"/>\n            <stop offset=\"50%\" stop-color=\"{{msg.middle}}\"/>\n            <stop offset=\"100%\" stop-color=\"{{msg.bottom}}\"/>\n        </linearGradient>\n    </defs>\n    \n    \n</svg>","clickableShapes":[{"targetId":"#Pumpe_ON","action":"click","payload":"Podna","payloadType":"str","topic":"Podna"},{"targetId":"#e4_ON","action":"click","payload":"Boiler","payloadType":"str","topic":"Boiler"},{"targetId":"#e6_ON","action":"click","payload":"RL","payloadType":"str","topic":"RL"}],"javascriptHandlers":[],"smilAnimations":[],"bindings":[],"showCoordinates":false,"autoFormatAfterEdit":false,"showBrowserErrors":false,"showBrowserEvents":false,"enableJsDebugging":false,"sendMsgWhenLoaded":false,"noClickWhenDblClick":false,"outputField":"payload","editorUrl":"//drawsvg.org/drawsvg.html","directory":"","panning":"disabled","zooming":"disabled","panOnlyWhenZoomed":false,"doubleClickZoomEnabled":false,"mouseWheelZoomEnabled":false,"dblClickZoomPercentage":150,"cssString":"div.ui-svg svg{\n    color: var(--nr-dashboard-widgetColor);\n    fill: currentColor !important;\n}\ndiv.ui-svg path {\n    fill: inherit;\n}","name":"1_1_2_ZIMA_PUFFER","x":890,"y":140,"wires":[[]]},{"id":"656fba2278163e98","type":"ui_slider","z":"74259cf82ee7a8a3","name":"","label":"slider","tooltip":"","group":"a31dba0162f486f6","order":2,"width":0,"height":0,"passthru":true,"outs":"all","topic":"topic","topicType":"msg","min":0,"max":10,"step":1,"className":"","x":190,"y":40,"wires":[["a6873dd18b204117"]]},{"id":"5dcd18dba70c3b98","type":"ui_ui_control","z":"74259cf82ee7a8a3","name":"","events":"all","x":200,"y":140,"wires":[["5808cc658ea40111"]]},{"id":"9dcbece6bc200ab2","type":"function","z":"74259cf82ee7a8a3","name":"DataReplayStore","func":"if (msg.topic == \"replay\") {\n    let messages = global.get(\"messages\") || {};\n    let keys = Object.keys(messages);\n\n    // Resend all messages (for all id's)\n    for(let i = 0; i < keys.length; i++) {\n        let key = keys[i];\n        debugger;\n        let clonedMsg = RED.util.cloneMessage(messages[key]);\n        clonedMsg.socketid = msg.socketid\n        \n        node.send(clonedMsg);\n    }\n\n    node.status({fill:\"blue\",shape:\"dot\",text:\"replayed (\" + keys.length + \")\"});\n}\nelse {\n    if (msg.hasOwnProperty(\"id\")\n            && typeof msg.id === \"string\"\n            && msg.id.length > 0\n            && /^[a-zA-Z0-9_]+$/.test(msg.id)) {\n        let messages = global.get(\"messages\") || {};\n        messages[msg.id] = msg;\n        // Store the (last) message for a specified id\n        global.set(\"messages\", messages);\n        let keys = Object.keys(messages);\n-\n        node.status({fill:\"blue\",shape:\"dot\",text:\"stored '\" + msg.id + \"' (\" + keys.length + \")\"});\n    }\n    else {\n        node.warn (\"Provide a msg.id (string of alpha-numeric and numeric characters)\");\n        node.warn (msg);\n    }\n\n    // Passthrough of the input message\n    return msg;\n}","outputs":1,"timeout":"","noerr":0,"initialize":"// Code added here will be run once\n// whenever the node is started.\nnode.status({fill:\"blue\",shape:\"ring\",text:\"inittialized (0)\"});","finalize":"","libs":[],"x":610,"y":140,"wires":[["999b1ef205adfb1b"]]},{"id":"5808cc658ea40111","type":"function","z":"74259cf82ee7a8a3","name":"ReplayOnConnect","func":"// Replay messages when connected (e.g. browser screen refreshed)\nif (msg.payload == \"connect\") {\n    msg.topic = \"replay\";\n    return msg;\n}\n\nif (msg.payload == \"change\" && msg.name == \"svgTabName\") {\n    msg.topic = \"replay\";\n    return msg;\n}","outputs":1,"timeout":"","noerr":0,"initialize":"// Code added here will be run once\n// whenever the node is started.\nnode.status({fill:\"blue\",shape:\"ring\",text:\"inittialized\"});","finalize":"","libs":[],"x":390,"y":140,"wires":[["9dcbece6bc200ab2"]]},{"id":"a31dba0162f486f6","type":"ui_group","name":"ZIMA","tab":"01469c1d4f16bbe6","order":1,"disp":true,"width":"25","collapse":false,"className":""},{"id":"01469c1d4f16bbe6","type":"ui_tab","name":"1_1_2_PUFFER","icon":"dashboard","order":4,"disabled":false,"hidden":false}]

@ninaaa11
Copy link

@bartbutenaers

Thank you
Unfortunately I don't understand much of what you wrote.
I have a few pumps and other visualized elements, I would like to visualize them and have the same status on all clients.

I tried your example and from the looks of it it is only applicable specifically to this example and cannot be reproduced.

At least not without further programming

[ { "id": "fc07fa0e875fef3e", "type": "tab", "label": "1_1_2_PUFER", "disabled": false, "info": "", "env": [] }, { "id": "44ffd383d9e2db89", "type": "group", "z": "fc07fa0e875fef3e", "style": { "stroke": "#999999", "stroke-opacity": "1", "fill": "none", "fill-opacity": "1", "label": true, "label-position": "nw", "color": "#a4a4a4" }, "nodes": [], "x": 1894, "y": 879, "w": 40, "h": 40 }, { "id": "613b7fb700ccb092", "type": "ui_svg_graphics", "z": "fc07fa0e875fef3e", "group": "e493bd4a0b06bea0", "order": 4, "width": 26, "height": 7, "svgString": "<svg version=\"1.1\" id=\"svg9\" width=\"1200\" height=\"400\" viewBox=\"0 0 200 400\" sodipodi:docname=\"ggg.svg\" inkscape:version=\"1.1.2 (b8e25be833, 2022-02-05)\" xmlns:inkscape=\"http://www.inkscape.org/namespaces/inkscape\" xmlns:sodipodi=\"http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns=\"http://www.w3.org/2000/svg\" preserveAspectRatio=\"xMidYMid meet\">\n <defs id=\"defs13\"/>\n <sodipodi:namedview id=\"namedview11\" pagecolor=\"#ffffff\" bordercolor=\"#666666\" borderopacity=\"1.0\" inkscape:pageshadow=\"2\" inkscape:pageopacity=\"0.0\" inkscape:pagecheckerboard=\"0\" showgrid=\"false\" inkscape:zoom=\"1.380626\" inkscape:cx=\"430.60177\" inkscape:cy=\"201.72009\" inkscape:window-width=\"1920\" inkscape:window-height=\"1003\" inkscape:window-x=\"-9\" inkscape:window-y=\"-9\" inkscape:window-maximized=\"1\" inkscape:current-layer=\"g15\" inkscape:snap-text-baseline=\"true\"/>\n <g inkscape:groupmode=\"layer\" inkscape:label=\"Image\" id=\"g15\">\n\n \n\n <g id=\"e1_group\" transform=\"matrix(1, 0, 0, 1, -266.424, -426.045)\">\n \n <path d=\"M -238.26824 33.754362 M -256.73024 72.391362 M -258.0621246219513 -20.871251802595523 z\"\n style=\"fill:#808080;stroke:#000000;stroke-width:1px\" id=\"Pumpe_ON\"\n transform=\"matrix(1, 0, 0, 1, -248.151, -10.3597)\" />\n \n \n </g>\n \n\n \n\n \n\n \n\n\n\n\n\n\n \n\n \n\n\n \n <text xml:space=\"preserve\" style=\"font-size:12px;line-height:1.25;font-family:AngsanaUPC;-inkscape-font-specification:'AngsanaUPC, Normal';font-variant-ligatures:none;font-weight:bold\" x=\"461.85541\" y=\"314.00134\" id=\"text29880-8\" transform=\"matrix(1, 0, 0, 1, -229.879, -113.903)\"/>\n <text xml:space=\"preserve\" style=\"font-size:12px;line-height:1.25;font-family:AngsanaUPC;-inkscape-font-specification:'AngsanaUPC, Normal';font-variant-ligatures:none;font-weight:bold\" x=\"466.453\" y=\"110.05737\" id=\"text29880-2\" transform=\"matrix(1, 0, 0, 1, -229.879, -113.903)\">\n \n </text>\n\n\n\n \n\n <text xml:space=\"preserve\" style=\"font-size:12px;line-height:1.25;font-family:AngsanaUPC;-inkscape-font-specification:'AngsanaUPC, Normal';font-variant-ligatures:none;font-weight:bold\" x=\"461.85541\" y=\"314.00134\" id=\"e2_text\" transform=\"matrix(1, 0, 0, 1, -229.879, -113.903)\"/></g>\n\n <rect id=\"svgEditorBackground\" x=\"-2.8972366\" y=\"18.832037\" width=\"200\" height=\"400\" style=\"fill: none; stroke: none;\"/>\n <defs id=\"defs13\"/>\n <sodipodi:namedview id=\"namedview11\" pagecolor=\"#ffffff\" bordercolor=\"#666666\" borderopacity=\"1.0\" inkscape:pageshadow=\"2\" inkscape:pageopacity=\"0.0\" inkscape:pagecheckerboard=\"0\" showgrid=\"false\" inkscape:zoom=\"0.690313\" inkscape:cx=\"412.13189\" inkscape:cy=\"288.99934\" inkscape:window-width=\"1920\" inkscape:window-height=\"1003\" inkscape:window-x=\"-9\" inkscape:window-y=\"-9\" inkscape:window-maximized=\"1\" inkscape:current-layer=\"g15\" inkscape:snap-text-baseline=\"true\"/>\n <g inkscape:groupmode=\"layer\" inkscape:label=\"Image\" id=\"g15\">\n\n\n\n\n\n </g>\n \n\n \n <text id=\"unten_temp\" x=\"681.801\" y=\"-511.503\" fill=\"#0000ff\" font-size=\"25px\" text-anchor=\"middle\" alignment-baseline=\"middle\" font-weight=\"bold\" transform=\"matrix(1, 0, 0, 1, -306.011, 688.537)\">0°C</text>\n <text id=\"Betriebsart\" x=\"-189.14552\" y=\"34.20179\" fill=\"#0000ff\" font-size=\"13.4989px\" text-anchor=\"middle\" alignment-baseline=\"middle\" font-weight=\"bold\" transform=\"matrix(1.25936, 0, 0, 0.794051, 118.807, 446.427)\" style=\"stroke-width:0.539955\"/>\n\n <g id=\"_Task_PathTriangleDigitTask\"/>\n \n \n \n\n <rect id=\"svgEditorBackground\" x=\"-2.8972366\" y=\"18.832037\" width=\"200\" height=\"400\" style=\"fill:none;stroke:none\"/>\n <defs id=\"defs13\"/>\n <sodipodi:namedview id=\"namedview11\" pagecolor=\"#ffffff\" bordercolor=\"#666666\" borderopacity=\"1.0\" inkscape:pageshadow=\"2\" inkscape:pageopacity=\"0.0\" inkscape:pagecheckerboard=\"0\" showgrid=\"false\" inkscape:zoom=\"0.690313\" inkscape:cx=\"412.13189\" inkscape:cy=\"288.99934\" inkscape:window-width=\"1920\" inkscape:window-height=\"1003\" inkscape:window-x=\"-9\" inkscape:window-y=\"-9\" inkscape:window-maximized=\"1\" inkscape:current-layer=\"g15\" inkscape:snap-text-baseline=\"true\"/>\n <g inkscape:groupmode=\"layer\" inkscape:label=\"Image\" id=\"g15\">\n\n\n\n \n\n\n\n </g>\n \n \n \n \n \n\n <g id=\"_Task_PathTriangleDigitTask\"/>\n\n\n\n <text id=\"e3_text\" x=\"-162.546\" y=\"-84.6876\" fill=\"#0000ff\" font-size=\"13.4989px\" text-anchor=\"middle\" alignment-baseline=\"middle\" font-weight=\"bold\" transform=\"matrix(1.25936, 0, 0, 0.794051, 118.807, 446.427)\" style=\"stroke-width:0.539955\"/>\n \n \n \n \n \n \n\n\n\n <defs>\n <linearGradient id=\"three-color-gradient\" x1=\"0\" x2=\"0\" y1=\"0\" y2=\"100%\">\n <stop offset=\"0%\" stop-color=\"{{msg.top}}\"/>\n <stop offset=\"50%\" stop-color=\"{{msg.middle}}\"/>\n <stop offset=\"100%\" stop-color=\"{{msg.bottom}}\"/>\n </linearGradient>\n </defs>\n \n \n<text id=\"oben_temp\" x=\"559.228\" y=\"-560.228\" fill=\"#0000ff\" font-size=\"25px\" text-anchor=\"middle\" alignment-baseline=\"middle\" font-weight=\"bold\" transform=\"matrix(1, 0, 0, 1, -306.011, 688.537)\">0°C</text><text id=\"mitte_temp\" x=\"739.662\" y=\"-582.306\" fill=\"#0000ff\" font-size=\"25px\" text-anchor=\"middle\" alignment-baseline=\"middle\" font-weight=\"bold\" transform=\"matrix(1, 0, 0, 1, -306.011, 688.537)\">0°C</text><path d=\"M230.225,250.019l-31.214,35.021l54.054,0Z\" style=\"fill:white;stroke:black;stroke-width:1px\" id=\"Pumpe_ON\"/></svg>", "clickableShapes": [ { "targetId": "#Pumpe_ON", "action": "click", "payload": "Podna", "payloadType": "str", "topic": "Podna" }, { "targetId": "#e4_ON", "action": "click", "payload": "Boiler", "payloadType": "str", "topic": "Boiler" }, { "targetId": "#e6_ON", "action": "click", "payload": "RL", "payloadType": "str", "topic": "RL" } ], "javascriptHandlers": [], "smilAnimations": [], "bindings": [], "showCoordinates": false, "autoFormatAfterEdit": false, "showBrowserErrors": false, "showBrowserEvents": false, "enableJsDebugging": false, "sendMsgWhenLoaded": false, "noClickWhenDblClick": false, "outputField": "payload", "editorUrl": "//drawsvg.org/drawsvg.html", "directory": "", "panning": "disabled", "zooming": "disabled", "panOnlyWhenZoomed": false, "doubleClickZoomEnabled": false, "mouseWheelZoomEnabled": false, "dblClickZoomPercentage": 150, "cssString": "div.ui-svg svg{\n color: var(--nr-dashboard-widgetColor);\n fill: currentColor !important;\n}\ndiv.ui-svg path {\n fill: inherit;\n}", "name": "1_1_2_ZIMA_PUFFER", "x": 1750, "y": 120, "wires": [ [] ] }, { "id": "d727356c13fe7c46", "type": "function", "z": "fc07fa0e875fef3e", "name": "Puffer_mitte_Temp", "func": "\n\nvar temperature = msg.payload;\nvar factor = msg.payload/ 50;\n\n\n\nmsg.payload= [{\n \"command\": \"update_text\",\n \"selector\": \"#mitte_temp\",\n \"textContent\": temperature + \"°C\"\n}]\n\nmsg.id = \"mitte_sensor\"\n\nreturn msg;\n", "outputs": 1, "timeout": "", "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 1210, "y": 180, "wires": [ [ "cafabf4669d7f71e" ] ] }, { "id": "23312d1a7c9029c9", "type": "ui_slider", "z": "fc07fa0e875fef3e", "name": "", "label": "slider", "tooltip": "", "group": "e493bd4a0b06bea0", "order": 1, "width": 0, "height": 0, "passthru": true, "outs": "all", "topic": "topic", "topicType": "msg", "min": 0, "max": 10, "step": 1, "className": "", "x": 1030, "y": 180, "wires": [ [ "d727356c13fe7c46" ] ] }, { "id": "ca70965f8ce77e65", "type": "ui_ui_control", "z": "fc07fa0e875fef3e", "name": "", "events": "all", "x": 1000, "y": 100, "wires": [ [ "cf3dd7c63e66d271" ] ] }, { "id": "cafabf4669d7f71e", "type": "function", "z": "fc07fa0e875fef3e", "name": "DataReplayStore", "func": "if (msg.topic == \"replay\") {\n let messages = global.get(\"messages\") || {};\n let keys = Object.keys(messages);\n\n // Resend all messages (for all id's)\n for(let i = 0; i < keys.length; i++) {\n let key = keys[i];\n debugger;\n let clonedMsg = RED.util.cloneMessage(messages[key]);\n clonedMsg.socketid = msg.socketid\n \n node.send(clonedMsg);\n }\n\n node.status({fill:\"blue\",shape:\"dot\",text:\"replayed (\" + keys.length + \")\"});\n}\nelse {\n if (msg.hasOwnProperty(\"id\")\n && typeof msg.id === \"string\"\n && msg.id.length > 0\n && /^[a-zA-Z0-9_]+$/.test(msg.id)) {\n let messages = global.get(\"messages\") || {};\n messages[msg.id] = msg;\n // Store the (last) message for a specified id\n global.set(\"messages\", messages);\n let keys = Object.keys(messages);\n-\n node.status({fill:\"blue\",shape:\"dot\",text:\"stored '\" + msg.id + \"' (\" + keys.length + \")\"});\n }\n else {\n node.warn (\"Provide a msg.id (string of alpha-numeric and numeric characters)\");\n node.warn (msg);\n }\n\n // Passthrough of the input message\n return msg;\n}", "outputs": 1, "timeout": "", "noerr": 0, "initialize": "// Code added here will be run once\n// whenever the node is started.\nnode.status({fill:\"blue\",shape:\"ring\",text:\"inittialized (0)\"});", "finalize": "", "libs": [], "x": 1770, "y": 240, "wires": [ [ "613b7fb700ccb092" ] ] }, { "id": "cf3dd7c63e66d271", "type": "function", "z": "fc07fa0e875fef3e", "name": "ReplayOnConnect", "func": "// Replay messages when connected (e.g. browser screen refreshed)\nif (msg.payload == \"connect\") {\n msg.topic = \"replay\";\n return msg;\n}\n\nif (msg.payload == \"change\" && msg.name == \"svgTabName\") {\n msg.topic = \"replay\";\n return msg;\n}", "outputs": 1, "timeout": "", "noerr": 0, "initialize": "// Code added here will be run once\n// whenever the node is started.\nnode.status({fill:\"blue\",shape:\"ring\",text:\"inittialized\"});", "finalize": "", "libs": [], "x": 1190, "y": 100, "wires": [ [ "cafabf4669d7f71e" ] ] }, { "id": "2c5cbe522c355bbb", "type": "function", "z": "fc07fa0e875fef3e", "name": "Puffer_unten_Temp", "func": "\n\nvar temperature = msg.payload;\nvar factor = msg.payload/ 50;\n\n\n\nmsg.payload= [{\n \"command\": \"update_text\",\n \"selector\": \"#unten_temp\",\n \"textContent\": temperature + \"°C\"\n}]\n\nmsg.id = \"unten_sensor\"\n\nreturn msg;\n", "outputs": 1, "timeout": "", "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 1210, "y": 240, "wires": [ [ "cafabf4669d7f71e" ] ] }, { "id": "9fc87adaf5daa98e", "type": "ui_slider", "z": "fc07fa0e875fef3e", "name": "", "label": "slider", "tooltip": "", "group": "e493bd4a0b06bea0", "order": 2, "width": 0, "height": 0, "passthru": true, "outs": "all", "topic": "topic", "topicType": "msg", "min": 0, "max": 10, "step": 1, "className": "", "x": 1030, "y": 240, "wires": [ [ "2c5cbe522c355bbb" ] ] }, { "id": "e3fda923433bd29e", "type": "function", "z": "fc07fa0e875fef3e", "name": "Puffer_oben_Temp", "func": "\n\nvar temperature = msg.payload;\nvar factor = msg.payload/ 50;\n\n\n\nmsg.payload= [{\n \"command\": \"update_text\",\n \"selector\": \"#oben_temp\",\n \"textContent\": temperature + \"°C\"\n}]\n\nmsg.id = \"oben_sensor\"\n\nreturn msg;\n", "outputs": 1, "timeout": "", "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 1210, "y": 300, "wires": [ [ "cafabf4669d7f71e" ] ] }, { "id": "e11d24b047329624", "type": "ui_slider", "z": "fc07fa0e875fef3e", "name": "", "label": "slider", "tooltip": "", "group": "e493bd4a0b06bea0", "order": 3, "width": 0, "height": 0, "passthru": true, "outs": "all", "topic": "topic", "topicType": "msg", "min": 0, "max": 10, "step": 1, "className": "", "x": 1030, "y": 300, "wires": [ [ "e3fda923433bd29e" ] ] }, { "id": "e493bd4a0b06bea0", "type": "ui_group", "name": "Group 1", "tab": "9fc6bf4953b3a419", "order": 1, "disp": true, "width": 26 }, { "id": "9fc6bf4953b3a419", "type": "ui_tab", "name": "Tab 1", "icon": "dashboard", "order": 1 } ]

@bartbutenaers
Copy link
Owner

@ninaaa11,
Hmm this is indeed a very tricky issue.
I am not fully understanding the problem, but I think I found a workaround.
But it is also not clear to me why it works for other users.

I will give you some detailed explanation, which hopefully helps you a bit during troubleshooting...
This is why I think it fails:

  1. You see the sliders and svg drawing in your dashboard. Your browser session has currently socketId A.
  2. You slide the 3 sliders, so 3 messages arrive in your Node-RED flow. All these messages contain socketId A.
  3. Those 3 messages are being stored in the DataReplayStore function node.
  4. You refresh your dashboard browser screen. Your new browser session will get a new socketId B.
  5. As a result the ui-control node sends a connect message to the DataReplayStore function node, which contains the new socketId B.
  6. The DataReplayStore function node will replay (i.e. resend) all the 3 old messages, which still contains the OLD socketId A. So the dashboard framework will send these messages (via a socket.io websocket) to the old dashboard session.
    • So these messages will never arrive in your new dashboard session, which means they are lost.
    • Therefore I had provided you a fix yesterday: before resending the old messages, I replaced their old socketId A by the new socketId B (which I get from the connect message):
      clonedMsg.socketid = msg.socketid;
      
      That way the messages will be send to the dashboard to socketId B, i.e. the new dashboard session.
  7. But NONE of your 3 resended messages arrived in your dashboard (via socketio on socketId B). I have no clue why, but I 'assume' they arrive to fast, i.e. when socketio is not fully aware of the new dashboard session. So socketio does not know what to do with messages that contain the new socketId B. But perhaps the problem is located not inside socketio, but in the dashboard framework itself...
  8. However at a refresh, the dashboard framework always resends the LAST message. As a result, the value of the last slider that you have slided will be resend. So only 1 of the 3 temperature values will be updated. So this is NOT by 1 of your 3 resended messages, but by the dashboard's own last-message-replay-mechanism.
    BTW I really hate that mechanism, because it has given me a LOT of headaches in the past...

What I have done tonight, is simply delaying the messages before resending them:

setTimeout(() => {
   node.send(clonedMsg);
}, 500);

So I only send the messages after 500 milliseconds (= 0.5 second). Then it works fine for me. If I set a very small delay value (near to 0) then it fails, and when I set a larger value (e.g. 1 second) then you will clearly see the delay in your drawing (which is annoying).

Here is your flow updated with the delayed message sending:

[{"id":"613b7fb700ccb092","type":"ui_svg_graphics","z":"fc07fa0e875fef3e","group":"e493bd4a0b06bea0","order":4,"width":26,"height":7,"svgString":"<svg version=\"1.1\" id=\"svg9\" width=\"1200\" height=\"400\" viewBox=\"0 0 200 400\" sodipodi:docname=\"ggg.svg\" inkscape:version=\"1.1.2 (b8e25be833, 2022-02-05)\" xmlns:inkscape=\"http://www.inkscape.org/namespaces/inkscape\" xmlns:sodipodi=\"http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns=\"http://www.w3.org/2000/svg\" preserveAspectRatio=\"xMidYMid meet\">\n    <defs id=\"defs13\"/>\n    <sodipodi:namedview id=\"namedview11\" pagecolor=\"#ffffff\" bordercolor=\"#666666\" borderopacity=\"1.0\" inkscape:pageshadow=\"2\" inkscape:pageopacity=\"0.0\" inkscape:pagecheckerboard=\"0\" showgrid=\"false\" inkscape:zoom=\"1.380626\" inkscape:cx=\"430.60177\" inkscape:cy=\"201.72009\" inkscape:window-width=\"1920\" inkscape:window-height=\"1003\" inkscape:window-x=\"-9\" inkscape:window-y=\"-9\" inkscape:window-maximized=\"1\" inkscape:current-layer=\"g15\" inkscape:snap-text-baseline=\"true\"/>\n    <g inkscape:groupmode=\"layer\" inkscape:label=\"Image\" id=\"g15\">\n\n        \n\n        <g id=\"e1_group\" transform=\"matrix(1, 0, 0, 1, -266.424, -426.045)\">\n            \n                <path d=\"M -238.26824 33.754362 M -256.73024 72.391362 M -258.0621246219513 -20.871251802595523 z\"\n                    style=\"fill:#808080;stroke:#000000;stroke-width:1px\" id=\"Pumpe_ON\"\n                    transform=\"matrix(1, 0, 0, 1, -248.151, -10.3597)\" />\n            \n            \n        </g>\n        \n\n        \n\n        \n\n        \n\n\n\n\n\n\n        \n\n        \n\n\n        \n        <text xml:space=\"preserve\" style=\"font-size:12px;line-height:1.25;font-family:AngsanaUPC;-inkscape-font-specification:'AngsanaUPC, Normal';font-variant-ligatures:none;font-weight:bold\" x=\"461.85541\" y=\"314.00134\" id=\"text29880-8\" transform=\"matrix(1, 0, 0, 1, -229.879, -113.903)\"/>\n        <text xml:space=\"preserve\" style=\"font-size:12px;line-height:1.25;font-family:AngsanaUPC;-inkscape-font-specification:'AngsanaUPC, Normal';font-variant-ligatures:none;font-weight:bold\" x=\"466.453\" y=\"110.05737\" id=\"text29880-2\" transform=\"matrix(1, 0, 0, 1, -229.879, -113.903)\">\n            \n        </text>\n\n\n\n        \n\n    <text xml:space=\"preserve\" style=\"font-size:12px;line-height:1.25;font-family:AngsanaUPC;-inkscape-font-specification:'AngsanaUPC, Normal';font-variant-ligatures:none;font-weight:bold\" x=\"461.85541\" y=\"314.00134\" id=\"e2_text\" transform=\"matrix(1, 0, 0, 1, -229.879, -113.903)\"/></g>\n\n    <rect id=\"svgEditorBackground\" x=\"-2.8972366\" y=\"18.832037\" width=\"200\" height=\"400\" style=\"fill: none; stroke: none;\"/>\n    <defs id=\"defs13\"/>\n    <sodipodi:namedview id=\"namedview11\" pagecolor=\"#ffffff\" bordercolor=\"#666666\" borderopacity=\"1.0\" inkscape:pageshadow=\"2\" inkscape:pageopacity=\"0.0\" inkscape:pagecheckerboard=\"0\" showgrid=\"false\" inkscape:zoom=\"0.690313\" inkscape:cx=\"412.13189\" inkscape:cy=\"288.99934\" inkscape:window-width=\"1920\" inkscape:window-height=\"1003\" inkscape:window-x=\"-9\" inkscape:window-y=\"-9\" inkscape:window-maximized=\"1\" inkscape:current-layer=\"g15\" inkscape:snap-text-baseline=\"true\"/>\n    <g inkscape:groupmode=\"layer\" inkscape:label=\"Image\" id=\"g15\">\n\n\n\n\n\n    </g>\n    \n\n    \n    <text id=\"unten_temp\" x=\"681.801\" y=\"-511.503\" fill=\"#0000ff\" font-size=\"25px\" text-anchor=\"middle\" alignment-baseline=\"middle\" font-weight=\"bold\" transform=\"matrix(1, 0, 0, 1, -306.011, 688.537)\">0°C</text>\n    <text id=\"Betriebsart\" x=\"-189.14552\" y=\"34.20179\" fill=\"#0000ff\" font-size=\"13.4989px\" text-anchor=\"middle\" alignment-baseline=\"middle\" font-weight=\"bold\" transform=\"matrix(1.25936, 0, 0, 0.794051, 118.807, 446.427)\" style=\"stroke-width:0.539955\"/>\n\n    <g id=\"_Task_PathTriangleDigitTask\"/>\n    \n    \n    \n\n    <rect id=\"svgEditorBackground\" x=\"-2.8972366\" y=\"18.832037\" width=\"200\" height=\"400\" style=\"fill:none;stroke:none\"/>\n    <defs id=\"defs13\"/>\n    <sodipodi:namedview id=\"namedview11\" pagecolor=\"#ffffff\" bordercolor=\"#666666\" borderopacity=\"1.0\" inkscape:pageshadow=\"2\" inkscape:pageopacity=\"0.0\" inkscape:pagecheckerboard=\"0\" showgrid=\"false\" inkscape:zoom=\"0.690313\" inkscape:cx=\"412.13189\" inkscape:cy=\"288.99934\" inkscape:window-width=\"1920\" inkscape:window-height=\"1003\" inkscape:window-x=\"-9\" inkscape:window-y=\"-9\" inkscape:window-maximized=\"1\" inkscape:current-layer=\"g15\" inkscape:snap-text-baseline=\"true\"/>\n    <g inkscape:groupmode=\"layer\" inkscape:label=\"Image\" id=\"g15\">\n\n\n\n        \n\n\n\n    </g>\n    \n    \n    \n    \n    \n\n    <g id=\"_Task_PathTriangleDigitTask\"/>\n\n\n\n    <text id=\"e3_text\" x=\"-162.546\" y=\"-84.6876\" fill=\"#0000ff\" font-size=\"13.4989px\" text-anchor=\"middle\" alignment-baseline=\"middle\" font-weight=\"bold\" transform=\"matrix(1.25936, 0, 0, 0.794051, 118.807, 446.427)\" style=\"stroke-width:0.539955\"/>\n    \n    \n    \n    \n    \n    \n\n\n\n    <defs>\n        <linearGradient id=\"three-color-gradient\" x1=\"0\" x2=\"0\" y1=\"0\" y2=\"100%\">\n            <stop offset=\"0%\" stop-color=\"{{msg.top}}\"/>\n            <stop offset=\"50%\" stop-color=\"{{msg.middle}}\"/>\n            <stop offset=\"100%\" stop-color=\"{{msg.bottom}}\"/>\n        </linearGradient>\n    </defs>\n    \n    \n<text id=\"oben_temp\" x=\"559.228\" y=\"-560.228\" fill=\"#0000ff\" font-size=\"25px\" text-anchor=\"middle\" alignment-baseline=\"middle\" font-weight=\"bold\" transform=\"matrix(1, 0, 0, 1, -306.011, 688.537)\">0°C</text><text id=\"mitte_temp\" x=\"739.662\" y=\"-582.306\" fill=\"#0000ff\" font-size=\"25px\" text-anchor=\"middle\" alignment-baseline=\"middle\" font-weight=\"bold\" transform=\"matrix(1, 0, 0, 1, -306.011, 688.537)\">0°C</text><path d=\"M230.225,250.019l-31.214,35.021l54.054,0Z\" style=\"fill:white;stroke:black;stroke-width:1px\" id=\"Pumpe_ON\"/></svg>","clickableShapes":[{"targetId":"#Pumpe_ON","action":"click","payload":"Podna","payloadType":"str","topic":"Podna"},{"targetId":"#e4_ON","action":"click","payload":"Boiler","payloadType":"str","topic":"Boiler"},{"targetId":"#e6_ON","action":"click","payload":"RL","payloadType":"str","topic":"RL"}],"javascriptHandlers":[],"smilAnimations":[],"bindings":[],"showCoordinates":false,"autoFormatAfterEdit":false,"showBrowserErrors":false,"showBrowserEvents":false,"enableJsDebugging":false,"sendMsgWhenLoaded":false,"noClickWhenDblClick":false,"outputField":"payload","editorUrl":"//drawsvg.org/drawsvg.html","directory":"","panning":"disabled","zooming":"disabled","panOnlyWhenZoomed":false,"doubleClickZoomEnabled":false,"mouseWheelZoomEnabled":false,"dblClickZoomPercentage":150,"cssString":"div.ui-svg svg{\n    color: var(--nr-dashboard-widgetColor);\n    fill: currentColor !important;\n}\ndiv.ui-svg path {\n    fill: inherit;\n}","name":"1_1_2_ZIMA_PUFFER","x":1670,"y":100,"wires":[[]]},{"id":"d727356c13fe7c46","type":"function","z":"fc07fa0e875fef3e","name":"Puffer_mitte_Temp","func":"\n\nvar temperature = msg.payload;\nvar factor = msg.payload/ 50;\n\n\n\nmsg.payload= [{\n    \"command\": \"update_text\",\n    \"selector\": \"#mitte_temp\",\n    \"textContent\": temperature + \"°C\"\n}]\n\nmsg.id = \"mitte_sensor\"\n\nreturn msg;\n","outputs":1,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[],"x":1210,"y":180,"wires":[["cafabf4669d7f71e"]]},{"id":"23312d1a7c9029c9","type":"ui_slider","z":"fc07fa0e875fef3e","name":"","label":"slider","tooltip":"","group":"e493bd4a0b06bea0","order":1,"width":0,"height":0,"passthru":true,"outs":"all","topic":"topic","topicType":"msg","min":0,"max":10,"step":1,"className":"","x":1030,"y":180,"wires":[["d727356c13fe7c46"]]},{"id":"ca70965f8ce77e65","type":"ui_ui_control","z":"fc07fa0e875fef3e","name":"","events":"all","x":1000,"y":100,"wires":[["cf3dd7c63e66d271"]]},{"id":"cafabf4669d7f71e","type":"function","z":"fc07fa0e875fef3e","name":"DataReplayStore","func":"if (msg.topic == \"replay\") {\n    node.warn(\"replaying\")\n    debugger\n    let messages = global.get(\"messages\") || {};\n    let keys = Object.keys(messages);\n\n    // Resend all messages (for all id's)\n    for(let i = 0; i < keys.length; i++) {\n        let key = keys[i];\n        debugger;\n        let clonedMsg = RED.util.cloneMessage(messages[key]);\n        clonedMsg.socketid = msg.socketid;\n        \n        setTimeout(() => {\n            node.send(clonedMsg);\n        }, 500);\n        \n    }\n\n    node.status({fill:\"blue\",shape:\"dot\",text:\"replayed (\" + keys.length + \")\"});\n}\nelse {\n    node.warn(\"not replaying\")\n    if (msg.hasOwnProperty(\"id\")\n            && typeof msg.id === \"string\"\n            && msg.id.length > 0\n            && /^[a-zA-Z0-9_]+$/.test(msg.id)) {\n        let messages = global.get(\"messages\") || {};\n        messages[msg.id] = msg;\n        // Store the (last) message for a specified id\n        global.set(\"messages\", messages);\n        let keys = Object.keys(messages);\n-\n        node.status({fill:\"blue\",shape:\"dot\",text:\"stored '\" + msg.id + \"' (\" + keys.length + \")\"});\n    }\n    else {\n        node.warn (\"Provide a msg.id (string of alpha-numeric and numeric characters)\");\n        node.warn (msg);\n    }\n\n    // Passthrough of the input message\n    return msg;\n}","outputs":1,"timeout":"","noerr":0,"initialize":"// Code added here will be run once\n// whenever the node is started.\nnode.status({fill:\"blue\",shape:\"ring\",text:\"inittialized (0)\"});","finalize":"","libs":[],"x":1430,"y":100,"wires":[["613b7fb700ccb092"]]},{"id":"cf3dd7c63e66d271","type":"function","z":"fc07fa0e875fef3e","name":"ReplayOnConnect","func":"// Replay messages when connected (e.g. browser screen refreshed)\nif (msg.payload == \"connect\") {\n    msg.topic = \"replay\";\n    return msg;\n}\n\nif (msg.payload == \"change\" && msg.name == \"svgTabName\") {\n    msg.topic = \"replay\";\n    return msg;\n}","outputs":1,"timeout":"","noerr":0,"initialize":"// Code added here will be run once\n// whenever the node is started.\nnode.status({fill:\"blue\",shape:\"ring\",text:\"inittialized\"});","finalize":"","libs":[],"x":1190,"y":100,"wires":[["cafabf4669d7f71e"]]},{"id":"2c5cbe522c355bbb","type":"function","z":"fc07fa0e875fef3e","name":"Puffer_unten_Temp","func":"\n\nvar temperature = msg.payload;\nvar factor = msg.payload/ 50;\n\n\n\nmsg.payload= [{\n    \"command\": \"update_text\",\n    \"selector\": \"#unten_temp\",\n    \"textContent\": temperature + \"°C\"\n}]\n\nmsg.id = \"unten_sensor\"\n\nreturn msg;\n","outputs":1,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[],"x":1210,"y":240,"wires":[["cafabf4669d7f71e"]]},{"id":"9fc87adaf5daa98e","type":"ui_slider","z":"fc07fa0e875fef3e","name":"","label":"slider","tooltip":"","group":"e493bd4a0b06bea0","order":2,"width":0,"height":0,"passthru":true,"outs":"all","topic":"topic","topicType":"msg","min":0,"max":10,"step":1,"className":"","x":1030,"y":240,"wires":[["2c5cbe522c355bbb"]]},{"id":"e3fda923433bd29e","type":"function","z":"fc07fa0e875fef3e","name":"Puffer_oben_Temp","func":"\n\nvar temperature = msg.payload;\nvar factor = msg.payload/ 50;\n\n\n\nmsg.payload= [{\n    \"command\": \"update_text\",\n    \"selector\": \"#oben_temp\",\n    \"textContent\": temperature + \"°C\"\n}]\n\nmsg.id = \"oben_sensor\"\n\nreturn msg;\n","outputs":1,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[],"x":1210,"y":300,"wires":[["cafabf4669d7f71e"]]},{"id":"e11d24b047329624","type":"ui_slider","z":"fc07fa0e875fef3e","name":"","label":"slider","tooltip":"","group":"e493bd4a0b06bea0","order":3,"width":0,"height":0,"passthru":true,"outs":"all","topic":"topic","topicType":"msg","min":0,"max":10,"step":1,"className":"","x":1030,"y":300,"wires":[["e3fda923433bd29e"]]},{"id":"e493bd4a0b06bea0","type":"ui_group","name":"Group 1","tab":"9fc6bf4953b3a419","order":1,"disp":true,"width":26},{"id":"9fc6bf4953b3a419","type":"ui_tab","name":"Tab 1","icon":"dashboard","order":1}]

@ninaaa11
Copy link

@bartbutenaers
Hello
thank you for your effort!!!!
I tried it out and was wondering if the “not replaying” warning is necessary for every value change?

Regarding the server history, that sounds good, but I have no idea how to set it up.

I'll read through it and let you know if necessary.

Thanks so much

@bartbutenaers
Copy link
Owner

@ninaaa11,
Sorry for the delay (again...)!

Yes indeed it is better to remove the warning from the function node, because in fact it is pretty normal if you arrive in that part of the code...

About the 'server history'. Not entirely sure what you mean. Do you mean the socket's I was talking about? If so I was just 'trying' to explain what went wrong. But if the flow should work for you, you can ignore my explanation. It was simply to give you some detailed insight, so you might do troubleshooting easier yourself afterwards...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants