How to Node-RED!

This is the project page to the How to Node-RED! video on YouTube. It shows how shows how to configure Node-RED on the Raspberry Pi and how to start creating home automation projects using MQTT and Node-RED. Some practical IoT examples are show.
As starting point a Raspberry PI with a Rasbian Stretch image and an installed MQTT Borker is used. Check out my MQTT project for this.

Updating/Installing Node-RED on the Raspberry Pi

Using the Rasbian Stretch image on the Raspberry Pi comes with Node-RED pre-installed. Currently the image lacks of the node packet manager npm.
This is an issue since Node-RED lacks in the possibility to install extensions without npm. But there is an easy solution following the upgrade instructions of the Node-RED homepage. From version 0.14.x Node-RED comes with an update script which takes care of everything. It can be simply executed from the terminal typing:

update-nodejs-and-nodered

If the script is not present you can simply get it using

bash <(curl -sL https://raw.githubusercontent.com/node-red/raspbian-deb-package/master/resources/update-nodejs-and-nodered)

Security (optional)

To protect your home automation from other people with access to the local network you can add also a basic authentication to Node-RED. It’s optional but recommended in a productive environment. First of all you should create password hashes of the users you want to add to the authentication using the admin tool.
Installing the tool is:

cd ~/.node-red
sudo npm install -g node-red-admin

After the tool is installed the hashes can be created using:

node-red-admin hash-pw

The password hash can now be copied from the console and added in the ~/.node-red/settings.js to a user using the nano editor

nano ~/.node-red/settings.js

The users are defined like this (you can find the corresponding lines and comment them in):

adminAuth: {
 type: "credentials",
 users: [{
 username: "YOUR USERNAME",
 password: "YOUR HASH HERE",
 permissions: "*"
 }]
},

You also need to activate the basic authentication for the HTTP nodes to secure our user interface defining this line:

httpNodeAuth: {user:"YOUR USERNAME",pass:"YOUR HASH HERE"},

To start Node Red automatically on power up we can use the following command:

sudo systemctl enable nodered.service

The Development Enviroment and UI

The Node-Red development environment is browser based and can be now found at the IP-address of the raspberry at port 1880 like here for my IP:

http://192.168.0.10:1880

To be able to create a user interface the node-red-dashboard extension has to be added using the palette manager which can be found in the menu (only available when npm is installed, what we did before):
   

After the installation the user interface can be accessed at the same address with /ui at the end:

http://192.168.0.10:1880/ui

Smartphone

No extra app is need on the smart phone. Using the chrome browser we can simply visit the ui page and use the “add to home screen” option. An icon will appear on your home screen which will take you straight to your user interface.

    

The flows

The flows can be imported and exported as JSON objects using the functions from the menu:

Here are my example flows from the video:
This is the basic MQTT switch:

[{"id":"3ac40792.7d18b8","type":"mqtt out","z":"a159b87f.b45138","name":"","topic":"home/switch0","qos":"1","retain":"true","broker":"171132c7.ece67d","x":875.1667060852051,"y":114.00000667572021,"wires":[]},{"id":"2786f27e.92b37e","type":"ui_switch","z":"a159b87f.b45138","name":"","label":"Lava Lamp","group":"7e338484.151fcc","order":0,"width":0,"height":0,"passthru":true,"decouple":"false","topic":"","style":"","onvalue":"1","onvalueType":"num","onicon":"","oncolor":"","offvalue":"0","offvalueType":"num","officon":"","offcolor":"","x":501.1667022705078,"y":114.0000171661377,"wires":[["3ac40792.7d18b8"]]},{"id":"171132c7.ece67d","type":"mqtt-broker","z":"","broker":"localhost","port":"1883","clientid":"","usetls":false,"compatmode":true,"keepalive":"60","cleansession":true,"willTopic":"","willQos":"0","willPayload":"","birthTopic":"","birthQos":"0","birthPayload":""},{"id":"7e338484.151fcc","type":"ui_group","z":"","name":"Sleeping Room","tab":"ea10702d.5708d","order":1,"disp":true,"width":"6"},{"id":"ea10702d.5708d","type":"ui_tab","z":"","name":"Lights","icon":"dashboard","order":3}]

This is for the weather station:

[{"id":"a6e66e24.246eb","type":"ui_chart","z":"83b78c60.0bd6f","name":"Temperature Chart","group":"c467b276.39485","order":2,"width":"4","height":"3","label":"","chartType":"line","legend":"false","xformat":"HH:mm","interpolate":"linear","nodata":"","dot":false,"ymin":"10","ymax":"40","removeOlder":"8","removeOlderPoints":"","removeOlderUnit":"3600","cutout":0,"colors":["#1f77b4","#aec7e8","#ff7f0e","#2ca02c","#98df8a","#d62728","#ff9896","#9467bd","#c5b0d5"],"useOldStyle":false,"x":921.1670455932617,"y":275.333553314209,"wires":[[],[]]},{"id":"56590d76.972014","type":"mqtt in","z":"83b78c60.0bd6f","name":"","topic":"weatherStation/temperature","qos":"1","broker":"171132c7.ece67d","x":419.1669006347656,"y":239.00030136108398,"wires":[["a6e66e24.246eb","4e7da728.df7028","f62c1c11.ee6cb"]]},{"id":"aa8c644f.d09798","type":"mqtt in","z":"83b78c60.0bd6f","name":"","topic":"weatherStation/humidity","qos":"1","broker":"171132c7.ece67d","x":411.00018310546875,"y":149.0001983642578,"wires":[["af9c7600.6c5cf8","f62c1c11.ee6cb","1112abd4.01dd04"]]},{"id":"f2c9049d.343428","type":"ui_chart","z":"83b78c60.0bd6f","name":"Humidity Chart","group":"c467b276.39485","order":4,"width":"4","height":"3","label":"","chartType":"line","legend":"false","xformat":"HH:mm","interpolate":"linear","nodata":"","dot":false,"ymin":"0","ymax":"100","removeOlder":"8","removeOlderPoints":"","removeOlderUnit":"3600","cutout":0,"colors":["#1f77b4","#aec7e8","#ff7f0e","#2ca02c","#98df8a","#d62728","#ff9896","#9467bd","#c5b0d5"],"useOldStyle":false,"x":912.0002098083496,"y":182.00018405914307,"wires":[[],[]]},{"id":"af9c7600.6c5cf8","type":"smooth","z":"83b78c60.0bd6f","name":"","action":"mean","count":"100","round":"","mult":"single","x":657.1667861938477,"y":149.00007438659668,"wires":[["f2c9049d.343428","ab3492b0.fa195"]]},{"id":"175b6880.a5b6c8","type":"mqtt in","z":"83b78c60.0bd6f","name":"","topic":"weatherStation/#","qos":"1","broker":"171132c7.ece67d","x":378.0002632141113,"y":506.00035667419434,"wires":[[]]},{"id":"6ffbf102.708af","type":"mqtt in","z":"83b78c60.0bd6f","name":"","topic":"weatherStation/pressure","qos":"1","broker":"171132c7.ece67d","x":410.0001525878906,"y":338.00010204315186,"wires":[["494cb1a9.47f47"]]},{"id":"b82a7caa.2821e","type":"ui_chart","z":"83b78c60.0bd6f","name":"Pressure Chart","group":"c467b276.39485","order":6,"width":"4","height":"3","label":"","chartType":"line","legend":"false","xformat":"HH:mm","interpolate":"linear","nodata":"","dot":false,"ymin":"900","ymax":"1100","removeOlder":"8","removeOlderPoints":"","removeOlderUnit":"3600","cutout":0,"colors":["#1f77b4","#aec7e8","#ff7f0e","#2ca02c","#98df8a","#d62728","#ff9896","#9467bd","#c5b0d5"],"useOldStyle":false,"x":915.1670532226562,"y":369.3334369659424,"wires":[[],[]]},{"id":"494cb1a9.47f47","type":"function","z":"83b78c60.0bd6f","name":"pascal to hecto","func":"msg.payload *= 0.01;\nreturn msg;","outputs":1,"noerr":0,"x":673.166877746582,"y":339.66680812835693,"wires":[["b82a7caa.2821e","31d0bf64.cd69a","f62c1c11.ee6cb"]]},{"id":"ab3492b0.fa195","type":"ui_gauge","z":"83b78c60.0bd6f","name":"","group":"c467b276.39485","order":3,"width":"2","height":"3","gtype":"wave","title":"Humidity","label":"%","format":"{{value|number:1}}","min":0,"max":"100","colors":["#5a5a5a","#34b92d","#0202ff"],"seg1":"","seg2":"","x":889.1668815612793,"y":132.0001096725464,"wires":[]},{"id":"4e7da728.df7028","type":"ui_gauge","z":"83b78c60.0bd6f","name":"","group":"c467b276.39485","order":1,"width":"2","height":"3","gtype":"gage","title":"Temperature","label":"°C","format":"{{value|number:1}}","min":"-20","max":"50","colors":["#0000ff","#e6e600","#ca3838"],"seg1":"0","seg2":"30","x":901.1668891906738,"y":230.0001163482666,"wires":[]},{"id":"31d0bf64.cd69a","type":"ui_gauge","z":"83b78c60.0bd6f","name":"","group":"c467b276.39485","order":5,"width":"2","height":"3","gtype":"gage","title":"Pressure","label":"hPa","format":"{{value|number:2}}","min":"900","max":"1100","colors":["#00b500","#e6e600","#ca3838"],"seg1":"","seg2":"","x":893.1668891906738,"y":326.0001411437988,"wires":[]},{"id":"442a7dcc.09d934","type":"mqtt in","z":"83b78c60.0bd6f","name":"","topic":"weatherStation/light","qos":"1","broker":"171132c7.ece67d","x":390.0001449584961,"y":420.0001468658447,"wires":[["dff18ee1.f7d5d","f62c1c11.ee6cb"]]},{"id":"dff18ee1.f7d5d","type":"ui_gauge","z":"83b78c60.0bd6f","name":"","group":"c467b276.39485","order":8,"width":"2","height":"3","gtype":"gage","title":"Light","label":"","format":"{{value|number:2}}","min":"0","max":"1","colors":["#000080","#c0c0c0","#ffff80"],"seg1":"","seg2":"","x":886.0002136230469,"y":418.0001468658447,"wires":[]},{"id":"7f4769a3.5900d8","type":"mqtt in","z":"83b78c60.0bd6f","name":"","topic":"humiditySensor/humidity","qos":"1","broker":"171132c7.ece67d","x":385.16673278808594,"y":633.0001592636108,"wires":[["b4ad1c70.ca013"]]},{"id":"1acc878a.73f7c8","type":"mqtt in","z":"83b78c60.0bd6f","name":"","topic":"humiditySensor/temperature","qos":"1","broker":"171132c7.ece67d","x":394.0000915527344,"y":720.000205039978,"wires":[["38bfc86e.685758"]]},{"id":"25ea93a.176966c","type":"mqtt in","z":"83b78c60.0bd6f","name":"","topic":"humiditySensor/voltage","qos":"1","broker":"171132c7.ece67d","x":368.0001449584961,"y":808.0002107620239,"wires":[["aa7ede7b.d0f11"]]},{"id":"b06806b3.c4ff58","type":"ui_chart","z":"83b78c60.0bd6f","name":"Humidity Chart","group":"f440b0b0.67c6e","order":7,"width":"4","height":"3","label":"","chartType":"line","legend":"false","xformat":"HH:mm","interpolate":"linear","nodata":"","dot":false,"ymin":"0","ymax":"100","removeOlder":"8","removeOlderPoints":"","removeOlderUnit":"3600","cutout":0,"colors":["#1f77b4","#aec7e8","#ff7f0e","#2ca02c","#98df8a","#d62728","#ff9896","#9467bd","#c5b0d5"],"useOldStyle":false,"x":886,"y":670,"wires":[[],[]]},{"id":"b4ad1c70.ca013","type":"smooth","z":"83b78c60.0bd6f","name":"","action":"mean","count":"6","round":"","mult":"single","x":631.166576385498,"y":636.9998903274536,"wires":[["b06806b3.c4ff58","2f8eb7d1.cd2218"]]},{"id":"2f8eb7d1.cd2218","type":"ui_gauge","z":"83b78c60.0bd6f","name":"","group":"f440b0b0.67c6e","order":6,"width":"2","height":"3","gtype":"wave","title":"Humidity","label":"%","format":"{{value|number:1}}","min":0,"max":"100","colors":["#5a5a5a","#34b92d","#0202ff"],"seg1":"","seg2":"","x":863.1666717529297,"y":619.9999256134033,"wires":[]},{"id":"aa7ede7b.d0f11","type":"function","z":"83b78c60.0bd6f","name":"scale","func":"msg.payload *= 3.304 / 2788;\nreturn msg;","outputs":1,"noerr":0,"x":641.1667060852051,"y":813.0002117156982,"wires":[["ce445d5d.65cd4"]]},{"id":"ce445d5d.65cd4","type":"ui_gauge","z":"83b78c60.0bd6f","name":"","group":"f440b0b0.67c6e","order":10,"width":"2","height":"3","gtype":"gage","title":"Voltage","label":"V","format":"{{value|number:2}}","min":"0","max":"3.6","colors":["#8e0000","#e3e300","#00c400"],"seg1":"2.5","seg2":"3","x":892.0001335144043,"y":820.000129699707,"wires":[]},{"id":"6f47ae7f.40cd2","type":"ui_chart","z":"83b78c60.0bd6f","name":"Temperature Chart","group":"f440b0b0.67c6e","order":5,"width":"4","height":"3","label":"","chartType":"line","legend":"false","xformat":"HH:mm","interpolate":"linear","nodata":"","dot":false,"ymin":"10","ymax":"40","removeOlder":"8","removeOlderPoints":"","removeOlderUnit":"3600","cutout":0,"colors":["#1f77b4","#aec7e8","#ff7f0e","#2ca02c","#98df8a","#d62728","#ff9896","#9467bd","#c5b0d5"],"useOldStyle":false,"x":898.0000457763672,"y":762.0000648498535,"wires":[[],[]]},{"id":"54a13ddb.33d9c4","type":"ui_gauge","z":"83b78c60.0bd6f","name":"","group":"f440b0b0.67c6e","order":4,"width":"2","height":"3","gtype":"gage","title":"Temperature","label":"°C","format":"{{value|number:1}}","min":"-20","max":"50","colors":["#0000ff","#e6e600","#ca3838"],"seg1":"0","seg2":"30","x":877.9998893737793,"y":716.6666278839111,"wires":[]},{"id":"38bfc86e.685758","type":"smooth","z":"83b78c60.0bd6f","name":"","action":"mean","count":"6","round":"","mult":"single","x":626.0001220703125,"y":726.0001239776611,"wires":[["54a13ddb.33d9c4","6f47ae7f.40cd2"]]},{"id":"e1dc9a15.31a108","type":"function","z":"83b78c60.0bd6f","name":"state to finished html icon","func":"//this one is buggy\n//I will fix it with the weather station video\n\nvar moon = \"&#127769;\";\nvar rain = \"&#127783;\";\nvar sun = \"&#127774\";\nvar cloud = \"&#9925;\";\n\ncontext.humidity = context.humidity | 50;\ncontext.light = context.light | 0.5;\ncontext.pressure = context.pressure | 1000;\n\nif(msg.topic === 'humidity' && msg.payload != 'nan')\n context.humidity = msg.payload;\nif(msg.topic === 'light' && msg.payload != 'nan')\n context.light = msg.payload;\nif(msg.topic === 'pressure' && msg.payload != 'nan')\n context.pressure = msg.payload;\n\nif(context.humidity < 50)\n{\n //if(context.light > 0.1)\n msg.payload = sun;\n //else\n // msg.payload = moon;\n}\nelse \nif(context.humidity < 80)\n{\n //if(context.light > 0.1)\n msg.payload = cloud;\n //else\n // msg.payload = moon;\n}\nelse\n{\n msg.payload = rain;\n}\n\nreturn msg;","outputs":1,"noerr":0,"x":986,"y":505,"wires":[["85c7cf27.1e66e"]]},{"id":"f62c1c11.ee6cb","type":"change","z":"83b78c60.0bd6f","name":"translate topic","rules":[{"t":"change","p":"topic","pt":"msg","from":"wheatherStation/humidity","fromt":"str","to":"humidity","tot":"str"},{"t":"change","p":"topic","pt":"msg","from":"wheatherStation/temperature","fromt":"str","to":"temperature","tot":"str"},{"t":"change","p":"topic","pt":"msg","from":"wheatherStation/light","fromt":"str","to":"light","tot":"str"},{"t":"change","p":"topic","pt":"msg","from":"wheatherStation/pressure","fromt":"str","to":"pressure","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":722,"y":506,"wires":[["e1dc9a15.31a108"]]},{"id":"85c7cf27.1e66e","type":"ui_template","z":"83b78c60.0bd6f","group":"c467b276.39485","name":"Weather symbol","order":7,"width":"3","height":"3","format":"<div ng-bind-html=\"msg.payload\" style=\"font-size: 50pt\"></div>","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":1238,"y":499,"wires":[[]]},{"id":"1112abd4.01dd04","type":"debug","z":"83b78c60.0bd6f","name":"","active":true,"console":"false","complete":"false","x":1315.166748046875,"y":238,"wires":[]},{"id":"c467b276.39485","type":"ui_group","z":"","name":"Outside","tab":"7894fc0d.fc8084","order":1,"disp":true,"width":"7"},{"id":"171132c7.ece67d","type":"mqtt-broker","z":"","broker":"localhost","port":"1883","clientid":"","usetls":false,"compatmode":true,"keepalive":"60","cleansession":true,"willTopic":"","willQos":"0","willPayload":"","birthTopic":"","birthQos":"0","birthPayload":""},{"id":"f440b0b0.67c6e","type":"ui_group","z":"","name":"Bathroom","tab":"7894fc0d.fc8084","order":2,"disp":true,"width":"6"},{"id":"7894fc0d.fc8084","type":"ui_tab","z":"","name":"Climate","icon":"dashboard","order":1}]

…and this for the washing machine:

[{"id":"f843944b.416128","type":"inject","z":"a34f2e41.dd53a","name":"","topic":"tick","payload":"","payloadType":"date","repeat":"1","crontab":"","once":false,"x":684.0003890991211,"y":856.0002117156982,"wires":[["caf8cadc.339188"]]},{"id":"2f8334f4.cefd7c","type":"ui_template","z":"a34f2e41.dd53a","group":"335f2e6.c0353d2","name":"Date Input","order":5,"width":0,"height":0,"format":"<input ng-model=\"me.item.value\" type=\"datetime-local\" style=\"z-index: 1;\" ng-change=\"send(me.item.value)\">","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":108.00011444091797,"y":692.3332109451294,"wires":[["bf0f137c.1b8"]]},{"id":"caf8cadc.339188","type":"function","z":"a34f2e41.dd53a","name":"reduce countdown","func":"context.countdown = context.countdown || 0;\ncontext.active = context.active || false;\nif(msg.topic === \"countdown\")\n context.countdown = msg.payload;\nif(msg.topic === \"active\")\n{\n context.active = msg.payload;\n if(context.active === false)\n {\n msg.topic = \"countdown\";\n msg.payload = \"\";\n return msg;\n }\n}\nif(msg.topic === \"tick\" && context.countdown > 0 && context.active)\n{\n context.countdown--;\n msg.topic = \"countdown\";\n msg.payload = context.countdown;\n return msg;\n}\n\n","outputs":1,"noerr":0,"x":936.0005683898926,"y":696.6667890548706,"wires":[["79174afc.970154","dbc5c3f7.eca9d"]]},{"id":"79174afc.970154","type":"ui_text","z":"a34f2e41.dd53a","group":"335f2e6.c0353d2","order":7,"width":0,"height":0,"name":"countdown","label":"Countdown","format":"{{msg.payload}}","layout":"row-spread","x":1165.167091369629,"y":693.0002031326294,"wires":[]},{"id":"6b75c69.6340e38","type":"ui_switch","z":"a34f2e41.dd53a","name":"","label":"Enable timer","group":"335f2e6.c0353d2","order":6,"width":0,"height":0,"passthru":true,"decouple":"false","topic":"active","style":"","onvalue":"true","onvalueType":"bool","onicon":"","oncolor":"","offvalue":"false","offvalueType":"bool","officon":"","offcolor":"","x":704.0003890991211,"y":392.0004291534424,"wires":[["caf8cadc.339188"]]},{"id":"8a9630f.59921d","type":"mqtt in","z":"a34f2e41.dd53a","name":"","topic":"washingMachine/led1","qos":"1","broker":"171132c7.ece67d","x":296.00003814697266,"y":190.00000286102295,"wires":[["78115f22.279f5","4c0a3616.308828"]]},{"id":"ab5c312e.bf284","type":"mqtt in","z":"a34f2e41.dd53a","name":"","topic":"washingMachine/led2","qos":"1","broker":"171132c7.ece67d","x":300.0000762939453,"y":122.0000467300415,"wires":[["b42290a1.ff735"]]},{"id":"90b9212b.6f362","type":"mqtt in","z":"a34f2e41.dd53a","name":"","topic":"washingMachine/led3","qos":"1","broker":"171132c7.ece67d","x":304,"y":55.999990463256836,"wires":[["f0af90f3.07b05"]]},{"id":"9a10e690.6aa5c8","type":"ui_toast","z":"a34f2e41.dd53a","position":"top right","displayTime":"3","highlight":"","outputs":0,"ok":"OK","cancel":"","topic":"","name":"","x":1469.1669387817383,"y":301.00010108947754,"wires":[]},{"id":"3b5443db.cd543c","type":"ui_switch","z":"a34f2e41.dd53a","name":"","label":"Notification","group":"335f2e6.c0353d2","order":8,"width":0,"height":0,"passthru":true,"decouple":"false","topic":"notify","style":"","onvalue":"true","onvalueType":"bool","onicon":"","oncolor":"","offvalue":"false","offvalueType":"bool","officon":"","offcolor":"","x":961.1673889160156,"y":275.0000982284546,"wires":[["4c0a3616.308828"]]},{"id":"388da9d4.a45616","type":"ui_button","z":"a34f2e41.dd53a","name":"","group":"335f2e6.c0353d2","order":4,"width":"3","height":"1","passthru":false,"label":"Start/Stop","color":"","bgcolor":"","icon":"","payload":"1","payloadType":"str","topic":"","x":1189.1669158935547,"y":451.00014781951904,"wires":[["49a79c5c.2bcaa4","a745b111.d733b"]]},{"id":"a745b111.d733b","type":"mqtt out","z":"a34f2e41.dd53a","name":"","topic":"washingMachine/servo","qos":"1","retain":"false","broker":"171132c7.ece67d","x":1469.1669387817383,"y":447.0001049041748,"wires":[]},{"id":"49a79c5c.2bcaa4","type":"function","z":"a34f2e41.dd53a","name":"Stop Countdown","func":"msg.topic = \"active\";\nmsg.payload = false;\nreturn msg;","outputs":1,"noerr":0,"x":1463.1669311523438,"y":616.0001983642578,"wires":[["6b75c69.6340e38"]]},{"id":"dbc5c3f7.eca9d","type":"function","z":"a34f2e41.dd53a","name":"start if countdown 0","func":"if(msg.payload === 0)\n{\n msg.payload = \"1\";\n return msg;\n}","outputs":1,"noerr":0,"x":1177.1669235229492,"y":618.0001974105835,"wires":[["49a79c5c.2bcaa4","a745b111.d733b"]]},{"id":"94ee0358.c8ccf","type":"ui_template","z":"a34f2e41.dd53a","group":"335f2e6.c0353d2","name":"door icon","order":1,"width":"1","height":"1","format":"","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":933.1667709350586,"y":57.00000762939453,"wires":[[]]},{"id":"f0af90f3.07b05","type":"function","z":"a34f2e41.dd53a","name":"state to lock html icon","func":"if(msg.payload === '0')\n msg.template = '<ui-icon icon=\"lock_open\"></ui-icon>';\nelse\n msg.template = '<ui-icon icon=\"lock\"></ui-icon>';\nreturn msg;","outputs":1,"noerr":0,"x":629.1669158935547,"y":56.666701316833496,"wires":[["94ee0358.c8ccf"]]},{"id":"b42290a1.ff735","type":"function","z":"a34f2e41.dd53a","name":"state to washing html icon","func":"if(msg.payload === '0')\n msg.template = '<ui-icon icon=\"crop_square\"></ui-icon>';\nelse\n msg.template = '<ui-icon icon=\"play_arrow\"></ui-icon>';\nreturn msg;","outputs":1,"noerr":0,"x":638.0000534057617,"y":118.00000667572021,"wires":[["b7fc71f2.9bc9"]]},{"id":"78115f22.279f5","type":"function","z":"a34f2e41.dd53a","name":"state to finished html icon","func":"if(msg.payload === '0')\n msg.template = '<ui-icon icon=\"hourglass_empty\"></ui-icon>';\nelse\n msg.template = '<ui-icon icon=\"done_all\"></ui-icon>';\nreturn msg;","outputs":1,"noerr":0,"x":646.0000152587891,"y":193.99999904632568,"wires":[["192ad6d4.27c7e9"]]},{"id":"b7fc71f2.9bc9","type":"ui_template","z":"a34f2e41.dd53a","group":"335f2e6.c0353d2","name":"washing icon","order":2,"width":"1","height":"1","format":"","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":944.0001525878906,"y":120.00001621246338,"wires":[[]]},{"id":"192ad6d4.27c7e9","type":"ui_template","z":"a34f2e41.dd53a","group":"335f2e6.c0353d2","name":"finished icon","order":3,"width":"1","height":"1","format":"","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":938.0000762939453,"y":194.00000858306885,"wires":[[]]},{"id":"56e691b9.db12c","type":"mqtt in","z":"a34f2e41.dd53a","name":"","topic":"washingMachine/servo","qos":"1","broker":"171132c7.ece67d","x":298.0000457763672,"y":266.00005435943604,"wires":[[]]},{"id":"4c0a3616.308828","type":"function","z":"a34f2e41.dd53a","name":"notify when finished","func":"context.notifyMe = context.notifyMe || false;\nif(msg.topic === 'notify')\n context.notifyMe = msg.payload;\n \nif(msg.topic === 'washingMachine/led1' && msg.payload === \"1\" && context.notifyMe)\n{\n msg.topic = 'notify';\n msg.payload = false;\n return msg;\n}\n","outputs":1,"noerr":0,"x":972.0000762939453,"y":362.0000238418579,"wires":[["3b5443db.cd543c","5508cd9b.a96a54"]]},{"id":"5508cd9b.a96a54","type":"function","z":"a34f2e41.dd53a","name":"notification message","func":"msg.topic = 'Washing Machine';\nmsg.payload = 'Finished washing!';\nreturn msg;","outputs":1,"noerr":0,"x":1239.1669235229492,"y":353.00010108947754,"wires":[["9a10e690.6aa5c8","91737052.620a"]]},{"id":"91737052.620a","type":"ui_audio","z":"a34f2e41.dd53a","name":"Audio","group":"335f2e6.c0353d2","voice":"2","always":true,"x":1447.1667709350586,"y":385.3333959579468,"wires":[]},{"id":"b0cc132e.b3725","type":"function","z":"a34f2e41.dd53a","name":"time string to millis","func":"var d = new Date(msg.payload); \nmsg.topic = \"teargetTimestamp\"\nmsg.payload = d.getTime();\nreturn msg;","outputs":1,"noerr":0,"x":454.00004959106445,"y":690.0000748634338,"wires":[["8ff136ff.0dd288"]]},{"id":"bf0f137c.1b8","type":"function","z":"a34f2e41.dd53a","name":"msg","func":"\nreturn {topic: '', payload: msg};","outputs":1,"noerr":0,"x":275.9996910095215,"y":687.3332080841064,"wires":[["b0cc132e.b3725"]]},{"id":"8ff136ff.0dd288","type":"function","z":"a34f2e41.dd53a","name":"set countdown in seconds","func":"msg.topic = \"countdown\";\nmsg.payload = Math.floor(((msg.payload - Date.now()) / 1000));\nreturn msg;","outputs":1,"noerr":0,"x":683.9999656677246,"y":688.0000371932983,"wires":[["caf8cadc.339188"]]},{"id":"335f2e6.c0353d2","type":"ui_group","z":"","name":"Washing Machine","tab":"d31f8864.3cea88","order":2,"disp":true,"width":"6"},{"id":"171132c7.ece67d","type":"mqtt-broker","z":"","broker":"localhost","port":"1883","clientid":"","usetls":false,"compatmode":true,"keepalive":"60","cleansession":true,"willTopic":"","willQos":"0","willPayload":"","birthTopic":"","birthQos":"0","birthPayload":""},{"id":"d31f8864.3cea88","type":"ui_tab","z":"","name":"Washing Machine","icon":"dashboard","order":2}]

Parts

Raspberry Pi on Ebay:
http://ebay.to/2yjS5Dc

…and on Amazon:

These Links are supporting my channel at no extra cost to you.

Need MOAR!?

Check out the Washing Machine and also the Weather Station project pages for more details on the hardware.
I will also add more stuff here.. so visit me from time to time 🙂