[{"id":"19f54c3b.bb52b4","type":"subflow","name":"Quiet Time","info":"","category":"","in":[{"x":50,"y":30,"wires":[{"id":"96040a89e21b4330"}]}],"out":[{"x":640,"y":20,"wires":[{"id":"96040a89e21b4330","port":0}]}],"env":[],"meta":{},"color":"#DDAA99"},{"id":"86b24cd21caa0ca2","type":"trigger-state","z":"19f54c3b.bb52b4","name":"","server":"194abd6174f64b4a","version":1,"exposeToHomeAssistant":false,"haConfig":[{"property":"name","value":""},{"property":"icon","value":""}],"entityid":"input_boolean.quiet_time","entityidfiltertype":"exact","debugenabled":true,"constraints":[{"targetType":"this_entity","targetValue":"","propertyType":"current_state","comparatorType":"is","comparatorValueDatatype":"bool","comparatorValue":"true","propertyValue":"new_state.state"}],"inputs":0,"outputs":2,"customoutputs":[],"outputinitially":false,"state_type":"habool","enableInput":false,"x":170,"y":100,"wires":[["e25ec9b97e298991"],[]]},{"id":"95121aa66e6b9e40","type":"debug","z":"19f54c3b.bb52b4","name":"","active":true,"tosidebar":true,"console":true,"tostatus":true,"complete":"payload","targetType":"msg","statusVal":"payload","statusType":"auto","x":740,"y":100,"wires":[]},{"id":"e25ec9b97e298991","type":"change","z":"19f54c3b.bb52b4","name":"","rules":[{"t":"change","p":"payload","pt":"msg","from":"true","fromt":"bool","to":"close","tot":"str"},{"t":"set","p":"topic","pt":"msg","to":"control","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":540,"y":100,"wires":[["95121aa66e6b9e40","96040a89e21b4330"]]},{"id":"de05add1092a0fba","type":"inject","z":"19f54c3b.bb52b4","name":"Auto off every morning","props":[{"p":"payload"}],"repeat":"","crontab":"00 07 * * *","once":false,"onceDelay":0.1,"topic":"","payload":"Off","payloadType":"str","x":150,"y":260,"wires":[["3bf8d4cfc061e976"]]},{"id":"3bf8d4cfc061e976","type":"api-call-service","z":"19f54c3b.bb52b4","name":"","server":"194abd6174f64b4a","version":3,"debugenabled":false,"service_domain":"homeassistant","service":"turn_off","entityId":"input_boolean.quiet_time","data":"","dataType":"jsonata","mergecontext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":440,"y":260,"wires":[[]]},{"id":"96040a89e21b4330","type":"gate","z":"19f54c3b.bb52b4","name":"","controlTopic":"control","defaultState":"open","openCmd":"open","closeCmd":"close","toggleCmd":"toggle","defaultCmd":"default","statusCmd":"status","persist":false,"storeName":"memory","x":330,"y":20,"wires":[[]]},{"id":"4db0fbe58f9a64cf","type":"change","z":"19f54c3b.bb52b4","name":"","rules":[{"t":"change","p":"payload","pt":"msg","from":"false","fromt":"bool","to":"open","tot":"str"},{"t":"set","p":"topic","pt":"msg","to":"control","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":400,"y":200,"wires":[["96040a89e21b4330","a11de4f389884fe4"]]},{"id":"a11de4f389884fe4","type":"debug","z":"19f54c3b.bb52b4","name":"","active":true,"tosidebar":true,"console":true,"tostatus":true,"complete":"payload","targetType":"msg","statusVal":"payload","statusType":"auto","x":620,"y":200,"wires":[]},{"id":"ecd7078c33026927","type":"trigger-state","z":"19f54c3b.bb52b4","name":"","server":"194abd6174f64b4a","version":1,"exposeToHomeAssistant":false,"haConfig":[{"property":"name","value":""},{"property":"icon","value":""}],"entityid":"input_boolean.quiet_time","entityidfiltertype":"exact","debugenabled":true,"constraints":[{"targetType":"this_entity","targetValue":"","propertyType":"current_state","comparatorType":"is","comparatorValueDatatype":"bool","comparatorValue":"false","propertyValue":"new_state.state"}],"inputs":0,"outputs":2,"customoutputs":[],"outputinitially":false,"state_type":"habool","enableInput":false,"x":170,"y":140,"wires":[["4db0fbe58f9a64cf"],[]]},{"id":"2d2a2c5d.038d44","type":"template","z":"19f54c3b.bb52b4","name":"","field":"payload","fieldType":"msg","format":"json","syntax":"mustache","template":"{\"data\": {\"entity_id\":\"{{data.entity_id}}\",\"brightness\":\"{{data.attributes.brightness}}\"}}","output":"str","x":640,"y":380,"wires":[["4f51c2cc.f32b4c"]]},{"id":"64c2e48e.e6747c","type":"inject","z":"19f54c3b.bb52b4","name":"","props":[{"p":"payload","v":"","vt":"date"},{"p":"topic","v":"","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":120,"y":380,"wires":[["69dd54c.1e7beac"]]},{"id":"69dd54c.1e7beac","type":"api-current-state","z":"19f54c3b.bb52b4","name":"","server":"aad53eb0.732ad","version":2,"outputs":1,"halt_if":"","halt_if_type":"str","halt_if_compare":"is","entity_id":"light.computer_desk_lights","state_type":"str","blockInputOverrides":false,"outputProperties":[{"property":"payload","propertyType":"msg","value":"","valueType":"entityState"},{"property":"data","propertyType":"msg","value":"","valueType":"entity"},{"property":"topic","propertyType":"msg","value":"","valueType":"triggerId"}],"x":380,"y":380,"wires":[["2d2a2c5d.038d44"]]},{"id":"bc9af540.9b59e8","type":"api-call-service","z":"19f54c3b.bb52b4","name":"","server":"aad53eb0.732ad","version":3,"service_domain":"light","service":"turn_on","data":"","mergecontext":"","outputProperties":[{"value":"","valueType":"data"}],"queue":"none","x":1010,"y":380,"wires":[[]]},{"id":"4f51c2cc.f32b4c","type":"delay","z":"19f54c3b.bb52b4","name":"","pauseType":"delay","timeout":"5","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"outputs":1,"x":820,"y":380,"wires":[["bc9af540.9b59e8"]]},{"id":"194abd6174f64b4a","type":"server","name":"Home Assistant View Road","version":2,"addon":false,"rejectUnauthorizedCerts":true,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":true,"cacheJson":true,"heartbeat":true,"heartbeatInterval":"30"},{"id":"aad53eb0.732ad","type":"server","name":"Home Assistant","version":2,"rejectUnauthorizedCerts":true,"ha_boolean":"y|yes|true|on|home|open","connectionDelay":true,"cacheJson":true,"heartbeat":false,"heartbeatInterval":30},{"id":"aa69d6219a52c4d6","type":"tab","label":"Oven Notifications","disabled":false,"info":"","env":[]},{"id":"bda712586b1c1964","type":"group","z":"aa69d6219a52c4d6","style":{"stroke":"#999999","stroke-opacity":"1","fill":"none","fill-opacity":"1","label":true,"label-position":"nw","color":"#a4a4a4"},"nodes":["49b0a15dac84f9a2","472646659f5b3541","4db1356efdbf8e83","ced8fa197a585a62","888283abdf05dfd2"],"x":1054,"y":99,"w":672,"h":142},{"id":"36f5580ec5a5551d","type":"group","z":"aa69d6219a52c4d6","style":{"stroke":"#999999","stroke-opacity":"1","fill":"none","fill-opacity":"1","label":true,"label-position":"nw","color":"#a4a4a4"},"nodes":["b0e9c1325134b458","823fbf8560c0df9c","14d4112db16ca0c9","fb7753450c4b3132","415bf3df68ea6ca3","5247ccb50a2ffacd","c77102c66558cc55","17456ff6bfb1095f","7c190130fb6a1741","8d97da4a79207b83"],"x":234,"y":179,"w":452,"h":302},{"id":"0b34903c8e63b79d","type":"group","z":"aa69d6219a52c4d6","style":{"stroke":"#999999","stroke-opacity":"1","fill":"none","fill-opacity":"1","label":true,"label-position":"nw","color":"#a4a4a4"},"nodes":["a9a87bc5b7df1bca","ee13a099d6298a2c","efb9fc99cd666fac","b8e4a4108b58c5fb","f2acdfe5244354f5","6ce923a42f474217","5741033e44de8bed","ba0ee44279504f29","ddaed4f024da5b26","71688b9d2a860ae0","cb6f03b66278c507","6da7350026aa133a"],"x":234,"y":499,"w":452,"h":662},{"id":"8c7c84bbd6c31889","type":"group","z":"aa69d6219a52c4d6","style":{"stroke":"#999999","stroke-opacity":"1","fill":"none","fill-opacity":"1","label":true,"label-position":"nw","color":"#a4a4a4"},"nodes":["d7d1471bb7935da6","5708e51658172aec","e12c42c010bd4c7e","f1ad20250c777baf","3c48b99c62c6a2ab","c25aa22035ee424b","fba7ddbe2f38c520"],"x":1054,"y":253,"w":812,"h":148},{"id":"7bd67f3d1bbf642f","type":"group","z":"aa69d6219a52c4d6","style":{"stroke":"#999999","stroke-opacity":"1","fill":"none","fill-opacity":"1","label":true,"label-position":"nw","color":"#a4a4a4"},"nodes":["a76bfc4296dde59e","73bcc387377a7ab7","581956480486be71","a61be1f1f40c0d08","a2d060253e0ca448","503c235049463e64"],"x":1054,"y":419,"w":792,"h":122},{"id":"d41e169c3fafbcb0","type":"group","z":"aa69d6219a52c4d6","style":{"stroke":"#999999","stroke-opacity":"1","fill":"none","fill-opacity":"1","label":true,"label-position":"nw","color":"#a4a4a4"},"nodes":["a3798d3c47f70b68","f91c02ec71070e1c","94ddb30f1a9e2ef1","d8d2d40ba5535537","2f3f13ccc12f6973","15a57bd93e503ac1"],"x":1054,"y":759,"w":512,"h":182},{"id":"272dc020b5c61328","type":"group","z":"aa69d6219a52c4d6","style":{"stroke":"#999999","stroke-opacity":"1","fill":"none","fill-opacity":"1","label":true,"label-position":"nw","color":"#a4a4a4"},"nodes":["c3735a8b230d334c","8c5d9b28bcc48e49","d3c79c4e60e0bc29","d14020bf21a7aced","4f97afa041176700","0d5408d4dcfb62c1"],"x":1054,"y":559,"w":572,"h":182},{"id":"3f27ad3e4ea74f1d","type":"group","z":"aa69d6219a52c4d6","style":{"stroke":"#999999","stroke-opacity":"1","fill":"none","fill-opacity":"1","label":true,"label-position":"nw","color":"#a4a4a4"},"nodes":["c124edfdb44faea1","403ab9925b217b6d","bf4334572404760b","ef8f3ea21d61bd24","d0465695d7ab7bf8","96b08f3f098196e9"],"x":1054,"y":959,"w":832,"h":142},{"id":"6e627c347b8c5096","type":"comment","z":"aa69d6219a52c4d6","name":"Settings","info":"","x":200,"y":100,"wires":[]},{"id":"b5efc0a0c8dfb177","type":"function","z":"aa69d6219a52c4d6","name":"Settings","func":"//see Setup tab\n","outputs":1,"noerr":0,"initialize":"// -----------------------------------------------------------------------\n// OVEN APPLIANCE MONITOR AND REMINDER\n// -----------------------------------------------------------------------\n// Notify and store power use and cost for an OVEN appliance\n// Full loop to calculate power average of appliance and \n// work out when it is operating. When operational,\n// fill arrays with power used, and cost of power calculated.\n//\n// Announce when oven likely is up to temperature and also\n// Every X minutes as a reminder that it is still on.\n// -----------------------------------------------------------------------\n// 2022-05-28 V1 - zorruno\n// - Taken from previous appliance script and modified for Oven use.\n// -----------------------------------------------------------------------\n\n// Debugging nodes on (true/false)\nflow.set(\"debugFlow\", true) ;\n\n// Appliance Names (for notifications)\nflow.set(\"applianceName\", \"Oven\") ; \nflow.set(\"applianceAction\", \"oven cooking\") ; \n\n//flow.set(\"JSONPowerTopic\", msg.payload.ENERGY.Power);\n\n// Announcement text (for voice notifications)\n// It is an array, and the announcement will be randomised.\nflow.set(\"voiceAnnouncements\", [\n \"Hey, the oven is up to temperature\",\n \"Notice, the oven has reached temperature\",\n \"The oven is up to temperature\",\n \"The oven is now pre heated\",\n \"Hey, the oven has reached preheat temperature\",\n ]) ;\n\n// -----------------------------------------------------------------------\n// Electrical tariff info \n// -----------------------------------------------------------------------\n// Updated with Auckland Contact Energy Costs, Feb 2022\n// cost is in cents per kWh and start and end are the times\n// to change tariffs.\n// Yes, free power between 9pm and 12am\nvar tariff = {\"costDay\": 0.2023, \n \"costNight\": 0.0,\n \"start\": 0,\n \"end\": 21} ;\n\n// -----------------------------------------------------------------------\n// applianceAction OPERATION Settings\n// -----------------------------------------------------------------------\n// offPower : Below this value, the applianceAction is \"Off\"\n// standbyPower : between this and offPower, the applianceAction is \"Standby\"\n// operatingPowerMinimum : between this and standbyPower, it is \"Waiting\"\n// : above this, the appliance is \"Operating\"\n// -----------------------------------------------------------------------\n\n// applianceAction shows \"Off\" if average power is below offPower\nflow.set(\"offPower\", 0.2) ;\n// applianceAction shows \"Standby\" if average power is below standbyPower\n// It will show \"Waiting\" if average power is between standbyPower\n// and operatingPowerMinimum\nflow.set(\"standbyPower\", 5) ;\n// Minimum power when fully \"Operating\".\n// This is averaged over 'resolution' values, so no problem\n// if it drops below this value at times during operation.\nflow.set(\"operatingPowerMinium\", 35) ;\n// How many times to do a power reading for rolling average.\nflow.set(\"resolution\", 6) ;\n// How often does the appliance report back (seconds)\nflow.set(\"metricFrequency\", 10) ;\n\n// -----------------------------------------------------------------------\n// For Oven Specifically\n// -----------------------------------------------------------------------\nflow.set(\"applianceUpToTemperature\", \"No\"); // Is the Oven up to temperature?\nflow.set(\"reminderFrequency\", 15); // How often, in Mins to voice remind that it is on\n\n// -----------------------------------------------------------------------\n// No need to change these. \n// Set up the Arrays, with their default values.\n// -----------------------------------------------------------------------\nflow.set(\"tariff\", tariff);\n\nflow.set(\"recentPowerArray\", [0]);\nflow.set(\"cycleCostArray\", [0]);\nflow.set(\"cyclePowerArray\", [0]);\n\nvar cycle = { \"cycleTimeStart\": null,\n \"cycleTimeStop\": null,\n \"totalCycleCostFormatted\": 0,\n \"totalCycleCostDollars\": 0,\n \"totalCyclePowerFormatted\": 0,\n \"totalCyclePowerWattHours\": 0,\n }\n\nflow.set(\"currentApplianceCycle\",cycle);\n\n\n\n","finalize":"","libs":[],"x":200,"y":140,"wires":[[]]},{"id":"23808a29ed20c018","type":"link out","z":"aa69d6219a52c4d6","name":"Appliance Completed","mode":"link","links":["ced8fa197a585a62","ef8f3ea21d61bd24","3c48b99c62c6a2ab"],"x":985,"y":500,"wires":[]},{"id":"c073ace0ccf735a5","type":"comment","z":"aa69d6219a52c4d6","name":"Operation","info":"","x":820,"y":280,"wires":[]},{"id":"10a50fc88593ea79","type":"comment","z":"aa69d6219a52c4d6","name":"Notifications","info":"","x":1126,"y":75,"wires":[]},{"id":"8603ae1b4dfc119f","type":"debug","z":"aa69d6219a52c4d6","name":"","active":false,"tosidebar":true,"console":true,"tostatus":true,"complete":"payload","targetType":"msg","statusVal":"payload","statusType":"auto","x":920,"y":140,"wires":[]},{"id":"26fa6eed05eeb181","type":"comment","z":"aa69d6219a52c4d6","name":"Power Input","info":"","x":370,"y":100,"wires":[]},{"id":"49b0a15dac84f9a2","type":"pushover","z":"aa69d6219a52c4d6","g":"bda712586b1c1964","name":"Pushover Phone MiZor","device":"MiZor,Kim_iphone","title":"","priority":0,"sound":"pianobar","url":"","url_title":"","html":false,"x":1600,"y":200,"wires":[]},{"id":"472646659f5b3541","type":"function","z":"aa69d6219a52c4d6","g":"bda712586b1c1964","name":"Notification Text","func":"// Get Current Cycle Symmary Array\nvar currentCycle = flow.get(\"currentApplianceCycle\");\n\nvar date = new Date();\nmsg.payload = {};\n\n// Function to convert unix epoch to X hours and Y mins\n// and format as 'Xh Xmin'. Drop the hours if less than 1.\nfunction secondsToHms(d) {\n d = Number(d);\n var h = Math.floor(d / 3600);\n var m = Math.floor(d % 3600 / 60);\n if (h < 1 ) {\n return ('0' + m).slice(-2)+\"min\";\n }\n else {\n return ('0' + h).slice(-2) + \"h \" + ('0' + m).slice(-2)+\"min\";\n }\n}\n\n// Function to convert unix epoch to 00:00\nfunction epochToFormattedTime(d) {\n d = Date(d * 1000);\n var h = d.gethours();\n var m = \"0\" + d.getminutes();\n return h + ':' + m.substr(-2);\n}\n\n\n// Extract start/stop time based on the unix timestamp\n// First multiply by 1000 so that the argument is in milliseconds, not seconds.\nvar startDateTime = new Date(currentCycle.cycleTimeStart * 1000);\nvar stopDateTime = new Date(currentCycle.cycleTimeStop * 1000);\nvar startDateHours = \"0\" + startDateTime.getHours();\nvar stopDateHours = \"0\" + stopDateTime.getHours();\nvar startDateMinutes = \"0\" + startDateTime.getMinutes();\nvar stopDateMinutes = \"0\" + stopDateTime.getMinutes();\n\n// Format times\n// Will display time in 10:30 format (no seconds)\nvar formattedStartTime = startDateHours.substr(-2) + ':' + startDateMinutes.substr(-2)\nvar formattedStopTime = stopDateHours.substr(-2) + ':' + stopDateMinutes.substr(-2)\n\n// Put together a notification ready for sending to notifying tools\nmsg.topic = flow.get(\"applianceName\") + \" Notification\";\nmsg.payload = \"Your \" + flow.get(\"applianceAction\") + \n \" is complete.\\nIt started at \" + formattedStartTime + \n \", finished at \" + formattedStopTime + \n \", and used \" + currentCycle.totalCyclePowerFormatted + \n \", taking \" + secondsToHms(currentCycle.cycleTimeStop - currentCycle.cycleTimeStart) + \n \" at a cost of \" + currentCycle.totalCycleCostFormatted;\n\nreturn msg;\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1400,"y":200,"wires":[["49b0a15dac84f9a2"]]},{"id":"4db1356efdbf8e83","type":"inject","z":"aa69d6219a52c4d6","g":"bda712586b1c1964","name":"Test Notification","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":1400,"y":140,"wires":[["472646659f5b3541"]]},{"id":"ced8fa197a585a62","type":"link in","z":"aa69d6219a52c4d6","g":"bda712586b1c1964","name":"Appliance Pushover Notification","links":["23808a29ed20c018"],"x":1095,"y":200,"wires":[["472646659f5b3541"]]},{"id":"888283abdf05dfd2","type":"comment","z":"aa69d6219a52c4d6","g":"bda712586b1c1964","name":"Pushover App","info":"","x":1150,"y":140,"wires":[]},{"id":"b0e9c1325134b458","type":"inject","z":"aa69d6219a52c4d6","g":"36f5580ec5a5551d","name":"","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"1800","payloadType":"num","x":330,"y":320,"wires":[["c77102c66558cc55"]]},{"id":"823fbf8560c0df9c","type":"debug","z":"aa69d6219a52c4d6","g":"36f5580ec5a5551d","name":"","active":false,"tosidebar":true,"console":true,"tostatus":true,"complete":"payload","targetType":"msg","statusVal":"payload","statusType":"auto","x":560,"y":380,"wires":[]},{"id":"14d4112db16ca0c9","type":"inject","z":"aa69d6219a52c4d6","g":"36f5580ec5a5551d","name":"","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"40","payloadType":"num","x":330,"y":360,"wires":[["c77102c66558cc55"]]},{"id":"fb7753450c4b3132","type":"inject","z":"aa69d6219a52c4d6","g":"36f5580ec5a5551d","name":"","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"14.2","payloadType":"num","x":330,"y":400,"wires":[["c77102c66558cc55"]]},{"id":"415bf3df68ea6ca3","type":"comment","z":"aa69d6219a52c4d6","g":"36f5580ec5a5551d","name":"Inject Values For Testing Only","info":"Can be used to generate test power values into the input","x":380,"y":220,"wires":[]},{"id":"5247ccb50a2ffacd","type":"inject","z":"aa69d6219a52c4d6","g":"36f5580ec5a5551d","name":"","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"3265","payloadType":"num","x":330,"y":280,"wires":[["c77102c66558cc55"]]},{"id":"c77102c66558cc55","type":"change","z":"aa69d6219a52c4d6","g":"36f5580ec5a5551d","name":"Passthrough","rules":[{"t":"set","p":"payload","pt":"msg","to":"payload","tot":"msg","dc":true}],"action":"","property":"","from":"","to":"","reg":false,"x":550,"y":320,"wires":[["823fbf8560c0df9c","55b2b942d7f708d2"]]},{"id":"17456ff6bfb1095f","type":"inject","z":"aa69d6219a52c4d6","g":"36f5580ec5a5551d","name":"","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"2","payloadType":"num","x":330,"y":440,"wires":[["c77102c66558cc55"]]},{"id":"7c190130fb6a1741","type":"inject","z":"aa69d6219a52c4d6","g":"36f5580ec5a5551d","name":"","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"0","payloadType":"num","x":550,"y":440,"wires":[["c77102c66558cc55"]]},{"id":"a9a87bc5b7df1bca","type":"debug","z":"aa69d6219a52c4d6","g":"0b34903c8e63b79d","name":"Debug : Cycle Cost Array","active":true,"tosidebar":true,"console":true,"tostatus":true,"complete":"$flowContext('debugCycleCostArray')\t","targetType":"jsonata","statusVal":"payload","statusType":"auto","x":520,"y":1060,"wires":[]},{"id":"ee13a099d6298a2c","type":"debug","z":"aa69d6219a52c4d6","g":"0b34903c8e63b79d","name":"Recent Power Readings","active":true,"tosidebar":true,"console":true,"tostatus":true,"complete":"$flowContext('debugRecentPowerArray')\t","targetType":"jsonata","statusVal":"payload","statusType":"auto","x":520,"y":1120,"wires":[]},{"id":"efb9fc99cd666fac","type":"comment","z":"aa69d6219a52c4d6","g":"0b34903c8e63b79d","name":"If Debugging On","info":"","x":340,"y":540,"wires":[]},{"id":"b8e4a4108b58c5fb","type":"debug","z":"aa69d6219a52c4d6","g":"0b34903c8e63b79d","name":"Debug: Cost So Far","active":true,"tosidebar":true,"console":true,"tostatus":true,"complete":"$flowContext('debugCostSoFar')","targetType":"jsonata","statusVal":"payload","statusType":"auto","x":500,"y":880,"wires":[]},{"id":"f2acdfe5244354f5","type":"debug","z":"aa69d6219a52c4d6","g":"0b34903c8e63b79d","name":"Debug: Power So Far","active":true,"tosidebar":true,"console":true,"tostatus":true,"complete":"$flowContext('debugPowerSoFar')","targetType":"jsonata","statusVal":"payload","statusType":"auto","x":510,"y":940,"wires":[]},{"id":"6ce923a42f474217","type":"debug","z":"aa69d6219a52c4d6","g":"0b34903c8e63b79d","name":"Debug: Average Now","active":true,"tosidebar":true,"console":true,"tostatus":true,"complete":"$flowContext('debugAverage')","targetType":"jsonata","statusVal":"payload","statusType":"auto","x":510,"y":640,"wires":[]},{"id":"5741033e44de8bed","type":"debug","z":"aa69d6219a52c4d6","g":"0b34903c8e63b79d","name":"Operation","active":true,"tosidebar":true,"console":true,"tostatus":true,"complete":"payload","targetType":"msg","statusVal":"payload","statusType":"auto","x":470,"y":580,"wires":[]},{"id":"d7d1471bb7935da6","type":"file","z":"aa69d6219a52c4d6","g":"8c7c84bbd6c31889","name":"Push to CSV File","filename":"","appendNewline":true,"createDir":true,"overwriteFile":"false","encoding":"none","x":1750,"y":360,"wires":[["f1ad20250c777baf"]]},{"id":"5708e51658172aec","type":"function","z":"aa69d6219a52c4d6","g":"8c7c84bbd6c31889","name":"Data Manipulation for CSV File","func":"// Get Current Cycle Symmary Array\nvar currentCycle = flow.get(\"currentApplianceCycle\");\n\nvar date = new Date();\nmsg.payload = {};\n\n// Function to convert unix epoch to X hours and Y mins\n// and format as 'Xh Xmin'. Drop the hours if less than 1.\nfunction secondsToHms(d) {\n d = Number(d);\n var h = Math.floor(d / 3600);\n var m = Math.floor(d % 3600 / 60);\n if (h < 1 ) { \n return ('0' + m).slice(-2)+\"min\"; \n }\n else {\n return ('0' + h).slice(-2) + \"h \" + ('0' + m).slice(-2)+\"min\"; \n }\n}\n\n// Function to convert unix epoch to 00:00\nfunction epochToFormattedTime(d) {\n d = Date(d * 1000);\n var h = d.gethours();\n var m = \"0\" + d.getminutes();\n return h + ':' + m.substr(-2);\n}\n\n\n// Extract start/stop time based on the unix timestamp\n// First multiply by 1000 so that the argument is in milliseconds, not seconds.\nvar startDateTime = new Date(currentCycle.cycleTimeStart * 1000);\nvar stopDateTime = new Date(currentCycle.cycleTimeStop * 1000);\nvar startDateHours = startDateTime.getHours();\nvar stopDateHours = stopDateTime.getHours();\nvar startDateMinutes = \"0\" + startDateTime.getMinutes();\nvar stopDateMinutes = \"0\" + stopDateTime.getMinutes();\n\n// Format times\n// Will display time in 10:30 format (no seconds)\nvar formattedStartTime = startDateHours + ':' + startDateMinutes.substr(-2)\nvar formattedStopTime = stopDateHours + ':' + stopDateMinutes.substr(-2)\n\ncsvPayload={\n \"date/time\": date,\n \"Appliance\": flow.get(\"applianceName\"), \n \"Start Time\": formattedStartTime, \n \"Finish Time\": formattedStopTime,\n \"Cycle Time Formatted\": secondsToHms(currentCycle.cycleTimeStop - currentCycle.cycleTimeStart), \n \"Cycle Time (s)\": currentCycle.cycleTimeStop - currentCycle.cycleTimeStart, \n \"Cycle Power Use Formatted\": currentCycle.totalCyclePowerFormatted, \n \"Cycle Power Use (Wh)\": currentCycle.totalCyclePowerWattHours, \n \"Cycle Cost Formatted\": currentCycle.totalCycleCostFormatted,\n \"Cycle Cost ($)\": currentCycle.totalCycleCostDollars,\n}\n\nmsg.payload=csvPayload;\nvar filename = flow.get(\"applianceName\"); \nmsg.filename = \"/data/csvlogs/\" + filename.replace(/\\s+/g, '') + \"_poweruse.csv\";\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1290,"y":360,"wires":[["e12c42c010bd4c7e"]]},{"id":"e12c42c010bd4c7e","type":"json","z":"aa69d6219a52c4d6","g":"8c7c84bbd6c31889","name":"Convert to JSON","property":"payload","action":"","pretty":false,"x":1550,"y":360,"wires":[["d7d1471bb7935da6"]]},{"id":"f1ad20250c777baf","type":"debug","z":"aa69d6219a52c4d6","g":"8c7c84bbd6c31889","name":"debug","active":true,"tosidebar":true,"console":true,"tostatus":true,"complete":"true","targetType":"full","statusVal":"payload","statusType":"auto","x":1740,"y":300,"wires":[]},{"id":"3c48b99c62c6a2ab","type":"link in","z":"aa69d6219a52c4d6","g":"8c7c84bbd6c31889","name":"Appliance History CSV File Creation","links":["23808a29ed20c018"],"x":1095,"y":360,"wires":[["5708e51658172aec"]]},{"id":"c25aa22035ee424b","type":"inject","z":"aa69d6219a52c4d6","g":"8c7c84bbd6c31889","name":"Test Notification","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":1400,"y":294,"wires":[["5708e51658172aec"]]},{"id":"fba7ddbe2f38c520","type":"comment","z":"aa69d6219a52c4d6","g":"8c7c84bbd6c31889","name":"Data to CSV File","info":"","x":1160,"y":294,"wires":[]},{"id":"a76bfc4296dde59e","type":"cast-to-client","z":"aa69d6219a52c4d6","g":"7bd67f3d1bbf642f","name":"Notify A Google Home","url":"","contentType":"","message":"","language":"","ip":"","port":"","volume":"50","x":1720,"y":500,"wires":[[]]},{"id":"73bcc387377a7ab7","type":"change","z":"aa69d6219a52c4d6","g":"7bd67f3d1bbf642f","name":"Google Home Notification Details","rules":[{"t":"set","p":"ip","pt":"msg","to":"192.168.2.210","tot":"str"},{"t":"set","p":"language","pt":"msg","to":"En-gb","tot":"str"},{"t":"set","p":"volume","pt":"msg","to":"80","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":1460,"y":500,"wires":[["a76bfc4296dde59e"]]},{"id":"581956480486be71","type":"link in","z":"aa69d6219a52c4d6","g":"7bd67f3d1bbf642f","name":"Appliance Google Home Announce","links":["82804458c4c01c96"],"x":1095,"y":500,"wires":[["503c235049463e64"]]},{"id":"a61be1f1f40c0d08","type":"inject","z":"aa69d6219a52c4d6","g":"7bd67f3d1bbf642f","name":"Test Notification","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"Test","payloadType":"str","x":1420,"y":460,"wires":[["73bcc387377a7ab7"]]},{"id":"a2d060253e0ca448","type":"comment","z":"aa69d6219a52c4d6","g":"7bd67f3d1bbf642f","name":"Google Home Announce","info":"","x":1190,"y":460,"wires":[]},{"id":"503c235049463e64","type":"subflow:19f54c3b.bb52b4","z":"aa69d6219a52c4d6","g":"7bd67f3d1bbf642f","name":"","x":1210,"y":500,"wires":[["73bcc387377a7ab7"]]},{"id":"99e7a8ba0ddb2fce","type":"poll-state","z":"aa69d6219a52c4d6","name":"","server":"194abd6174f64b4a","version":2,"exposeToHomeAssistant":false,"haConfig":[{"property":"name","value":""},{"property":"icon","value":""}],"updateinterval":"10","updateIntervalType":"num","updateIntervalUnits":"seconds","outputinitially":false,"outputonchanged":false,"entity_id":"sensor.main_oven_power_3","state_type":"str","halt_if":"","halt_if_type":"str","halt_if_compare":"is","outputs":1,"x":450,"y":140,"wires":[["8603ae1b4dfc119f","55b2b942d7f708d2"]]},{"id":"ec9bb17646afd295","type":"link out","z":"aa69d6219a52c4d6","name":"Oven Up to Temp","mode":"link","links":["4f97afa041176700","d8d2d40ba5535537"],"x":985,"y":620,"wires":[]},{"id":"07facb7be37eb16b","type":"switch","z":"aa69d6219a52c4d6","name":"Operation Mode","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"Finished","vt":"str"},{"t":"eq","v":"UpToTemperature","vt":"str"}],"checkall":"true","repair":false,"outputs":2,"x":840,"y":500,"wires":[["23808a29ed20c018"],["43524c3af6134ffe"]]},{"id":"ba0ee44279504f29","type":"debug","z":"aa69d6219a52c4d6","g":"0b34903c8e63b79d","name":"Debug: Hours","active":true,"tosidebar":true,"console":true,"tostatus":true,"complete":"$flowContext('debugHours')","targetType":"jsonata","statusVal":"payload","statusType":"auto","x":480,"y":820,"wires":[]},{"id":"ddaed4f024da5b26","type":"debug","z":"aa69d6219a52c4d6","g":"0b34903c8e63b79d","name":"Debug: Reminder Mins","active":true,"tosidebar":true,"console":true,"tostatus":true,"complete":"$flowContext('debugReminderMins')","targetType":"jsonata","statusVal":"payload","statusType":"auto","x":510,"y":700,"wires":[]},{"id":"71688b9d2a860ae0","type":"debug","z":"aa69d6219a52c4d6","g":"0b34903c8e63b79d","name":"Debug: Reminder Due?","active":true,"tosidebar":true,"console":true,"tostatus":true,"complete":"$flowContext('debugRemindNow')","targetType":"jsonata","statusVal":"payload","statusType":"auto","x":510,"y":760,"wires":[]},{"id":"8d97da4a79207b83","type":"inject","z":"aa69d6219a52c4d6","d":true,"g":"36f5580ec5a5551d","name":"","props":[{"p":"payload"}],"repeat":"10","crontab":"","once":true,"onceDelay":0.1,"topic":"","payload":"1800","payloadType":"num","x":530,"y":260,"wires":[["c77102c66558cc55"]]},{"id":"55b2b942d7f708d2","type":"function","z":"aa69d6219a52c4d6","name":"MAIN OPERATION","func":"// ---------------------------------------------------\n// Modified code from the other appliance monitoring\n// Specifically to measure and notify re an electric oven\n// MAIN LOOP\n// Full loop to calculate power average of appliance and \n// work out when it is operating or up to temperature. \n// When operational it\n// fill arrays with power used, and cost of power calculated.\n// ---------------------------------------------------\n// 2022-02-27 V1.0 - zorruno\n// - First version from the previous appriance monitoring script\n// ---------------------------------------------------\n\n// The input message must be the current power in Watts\nvar power = parseInt(msg.payload) ;\n\n// Get context variables into local variables\nvar operation = context.get(\"operation\") || \"Off\" ; // current Operation\nvar applianceUpToTemperature = context.get(\"applianceUpToTemperature\") || \"No\" ;\n\nvar reminderDue = context.get(\"reminderDue\") ; // can't use the || trick for booleans\nif (reminderDue === undefined) { reminderDue = true }\n\n// Get flow user settings variables into local variables\nvar res = flow.get(\"resolution\") ;\nvar tariff = flow.get(\"tariff\") ;\nvar metricsf = flow.get(\"metricFrequency\") ;\nvar standby = flow.get(\"standbyPower\") ;\nvar applianceName = flow.get(\"applianceName\") ;\nvar opPowerMin = flow.get(\"operatingPowerMinium\") ;\nvar currentCycle = flow.get(\"currentApplianceCycle\") ;\nvar reminderFrequency = flow.get(\"reminderFrequency\") ; // How often, in Mins to voice remind that it is on\n\n// Get flow arrays into local variables\nvar recentPowerArray = flow.get(\"recentPowerArray\") || [0];\nvar cycleCostArray = flow.get(\"cycleCostArray\") || [0];\nvar cyclePowerArray = flow.get(\"cyclePowerArray\") || [0];\n\n// Get date, seconds and hours\nvar date = new Date();\nvar dateS = date.getTime()/1000;\nvar hour = date.getHours();\n\n// ---------------------------------------------------\n// AVERAGE POWER\n// Fill power array, and calculate average \n// power. Do this on every loop.\n// ---------------------------------------------------\n//\n// Function add for reduce array\nfunction add(accumulator, a) \n {\n return accumulator + a;\n }\n\n// Push power into TotalPower array for average\nrecentPowerArray.unshift(power);\n\n// Remove X element to get total resolution for average calc\nif(recentPowerArray[res] === undefined) \n {\n flow.set(\"recentPowerArray\", recentPowerArray);\n }\nelse \n {\n recentPowerArray.splice(res, 1);\n flow.set(\"recentPowerArray\", recentPowerArray);\n }\n\n// Calculate average power from array\nvar sum = recentPowerArray;\nvar average = (sum.reduce(add)/recentPowerArray.length); // Average the array\n\n\n// ---------------------------------------------------\n// OFF\n// Appliance is \"Off\"\n// 0.2 is just an arbitrary low value, in case not exactly 0\n// ---------------------------------------------------\nif (average < 0.2)\n {\n context.set(\"operation\", \"Off\") ;\n }\n// ---------------------------------------------------\n\n\n// ---------------------------------------------------\n// STANDBY\n// Appliance is \"Standby\" (i.e. powered up but no element\n// ---------------------------------------------------\nif (average >= 0.2 && average <= standby)\n {\n context.set(\"operation\", \"Standby\") ;\n }\n// ---------------------------------------------------\n\n// ---------------------------------------------------\n// OPERATING\n// Appliance has just started its Operating cycle \n// from Standby or Off\n// ---------------------------------------------------\n//if((average > standby && operation === \"Standby\") \n// || (average > standby && operation === \"Off\") ) {\n \nif (average > standby && ( operation === \"Standby\" || operation === \"Off\"))\n {\n context.set(\"operation\", \"Operating\"); \n \n // Put the start time into the currentCycle array\n currentCycle.cycleTimeStart = dateS; \n flow.set(\"currentApplianceCycle\",currentCycle);\n \n // Clear the power calc array to start calculating for new cycle\n cyclePowerArray = [0]; // Clear array to start cycle\n flow.set(\"cyclePowerArray\",cyclePowerArray);\n \n // Clear the cost array to start calculating for new cycle\n cycleCostArray = [0]; \n flow.set(\"cycleCostArray\",cycleCostArray);\n }\n// ---------------------------------------------------\n\n// ---------------------------------------------------\n// OPERATING\n// Appliance is now Operating \n// ---------------------------------------------------\nif (average >= opPowerMin && operation !== \"Operating\")\n {\n context.set(\"operation\", \"Operating\") ;\n }\n// ---------------------------------------------------\n\n// ---------------------------------------------------\n// WAITING\n// Appliance is \"Waiting\" (i.e. is on or just up to temp)\n// If has just switched to Waiting and was prevously \"Operating\"\n// the it is \"UpToTemperature\"\n// ---------------------------------------------------\nif (average >= standby && average <= opPowerMin)\n {\n if (operation === \"Operating\" && applianceUpToTemperature != \"Yes\" ) \n {\n context.set(\"operation\", \"UpToTemperature\") ;\n context.set(\"applianceUpToTemperature\", \"Yes\") ;\n }\n else \n {\n context.set(\"operation\", \"Waiting\") ; \n }\n }\n// ---------------------------------------------------\n\n// ---------------------------------------------------\n// POWER CALCULATION\n// Calculate power and cost and put into array.\n// Only do this when cycle is occurring (Operating, OR Waiting).\n// Note this method doesn't capture EVERY data point - \n// eg we'll miss the first few as we are calculating an \n// average. We could capture more, but that is less efficient.\n// ---------------------------------------------------\nif( (operation === \"Operating\") || (operation === \"Waiting\") ) \n {\n // Push watthours into cyclePowerArray for cycle\n var wattHoursNow = power / ( 60 * ( 60 / metricsf )) ;\n cyclePowerArray.push(wattHoursNow) ;\n flow.set(\"cyclePowerArray\", cyclePowerArray) ;\n\n // Calculate the cost of power\n var price ;\n if ( hour >= tariff.start && hour < tariff.end )\n {\n price = tariff.costDay ; // Apply day tariff\n }\n if ( hour < tariff.start || hour >= tariff.end )\n {\n price = tariff.costNight ; // Apply night tariff\n }\n\n // Fill cycleCostArray\n var costPerMinute = power/1000 * price / (60* (60/metricsf)) ;\n cycleCostArray.push(costPerMinute) ;\n flow.set(\"cycleCostArray\", cycleCostArray) ; // Add to cost array\n }\n// ---------------------------------------------------\n\n// ---------------------------------------------------\n// FINISHED\n// Appliance was in Operating cycle OR Waiting, \n// but now has now finished (i.e. switched off or into Standby)\n// ---------------------------------------------------\n//if ((average < standby && operation === \"Operating\")\n// || (average < standby && operation === \"Waiting\") ) \n\nif (average <= standby && ( operation === \"Operating\" || operation === \"Waiting\"))\n {\n context.set(\"operation\", \"Finished\") ; // we are Finished\n context.set(\"applianceUpToTemperature\", \"No\") ; // reset this for next operation\n currentCycle.cycleTimeStop = dateS ; // log the end time\n\n // Calculate & format total cost of the entire cycle\n var sumCost = flow.get(\"cycleCostArray\") ;\n var costOfPower = sumCost.reduce(add) ;\n currentCycle.totalCycleCostDollars = costOfPower ;\n \n // Format as $ or cents\n if ( costOfPower < 0.01 ){\n costOfPower = '<1c' ;\n } else if ( costOfPower < 1){\n costOfPower = costOfPower * 100 ;\n costOfPower = Math.round(costOfPower) ;\n costOfPower = costOfPower.toString() + 'c' ;\n } else {\n costOfPower = costOfPower.toFixed(2) ;\n costOfPower = '$' + costOfPower.toString() ;\n }\n currentCycle.totalCycleCostFormatted = costOfPower ;\n\n // Calculate & format total power use of the entire cycle\n var sumPower = flow.get(\"cyclePowerArray\") ;\n var sumOfPower = sumPower.reduce(add) ;\n currentCycle.totalCyclePowerWattHours = sumOfPower ;\n\n // Format as wH or kWh\n if ( sumOfPower >= 1000 ){\n sumOfPower = sumOfPower / 1000 ;\n sumOfPower = sumOfPower.toFixed(1); // 1 decimal place\n sumOfPower = sumOfPower.toString() + 'kWh' ;\n } else if ( costOfPower < 1){\n costOfPower = '<1Wh' ;\n } else {\n sumOfPower = sumOfPower.toFixed(1); // 1 decimal place\n sumOfPower = sumOfPower.toString() + 'Wh' ;\n }\n currentCycle.totalCyclePowerFormatted = sumOfPower ;\n \n flow.set(\"currentApplianceCycle\",currentCycle); // Store in flow variable\n}\n\n// ---------------------------------------------------\n// REMINDER\n// Appliance is in Operating cycle OR Waiting, \n// and is still operating (e.e above standby power)\n// Send reminder (to second output asynchrously)\n// ---------------------------------------------------\n\nif (average >= standby && ( operation === \"Operating\" || operation === \"Waiting\"))\n {\n // Calculate how long has passed in minutes from cycle start\n var msg2 ;\n var diffMilliseconds = (date - currentCycle.cycleTimeStart * 1000) ; // milliseconds between now & currentCycleStart\n var diffMinsFromStart = Math.round(((diffMilliseconds % 86400000) % 3600000) / 60000) ; // minutes between now & currentCycleStart\n if ( diffMinsFromStart > 0 && diffMinsFromStart % reminderFrequency == 0 ) // use modulus to see if a reminder is due\n {\n if ( reminderDue )\n {\n msg2 = {payload: \"A reminder, the \" + applianceName \n + \" has been on for \" + diffMinsFromStart \n + \" Minutes.\"} ;\n node.send([null, msg2]) ;\n reminderDue = false ;\n } \n }\n else \n {\n reminderDue = true ;\n }\n context.set(\"reminderDue\", reminderDue) ; // set to node context for next round\n }\n \n// ---------------------------------------------------\n// Output debug stuff on each loop\n// ---------------------------------------------------\nif (flow.get(\"debugFlow\") === true)\n {\n flow.set(\"debugAverage\",average) ;\n flow.set(\"debugHours\",hour) ;\n\n // Calculate total cost of the entire cycle so far\n var costSoFar = flow.get(\"cycleCostArray\").reduce(add);\n flow.set(\"debugCostSoFar\",costSoFar) ;\n\n // Calculate total power use of the entire cycle so far\n var powerSoFar = flow.get(\"cyclePowerArray\").reduce(add);\n flow.set(\"debugPowerSoFar\",powerSoFar) ;\n\n flow.set(\"debugCyclePowerArray\",cyclePowerArray) ;\n flow.set(\"debugCycleCostArray\",cycleCostArray) ;\n flow.set(\"debugRecentPowerArray\",recentPowerArray) ;\n \n flow.set(\"debugReminderMins\",diffMinsFromStart) ;\n \n flow.set(\"debugRemindNow\",reminderDue) ;\n }\n\nmsg.payload = context.get(\"operation\") ;\n//return [msg,msg2];\nreturn [msg,null];","outputs":2,"noerr":0,"initialize":"","finalize":"","libs":[],"x":850,"y":320,"wires":[["07facb7be37eb16b","c02a52a199e619e8"],["348344baec71b7b3"]]},{"id":"cb6f03b66278c507","type":"debug","z":"aa69d6219a52c4d6","g":"0b34903c8e63b79d","name":"Debug: Cycle Power Array","active":true,"tosidebar":true,"console":true,"tostatus":true,"complete":"$flowContext('debugCyclePowerArray')\t","targetType":"jsonata","statusVal":"$flowContext('debugCyclePowerArray')\t","statusType":"auto","x":520,"y":1000,"wires":[]},{"id":"348344baec71b7b3","type":"link out","z":"aa69d6219a52c4d6","name":"Oven Reminder Out","mode":"link","links":["4f97afa041176700","d8d2d40ba5535537"],"x":985,"y":400,"wires":[]},{"id":"6da7350026aa133a","type":"link in","z":"aa69d6219a52c4d6","g":"0b34903c8e63b79d","name":"Debug In","links":["c02a52a199e619e8"],"x":295,"y":800,"wires":[["5741033e44de8bed","6ce923a42f474217","ddaed4f024da5b26","71688b9d2a860ae0","ba0ee44279504f29","b8e4a4108b58c5fb","f2acdfe5244354f5","cb6f03b66278c507","a9a87bc5b7df1bca"]]},{"id":"c02a52a199e619e8","type":"link out","z":"aa69d6219a52c4d6","name":"Main Operation Debug Out","mode":"link","links":["6da7350026aa133a"],"x":995,"y":260,"wires":[]},{"id":"43524c3af6134ffe","type":"function","z":"aa69d6219a52c4d6","name":"Random Msg","func":"// Get a set of statements and push one at random back to\n// the payload. An example for a washing machine is below\n//\n// var announce = [\n// \"The washing machine is now complete\",\n// \"Your washing is complete\",\n// \"The washing is done\",\n// \"The washing machine has finished\",\n// \"Washing has now finished\",\n// ];\n \nvar announce = flow.get(\"voiceAnnouncements\");\n \nvar random = announce[Math.floor(Math.random() * announce.length)];\nmsg.payload = random;\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":850,"y":620,"wires":[["ec9bb17646afd295"]]},{"id":"15a57bd93e503ac1","type":"play audio","z":"aa69d6219a52c4d6","g":"d41e169c3fafbcb0","name":"","voice":"36","x":1450,"y":860,"wires":[]},{"id":"a3798d3c47f70b68","type":"inject","z":"aa69d6219a52c4d6","g":"d41e169c3fafbcb0","name":"Test Notification","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"Test","payloadType":"str","x":1420,"y":800,"wires":[["15a57bd93e503ac1"]]},{"id":"f91c02ec71070e1c","type":"comment","z":"aa69d6219a52c4d6","g":"d41e169c3fafbcb0","name":"Local Browser Announce","info":"","x":1190,"y":800,"wires":[]},{"id":"94ddb30f1a9e2ef1","type":"subflow:19f54c3b.bb52b4","z":"aa69d6219a52c4d6","g":"d41e169c3fafbcb0","name":"","x":1250,"y":860,"wires":[["15a57bd93e503ac1"]]},{"id":"d8d2d40ba5535537","type":"link in","z":"aa69d6219a52c4d6","g":"d41e169c3fafbcb0","name":"Appliance Local Browser Announce","links":["348344baec71b7b3","ec9bb17646afd295"],"x":1095,"y":860,"wires":[["94ddb30f1a9e2ef1","2f3f13ccc12f6973"]]},{"id":"2f3f13ccc12f6973","type":"debug","z":"aa69d6219a52c4d6","g":"d41e169c3fafbcb0","name":"","active":true,"tosidebar":true,"console":true,"tostatus":true,"complete":"payload","targetType":"msg","statusVal":"payload","statusType":"auto","x":1260,"y":900,"wires":[]},{"id":"c3735a8b230d334c","type":"comment","z":"aa69d6219a52c4d6","g":"272dc020b5c61328","name":"Touchscreen Speaker Announce","info":"","x":1210,"y":600,"wires":[]},{"id":"8c5d9b28bcc48e49","type":"subflow:19f54c3b.bb52b4","z":"aa69d6219a52c4d6","g":"272dc020b5c61328","name":"","x":1250,"y":660,"wires":[["d3c79c4e60e0bc29"]]},{"id":"d3c79c4e60e0bc29","type":"api-call-service","z":"aa69d6219a52c4d6","g":"272dc020b5c61328","name":"Google say","server":"194abd6174f64b4a","version":3,"debugenabled":false,"service_domain":"tts","service":"google_say","entityId":"media_player.mpd","data":"{\"entity_id\":\"media_player.mpd\",\"message\":\"{{payload}}\",\"language\":\"en\"}","dataType":"json","mergecontext":"","mustacheAltTags":false,"outputProperties":[],"queue":"none","x":1470,"y":660,"wires":[[]]},{"id":"d14020bf21a7aced","type":"inject","z":"aa69d6219a52c4d6","g":"272dc020b5c61328","name":"Test Speak \"Hello World\"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"Hello World","payloadType":"str","x":1490,"y":600,"wires":[["d3c79c4e60e0bc29"]]},{"id":"4f97afa041176700","type":"link in","z":"aa69d6219a52c4d6","g":"272dc020b5c61328","name":"Appliance Touchscreen Speaker Announce","links":["348344baec71b7b3","82804458c4c01c96","ec9bb17646afd295"],"x":1095,"y":660,"wires":[["8c5d9b28bcc48e49","0d5408d4dcfb62c1"]]},{"id":"0d5408d4dcfb62c1","type":"debug","z":"aa69d6219a52c4d6","g":"272dc020b5c61328","name":"","active":true,"tosidebar":true,"console":true,"tostatus":true,"complete":"payload","targetType":"msg","statusVal":"payload","statusType":"auto","x":1260,"y":700,"wires":[]},{"id":"c124edfdb44faea1","type":"comment","z":"aa69d6219a52c4d6","g":"3f27ad3e4ea74f1d","name":"MQTT Feed Notification","info":"","x":1180,"y":1000,"wires":[]},{"id":"403ab9925b217b6d","type":"inject","z":"aa69d6219a52c4d6","g":"3f27ad3e4ea74f1d","name":"Test Notification","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":1420,"y":1000,"wires":[["96b08f3f098196e9"]]},{"id":"bf4334572404760b","type":"mqtt out","z":"aa69d6219a52c4d6","g":"3f27ad3e4ea74f1d","name":"","topic":"viewroad-status/activityfeed/ovencomplete","qos":"","retain":"true","respTopic":"","contentType":"","userProps":"","correl":"","expiry":"","broker":"e28b763a.77bd98","x":1700,"y":1060,"wires":[]},{"id":"ef8f3ea21d61bd24","type":"link in","z":"aa69d6219a52c4d6","g":"3f27ad3e4ea74f1d","name":"Appliance MQTT Report","links":["23808a29ed20c018"],"x":1095,"y":1060,"wires":[["96b08f3f098196e9"]]},{"id":"d0465695d7ab7bf8","type":"moment","z":"aa69d6219a52c4d6","g":"3f27ad3e4ea74f1d","name":"Date Format","topic":"","input":"","inputType":"msg","inTz":"Pacific/Auckland","adjAmount":0,"adjType":"days","adjDir":"add","format":"LT","locale":"en-US","output":"","outputType":"msg","outTz":"Pacific/Auckland","x":1430,"y":1060,"wires":[["bf4334572404760b"]]},{"id":"96b08f3f098196e9","type":"change","z":"aa69d6219a52c4d6","g":"3f27ad3e4ea74f1d","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"","tot":"date"}],"action":"","property":"","from":"","to":"","reg":false,"x":1240,"y":1060,"wires":[["d0465695d7ab7bf8"]]},{"id":"e28b763a.77bd98","type":"mqtt-broker","name":"Panda","broker":"192.168.3.200","port":"1883","clientid":"","autoConnect":true,"usetls":false,"compatmode":false,"protocolVersion":4,"keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"0","birthPayload":"","closeTopic":"","closeQos":"0","closePayload":"","willTopic":"","willQos":"0","willPayload":""}]