Saturday, December 30, 2017

CHANGE node - Part 3 - Rule Move

According to Node-RED documentation, the MOVE rule from the Change node allows you to move or rename properties from the Node-RED object.

The move rule will "cut" the key/value from its place in the object and will "paste" in a new place.



Example #1
The below rule will move the property father:"f" to a new position, or we could say, to a new path inside the object msg.






Node-RED msg object before the rule:




Node-RED msg object  after the rule:





We can use the rule MOVE as a way to rename the key of a property. In order to do so we keep the object in the same place (same path) and use a new key in the rule.



Example #2
Rename the key "father" to "papa".




Node-RED msg object before the rule:




Node-RED msg object  after the rule:



Example #3
Lets say we want to change the key paylo\d to be the name of the family. So how we can rename payload to Brown ?






Before the rule is applied:





After the rule is appplied:





Example #4
Be careful to not make a mistake in the rule otherwise we may end up with unexpected results. For instance, let's say you wrote a wrong rule, like the one below (trying to assign a value to the new property):



You will get the following object. Notice that the property msg.payload.msg1.father was deleted but the new one (msg.payload.msg1.papa) was not created. You will no error warnings in Node-Red debug window.






Example #5
Arrays of objects must be handled with care.  See what happens when you create below rule, that move a property to itself. You may think this is harmless. Think again.



Node-RED msg object  before the rule:




Node-RED msg object   after the rule:



Our rule ended up deleting the property from the object. Interesting to note that the same would happen if you tried to perform such rule over the last element of the array = msg.payload.msg3.grands[3] = "J".



Example #6
See another side effect of a misused rule.




You tried to move msg.payload.msg3.grands[1] to msg.payload.msg3.grands[4]. That seemed reasonable since the first free element of the array was [4]. See the result:

Node-RED msg object  before the rule:





Node-RED msg object after the rule:






You ended up with a null element in msg.payload.msg3.grands[3].




Thursday, December 28, 2017

CHANGE node - Part 2 - Rule Delete

Probably the easiest operation that can be performed in a Node-RED object is removing (deleting) a property.

Using our "familiar" Node-RED msg object example:









Example #1
Deleting the "mother" property with the following configuration in the Change node:





will result in the following object;






Example #2
Deleting the object msg1 that contains two properties(mother and father):



will result:






Example #3
Deleting the property "grands" that is an array inside the object msg3. This will remove the property and will result in an empty object (as expected).







Example #4
Deleting only one element from an array, let's say we want to delete the property "h" from msg.payload.msg3.grands. We know it is the second element of the array (therefore index 1).


We use:



resulting in:


Notice that the elements of the array were automatically shifted and changed their indexes.


Notice also that the debug tab from Node-RED will show 3 icons when you hover the mouse pointer over an element of the object, like below:




The first icon with symbol >_ will allow you to copy the path of the object to the clipboard. This way you will know exactly what is the object that you are manipulating.

For the above example the path of the 4th element of "grands" is :

payload.msg3.grands[3]


This can be very handy when the structure of the object is complex and large. By checking the path you will know exactly how to refer to the element.



Example #5
Let's say we want to delete the property "w1" from  msg4.ancestors. We better to copy the path as shown before:

Path = payload.msg4.ancestors[0][0]





Then we can safely delete with the proper configuration in the Change node:



Looks like we did not delete the element payload.msg4.ancestors[0][0] ?

We did but the elements of the array have been automatically shifted as expected so payload.msg4.ancestors[0][1] became the new payload.msg4.ancestors[0][0]





Just to close this post let ´s see how we could delete properties without using the Change node.



1 - Refactor the object by iterating over each element, filter the unwanted properties and building a new object (obviously using a function node).

2- Using the "delete" JavaScript statement inside a function node.

3- Setting the value of the property to value "undefined"



I will create a separate post in the future to show how to delete properties programmatically using the function node.

End.



Monday, December 25, 2017

CHANGE node - Part 1 - Introduction

The Change node from Node-RED is one of the most useful nodes.

Its purpose is to change the structure (properties and values) of the msg object, so it allows to add, change, move or delete properties (values from the key/value pairs).

A single node allows you to configure several rules in the same configuration dialog tab. The rules can mix the four different kinds of property operations. Each and every rule will be verified in the sequence they have been created.






