Using Raspberry PI and node-red template node, I want to modify color of many SVG groups in a single SVG created from inkscape.
As I am new to SVG manipulation in real time, for starters, I began experimenting with a available code snippets and node-red. I am using below code in a template node in node-red. When I send fill-color string as a message to the template node, I expect fill color of the circle to be update. But, it stays black.
Need help to fix the situation
<!DOCTYPE HTML>
<html>
<head>
<title>Live (websocket)</title>
<script type="text/javascript">
var ws;
var wsUri = "ws:";
var loc = window.location;
console.log(loc);
if (loc.protocol === "https:") { wsUri = "wss:"; }
// This needs to point to the web socket in the Node-RED flow
// ... in this case it's ws/simple
wsUri += "//" + loc.host +
loc.pathname.replace("simple","ws/simple");
function wsConnect() {
console.log("connect",wsUri);
ws = new WebSocket(wsUri);
//var line = ""; // either uncomment this for a building list of messages
ws.onmessage = function(msg) {
var line = ""; // or uncomment this to overwrite the existing message
// parse the incoming message as a JSON object
var data = msg.data;
//console.log(data);
// build the output from the topic and payload parts of the object
line += "<p>"+data+"</p>";
// replace the messages div with the new "line"
document.getElementById('messages').innerHTML = line;
//ws.send(JSON.stringify({data:data}));
}
ws.onopen = function() {
// update the status div with the connection status
document.getElementById('status').innerHTML = "connected";
//ws.send("Open for data");
console.log("connected");
}
ws.onclose = function() {
// update the status div with the connection status
document.getElementById('status').innerHTML = "not connected";
// in case of lost connection tries to reconnect every 3 secs
setTimeout(wsConnect,3000);
}
}
function doit(m) {
if (ws) { ws.send(m); }
}
</script>
</head>
<body onload="wsConnect();" onunload="ws.disconnect();">
<font face="Arial">
<h1>Realtime control display</h1>
<div id="messages"></div>
<button type="button" onclick='doit("on");'>On</button>
<hr/>
<button type="button" onclick='doit("off");'>Off</button>
<hr/>
<div id="status">unknown</div>
</font>
<svg height="100" width="100">
<circle cx="50" cy="50" r="40" stroke="black" stroke-width="3" fill="{{msg.payload}}" />
</svg>
</body>
The flow:
[{"id":"b42c1d77.a106","type":"tab","label":"Flow 4","disabled":false,"info":""},{"id":"26b9acf6.07d0f4","type":"inject","z":"b42c1d77.a106","name":"Tick every 5 secs","topic":"test","payload":"","payloadType":"date","repeat":"1","crontab":"","once":false,"x":270,"y":540,"wires":[["30c6a524.97098a"]]},{"id":"9a2dd892.72c338","type":"websocket out","z":"b42c1d77.a106","name":"","server":"c74fd37a.71a1a","client":"","x":760,"y":540,"wires":[]},{"id":"43b92be3.166a34","type":"http response","z":"b42c1d77.a106","name":"","statusCode":"","headers":{},"x":910,"y":280,"wires":[]},{"id":"6a79a785.0d46d8","type":"http in","z":"b42c1d77.a106","name":"","url":"/simple","method":"get","upload":false,"swaggerDoc":"","x":270,"y":160,"wires":[["e79b8060.3bbdb"]]},{"id":"29d9680c.f456a8","type":"template","z":"b42c1d77.a106","name":"Simple Web Page","field":"payload","fieldType":"msg","format":"javascript","syntax":"mustache","template":"<!DOCTYPE HTML>\n<html>\n <head>\n <title>Live (websocket)</title>\n <script type=\"text/javascript\">\n var ws;\n var wsUri = \"ws:\";\n var loc = window.location;\n console.log(loc);\n if (loc.protocol === \"https:\") { wsUri = \"wss:\"; }\n // This needs to point to the web socket in the Node-RED flow\n // ... in this case it's ws/simple\n wsUri += \"//\" + loc.host + loc.pathname.replace(\"simple\",\"ws/simple\");\n\n function wsConnect() {\n console.log(\"connect\",wsUri);\n ws = new WebSocket(wsUri);\n //var line = \"\"; // either uncomment this for a building list of messages\n ws.onmessage = function(msg) {\n var line = \"\"; // or uncomment this to overwrite the existing message\n // parse the incoming message as a JSON object\n var data = msg.data;\n //console.log(data);\n // build the output from the topic and payload parts of the object\n line += \"<p>\"+data+\"</p>\";\n // replace the messages div with the new \"line\"\n document.getElementById('messages').innerHTML = line;\n //ws.send(JSON.stringify({data:data}));\n }\n ws.onopen = function() {\n // update the status div with the connection status\n document.getElementById('status').innerHTML = \"connected\";\n //ws.send(\"Open for data\");\n console.log(\"connected\");\n }\n ws.onclose = function() {\n // update the status div with the connection status\n document.getElementById('status').innerHTML = \"not connected\";\n // in case of lost connection tries to reconnect every 3 secs\n setTimeout(wsConnect,3000);\n }\n }\n \n function doit(m) {\n if (ws) { ws.send(m); }\n }\n </script>\n </head>\n <body onload=\"wsConnect();\" onunload=\"ws.disconnect();\">\n <font face=\"Arial\">\n <h1>Realtime control display</h1>\n <div id=\"messages\"></div>\n <button type=\"button\" onclick='doit(\"on\");'>On</button>\n <hr/>\n\t\t<button type=\"button\" onclick='doit(\"off\");'>Off</button>\n <hr/>\n <div id=\"status\">unknown</div>\n </font>\n <svg height=\"100\" width=\"100\">\n <circle cx=\"50\" cy=\"50\" r=\"40\" stroke=\"black\" stroke-width=\"3\" fill=\"{{msg.payload}}\" />\n </svg>\n</body>\n</html>\n\n\n","x":710,"y":280,"wires":[["43b92be3.166a34"]]},{"id":"30c6a524.97098a","type":"function","z":"b42c1d77.a106","name":"format time nicely","func":"msg.payload = Date(msg.payload).toString();\nreturn msg;","outputs":1,"noerr":0,"x":530,"y":540,"wires":[["9a2dd892.72c338"]]},{"id":"6900903b.9c411","type":"websocket in","z":"b42c1d77.a106","name":"","server":"c74fd37a.71a1a","client":"","x":280,"y":400,"wires":[["e79b8060.3bbdb","3c0453f0.6d3a4c","2e506fd.e6a219"]]},{"id":"e79b8060.3bbdb","type":"debug","z":"b42c1d77.a106","name":"","active":true,"tosidebar":true,"console":false,"complete":"false","x":510,"y":220,"wires":[]},{"id":"dc0f2d44.3e53","type":"rpi-gpio out","z":"b42c1d77.a106","name":"","pin":"15","set":"","level":"0","freq":"","out":"out","x":760,"y":400,"wires":[]},{"id":"3c0453f0.6d3a4c","type":"change","z":"b42c1d77.a106","name":"","rules":[{"t":"change","p":"payload","pt":"msg","from":"on","fromt":"str","to":"0","tot":"num"},{"t":"change","p":"payload","pt":"msg","from":"off","fromt":"str","to":"1","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":512,"y":402,"wires":[["dc0f2d44.3e53"]]},{"id":"723486cc.880e98","type":"inject","z":"b42c1d77.a106","name":"","topic":"","payload":"0","payloadType":"num","repeat":"","crontab":"","once":false,"onceDelay":"","x":510,"y":480,"wires":[["dc0f2d44.3e53"]]},{"id":"2e506fd.e6a219","type":"change","z":"b42c1d77.a106","name":"","rules":[{"t":"change","p":"payload","pt":"msg","from":"on","fromt":"str","to":"lime","tot":"num"},{"t":"change","p":"payload","pt":"msg","from":"off","fromt":"str","to":"red","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":520,"y":340,"wires":[["29d9680c.f456a8"]]},{"id":"c74fd37a.71a1a","type":"websocket-listener","z":"b42c1d77.a106","path":"/ws/simple","wholemsg":"false"}]
Thank you for suggestion, I have updated my username.
Quick update: Reason I want to use websocket is to be able to do session login control for admin and multiple users. Not sure if this flow is the best approach. I tried copying this idea websocket + node-red. But, cannot figure out how to place server side scripts in the flow.
I also tried SVG manipulation directly by using ui_template node. But again, changing color of individual group elements; independently, remains a question :(
Got a good direction from hardillb
Updated the node as below to have first meaningful connection between http and websocket nodes.
[{"id":"7bef62d0.5edcfc","type":"tab","label":"Flow 1","disabled":false,"info":""},{"id":"9de3d2d9.d89de","type":"websocket out","z":"7bef62d0.5edcfc","name":"","server":"1a7afc32.b3ad64","client":"","x":800,"y":260,"wires":[]},{"id":"2944ff33.7e483","type":"http response","z":"7bef62d0.5edcfc","name":"","statusCode":"","headers":{},"x":810,"y":180,"wires":[]},{"id":"4333a9ac.bae3b8","type":"http in","z":"7bef62d0.5edcfc","name":"","url":"/simple","method":"get","upload":false,"swaggerDoc":"","x":270,"y":180,"wires":[["708c64d.fce949c"]]},{"id":"708c64d.fce949c","type":"template","z":"7bef62d0.5edcfc","name":"Simple Web Page","field":"payload","fieldType":"msg","format":"javascript","syntax":"mustache","template":"<!DOCTYPE HTML>\n<html>\n <head>\n <title>Live (websocket)</title>\n <script type=\"text/javascript\">\n var ws;\n var wsUri = \"ws:\";\n var loc = window.location;\n console.log(loc);\n if (loc.protocol === \"https:\") { wsUri = \"wss:\"; }\n // This needs to point to the web socket in the Node-RED flow\n // ... in this case it's ws/simple\n wsUri += \"//\" + loc.host + loc.pathname.replace(\"simple\",\"ws/simple\");\n\n function wsConnect() {\n console.log(\"connect\",wsUri);\n ws = new WebSocket(wsUri);\n //var line = \"\"; // either uncomment this for a building list of messages\n ws.onmessage = function(msg) {\n var line = \"\"; // or uncomment this to overwrite the existing message\n // parse the incoming message as a JSON object\n var data = msg.data;\n //console.log(data);\n // build the output from the topic and payload parts of the object\n line += \"<p>\"+data+\"</p>\";\n // replace the messages div with the new \"line\"\n document.getElementById('messages').innerHTML = line;\n document.getElementById('circle').setAttribute('fill',data)\n //ws.send(JSON.stringify({data:data}));\n }\n ws.onopen = function() {\n // update the status div with the connection status\n document.getElementById('status').innerHTML = \"connected\";\n //ws.send(\"Open for data\");\n console.log(\"connected\");\n }\n ws.onclose = function() {\n // update the status div with the connection status\n document.getElementById('status').innerHTML = \"not connected\";\n // in case of lost connection tries to reconnect every 3 secs\n setTimeout(wsConnect,3000);\n }\n }\n \n function doit(m) {\n if (ws) { ws.send(m); }\n }\n </script>\n </head>\n <body onload=\"wsConnect();\" onunload=\"ws.disconnect();\">\n <font face=\"Arial\">\n <h1>Realtime control display</h1>\n <div id=\"messages\"></div>\n <button type=\"button\" onclick='doit(\"on\");'>On</button>\n <hr/>\n\t\t<button type=\"button\" onclick='doit(\"off\");'>Off</button>\n <hr/>\n <div id=\"status\">unknown</div>\n </font>\n <svg height=\"100\" width=\"100\">\n <circle id=\"circle\" cx=\"50\" cy=\"50\" r=\"40\" stroke=\"black\" stroke-width=\"3\" fill=\"{{msg.payload}}\" />\n </svg>\n</body>\n</html>\n\n\n","x":570,"y":180,"wires":[["2944ff33.7e483"]]},{"id":"ca3dab00.a83708","type":"websocket in","z":"7bef62d0.5edcfc","name":"","server":"1a7afc32.b3ad64","client":"","x":320,"y":260,"wires":[["988c505.812f3b"]]},{"id":"988c505.812f3b","type":"change","z":"7bef62d0.5edcfc","name":"","rules":[{"t":"change","p":"payload","pt":"msg","from":"on","fromt":"str","to":"green","tot":"str"},{"t":"change","p":"payload","pt":"msg","from":"off","fromt":"str","to":"red","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":560,"y":260,"wires":[["9de3d2d9.d89de"]]},{"id":"1a7afc32.b3ad64","type":"websocket-listener","z":"7bef62d0.5edcfc","path":"/ws/simple","wholemsg":"false"}]
However relying on my first principles approach, I still do not have any idea about how to connect dots between admin/user session login, websockets and mongoDB all via node red.
Any pointers in this direction are very welcome...
OK, to start with you have no path from your http-in node to your http-response node so you will never return anything to the browser.
The following flow does what I think you are looking to do, it changes the colour of the circle every second based on toggling a value (stored in the context) each time the inject node fires.
[{"id":"24197499.be00c4","type":"inject","z":"5be0b71a.38c42","name":"Tick every 1 second","topic":"test","payload":"","payloadType":"date","repeat":"1","crontab":"","once":false,"x":280,"y":340,"wires":[["e1102298.1909f8"]]},{"id":"b4c3d38c.82c0d","type":"websocket out","z":"5be0b71a.38c42","name":"","server":"2a3ae677.f9c272","client":"","x":760,"y":340,"wires":[]},{"id":"dc2352e9.bdfdd","type":"http response","z":"5be0b71a.38c42","name":"","statusCode":"","headers":{},"x":810,"y":160,"wires":[]},{"id":"5f7966e5.03b278","type":"http in","z":"5be0b71a.38c42","name":"","url":"/simple","method":"get","upload":false,"swaggerDoc":"","x":270,"y":160,"wires":[["cef934de.0ad83"]]},{"id":"cef934de.0ad83","type":"template","z":"5be0b71a.38c42","name":"Simple Web Page","field":"payload","fieldType":"msg","format":"javascript","syntax":"mustache","template":"<!DOCTYPE HTML>\n<html>\n <head>\n <title>Live (websocket)</title>\n <script type=\"text/javascript\">\n var ws;\n var wsUri = \"ws:\";\n var loc = window.location;\n console.log(loc);\n if (loc.protocol === \"https:\") { wsUri = \"wss:\"; }\n // This needs to point to the web socket in the Node-RED flow\n // ... in this case it's ws/simple\n wsUri += \"//\" + loc.host + loc.pathname.replace(\"simple\",\"ws/simple\");\n\n function wsConnect() {\n console.log(\"connect\",wsUri);\n ws = new WebSocket(wsUri);\n //var line = \"\"; // either uncomment this for a building list of messages\n ws.onmessage = function(msg) {\n var line = \"\"; // or uncomment this to overwrite the existing message\n // parse the incoming message as a JSON object\n var data = msg.data;\n //console.log(data);\n // build the output from the topic and payload parts of the object\n line += \"<p>\"+data+\"</p>\";\n // replace the messages div with the new \"line\"\n document.getElementById('messages').innerHTML = line;\n document.getElementById('circle').setAttribute('fill',data)\n //ws.send(JSON.stringify({data:data}));\n }\n ws.onopen = function() {\n // update the status div with the connection status\n document.getElementById('status').innerHTML = \"connected\";\n //ws.send(\"Open for data\");\n console.log(\"connected\");\n }\n ws.onclose = function() {\n // update the status div with the connection status\n document.getElementById('status').innerHTML = \"not connected\";\n // in case of lost connection tries to reconnect every 3 secs\n setTimeout(wsConnect,3000);\n }\n }\n \n function doit(m) {\n if (ws) { ws.send(m); }\n }\n </script>\n </head>\n <body onload=\"wsConnect();\" onunload=\"ws.disconnect();\">\n <font face=\"Arial\">\n <h1>Realtime control display</h1>\n <div id=\"messages\"></div>\n <button type=\"button\" onclick='doit(\"on\");'>On</button>\n <hr/>\n\t\t<button type=\"button\" onclick='doit(\"off\");'>Off</button>\n <hr/>\n <div id=\"status\">unknown</div>\n </font>\n <svg height=\"100\" width=\"100\">\n <circle id=\"circle\" cx=\"50\" cy=\"50\" r=\"40\" stroke=\"black\" stroke-width=\"3\" fill=\"{{msg.payload}}\" />\n </svg>\n</body>\n</html>\n\n\n","x":570,"y":160,"wires":[["dc2352e9.bdfdd"]]},{"id":"e1102298.1909f8","type":"function","z":"5be0b71a.38c42","name":"format time nicely","func":"if (context.get('state') == 'on') {\n context.set('state', 'off')\n msg.payload = 'green'\n} else {\n context.set('state', 'on')\n msg.payload = 'red';\n}\nreturn msg;","outputs":1,"noerr":0,"x":530,"y":340,"wires":[["b4c3d38c.82c0d"]]},{"id":"2a3ae677.f9c272","type":"websocket-listener","z":"5be0b71a.38c42","path":"/ws/simple","wholemsg":"false"}]
If you just want to change the colour of the circle without using your own websocket connection then the Dashboard-UI ui-template node is the way forward, but you will have to learn some basic angular to get that to work. There are plenty of examples around to help with that.