Washing Machine Notifications (Alexa, Google Home, Android and Windows))

enter image description here

We have all been there at some point, leaving washing in the washing machine for longer than required. I decided to fix this with NodeRED. These are Washing Machine Notifications. There is no need to set up anything as the flow measures the power use of the washing machine and activates when the washing starts and resets when the machine has been swiched off.

Features:

  • Google Home, Android, Alexa, and Windows 10 Notifications
  • No timers, nothing to set up
  • Nagging mode for Google Home
  • Cost of washing (supports multi tarifs)

You will need the following nodes:

  • node-red-contrib-castv2 (for google home)
  • node-red-contrib-join-joaoapps (for android)
  • node-red-contrib-alexa-notifyme

and Join app for Android notifications

You will need **Sonoff POWR2 ** or similar buy here:

Settings

See Settings node in the setup menu - each setting had been explained in the comment. Depending on the MQTT message structure, you will need to adjust it to your needs.

[{"id":"785fa28c.32493c","type":"tab","label":"Washing Machine Notifications","disabled":false,"info":"![enter image description here](https://notenoughtech.com/wp-content/uploads/2019/09/maxresdefault-17.jpg)\n\nWe have all been there at some point, leaving washing in the washing machine for longer than required. I decided to fix this with NodeRED. These are Washing Machine Notifications. \nThere is no need to set up anything as the flow measures the power use of the washing machine and activates when the washing starts and resets when the machine has been swiched off.\n\n - [Complete instructions for **Google Home, Android & Windows**](https://notenoughtech.com/home-automation/washing-machine-notifications/)\n - [Complete instructions for **Alexa**](https://notenoughtech.com/home-automation/alexa-is-my-washing-ready/): \n\n**Features**:\n\n-   Google Home, Android, Alexa, and Windows 10 Notifications \n-   No timers, nothing to set up    \n-   Nagging mode for Google Home    \n-   Cost of washing (supports multi tarifs)    \n\nYou will need the following nodes:\n\n - node-red-contrib-castv2 (for google home)\n - node-red-contrib-join-joaoapps (for android)\n - node-red-contrib-alexa-notifyme\n\nand [Join app](https://play.google.com/store/apps/details?id=com.joaomgcd.join&hl=en_GB) for Android notifications \n\n## You will need **Sonoff POWR2 **buy here:\n\n - [Aliexpress](http://s.click.aliexpress.com/e/by4YqwXQ)\n - [Banggood](https://www.banggood.com/custlink/mGmvyM4HC2)\n - [Gearbest](https://www.gearbest.com/smart-home-controls/pp_1829203.html?wid=1433363&lkid=20102743)\n - [AmazonUK](https://amzn.to/2TJRPN6)\n - [AmazonUS](https://amzn.to/2u9E0bs)\n - [Itead store](http://shrsl.com/1i9e8)\n\n\n\n# Settings\nSee Settings node in the setup menu - each setting had been explained in the comment. Depending on the MQTT message structure, you will need to adjust it to your needs. \n"},{"id":"c18f8f30.55902","type":"group","z":"785fa28c.32493c","name":"Notifications","style":{"label":true,"fill":"#ffffff"},"nodes":["a09a6bc9.8a5f78","aa8c53ef.627c","ab11ad32.029cd","f9862f67.ddf08"],"x":614,"y":93,"w":1268,"h":454},{"id":"aa8c53ef.627c","type":"group","z":"785fa28c.32493c","g":"c18f8f30.55902","name":"Goolge Home + Nagging","style":{"stroke":"#0070c0","fill":"#bfdbef","label":true},"nodes":["cfc6b2e7.f36d6","9a49677.8b31498","4ee6cd11.ba2e94","e6699251.ae858","8cfc58e4.1d3178","9d8618f7.246fc8","85f3656f.8f0738","18bba6f8.400d09"],"x":694,"y":119,"w":1162,"h":162},{"id":"a09a6bc9.8a5f78","type":"group","z":"785fa28c.32493c","g":"c18f8f30.55902","name":"Alexa","style":{"stroke":"#92d04f","fill":"#e3f3d3","label":true},"nodes":["f7bfebd4.d14128","a7eda664.d96268"],"x":714,"y":319,"w":452,"h":82},{"id":"ab11ad32.029cd","type":"group","z":"785fa28c.32493c","g":"c18f8f30.55902","name":"Android","style":{"stroke":"#ffC000","fill":"#ffefbf","label":true},"nodes":["3ece21ba.ae679e","920d3719.486708"],"x":714,"y":439,"w":392,"h":82},{"id":"d4afe973.ec1bb8","type":"function","z":"785fa28c.32493c","name":"Calculate power","func":"var power = msg.payload.Outputs[0].Load;  //adjust message structure to your needs \nvar res   = flow.get(\"Resolution\");\nvar total = flow.get(\"TotalPower\");\nvar cost  = flow.get(\"CostArray\");\nvar tariff = flow.get(\"Tariff\");\nvar metricsf = flow.get(\"MetricFrequency\");\nvar standby = flow.get(\"StandbyPower\");\nvar operation = flow.get(\"Operation\");\nvar currentWash = flow.get(\"CurrentWashCycle\");\nvar history = flow.get(\"WashingHistory\");\n\nvar date = new Date();\nvar dateS = date.getTime()/1000;\nvar hour = date.getHours();\n\nfunction secondsToHms(d) {\n    d = Number(d);\n    var h = Math.floor(d / 3600);\n    var m = Math.floor(d % 3600 / 60);\n    return ('0' + h).slice(-2) + \"h \" + ('0' + m).slice(-2)+\"min\";\n}\n\n//push element\ntotal.unshift(power);\n//remove X elementh\nif(total[res] === undefined) {flow.set(\"TotalPower\", total);}\nelse {\n    total.splice(res, 1);\n    flow.set(\"TotalPower\", total);\n}\n\n\n//calculate average\nvar sum = total;\nfunction add(accumulator, a) {\n    return accumulator + a;\n}\n\nvar average = (sum.reduce(add)/total.length);\nflow.set(\"average\", average);\n\n\n//power off\nif(average === 0){\n    flow.set(\"Operation\", \"off\");\n    return [msg,null];\n}\n\n\n\n\nvar price;\n //apply day tariff\nif(hour >= tariff.Start && hour < tariff.End){\n    price = tariff.CostDay;\n}\n//apply night tariff\nif(hour < tariff.Start || hour >= tariff.End){\n    price = tariff.CostNight;\n}\n\nvar costPerMinute =  power/1000 * price / (60* (60/metricsf));\ncost.push(costPerMinute);\nflow.set(\"CostArray\", cost);\n\n\n\n\n\n//standby\nif(average >= standby && operation === \"off\"){\n    flow.set(\"Operation\", \"standby\");\n    currentWash.standbyTimeStart = dateS;\n    \n}\n\n\n//washing\nif(average > 5 ){\n    flow.set(\"collected\", false);\n    flow.set(\"Operation\", \"washing\");\n    if(currentWash.standbyTimeStart === null){\n        currentWash.standbyTimeStart = dateS;\n        currentWash.standbyTimeStop = dateS;\n    }\n    currentWash.standbyTimeStop = dateS;\n    currentWash.washTimeStart = dateS;\n    \n}\n\n\n//finished washing\nif(average < 5 && average >= standby && operation === \"washing\"){\n    flow.set(\"Operation\", \"finished\");\n    currentWash.washTimeStop = dateS;\n    currentWash.washFinishStart = dateS;\n    \n    //total cost\n    var sumCost = flow.get(\"CostArray\");\n    var costofpower = sumCost.reduce(add);\n    currentWash.totalCost = Math.round(costofpower * 100) / 100;\n    return [null, msg];\n}\n\n\n//washing collected\nif(average < standby && operation === \"finished\"){\n    currentWash.washFinishStop = dateS;\n    \n    wash = {\n        \"date\" : date,\n        \"cost\" : currentWash.totalCost,\n        \"TotalWashTime\" : secondsToHms(currentWash.washTimeStart -currentWash.standbyTimeStart),\n        \"TotalStandby\" : secondsToHms(currentWash.standbyTimeStop - currentWash.standbyTimeStart),\n        \"TotalWash\" : secondsToHms(currentWash.washTimeStop - currentWash.washTimeStart),\n        \"TotalFinishWait\": secondsToHms(currentWash.washFinishStop - currentWash.washFinishStart)\n    };\n    \n    flow.set(\"collected\", true);\n    history.push(wash);\n    flow.set(\"WashingHistory\", history);\n    flow.set(\"CostArray\", [0]);\n    \n    var cycle = {\"standbyTimeStart\": null,\n        \"standbyTimeStop\": null,\n        \"washTimeStart\": null,\n        \"washTimeStop\": null,\n        \"washFinishStart\": null,\n        \"washFinishStop\": null,\n        \"totalCost\": 0,\n}\n    \n    \n    flow.set(\"CurrentWashCycle\", cycle);\n    flow.set(\"Operation\", \"off\");\n}\n\n\n \n","outputs":2,"noerr":0,"initialize":"","finalize":"","x":400,"y":340,"wires":[[],["999c8e87.dcccf"]]},{"id":"3ece21ba.ae679e","type":"function","z":"785fa28c.32493c","g":"ab11ad32.029cd","name":"Join ","func":"var currentCycle = flow.get(\"CurrentWashCycle\");\n\nvar date = new Date();\nmsg.payload = {};\n\nfunction secondsToHms(d) {\n    d = Number(d);\n    var h = Math.floor(d / 3600);\n    var m = Math.floor(d % 3600 / 60);\n    return ('0' + h).slice(-2) + \"h \" + ('0' + m).slice(-2)+\"min\";\n}\n\nvar wash = {\n        \"date\" : date,\n        \"cost\" : currentCycle.totalCost,\n        \"TotalWashTime\" : secondsToHms(currentCycle.washTimeStart -currentCycle.standbyTimeStart),\n        \"TotalStandby\" : secondsToHms(currentCycle.standbyTimeStop - currentCycle.standbyTimeStart),\n        \"TotalWash\" : secondsToHms(currentCycle.washTimeStop - currentCycle.washTimeStart),\n        \"TotalFinishWait\": secondsToHms(currentCycle.washFinishStop - currentCycle.washFinishStart)\n    };\n\nvar phone = global.get(\"JOIN_mi9\");\nvar desktop = global.get(\"JOIN_desktop\");\nvar laptop = global.get(\"JOIN_laptop\");\n\nmsg.push = {\n    \"deviceIds\": phone +\",\"+ desktop,\n    \"title\":\"Your washing has been done in \" + wash.TotalWashTime,\n    \"text\":\"Don't be a fool - go and take out the laundry before wife nags you! The total cost of the wash is: £\" + wash.cost,\n    \"icon\":\"https://cdn3.iconfinder.com/data/icons/household-appliances-2/500/Automatic_automatic_machine_clean_machine_wash_washing-512.png\",\n};\n\nreturn msg;\n","outputs":1,"noerr":0,"initialize":"","finalize":"","x":790,"y":480,"wires":[["920d3719.486708"]]},{"id":"cfc6b2e7.f36d6","type":"delay","z":"785fa28c.32493c","g":"aa8c53ef.627c","name":"","pauseType":"delay","timeout":"5","timeoutUnits":"minutes","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":840,"y":160,"wires":[["8cfc58e4.1d3178"]]},{"id":"9a49677.8b31498","type":"switch","z":"785fa28c.32493c","g":"aa8c53ef.627c","name":"Nagging enabled","property":"nagging","propertyType":"flow","rules":[{"t":"true"}],"checkall":"true","repair":false,"outputs":1,"x":1210,"y":160,"wires":[["4ee6cd11.ba2e94"]]},{"id":"4ee6cd11.ba2e94","type":"function","z":"785fa28c.32493c","g":"aa8c53ef.627c","name":"Random Naggings of my WiFi","func":"var nagging = [\n    \"If you don't take care of washing I will divorce you\",\n    \"Stop being useless and get the washing out\",\n    \"Either you take the washing out right now, or you sleep on the sofa tonight\",\n    \"How many times do I have to tell you to empty the washing machine\",\n    \"Washing machine is not going to empty itself - move your bum\"\n    ];\nvar random = nagging[Math.floor(Math.random() * nagging.length)];\nmsg.payload = {\n    app: \"DefaultMediaReceiver\",\n    type: \"TTS\",\n    text: random,\n    speed: 1, // optional to adjust TTS speed, defaults to 1\n    language: \"en\", // optional to set TTS language, default to en\n    metadata: { // optional unless desired, follows normal metadata rules noted above\n      title: \"Media title\"\n    }\n  }\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":1450,"y":160,"wires":[["e6699251.ae858"]]},{"id":"1befff60.e48031","type":"comment","z":"785fa28c.32493c","name":"Settings","info":"","x":180,"y":100,"wires":[]},{"id":"f7bfebd4.d14128","type":"function","z":"785fa28c.32493c","g":"a09a6bc9.8a5f78","name":"Alexa Notification","func":"msg.payload = \"Your washing is ready!\";\nreturn msg;\n","outputs":1,"noerr":0,"initialize":"","finalize":"","x":830,"y":360,"wires":[["a7eda664.d96268"]]},{"id":"a7eda664.d96268","type":"alexa-notifyme","z":"785fa28c.32493c","g":"a09a6bc9.8a5f78","name":"Alexa Notification","notification":"","x":1050,"y":360,"wires":[[]]},{"id":"920d3719.486708","type":"join-message","z":"785fa28c.32493c","g":"ab11ad32.029cd","name":"","text":"","title":"","url":"","notificationicon":"","joinConfig":"43463bd8.73c264","x":1020,"y":480,"wires":[[]]},{"id":"86bf2758.c99c18","type":"function","z":"785fa28c.32493c","name":"Settings","func":"//see Setup tab\n","outputs":1,"noerr":0,"initialize":"//Electrical tariff info   \n\nvar tariff = {\"CostDay\": 0.183, \n              \"CostNight\": 0.183,\n              \"Start\": 7,\n              \"End\": 19};\nflow.set(\"Tariff\", tariff);\nflow.set(\"CostArray\", [0]);\n\n//Google Home Nagging\nvar nagging = {\n    \"status\" : false,\n    \"frequency\" : 5};\nflow.set(\"Nagging\", nagging); \n\n\n// washing Machine settings\nflow.set(\"StandbyPower\", 1);   //average power in standby mode\nflow.set(\"hostname\", \"washingmachine.lan\");   //in case you use HTTP\nflow.set(\"TotalPower\", []);   \nflow.set(\"Resolution\", 5);         // number of measurements taken for rolling power average\nflow.set(\"MetricFrequency\", 60);  // how often washing machine reports back\nflow.set(\"Operation\", \"off\");     //current operation state   off/standby/washing/finished\n\nvar cycle = {\"standbyTimeStart\": null,\n        \"standbyTimeStop\": null,\n        \"washTimeStart\": null,\n        \"washTimeStop\": null,\n        \"washFinishStart\": null,\n        \"washFinishStop\": null,\n        \"totalCost\": 0,\n}\nflow.set(\"CurrentWashCycle\",cycle);\nflow.set(\"WashingHistory\", []);  ","finalize":"","x":180,"y":140,"wires":[[]]},{"id":"9df27ed3.75732","type":"mqtt in","z":"785fa28c.32493c","name":"Washing Machine","topic":"devices/washingmachine/status","qos":"0","datatype":"json","broker":"6e117ba5.8026e4","x":170,"y":340,"wires":[["d4afe973.ec1bb8"]]},{"id":"e6699251.ae858","type":"castv2-sender","z":"785fa28c.32493c","g":"aa8c53ef.627c","name":"","connection":"15221994.6242e6","spotifyAccessToken":"","spotifyAccessTokenExpiration":"","spotifyDeviceName":"","x":1680,"y":240,"wires":[["85f3656f.8f0738"]]},{"id":"8cfc58e4.1d3178","type":"switch","z":"785fa28c.32493c","g":"aa8c53ef.627c","name":"isCollected","property":"collected","propertyType":"flow","rules":[{"t":"true"}],"checkall":"true","repair":false,"outputs":1,"x":1030,"y":160,"wires":[["9a49677.8b31498"]]},{"id":"9d8618f7.246fc8","type":"link in","z":"785fa28c.32493c","g":"aa8c53ef.627c","name":"","links":["85f3656f.8f0738"],"x":735,"y":160,"wires":[["cfc6b2e7.f36d6"]]},{"id":"85f3656f.8f0738","type":"link out","z":"785fa28c.32493c","g":"aa8c53ef.627c","name":"","links":["9d8618f7.246fc8"],"x":1815,"y":240,"wires":[]},{"id":"f9862f67.ddf08","type":"link in","z":"785fa28c.32493c","g":"c18f8f30.55902","name":"","links":[],"x":655,"y":360,"wires":[["f7bfebd4.d14128"]]},{"id":"999c8e87.dcccf","type":"link out","z":"785fa28c.32493c","name":"","links":["18bba6f8.400d09"],"x":535,"y":400,"wires":[]},{"id":"18bba6f8.400d09","type":"link in","z":"785fa28c.32493c","g":"aa8c53ef.627c","name":"","links":["999c8e87.dcccf"],"x":1495,"y":240,"wires":[["e6699251.ae858"]]},{"id":"43463bd8.73c264","type":"join-config","name":"Join Configuration","register":true},{"id":"6e117ba5.8026e4","type":"mqtt-broker","name":"MQTT","broker":"home.lan","port":"1883","clientid":"","usetls":false,"compatmode":true,"keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"0","birthPayload":"","closeTopic":"","closeQos":"0","closePayload":"","willTopic":"","willQos":"0","willPayload":""},{"id":"15221994.6242e6","type":"castv2-connection","name":"","target":"Google Home","host":"","port":"8009"}]

Flow Info

Created 6 years ago
Updated 4 years, 7 months ago
Rating: not yet rated

Actions

Rate:

Node Types

Core
  • comment (x1)
  • delay (x1)
  • function (x5)
  • link in (x3)
  • link out (x2)
  • mqtt in (x1)
  • mqtt-broker (x1)
  • switch (x2)
Other

Tags

  • washing
  • machine
  • notification
  • google
  • home
  • assistant
  • join
  • android
  • alexa
Copy this flow JSON to your clipboard and then import into Node-RED using the Import From > Clipboard (Ctrl-I) menu option