The Change node has a couple of powerful functionalities: regular expressions when used along with the change rule and JSONata expressions, only for the set rule. JSONata is so powerful that it would deserve a dedicated node (in my opinion). JSONata allows you to manipulate any part of a JSON data structure, including the keys from the key/values pairs (which is not possible in another way by the change node, at least to the best of my knowledge).



Sometimes you may want to get some JSON data, change it to be a JavaScript object and manipulate this data with Node-RED. The JSON data may come from many different sources, like:


1- A  JSON string hard-coded in a Node-RED inject node.

2- An input MQTT node receiving a JSON string from an MQTT broker (as long as the topic configures the JSON string).

3- A Node-RED HTTP request node used to access web services (APIs). Depending on the API the JSON received can be very large and complex.

4- A Node-RED  DWEET node.

5- A database with stored JSON data.


When the input is a standard JSON data you will need to use a Node-RED JSON node to convert the JSON data structure to a JavaScript object.





Notice that injecting a JSON structure (JSON string) inside a Node-RED flow can easily be done with the inject node.




For the purpose of this post, let's craft a JSON string that is simple but has enough elements for testing the node.


By hosting this JSON string inside an inject node we will have an msg object with :

ms.topic
msg.payload



The JSON string will be the value of msg.payload and this msg.payload will have four objects inside:

msg.payload.msg1
msg.payload.msg2
msg.payload.msg3
msg.payload.msg4

The parameter of msg.payload.msg3 will be an array with 4 string.

The parameter of msg.payload.msg4 will be an array of arrays.

I order to keep the testing as simple as possible I will abbreviate the name of the persons with the first letter only (eg. f instead of Frederic).

This is the JSON string I will be using for testing the Change node. When it is hard-coded in a Node-RED inject node it will be used as the payload of the msg object.



{
"msg1": {
"father": "f",
"mother": "m"
},
"msg2": {
"brother": "b",
"sister": "s"
},
"msg3": {
"grands": ["g", "h", "i", "j"]
},
"msg4": {
"ancestors": [
["w1", "w2"],
["x1", "x2"],
["y1", "y2"],
["z1", "z2"]
]
}
}




Alternatively, it could be defined inside a function node by using the statement var msg = {JSON string here};







Flow:


