bartbutenaers / node-red-contrib-ui-svg

A Node-RED widget node to show interactive SVG (vector graphics) in the dashboard
Apache License 2.0
94 stars 27 forks source link

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

Closed maartenlambrecht closed 4 years ago

maartenlambrecht commented 4 years ago

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 commented 4 years ago

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 commented 4 years ago

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 commented 4 years ago

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 commented 4 years ago

Hey Maarten, Thanks a lot for sharing your solution! So you record all messages, and replay them afterwards. Clever! Although I'm wondering how long you keep remembering and replaying messages?

We had another proposal last week on the forum: https://discourse.nodered.org/t/ui-svg-attributevalue-of-an-attributename/24445/11?u=bartbutenaers

Although I proposed that to solve another feature request, we could also use it 'perhaps' for your issue. Because if the SVG node had a DOM tree at server side, we could send that DOM tree content to the client side when needed. But of course it wouldn't survive system reboots.

Just wondering: what do you do at reboot? Is your message list in the flow memory persistent perhaps?

And it is also not clear to me why users need to store somehow the current state of their svg... I thought you guys would use it like this: you read your sensors or other data sources, and then you update the svg to visualize that state. And a deploy or reboot you again read the current status of all those data sources again, and you send those again to the SVG...

But surely I have forgotten some use cases where this isn't possible. Could you please explain me with a simple use case why it cannot be done like that?

Thanks a lot for this constructive discussion, which may help lots of other users! Bart

maartenlambrecht commented 4 years ago

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 commented 1 year ago

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 commented 1 year ago

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

doit4fun commented 1 year ago

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 commented 11 months ago

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 commented 11 months ago

I assume you are talking about my code from https://github.com/bartbutenaers/node-red-contrib-ui-svg/issues/55#issuecomment-1311796899 ? You need to have an 'id' field in the message sent to the node that is unique to the what you are updating.

ninaaa11 commented 11 months ago

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 commented 11 months ago

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

Alloc86 commented 11 months ago

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 commented 11 months ago

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 commented 11 months ago

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 commented 11 months ago

@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 commented 11 months ago

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 commented 11 months ago

@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 commented 11 months ago

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 commented 11 months ago

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

ninaaa11 commented 11 months ago

Could anyone help with this please

Does my example work for you?

bartbutenaers commented 11 months ago

@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 commented 10 months ago

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 commented 10 months ago

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 commented 10 months ago

@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 commented 10 months ago

@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 commented 10 months ago

@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 commented 10 months ago

@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 commented 10 months ago

@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...