[{"id":"f95ef9d9.55c618","type":"inject","z":"245b0549.fd469a","name":"","topic":"","payload":"{\"msg1\":{\"father\":\"f\",\"mother\":\"m\"},\"msg2\":{\"brother\":\"b\",\"sister\":\"s\"},\"msg3\":{\"grands\":[\"g\",\"h\",\"i\",\"j\"]},\"msg4\":{\"ancestors\":[[\"w1\",\"w2\"],[\"x1\",\"x2\"],[\"y1\",\"y2\"],[\"z1\",\"z2\"]]}}","payloadType":"json","repeat":"","crontab":"","once":false,"x":90,"y":60,"wires":[["5af687da.cf8098"]]},{"id":"dd34d677.51a918","type":"debug","z":"245b0549.fd469a","name":"","active":true,"console":"false","complete":"true","x":430,"y":60,"wires":[]},{"id":"5af687da.cf8098","type":"change","z":"245b0549.fd469a","name":"","rules":[{"t":"set","p":"","pt":"msg","to":"","tot":"msg"},{"t":"change","p":"","pt":"msg","from":"","fromt":"str","to":"","tot":"str"},{"t":"delete","p":"","pt":"msg"},{"t":"move","p":"","pt":"msg","to":"","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":260,"y":60,"wires":[["dd34d677.51a918"]]}]

Tuesday, December 19, 2017

An updated game for testing the dashboard

Some time ago I did a  Node_RED flow just for learning how to use Freeboard Dashboard (click here for the link)

I stopped using Freeboard since NodeRED team incorporated dashboard nodes to the core of Node-RED.


I decided then to update that game ,also for learning purposes.


Here is how the dashboard looks like while the game is running:




This is how the flow looks like:




Flow:

[{"id":"8b9c16c1.9d2c78","type":"inject","z":"ab22dba5.2bb948","name":"Fire","topic":"none","payload":"fire","payloadType":"str","repeat":"","crontab":"","once":false,"x":240,"y":411.0000171661377,"wires":[["90f89153.24b3e"]]},{"id":"2099b281.cc909e","type":"function","z":"ab22dba5.2bb948","name":"Random","func":"msg.value1=Math.floor(Math.random()*100);\nmsg.value2=Math.floor(Math.random()*100);\nmsg.light1=0;\nmsg.light2=0;\nmsg.light3=0;\n\nmsg.runs +=1;\nif (msg.value1>msg.value2) {\n    msg.win1+=1\n    msg.light1=1;\n    msg.light2=0;\n}else if (msg.value2>msg.value1) {\n    msg.win2+=1;\n    msg.light1=0;\n    msg.light2=1;\n}else {\n    msg.light1=1;\n    msg.light2=1;\n    msg.light3=1;\n    msg.stop = true;\n    if (msg.win1 > msg.win2) {\n        msg.winner = \"Player 1\";\n    } else if (msg.win2 > msg.win1) {\n            msg.winner = \"Player 2\";\n        } else {\n            msg.winner = \"It is a draw ! !\";\n        }\n    }\n\n\nreturn msg;","outputs":1,"noerr":0,"x":412.00001525878906,"y":318.0000114440918,"wires":[["f41892a5.e7945","29835b6a.459594","28416391.e7b69c"]]},{"id":"29835b6a.459594","type":"function","z":"ab22dba5.2bb948","name":"Test Stop","func":"\nif (msg.stop) {\n    \n    return null;  \n} else {return msg;}\n\nif (msg.start) {\n    return msg;\n}\n\n","outputs":1,"noerr":0,"x":550,"y":411.0000171661377,"wires":[["68f31cc0.517654"]]},{"id":"68f31cc0.517654","type":"delay","z":"ab22dba5.2bb948","name":"","pauseType":"delay","timeout":"5","timeoutUnits":"seconds","rate":"1","nbRateUnits":"","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":252.00001525878906,"y":318.0000114440918,"wires":[["2099b281.cc909e"]]},{"id":"90f89153.24b3e","type":"function","z":"ab22dba5.2bb948","name":"Start","func":"msg.start = true;\nmsg.stop = false;\n\nif (msg.start) {\n    msg.value1=0;\n    msg.value2=0;\n    msg.light1=0;\n    msg.light2=0;\n    msg.light3=0;\n    msg.win1=0;\n    msg.win2=0;\n    msg.runs=0;\n    msg.winner=\"open game\";\n    msg.start=false;\n}\nreturn msg;\n","outputs":1,"noerr":0,"x":380,"y":411.0000171661377,"wires":[["29835b6a.459594","ef05496a.38a308"]]},{"id":"f41892a5.e7945","type":"debug","z":"ab22dba5.2bb948","name":"","active":true,"console":"false","complete":"true","x":582.0000152587891,"y":318.0000114440918,"wires":[]},{"id":"28416391.e7b69c","type":"function","z":"ab22dba5.2bb948","name":"Format Dashboard","func":"var msg1={payload:msg.value1};\nvar msg2={payload:msg.value2};\nvar msg3={payload:msg.runs};\nvar msg4={payload:msg.win1};\nvar msg5={payload:msg.win2};\nvar msg6={payload:msg.winner};\nreturn [msg1, msg2, msg3, msg4, msg5, msg6];","outputs":"6","noerr":0,"x":350,"y":120,"wires":[["f19a4aae.e10238"],["5f728cb7.96f5b4"],["66a9bc7c.0a63e4"],["7a6e1f5f.f64fe"],["456203cc.1a91dc"],["1ca0211e.906b1f"]]},{"id":"f19a4aae.e10238","type":"ui_gauge","z":"ab22dba5.2bb948","name":"","group":"d3e8886d.948888","order":1,"width":0,"height":0,"gtype":"donut","title":"Player 1","label":"","format":"{{value}}","min":0,"max":"100","colors":["#00b500","#e6e600","#ca3838"],"seg1":"","seg2":"","x":560,"y":60,"wires":[]},{"id":"5f728cb7.96f5b4","type":"ui_gauge","z":"ab22dba5.2bb948","name":"","group":"d3e8886d.948888","order":2,"width":0,"height":0,"gtype":"donut","title":"Player 2","label":"","format":"{{value}}","min":0,"max":"100","colors":["#00b500","#e6e600","#ca3838"],"seg1":"","seg2":"","x":560,"y":100,"wires":[]},{"id":"66a9bc7c.0a63e4","type":"ui_text","z":"ab22dba5.2bb948","group":"d3e8886d.948888","order":3,"width":"3","height":"1","name":"","label":"RUNS","format":"{{msg.payload}}","layout":"row-spread","x":550,"y":140,"wires":[]},{"id":"7a6e1f5f.f64fe","type":"ui_text","z":"ab22dba5.2bb948","group":"d3e8886d.948888","order":4,"width":0,"height":0,"name":"","label":"Wins Player 1","format":"{{msg.payload}}","layout":"row-spread","x":580,"y":180,"wires":[]},{"id":"456203cc.1a91dc","type":"ui_text","z":"ab22dba5.2bb948","group":"d3e8886d.948888","order":5,"width":0,"height":0,"name":"","label":"Wins Player 2","format":"{{msg.payload}}","layout":"row-spread","x":580,"y":220,"wires":[]},{"id":"1ca0211e.906b1f","type":"ui_text","z":"ab22dba5.2bb948","group":"d3e8886d.948888","order":5,"width":0,"height":0,"name":"","label":"The Winner is...","format":"{{msg.payload}}","layout":"row-spread","x":580,"y":260,"wires":[]},{"id":"ef05496a.38a308","type":"debug","z":"ab22dba5.2bb948","name":"","active":true,"console":"false","complete":"true","x":518.1000061035156,"y":493.0000171661377,"wires":[]},{"id":"d3e8886d.948888","type":"ui_group","z":"","name":"Button1","tab":"4ce637e8.4ba768","disp":true,"width":"6"},{"id":"4ce637e8.4ba768","type":"ui_tab","z":"","name":"Button Panel","icon":"dashboard"}]

The three relay problem


This was a request for help posted in the Node-RED group.


The requirements:

Use Node-RED to control three remote relays via MQTT.
Once the first relay is activated (by sending an ON command via MQTT) it should remain active for 5 minutes. When it turns off the second should start and run for 5 minutes, when it stops the third should start and run 5 min when it stops it should start the first one again and continue looping in such way until an OFF command is triggered.



Proposed Solution:

It was implemented a cycling engine, inside a function node, that "rotates" the desired outputs to the relays. The very first run will command all three relays OFF (without delays). I used a variable in the global context to store the user command to stop the flow. There is an inject node to stop the flow. It will stop immediately after the execution of the ongoing delay (which was configured for 15 seconds to speed up the flow - it should be changed to 5 minutes to comply with the requirements). The way the flow was written facilitates to change the logic if there are any changes in the requirements (more relays or relays being activated in a different sequence, for instance).






Flow:



[{"id":"f98def0.4f2101","type":"function","z":"108c9253.cb4bfe","name":"Cycle","func":"if (msg.firstRun || msg.lastRun) {\n    msg.payload1=\"OFF\"; \n    msg.payload2=\"OFF\"; \n    msg.payload3=\"OFF\";\n    if (msg.firstRun) msg.firstRun=false;\n    \n} else \n    \n\nswitch (msg.cycle) {\n    \n   \n        \n    case 1:\n        msg.payload1=\"ON\"; \n        msg.payload2=\"OFF\"; \n        msg.payload3=\"OFF\";\n        msg.cycle=2;\n        break;\n    case 2:\n        msg.payload1=\"OFF\"; \n        msg.payload2=\"ON\"; \n        msg.payload3=\"OFF\";\n        msg.cycle=3;\n        break;  \n        \n    case 3:\n        msg.payload1=\"OFF\"; \n        msg.payload2=\"OFF\"; \n        msg.payload3=\"ON\";\n        msg.cycle=1;\n        break;\n        \n}\n\n\n   \n    msg1={topic:msg.topic1, payload:msg.payload1};\n    msg2={topic:msg.topic2, payload:msg.payload2};\n    msg3={topic:msg.topic3, payload:msg.payload3}; \n    \n    \n    return [[msg1, msg2, msg3], msg];\n    \n\n\n\n\n\n\n","outputs":"2","noerr":0,"x":544,"y":169.00001430511475,"wires":[["6897db12.4f3d34"],["cb723b20.0ecee8","9019f171.0794a"]]},{"id":"4b6261af.a6b63","type":"function","z":"108c9253.cb4bfe","name":"Initialize","func":"    \n    global.set(\"keepWalking\",true);\n    msg.keepWalking = global.get(\"keepWalking\");\n    \n    msg.cycle = 1;\n    msg.firstRun = true;\n    msg.lastRun = false;\n    msg.topic1 = \"cmnd/kb1/power1\";\n    msg.topic2 = \"cmnd/kb1/power2\";\n    msg.topic3 = \"cmnd/kb1/power3\";\n    \n    msg.payload1 = \"OFF\";\n    msg.payload2 = \"OFF\";\n    msg.payload3 = \"OFF\";\n\nreturn msg;","outputs":1,"noerr":0,"x":379.9999580383301,"y":169.00003814697266,"wires":[["f98def0.4f2101"]]},{"id":"cb723b20.0ecee8","type":"debug","z":"108c9253.cb4bfe","name":"Debug only","active":true,"console":"false","complete":"true","x":744.1001205444336,"y":174.00003051757812,"wires":[]},{"id":"d7233232.fb09b","type":"delay","z":"108c9253.cb4bfe","name":"","pauseType":"delay","timeout":"15","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":579.1000709533691,"y":308.0000171661377,"wires":[["f98def0.4f2101"]]},{"id":"21c221de.0190de","type":"inject","z":"108c9253.cb4bfe","name":"Switch ON","topic":"","payload":"SON","payloadType":"str","repeat":"","crontab":"","once":false,"x":219.99996185302734,"y":170.00003719329834,"wires":[["4b6261af.a6b63"]]},{"id":"9019f171.0794a","type":"function","z":"108c9253.cb4bfe","name":"Test Stop","func":"// keepWalking: false, lastRun: false=> cycle last time\n// keepWalking: false, lastRun: true => end flow\n\n// keepWalking: true => just return msg\n//\n//\n\nif (!global.get(\"keepWalking\")) {\n    if (!msg.lastRun) {\n        msg.lastRun=true;\n        node.warn(\"Commanding Relays off...\");\n        return msg;\n    } else {\n        node.warn(\"Relays confirmed OFF\");\n        return null;}\n    \n} else {return msg;}\n","outputs":1,"noerr":0,"x":429.0999698638916,"y":308.000018119812,"wires":[["d7233232.fb09b"]]},{"id":"f7ab90b3.cf35f","type":"inject","z":"108c9253.cb4bfe","name":"Switch OFF","topic":"SOFF","payload":"","payloadType":"str","repeat":"","crontab":"","once":false,"x":345.09996795654297,"y":396.00002002716064,"wires":[["78a8b3e0.63e5fc"]]},{"id":"78a8b3e0.63e5fc","type":"function","z":"108c9253.cb4bfe","name":"Command Stop","func":"global.set(\"keepWalking\",false);\nmsg.keepWalking = global.get(\"keepWalking\");\nreturn msg;","outputs":1,"noerr":0,"x":540.0999717712402,"y":397.00002002716064,"wires":[[]]},{"id":"6897db12.4f3d34","type":"mqtt out","z":"108c9253.cb4bfe","name":"","topic":"","qos":"2","retain":"false","broker":"752751ba.451be","x":734.1000061035156,"y":104,"wires":[]},{"id":"752751ba.451be","type":"mqtt-broker","z":"","broker":"broker.mqttdashboard.com","port":"1883","clientid":"","usetls":false,"compatmode":true,"keepalive":"60","cleansession":true,"willTopic":"","willQos":"0","willPayload":"","birthTopic":"","birthQos":"0","birthPayload":""}]



Thursday, December 14, 2017

How to display a blinking LED in Node-RED dashboard

There are probably a thousand different ways of doing a blinking LED in the dashboard.

The first idea that comes to my mind is to use an inject node to trigger the flashing every second, for instance. There will be a trigger node that will send the color green, wait for 400 milliseconds and after that delay, it will send the black color as the payload. This way the LED will be green for 400ms and black for 600ms. You can easily change these delays in those two nodes.





A dashboard template is used to display the LED shape (a simple circle).

Following SVG config is added to the template field in the Template node.


<svg>
<circle cx="10" cy="10" r="10" style="stroke: none; fill: {{msg.payload}};"/>
</svg>


This is the end result in the dashboard (pretend that the LED is blinking)





Node-RED flow:

[{"id":"2a2791e4.ff3ade","type":"trigger","z":"9e8ac502.a77a18","op1":"lime","op2":"black","op1type":"str","op2type":"str","duration":"400","extend":false,"units":"ms","reset":"","name":"","x":300,"y":220,"wires":[["db1b4e43.c133a"]]},{"id":"db1b4e43.c133a","type":"ui_template","z":"9e8ac502.a77a18","group":"130aff60.890011","name":"","order":0,"width":0,"height":0,"format":"<svg>\n<circle cx=\"10\" cy=\"10\" r=\"10\" style=\"stroke: none; fill: {{msg.payload}};\"/>\n</svg>","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":480,"y":220,"wires":[[]]},{"id":"f49a431f.78814","type":"inject","z":"9e8ac502.a77a18","name":"","topic":"","payload":"Fire","payloadType":"str","repeat":"1","crontab":"","once":false,"x":110,"y":220,"wires":[["2a2791e4.ff3ade"]]},{"id":"130aff60.890011","type":"ui_group","z":"","name":"Blinking LED","tab":"f8f951a0.956ef","disp":true,"width":"6"},{"id":"f8f951a0.956ef","type":"ui_tab","z":"","name":"Blinking LED","icon":"dashboard"}]

How to display a LED in Node-RED Dashboard

Node-RED does not provide a user interface node specific to represent a LED in the dashboard.

This is not an issue at all since there are a few different ways to achieve this goal.


1- Using a Text output node from the Dashboard along with an icon from Font Awesome (http://fontawesome.io/icons/)



I have used the most basic representation icon which is the fa-circle.



Simple flow to demonstrate how to configure an icon to represent a LED:


As we want the LED to change colors, normally to green or red we have to add some code to manage the color change.  For this testing, I created a property in the .msg object and assigned to it a color (lime or red).

See the Javascript code inside the function node. It simply adds a color to msg.color property. If msg.payload is "ON" then msg.color will be "lime" (a light green) otherwise (for any other payload) msg.color will be "red"



The text output node should have the following configuration in the field Value format:

<font color={{msg.color}} ><i class="fa fa-circle" style="font-size:24px;"></i></font>






This is the end result of the dashboard.




Flow :

[{"id":"17ca9b9e.d2a564","type":"function","z":"3fc1de78.729e82","name":"Test","func":"msg.color = (msg.payload === \"ON\")?\"lime\":\"red\";\nreturn msg;","outputs":1,"noerr":0,"x":330,"y":200,"wires":[["872b1d71.45076"]]},{"id":"c6ac5bac.e91e38","type":"inject","z":"3fc1de78.729e82","name":"","topic":"","payload":"ON","payloadType":"str","repeat":"","crontab":"","once":false,"x":170,"y":180,"wires":[["17ca9b9e.d2a564"]]},{"id":"872b1d71.45076","type":"ui_text","z":"3fc1de78.729e82","group":"a6e358b.672ffa8","order":3,"width":"3","height":"1","name":"","label":"LED","format":"<font color={{msg.color}} ><i class=\"fa fa-circle\" style=\"font-size:24px;\"></i></font>","layout":"row-left","x":510,"y":200,"wires":[]},{"id":"9d39dfc1.aff32","type":"inject","z":"3fc1de78.729e82","name":"","topic":"","payload":"OFF","payloadType":"str","repeat":"","crontab":"","once":false,"x":170,"y":220,"wires":[["17ca9b9e.d2a564"]]},{"id":"a6e358b.672ffa8","type":"ui_group","z":"","name":"LED Testing","tab":"4e528085.a1bfa","disp":true,"width":"4"},{"id":"4e528085.a1bfa","type":"ui_tab","name":"Tab","icon":"dashboard","order":0}]



2- Using a template node from the Dashboard along with very simple SVG directives




Following code, with SVG directives, must be added to the Template field in the configuration dialog page from the node.


<svg width="100" height="80">
    <circle id="circle1" cx="20" cy="20" r="10"
            style="stroke: none; fill: {{msg.color}};"/>
</svg>


Alternatively, instead of writing the parameters stroke and fill inside the SVG tags it is possible (and many times desirable) to use the CSS way of working. We do that using an additional pair of tags <style></style> and write those parameters as property : value; in each line. The hashtag #circle1 defines the style parameters for the HTML element with id = "circle1".


<style>

#circle1 {
    stroke: none;
    fill: {{msg.color}};
}

</style>

<svg>
    <circle id="circle1" cx="10" cy="20" r="10"/>
</svg>






This is the result we get on the dashboard:





Below a variation on the LED design:


<svg width="100" height="80">
    <circle id="circle1" cx="20" cy="20" r="10" stroke={{msg.color}} fill="transparent" stroke-width="5"/>
</svg>