Skip to content

Instantly share code, notes, and snippets.

@notenoughtech
Created January 13, 2021 06:44
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save notenoughtech/4d5343259b1fc1f0b81152a88734190c to your computer and use it in GitHub Desktop.
Save notenoughtech/4d5343259b1fc1f0b81152a88734190c to your computer and use it in GitHub Desktop.
DIY Smart Heating 3.0

enter image description here

The third-year running, it's time to push this $5 idea further and turn this DIY Smart Heating into something awesome! Complete instructions on

Features:

  • New Dashboard
  • Redesigned underlying code
  • support for an unlimited number of rooms
  • dynamic display features
  • Alexa monitors the room that you are in
  • Alexa integration
  • Google Home integration
  • Tasker Integration
  • 1/12/24 today/yesterday filters
  • Extensive data collection (temperature, humidity, pressure, thermostat values, the weather outside)
  • historical data
  • InfluxDB integration
  • Grafana integration
  • PIR support with room scores
  • Score-driven heating policies
  • Slider based timers for each day of the week with individual temperature controls
  • Controls for individual radiators
  • Possible Machine Learning based on room scores and historical data

enter image description here

You will need

Settings

See article for complete walkthrough and setup guide

More about me:

If you want to get the latest updates to this project you can follow me via your preferred social media:

And if you feeling like buying me a coffee or supporting me in a more continuous way:

I hope you have enjoyed the project!

[{"id":"36b21c99.3c42f4","type":"tab","label":"DIY Smart Heating 3.0","disabled":false,"info":"\n![enter image description here](https://notenoughtech.com/wp-content/uploads/2021/01/maxresdefault-2.jpg)\n\nThe third-year running, it's time to push this $5 idea further and turn this DIY Smart Heating into something awesome! \n[Complete instructions on](https://notenoughtech.com/home-automation/diy-smart-heating-v3-0/)\n\n**Features**:\n\n- New Dashboard\n- Redesigned underlying code\n- support for an unlimited number of rooms\n- dynamic display features\n- Alexa monitors the room that you are in\n- Alexa integration\n- Google Home integration\n- Tasker Integration\n- 1/12/24 today/yesterday filters\n- Extensive data collection (temperature, humidity, pressure, thermostat values, the weather outside)\n- historical data\n- InfluxDB integration\n- Grafana integration\n- PIR support with room scores \n- Score-driven heating policies \n- Slider based timers for each day of the week with individual temperature controls\n- Controls for individual radiators\n- Possible Machine Learning based on room scores and historical data \n\n ![enter image description here](https://notenoughtech.com/wp-content/uploads/2021/01/2021-01-10-22_43d_44-Window.jpg)\n\n## You will need \n\n - [Sonoff Basic](http://shrsl.com/1jqli)\n- [Sonoff Temp & Humidity](http://shrsl.com/2bc1y) \n- [Sonoff PIR](https://shrsl.com/2bc1v) \n- [CC2531](https://notenoughtech.com/news/get-cc2531-on-the-itead-store-instead/) or [CC2530](https://s.click.aliexpress.com/e/_99wzHn) or [CC2538 + CC2592](https://s.click.aliexpress.com/e/_AktrB3)\n\n\n\n# Settings\n\nSee article for complete walkthrough and setup guide\n \n## More about me:\n\nIf you want to get the latest updates to this project you can follow me via your preferred social media:\n\n- [Facebook](https://www.facebook.com/NotEnoughTECH/)\n- [Twitter](https://twitter.com/NotEnoughTECH)\n- [Instagram](https://www.instagram.com/notenoughtech/)\n- [YouTube](https://www.youtube.com/user/Polepositionpage)\n\nAnd if you feeling like buying me a coffee or supporting me in a more continuous way:\n\n- [Paypal](https://www.paypal.me/notenoughtech)\n- [Patreon](https://www.patreon.com/NotEnoughTECH)\n\nI hope you have enjoyed the project!"},{"id":"2477241c.186dac","type":"group","z":"36b21c99.3c42f4","name":"Google Home","style":{"label":true,"stroke":"#3f5787","fill":"#bfdbef","fill-opacity":"0.73"},"nodes":["775ca3fd.20495c","6287a6ae.41be28","d965a399.a3f2d","e71b9eba.0c70f"],"x":1214,"y":339,"w":772,"h":82},{"id":"569d420c.08af2c","type":"group","z":"36b21c99.3c42f4","name":"Dashboard Interface","style":{"stroke":"#6f2fa0","fill":"#dbcbe7","label":true,"label-position":"n","color":"#ffffff"},"nodes":["c3668690.b8b078","5e8634f8.e933fc","a544c709.93b3d8","2e1c0fbc.5dcae","e1c37e19.913ff"],"x":28,"y":753,"w":1944,"h":814},{"id":"a544c709.93b3d8","type":"group","z":"36b21c99.3c42f4","g":"569d420c.08af2c","name":"Buttons Rooms","style":{"label":true,"fill":"#ffefbf"},"nodes":["8c2c0718.6f84a8","6c7f2d7e.ed3f54","3eb5a6cd.1f6f7a","ea281eb2.94679","d5100603.469808","3f29d200.e4805e","ced99e49.f1a51","3d444d9a.2bade2","266d61ac.bb2a0e"],"x":1134,"y":1259,"w":812,"h":282},{"id":"2e1c0fbc.5dcae","type":"group","z":"36b21c99.3c42f4","g":"569d420c.08af2c","name":"Room Charts","style":{"label":true,"stroke":"#0070c0","fill":"#bfdbef"},"nodes":["f1c766c6.15fac8","51b514be.4176ec","76fe14dc.376ccc","63ab6867.0cbf18","7e0f18d7.36ce98","ccf019a2.dbdf98","6cc58078.d0289","71a76b4e.e70f94","4d89c2a2.88c4ac"],"x":1134,"y":1079,"w":632,"h":162},{"id":"c3668690.b8b078","type":"group","z":"36b21c99.3c42f4","g":"569d420c.08af2c","name":"Thermostat","style":{"label":true,"stroke":"#ffC000","fill":"#ffffbf"},"nodes":["93c4e267.d9bb8","8c04ac5.a63405","476959d4.554778","d4a40936.45d7b8","9a3a7014.5497d","83fa979b.459908","889acb23.2ba608","bc4c236e.9ca86","13cae6c.d37c119","23f14f3d.df47b","a6f01708.d4de48","ba4edbec.9d8d88"],"x":1134,"y":779,"w":672,"h":282},{"id":"e1c37e19.913ff","type":"group","z":"36b21c99.3c42f4","g":"569d420c.08af2c","name":"Dash dthermostat dial","style":{"label":true,"fill":"#ffffff"},"nodes":["fc723538.fd4678","d5b49829.73b908","fe7df1af.7812e","e090ab96.d31ee8","75881a1d.bd1b04","34e9de03.141992","febbe3f9.6ead4"],"x":54,"y":799,"w":932,"h":142},{"id":"5e8634f8.e933fc","type":"group","z":"36b21c99.3c42f4","g":"569d420c.08af2c","name":"Dash buttons","style":{"label":true,"fill":"#e3f3d3"},"nodes":["526028f3.9a13e8","e6265270.edfef","9d372453.44d268","40455f52.b3e55","c74dac0a.b129e","681a2c79.be7694","91ad14d.90f23e8","2a24b497.1ecd8c","762a4eaa.b24b7","97a25797.c16508","49422d52.4b46e4","d5383e17.db1f2","8da2a624.245428","ea9504df.3da778","ca1e09ec.975df8","43093d89.fa6134"],"x":54,"y":979,"w":842,"h":382},{"id":"66accf0a.1210e","type":"group","z":"36b21c99.3c42f4","name":"Rooms","style":{"stroke":"#92d04f","fill":"#92d04f","fill-opacity":"0.32","label":true},"nodes":["ca8283b4.378c7","5206c1e0.16c11","6dacfdea.e43aa4","69e292ad.27800c","a2a4234e.31f84","2ac4f5c3.d97e5a","c4bfce99.f9f88","28971d8e.b00c92","8e849ca.78f136","3410ee29.ab43b2","5ffec6c6.acffd8","c7465359.89565","88c0de21.674ec","1a619c76.d311f4","cc289d73.c4d3b","c121ba2f.107eb8","619e42d9.cd281c","5b4cfff8.8b618","ffe81f8a.75979","1c4a5d72.c19463"],"x":34,"y":159,"w":982,"h":282},{"id":"7745e9a9.8d0398","type":"group","z":"36b21c99.3c42f4","name":"Send data to InfluxDB","style":{"label":true,"fill":"#ffbfbf"},"nodes":["9f6b6139.23881","3e7c2889.07fd38","a620940e.c8f9d8","67b3f400.7652fc","77307f6d.cfc01","bd21e083.8274","6e727b09.6db6e4"],"x":34,"y":459,"w":872,"h":162},{"id":"87b0b89f.042338","type":"group","z":"36b21c99.3c42f4","name":"Weather API","style":{"stroke":"#ffC000","fill":"#ffcf3f","fill-opacity":"0.12","label":true},"nodes":["4b73a352.57ad4c","f2e9754b.ae5848","ab83ae24.86c5e","573dfa1d.56ddd4"],"x":34,"y":639,"w":832,"h":82},{"id":"ae59fa39.00c6b8","type":"group","z":"36b21c99.3c42f4","name":"Sonoff Basic control","style":{"label":true,"fill":"#d1d1d1"},"nodes":["8b4a5a68.935418","dbdcc81c.45bbc8","a6671c29.8a21"],"x":1514,"y":639,"w":452,"h":82},{"id":"d4a2fc72.87791","type":"group","z":"36b21c99.3c42f4","name":"Alexa","style":{"stroke":"#3f5787","fill":"#bfc7d7","label":true},"nodes":["24fb0275.07b2fe","a0ebdcc9.5f424","a73a0046.adffb","79d7561b.7e02c8","6d9ce98.c7e6418","e63e5132.7bae2","e534480b.c21b78"],"x":1214,"y":439,"w":752,"h":182},{"id":"8b4a5a68.935418","type":"mqtt out","z":"36b21c99.3c42f4","g":"ae59fa39.00c6b8","name":"Control Sonoff","topic":"thermostat/cmnd/POWER1","qos":"0","retain":"","broker":"6e117ba5.8026e4","x":1860,"y":680,"wires":[]},{"id":"dbdcc81c.45bbc8","type":"function","z":"36b21c99.3c42f4","g":"ae59fa39.00c6b8","name":"Control relay","func":"var thermostat = flow.get(\"thermostat\");\n\nif(thermostat.switch === true) {\n msg.payload = \"ON\";\n}\n\nif(thermostat.switch === false) {\n msg.payload = \"OFF\";\n}\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":1670,"y":680,"wires":[["8b4a5a68.935418"]]},{"id":"5d6ca21c.96c37c","type":"comment","z":"36b21c99.3c42f4","name":"Set preferences","info":"","x":160,"y":80,"wires":[]},{"id":"3d627b78.6741f4","type":"function","z":"36b21c99.3c42f4","name":"Defaults","func":"//see Setup","outputs":1,"noerr":0,"initialize":"// Code added here will be run once\n// whenever the node is deployed.\nvar thermostat = flow.get(\"thermostat\");\nvar rooms = flow.get(\"rooms\");\nvar defaultLead = flow.get(\"defaultLead\"); \n\n \nvar sampleRooms = []; \nvar sampleLead = \"Hall\";\n \n \nvar sampleThermostat = {\n \"away\" : false, \n \"temp\" :0,\n \"ambient\" : null,\n \"mode\" : null,\n \"low\": null,\n \"high\": null,\n \"eco\": false,\n \"leadingRoom\": null,\n \"switch\": false,\n \"defaultTemp\" : 20,\n \"active\": null\n \n };\n\n// set default values\nif(thermostat === undefined){\n flow.set(\"thermostat\", sampleThermostat);\n}\n\nif(rooms === undefined){\n flow.set(\"rooms\", sampleRooms);\n}\n\nif(roomsHistory === undefined){\n flow.set(\"roomsHistory\", sampleRoomHistory);\n}\n\nif(defaultLead === undefined){\n flow.set(\"defaultLead\", sampleLead);\n}\n","finalize":"","x":140,"y":120,"wires":[[]]},{"id":"fc723538.fd4678","type":"inject","z":"36b21c99.3c42f4","g":"e1c37e19.913ff","name":"Refresh every 5 sec","props":[{"p":"payload"}],"repeat":"5","crontab":"","once":true,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":200,"y":900,"wires":[["d5b49829.73b908"]]},{"id":"d5b49829.73b908","type":"function","z":"36b21c99.3c42f4","g":"e1c37e19.913ff","name":"Update slider","func":"var slider = flow.get('thermostat');\nmsg.thermostat = slider;\nmsg.payload = slider.temp;\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":410,"y":900,"wires":[["75881a1d.bd1b04","e090ab96.d31ee8"]]},{"id":"fe7df1af.7812e","type":"comment","z":"36b21c99.3c42f4","g":"e1c37e19.913ff","name":"Update Dial ","info":"","x":150,"y":860,"wires":[]},{"id":"e090ab96.d31ee8","type":"function","z":"36b21c99.3c42f4","g":"e1c37e19.913ff","name":"update","func":"var target = msg.payload;\nvar topic = msg.topic;\nvar index;\n\nvar thermostat = flow.get(\"thermostat\");\nvar rooms = flow.get(\"rooms\");\nvar defaultLead = flow.get(\"defaultLead\");\n\n//unset away\nif(topic === \"slider\"){\n thermostat.away = false;\n \n}\n\n// set leading room\nvar leadingRoom = rooms.find(\n (o, i) =>{if(o.room === thermostat.leadingRoom){\n index = i;\n return true;\n }});\n\nif(leadingRoom === undefined) {\n index = 0;\n thermostat.leadingRoom = defaultLead;\n}\n\n//thermostat updates\n\n//set ambient\nthermostat.ambient = rooms[index].temp;\n\n// update target\nthermostat.temp = target;\n\n\n// set leaf\nif(rooms[index].temp >= 18 && rooms[index].temp < 22){thermostat.eco = true;}\nif(rooms[index].temp < 18 || rooms[index].temp >= 22){thermostat.eco = false;}\n \n//set colour\nif (thermostat.ambient < thermostat.temp && thermostat.away === false){\n thermostat.mode = \"heating\";\n thermostat.switch = true;\n thermostat.active = 1;\n}\nif (thermostat.ambient >= thermostat.temp && thermostat.away === false){\n thermostat.mode = \"off\";\n thermostat.switch = false;\n thermostat.active = 0;\n}\n\n\nmsg.topic = \"setValues\";\nmsg.ambient = rooms[index].temp;\nmsg.target = thermostat.temp;\nmsg.hvac = thermostat.mode;\nmsg.leaf = thermostat.eco;\nmsg.away = thermostat.away;\nmsg.leadingRoom = thermostat.leadingRoom;\n\nflow.set(\"thermostat\", thermostat);\n\n\nreturn msg;\n","outputs":1,"noerr":0,"initialize":"","finalize":"","x":730,"y":900,"wires":[["34e9de03.141992","febbe3f9.6ead4"]]},{"id":"24fb0275.07b2fe","type":"function","z":"36b21c99.3c42f4","g":"d4a2fc72.87791","name":"Process Alexa responses","func":"var thermostat = flow.get(\"thermostat\");\n\nif (msg.command === \"GetTemperatureReadingRequest\"){\n msg.extra = {\"temperatureReading\": {\"value\": thermostat.temp},\n \"applianceResponseTimestamp\": new Date().toISOString()};\n msg.payload = true;\n }\n\nif (msg.command === \"SetTargetTemperatureRequest\"){\n if (msg.payload < 10 || msg.payload > 30) {\n var range = { min: 10.0, max: 30.0}\n msg.payload = false;\n msg.extra = range;\n } \n else {\n msg.extra = {targetTemperature: {value: msg.payload}};\n thermostat.temp = msg.payload;\n thermostat.mode = \"heating\";\n msg.payload = true;\n }\n}\n\n// Turn it on\nif (msg.command === \"TurnOnRequest\"){thermostat.away = false; msg.payload = true;\n thermostat.temp = thermostat.defaultTemp;}\n \n// Turn it off\nif (msg.command === \"TurnOffRequest\"){thermostat.away = true; msg.payload = true;}\n\n\nflow.set(\"thermostat\", thermostat);\nreturn msg;\n","outputs":1,"noerr":0,"initialize":"","finalize":"","x":1530,"y":520,"wires":[["e534480b.c21b78"]]},{"id":"a0ebdcc9.5f424","type":"comment","z":"36b21c99.3c42f4","g":"d4a2fc72.87791","name":"Alexa Responses","info":"","x":1340,"y":480,"wires":[]},{"id":"a73a0046.adffb","type":"function","z":"36b21c99.3c42f4","g":"d4a2fc72.87791","name":"","func":"var device = msg.payload.name;\nvar deviceID = msg.payload.deviceSerialNumber;\nvar command = msg.payload.description.summary; \nvar thermostat = flow.get(\"thermostat\");\n\nvar test = command.match(/set.*heating/);\n\nif(test !== null){\n thermostat.leadingRoom = device;\n flow.set(\"thermostat\", thermostat);\n var reply = \"Sure, I'll keep the \" + device + \" warm for you.\"\n msg.payload = { \"type\": \"speak\", \"payload\": { \"type\": 'regular', \"text\": reply, \"devices\": [deviceID]}};\n \n return msg;\n}\n","outputs":1,"noerr":0,"initialize":"","finalize":"","x":1580,"y":580,"wires":[["6d9ce98.c7e6418"]]},{"id":"8c2c0718.6f84a8","type":"function","z":"36b21c99.3c42f4","g":"a544c709.93b3d8","name":"Lead Room updates","func":"var thermostat = flow.get(\"thermostat\");\nvar rooms = flow.get(\"rooms\");\n\nvar buttons = [];\n\nfor (var x in rooms){\n //set up each button based on room props\n var background = \"\";\n if(rooms[x].temp >= thermostat.temp){\n background = \"orange\";\n }\n if(rooms[x].temp < thermostat.temp){\n background = \"grey\";\n }\n \n if(rooms[x].room === thermostat.leadingRoom){\n background = \"red\";\n }\n \n \n let button = {\n \"room\" : rooms[x].room,\n \"temp\" : rooms[x].temp,\n \"background\" : background\n }\n \n buttons.push(button);\n}\n\nreturn buttons;\n\n\n\n\n","outputs":6,"noerr":0,"initialize":"","finalize":"","x":1340,"y":1400,"wires":[["3eb5a6cd.1f6f7a"],["266d61ac.bb2a0e"],["ced99e49.f1a51"],["d5100603.469808"],["3f29d200.e4805e"],["3d444d9a.2bade2"]]},{"id":"526028f3.9a13e8","type":"ui_button","z":"36b21c99.3c42f4","g":"5e8634f8.e933fc","name":"","group":"d3f4c38f.616e3","order":1,"width":5,"height":1,"passthru":false,"label":"Temperature","tooltip":"","color":"","bgcolor":"","icon":"","payload":"{\"group\":{\"hide\":[\"Heating_Rooms_All_Data\",\"Heating_Rooms_Humidity\",\"Heating_Rooms_Pressure\"],\"show\":[\"Heating_Rooms_Temp\"]}}","payloadType":"json","topic":"","x":390,"y":1240,"wires":[["40455f52.b3e55"]]},{"id":"e6265270.edfef","type":"ui_button","z":"36b21c99.3c42f4","g":"5e8634f8.e933fc","name":"","group":"d3f4c38f.616e3","order":3,"width":5,"height":1,"passthru":false,"label":"Humidity","tooltip":"","color":"","bgcolor":"","icon":"","payload":"{\"group\":{\"hide\":[\"Heating_Rooms_All_Data\",\"Heating_Rooms_Pressure\",\"Heating_Rooms_Temp\"],\"show\":[\"Heating_Rooms_Humidity\"]}}","payloadType":"json","topic":"","x":380,"y":1280,"wires":[["40455f52.b3e55"]]},{"id":"9d372453.44d268","type":"ui_button","z":"36b21c99.3c42f4","g":"5e8634f8.e933fc","name":"","group":"d3f4c38f.616e3","order":2,"width":5,"height":1,"passthru":false,"label":"Pressure","tooltip":"","color":"","bgcolor":"","icon":"","payload":"{\"group\":{\"hide\":[\"Heating_Rooms_All_Data\",\"Heating_Rooms_Humidity\",\"Heating_Rooms_Humidity\",\"Heating_Rooms_Temp\"],\"show\":[\"Heating_Rooms_Pressure\"]}}","payloadType":"json","topic":"","x":380,"y":1320,"wires":[["40455f52.b3e55"]]},{"id":"75881a1d.bd1b04","type":"ui_slider","z":"36b21c99.3c42f4","g":"e1c37e19.913ff","name":"Slider","label":"Target Temp","tooltip":"","group":"604a48df.caa088","order":22,"width":7,"height":1,"passthru":true,"outs":"all","topic":"slider","min":"10","max":"30","step":1,"x":570,"y":840,"wires":[["e090ab96.d31ee8"]]},{"id":"40455f52.b3e55","type":"ui_ui_control","z":"36b21c99.3c42f4","g":"5e8634f8.e933fc","name":"","x":580,"y":1280,"wires":[[]]},{"id":"34e9de03.141992","type":"ui_template","z":"36b21c99.3c42f4","g":"e1c37e19.913ff","group":"604a48df.caa088","name":"Nest 3","order":1,"width":7,"height":8,"format":"<div id=\"thermostat1\"></div>\n\n<style>\n@import url(http://fonts.googleapis.com/css?family=Open+Sans:300);\n#thermostat {\n margin: 0 auto;\n -webkit-tap-highlight-color: rgba(0, 0, 0, 0);\n}\n.dial {\n -webkit-user-select: none;\n -moz-user-select: none;\n -ms-user-select: none;\n user-select: none;\n}\n.dial.away .dial__ico__leaf {\n visibility: hidden;\n}\n.dial.away .dial__lbl--target {\n visibility: hidden;\n}\n.dial.away .dial__lbl--target--half {\n visibility: hidden;\n}\n.dial.away .dial__lbl--away {\n opacity: 1;\n}\n.dial .dial__shape {\n -webkit-transition: fill 0.5s;\n transition: fill 0.5s;\n}\n.dial__ico__leaf {\n fill: #13EB13;\n opacity: 0;\n -webkit-transition: opacity 0.5s;\n transition: opacity 0.5s;\n pointer-events: none;\n}\n.dial.has-leaf .dial__ico__leaf {\n display: block;\n opacity: 1;\n pointer-events: initial;\n}\n.dial__editableIndicator {\n fill: white;\n fill-rule: evenodd;\n opacity: 0;\n -webkit-transition: opacity 0.5s;\n transition: opacity 0.5s;\n}\n.dial--edit .dial__editableIndicator {\n opacity: 1;\n}\n.dial--state--off .dial__shape {\n fill: #3d3c3c;\n}\n.dial--state--heating .dial__shape {\n fill: #E36304;\n}\n.dial--state--cooling .dial__shape {\n fill: #007AF1;\n}\n.dial__ticks path {\n fill: rgba(255, 255, 255, 0.3);\n}\n.dial__ticks path.active {\n fill: rgba(255, 255, 255, 0.8);\n}\n.dial text {\n fill: white;\n text-anchor: middle;\n font-family: Helvetica, sans-serif;\n alignment-baseline: central;\n}\n.dial__lbl--target {\n font-size: 120px;\n font-weight: bold;\n}\n.dial__lbl--target--half {\n font-size: 40px;\n font-weight: bold;\n opacity: 0;\n -webkit-transition: opacity 0.1s;\n transition: opacity 0.1s;\n}\n.dial__lbl--target--half.shown {\n opacity: 1;\n -webkit-transition: opacity 0s;\n transition: opacity 0s;\n}\n.dial__lbl--ambient {\n font-size: 22px;\n font-weight: bold;\n}\n.dial__lbl--away {\n font-size: 72px;\n font-weight: bold;\n opacity: 0;\n pointer-events: none;\n}\n#controls {\n font-family: Open Sans;\n background-color: rgba(255, 255, 255, 0.25);\n padding: 20px;\n border-radius: 5px;\n position: absolute;\n left: 50%;\n -webkit-transform: translatex(-50%);\n transform: translatex(-50%);\n margin-top: 20px;\n}\n#controls label {\n text-align: left;\n display: block;\n}\n#controls label span {\n display: inline-block;\n width: 200px;\n text-align: right;\n font-size: 0.8em;\n text-transform: uppercase;\n}\n#controls p {\n margin: 0;\n margin-bottom: 1em;\n padding-bottom: 1em;\n border-bottom: 2px solid #ccc;\n}\n</style>\n<script>\n var thermostatDial = (function() {\n\t\n\t/*\n\t * Utility functions\n\t */\n\t\n\t// Create an element with proper SVG namespace, optionally setting its attributes and appending it to another element\n\tfunction createSVGElement(tag,attributes,appendTo) {\n\t\tvar element = document.createElementNS('http://www.w3.org/2000/svg',tag);\n\t\tattr(element,attributes);\n\t\tif (appendTo) {\n\t\t\tappendTo.appendChild(element);\n\t\t}\n\t\treturn element;\n\t}\n\t\n\t// Set attributes for an element\n\tfunction attr(element,attrs) {\n\t\tfor (var i in attrs) {\n\t\t\telement.setAttribute(i,attrs[i]);\n\t\t}\n\t}\n\t\n\t// Rotate a cartesian point about given origin by X degrees\n\tfunction rotatePoint(point, angle, origin) {\n\t\tvar radians = angle * Math.PI/180;\n\t\tvar x = point[0]-origin[0];\n\t\tvar y = point[1]-origin[1];\n\t\tvar x1 = x*Math.cos(radians) - y*Math.sin(radians) + origin[0];\n\t\tvar y1 = x*Math.sin(radians) + y*Math.cos(radians) + origin[1];\n\t\treturn [x1,y1];\n\t}\n\t\n\t// Rotate an array of cartesian points about a given origin by X degrees\n\tfunction rotatePoints(points, angle, origin) {\n\t\treturn points.map(function(point) {\n\t\t\treturn rotatePoint(point, angle, origin);\n\t\t});\n\t}\n\t\n\t// Given an array of points, return an SVG path string representing the shape they define\n\tfunction pointsToPath(points) {\n\t\treturn points.map(function(point, iPoint) {\n\t\t\treturn (iPoint>0?'L':'M') + point[0] + ' ' + point[1];\n\t\t}).join(' ')+'Z';\n\t}\n\t\n\tfunction circleToPath(cx, cy, r) {\n\t\treturn [\n\t\t\t\"M\",cx,\",\",cy,\n\t\t\t\"m\",0-r,\",\",0,\n\t\t\t\"a\",r,\",\",r,0,1,\",\",0,r*2,\",\",0,\n\t\t\t\"a\",r,\",\",r,0,1,\",\",0,0-r*2,\",\",0,\n\t\t\t\"z\"\n\t\t].join(' ').replace(/\\s,\\s/g,\",\");\n\t}\n\t\n\tfunction donutPath(cx,cy,rOuter,rInner) {\n\t\treturn circleToPath(cx,cy,rOuter) + \" \" + circleToPath(cx,cy,rInner);\n\t}\n\t\n\t// Restrict a number to a min + max range\n\tfunction restrictToRange(val,min,max) {\n\t\tif (val < min) return min;\n\t\tif (val > max) return max;\n\t\treturn val;\n\t}\n\t\n\t// Round a number to the nearest 0.5\n\tfunction roundHalf(num) {\n\t\treturn Math.round(num*2)/2;\n\t}\n\t\n\tfunction setClass(el, className, state) {\n\t\tel.classList[state ? 'add' : 'remove'](className);\n\t}\n\t\n\t/*\n\t * The \"MEAT\"\n\t */\n\n\treturn function(targetElement, options) {\n\t\tvar self = this;\n\t\t\n\t\t/*\n\t\t * Options\n\t\t */\n\t\toptions = options || {};\n\t\toptions = {\n\t\t\tdiameter: options.diameter || 300,\n\t\t\tminValue: options.minValue || 10, // Minimum value for target temperature\n\t\t\tmaxValue: options.maxValue || 30, // Maximum value for target temperature\n\t\t\tnumTicks: options.numTicks || 200, // Number of tick lines to display around the dial\n\t\t\tonSetTargetTemperature: options.onSetTargetTemperature || function() {}, // Function called when new target temperature set by the dial\n\t\t};\n\t\t\n\t\t/*\n\t\t * Properties - calculated from options in many cases\n\t\t */\n\t\tvar properties = {\n\t\t\ttickDegrees: 300, // Degrees of the dial that should be covered in tick lines\n\t\t\trangeValue: options.maxValue - options.minValue,\n\t\t\tradius: options.diameter/2,\n\t\t\tticksOuterRadius: options.diameter / 30,\n\t\t\tticksInnerRadius: options.diameter / 8,\n\t\t\thvac_states: ['off', 'heating', 'cooling'],\n\t\t\tdragLockAxisDistance: 15,\n\t\t}\n\t\tproperties.lblAmbientPosition = [properties.radius, properties.ticksOuterRadius-(properties.ticksOuterRadius-properties.ticksInnerRadius)/2]\n\t\tproperties.offsetDegrees = 180-(360-properties.tickDegrees)/2;\n\t\t\n\t\t/*\n\t\t * Object state\n\t\t */\n\t\tvar state = {\n\t\t\ttarget_temperature: options.minValue,\n\t\t\tambient_temperature: options.minValue,\n\t\t\thvac_state: properties.hvac_states[0],\n\t\t\thas_leaf: false,\n\t\t\taway: false\n\t\t};\n\t\t\n\t\t/*\n\t\t * Property getter / setters\n\t\t */\n\t\tObject.defineProperty(this,'target_temperature',{\n\t\t\tget: function() {\n\t\t\t\treturn state.target_temperature;\n\t\t\t},\n\t\t\tset: function(val) {\n\t\t\t\tstate.target_temperature = restrictTargetTemperature(+val);\n\t\t\t\trender();\n\t\t\t}\n\t\t});\n\t\tObject.defineProperty(this,'ambient_temperature',{\n\t\t\tget: function() {\n\t\t\t\treturn state.ambient_temperature;\n\t\t\t},\n\t\t\tset: function(val) {\n\t\t\t\tstate.ambient_temperature = roundHalf(+val);\n\t\t\t\trender();\n\t\t\t}\n\t\t});\n\t\tObject.defineProperty(this,'hvac_state',{\n\t\t\tget: function() {\n\t\t\t\treturn state.hvac_state;\n\t\t\t},\n\t\t\tset: function(val) {\n\t\t\t\tif (properties.hvac_states.indexOf(val)>=0) {\n\t\t\t\t\tstate.hvac_state = val;\n\t\t\t\t\trender();\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\t\tObject.defineProperty(this,'has_leaf',{\n\t\t\tget: function() {\n\t\t\t\treturn state.has_leaf;\n\t\t\t},\n\t\t\tset: function(val) {\n\t\t\t\tstate.has_leaf = !!val;\n\t\t\t\trender();\n\t\t\t}\n\t\t});\n\t\tObject.defineProperty(this,'away',{\n\t\t\tget: function() {\n\t\t\t\treturn state.away;\n\t\t\t},\n\t\t\tset: function(val) {\n\t\t\t\tstate.away = !!val;\n\t\t\t\trender();\n\t\t\t}\n\t\t});\n\t\t\n\t\t/*\n\t\t * SVG\n\t\t */\n\t\tvar svg = createSVGElement('svg',{\n\t\t\twidth: '100%', //options.diameter+'px',\n\t\t\theight: '100%', //options.diameter+'px',\n\t\t\tviewBox: '0 0 '+options.diameter+' '+options.diameter,\n\t\t\tclass: 'dial'\n\t\t},targetElement);\n\t\t// CIRCULAR DIAL\n\t\tvar circle = createSVGElement('circle',{\n\t\t\tcx: properties.radius,\n\t\t\tcy: properties.radius,\n\t\t\tr: properties.radius,\n\t\t\tclass: 'dial__shape'\n\t\t},svg);\n\t\t// EDITABLE INDICATOR\n\t\tvar editCircle = createSVGElement('path',{\n\t\t\td: donutPath(properties.radius,properties.radius,properties.radius-4,properties.radius-8),\n\t\t\tclass: 'dial__editableIndicator',\n\t\t},svg);\n\t\t\n\t\t/*\n\t\t * Ticks\n\t\t */\n\t\tvar ticks = createSVGElement('g',{\n\t\t\tclass: 'dial__ticks'\t\n\t\t},svg);\n\t\tvar tickPoints = [\n\t\t\t[properties.radius-1, properties.ticksOuterRadius],\n\t\t\t[properties.radius+1, properties.ticksOuterRadius],\n\t\t\t[properties.radius+1, properties.ticksInnerRadius],\n\t\t\t[properties.radius-1, properties.ticksInnerRadius]\n\t\t];\n\t\tvar tickPointsLarge = [\n\t\t\t[properties.radius-1.5, properties.ticksOuterRadius],\n\t\t\t[properties.radius+1.5, properties.ticksOuterRadius],\n\t\t\t[properties.radius+1.5, properties.ticksInnerRadius+20],\n\t\t\t[properties.radius-1.5, properties.ticksInnerRadius+20]\n\t\t];\n\t\tvar theta = properties.tickDegrees/options.numTicks;\n\t\tvar tickArray = [];\n\t\tfor (var iTick=0; iTick<options.numTicks; iTick++) {\n\t\t\ttickArray.push(createSVGElement('path',{d:pointsToPath(tickPoints)},ticks));\n\t\t};\n\t\t\n\t\t/*\n\t\t * Labels\n\t\t */\n\t\tvar lblTarget = createSVGElement('text',{\n\t\t\tx: properties.radius,\n\t\t\ty: properties.radius,\n\t\t\tclass: 'dial__lbl dial__lbl--target'\n\t\t},svg);\n\t\tvar lblTarget_text = document.createTextNode('');\n\t\tlblTarget.appendChild(lblTarget_text);\n\t\t//\n\t\tvar lblTargetHalf = createSVGElement('text',{\n\t\t\tx: properties.radius + properties.radius/2.5,\n\t\t\ty: properties.radius - properties.radius/8,\n\t\t\tclass: 'dial__lbl dial__lbl--target--half'\n\t\t},svg);\n\t\tvar lblTargetHalf_text = document.createTextNode('5');\n\t\tlblTargetHalf.appendChild(lblTargetHalf_text);\n\t\t//\n\t\tvar lblAmbient = createSVGElement('text',{\n\t\t\tclass: 'dial__lbl dial__lbl--ambient'\n\t\t},svg);\n\t\tvar lblAmbient_text = document.createTextNode('');\n\t\tlblAmbient.appendChild(lblAmbient_text);\n\t\t//\n\t\tvar lblAway = createSVGElement('text',{\n\t\t\tx: properties.radius,\n\t\t\ty: properties.radius,\n\t\t\tclass: 'dial__lbl dial__lbl--away'\n\t\t},svg);\n\t\tvar lblAway_text = document.createTextNode('AWAY');\n\t\tlblAway.appendChild(lblAway_text);\n\t\t//\n\t\tvar icoLeaf = createSVGElement('path',{\n\t\t\tclass: 'dial__ico__leaf'\n\t\t},svg);\n\t\t\n\t\t/*\n\t\t * LEAF\n\t\t */\n\t\tvar leafScale = properties.radius/5/100;\n\t\tvar leafDef = [\"M\", 3, 84, \"c\", 24, 17, 51, 18, 73, -6, \"C\", 100, 52, 100, 22, 100, 4, \"c\", -13, 15, -37, 9, -70, 19, \"C\", 4, 32, 0, 63, 0, 76, \"c\", 6, -7, 18, -17, 33, -23, 24, -9, 34, -9, 48, -20, -9, 10, -20, 16, -43, 24, \"C\", 22, 63, 8, 78, 3, 84, \"z\"].map(function(x) {\n\t\t\treturn isNaN(x) ? x : x*leafScale;\n\t\t}).join(' ');\n\t\tvar translate = [properties.radius-(leafScale*100*0.5),properties.radius*1.5]\n\t\tvar icoLeaf = createSVGElement('path',{\n\t\t\tclass: 'dial__ico__leaf',\n\t\t\td: leafDef,\n\t\t\ttransform: 'translate('+translate[0]+','+translate[1]+')'\n\t\t},svg);\n\t\t\t\n\t\t/*\n\t\t * RENDER\n\t\t */\n\t\tfunction render() {\n\t\t\trenderAway();\n\t\t\trenderHvacState();\n\t\t\trenderTicks();\n\t\t\trenderTargetTemperature();\n\t\t\trenderAmbientTemperature();\n\t\t\trenderLeaf();\n\t\t}\n\t\trender();\n\n\t\t/*\n\t\t * RENDER - ticks\n\t\t */\n\t\tfunction renderTicks() {\n\t\t\tvar vMin, vMax;\n\t\t\tif (self.away) {\n\t\t\t\tvMin = self.ambient_temperature;\n\t\t\t\tvMax = vMin;\n\t\t\t} else {\n\t\t\t\tvMin = Math.min(self.ambient_temperature, self.target_temperature);\n\t\t\t\tvMax = Math.max(self.ambient_temperature, self.target_temperature);\n\t\t\t}\n\t\t\tvar min = restrictToRange(Math.round((vMin-options.minValue)/properties.rangeValue * options.numTicks),0,options.numTicks-1);\n\t\t\tvar max = restrictToRange(Math.round((vMax-options.minValue)/properties.rangeValue * options.numTicks),0,options.numTicks-1);\n\t\t\t//\n\t\t\ttickArray.forEach(function(tick,iTick) {\n\t\t\t\tvar isLarge = iTick==min || iTick==max;\n\t\t\t\tvar isActive = iTick >= min && iTick <= max;\n\t\t\t\tattr(tick,{\n\t\t\t\t\td: pointsToPath(rotatePoints(isLarge ? tickPointsLarge: tickPoints,iTick*theta-properties.offsetDegrees,[properties.radius, properties.radius])),\n\t\t\t\t\tclass: isActive ? 'active' : ''\n\t\t\t\t});\n\t\t\t});\n\t\t}\n\t\n\t\t/*\n\t\t * RENDER - ambient temperature\n\t\t */\n\t\tfunction renderAmbientTemperature() {\n\t\t\tlblAmbient_text.nodeValue = Math.floor(self.ambient_temperature);\n\t\t\tif (self.ambient_temperature%1!=0) {\n\t\t\t\tlblAmbient_text.nodeValue += '⁵';\n\t\t\t}\n\t\t\tvar peggedValue = restrictToRange(self.ambient_temperature, options.minValue, options.maxValue);\n\t\t\tdegs = properties.tickDegrees * (peggedValue-options.minValue)/properties.rangeValue - properties.offsetDegrees;\n\t\t\tif (peggedValue > self.target_temperature) {\n\t\t\t\tdegs += 8;\n\t\t\t} else {\n\t\t\t\tdegs -= 8;\n\t\t\t}\n\t\t\tvar pos = rotatePoint(properties.lblAmbientPosition,degs,[properties.radius, properties.radius]);\n\t\t\tattr(lblAmbient,{\n\t\t\t\tx: pos[0],\n\t\t\t\ty: pos[1]\n\t\t\t});\n\t\t}\n\n\t\t/*\n\t\t * RENDER - target temperature\n\t\t */\n\t\tfunction renderTargetTemperature() {\n\t\t\tlblTarget_text.nodeValue = Math.floor(self.target_temperature);\n\t\t\tsetClass(lblTargetHalf,'shown',self.target_temperature%1!=0);\n\t\t}\n\t\t\n\t\t/*\n\t\t * RENDER - leaf\n\t\t */\n\t\tfunction renderLeaf() {\n\t\t\tsetClass(svg,'has-leaf',self.has_leaf);\n\t\t}\n\t\t\n\t\t/*\n\t\t * RENDER - HVAC state\n\t\t */\n\t\tfunction renderHvacState() {\n\t\t\tArray.prototype.slice.call(svg.classList).forEach(function(c) {\n\t\t\t\tif (c.match(/^dial--state--/)) {\n\t\t\t\t\tsvg.classList.remove(c);\n\t\t\t\t};\n\t\t\t});\n\t\t\tsvg.classList.add('dial--state--'+self.hvac_state);\n\t\t}\n\t\t\n\t\t/*\n\t\t * RENDER - away\n\t\t */\n\t\tfunction renderAway() {\n\t\t\tsvg.classList[self.away ? 'add' : 'remove']('away');\n\t\t}\n\t\t\n\t\t/*\n\t\t * Drag to control\n\t\t */\n\t\tvar _drag = {\n\t\t\tinProgress: false,\n\t\t\tstartPoint: null,\n\t\t\tstartTemperature: 0,\n\t\t\tlockAxis: undefined\n\t\t};\n\t\t\n\t\tfunction eventPosition(ev) {\n\t\t\tif (ev.targetTouches && ev.targetTouches.length) {\n\t\t\t\treturn [ev.targetTouches[0].clientX, ev.targetTouches[0].clientY];\n\t\t\t} else {\n\t\t\t\treturn [ev.x, ev.y];\n\t\t\t};\n\t\t}\n\t\t\n\t\tvar startDelay;\n\t\tfunction dragStart(ev) {\n\t\t\tstartDelay = setTimeout(function() {\n\t\t\t\tsetClass(svg, 'dial--edit', true);\n\t\t\t\t_drag.inProgress = true;\n\t\t\t\t_drag.startPoint = eventPosition(ev);\n\t\t\t\t_drag.startTemperature = self.target_temperature || options.minValue;\n\t\t\t\t_drag.lockAxis = undefined;\n\t\t\t},1000);\n\t\t};\n\t\t\n\t\tfunction dragEnd (ev) {\n\t\t\tclearTimeout(startDelay);\n\t\t\tsetClass(svg, 'dial--edit', false);\n\t\t\tif (!_drag.inProgress) return;\n\t\t\t_drag.inProgress = false;\n\t\t\tif (self.target_temperature != _drag.startTemperature) {\n\t\t\t\tif (typeof options.onSetTargetTemperature == 'function') {\n\t\t\t\t\toptions.onSetTargetTemperature(self.target_temperature);\n\t\t\t\t};\n\t\t\t};\n\t\t};\n\t\t\n\t\tfunction dragMove(ev) {\n\t\t\tev.preventDefault();\n\t\t\tif (!_drag.inProgress) return;\n\t\t\tvar evPos = eventPosition(ev);\n\t\t\tvar dy = _drag.startPoint[1]-evPos[1];\n\t\t\tvar dx = evPos[0] - _drag.startPoint[0];\n\t\t\tvar dxy;\n\t\t\tif (_drag.lockAxis == 'x') {\n\t\t\t\tdxy = dx;\n\t\t\t} else if (_drag.lockAxis == 'y') {\n\t\t\t\tdxy = dy;\n\t\t\t} else if (Math.abs(dy) > properties.dragLockAxisDistance) {\n\t\t\t\t_drag.lockAxis = 'y';\n\t\t\t\tdxy = dy;\n\t\t\t} else if (Math.abs(dx) > properties.dragLockAxisDistance) {\n\t\t\t\t_drag.lockAxis = 'x';\n\t\t\t\tdxy = dx;\n\t\t\t} else {\n\t\t\t\tdxy = (Math.abs(dy) > Math.abs(dx)) ? dy : dx;\n\t\t\t};\n\t\t\tvar dValue = (dxy*getSizeRatio())/(options.diameter)*properties.rangeValue;\n\t\t\tself.target_temperature = roundHalf(_drag.startTemperature+dValue);\n\t\t}\n\t\t\n\t\tsvg.addEventListener('mousedown',dragStart);\n\t\tsvg.addEventListener('touchstart',dragStart);\n\t\t\n\t\tsvg.addEventListener('mouseup',dragEnd);\n\t\tsvg.addEventListener('mouseleave',dragEnd);\n\t\tsvg.addEventListener('touchend',dragEnd);\n\t\t\n\t\tsvg.addEventListener('mousemove',dragMove);\n\t\tsvg.addEventListener('touchmove',dragMove);\n\t\t//\n\t\t\n\t\t/*\n\t\t * Helper functions\n\t\t */\n\t\tfunction restrictTargetTemperature(t) {\n\t\t\treturn restrictToRange(roundHalf(t),options.minValue,options.maxValue);\n\t\t}\n\t\t\n\t\tfunction angle(point) {\n\t\t\tvar dx = point[0] - properties.radius;\n\t\t\tvar dy = point[1] - properties.radius;\n\t\t\tvar theta = Math.atan(dx/dy) / (Math.PI/180);\n\t\t\tif (point[0]>=properties.radius && point[1] < properties.radius) {\n\t\t\t\ttheta = 90-theta - 90;\n\t\t\t} else if (point[0]>=properties.radius && point[1] >= properties.radius) {\n\t\t\t\ttheta = 90-theta + 90;\n\t\t\t} else if (point[0]<properties.radius && point[1] >= properties.radius) {\n\t\t\t\ttheta = 90-theta + 90;\n\t\t\t} else if (point[0]<properties.radius && point[1] < properties.radius) {\n\t\t\t\ttheta = 90-theta+270;\n\t\t\t}\n\t\t\treturn theta;\n\t\t};\n\t\t\n\t\tfunction getSizeRatio() {\n\t\t\treturn options.diameter / targetElement.clientWidth;\n\t\t}\n\t\t\n\t};\n})();\n\n/* ==== */\n(function(scope) {\n \n var nest = new thermostatDial(document.getElementById('thermostat1'),{\n \tonSetTargetTemperature: function(v) {\n \t\tscope.send({topic: \"target_temperature\", payload: v});\n \t}\n });\n\n\n scope.$watch('msg', function(data) {\n //console.log(data.topic+\" \"+data.payload);\n if (data.topic == \"setValues\") {\n nest.ambient_temperature = data.ambient;\n nest.target_temperature = data.target;\n nest.hvac_state = data.hvac;\n nest.has_leaf = data.leaf;\n nest.away = data.away;\n \n }\n });\n})(scope);\n\n</script>","storeOutMessages":false,"fwdInMessages":false,"resendOnRefresh":false,"templateScope":"local","x":910,"y":900,"wires":[[]]},{"id":"79d7561b.7e02c8","type":"alexa-remote-event","z":"36b21c99.3c42f4","g":"d4a2fc72.87791","name":"Listen to Routines","account":"9d26c7ce.162eb8","event":"ws-device-activity","x":1330,"y":580,"wires":[["a73a0046.adffb"]]},{"id":"6d9ce98.c7e6418","type":"alexa-remote-routine","z":"36b21c99.3c42f4","g":"d4a2fc72.87791","name":"","account":"9d26c7ce.162eb8","routineNode":{"type":"custom","payload":{"type":"msg","value":"payload"}},"x":1800,"y":580,"wires":[[]]},{"id":"e63e5132.7bae2","type":"alexa-home","z":"36b21c99.3c42f4","g":"d4a2fc72.87791","conf":"241b578d.91d228","device":"35103","acknoledge":false,"name":"Heating","topic":"Heating","x":1290,"y":520,"wires":[["24fb0275.07b2fe"]]},{"id":"e534480b.c21b78","type":"alexa-home-resp","z":"36b21c99.3c42f4","g":"d4a2fc72.87791","x":1840,"y":520,"wires":[]},{"id":"9f6b6139.23881","type":"influxdb out","z":"36b21c99.3c42f4","g":"7745e9a9.8d0398","influxdb":"6a97c1ce.7814a","name":"","measurement":"","precision":"s","retentionPolicy":"","database":"test","precisionV18FluxV20":"ms","retentionPolicyV18Flux":"","org":"my-org","bucket":"test","x":760,"y":540,"wires":[]},{"id":"3e7c2889.07fd38","type":"inject","z":"36b21c99.3c42f4","g":"7745e9a9.8d0398","name":"every 1 min","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"60","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":150,"y":580,"wires":[["77307f6d.cfc01"]]},{"id":"a620940e.c8f9d8","type":"function","z":"36b21c99.3c42f4","g":"7745e9a9.8d0398","name":"Weather to InfluxDB","func":"var weather = flow.get(\"weather\");\n\n// get weather data and format for InfluxDB\nmsg.measurement = \"weather\";\nmsg.payload = [{\n temp: weather.main.temp,\n humidity: weather.main.humidity,\n pressure: weather.main.pressure},\n \n {location: \"outside\"}\n];\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":400,"y":500,"wires":[["9f6b6139.23881"]]},{"id":"67b3f400.7652fc","type":"function","z":"36b21c99.3c42f4","g":"7745e9a9.8d0398","name":"Thermostat to InfluxDB","func":"var thermostat = flow.get(\"thermostat\");\n\n\n// get thermostat data and format for InfluxDB\nmsg.measurement = \"thermostat\";\nmsg.payload = [{\n targetTemp: thermostat.temp,\n ambientTemp: thermostat.ambient,\n leadRoom: thermostat.leadingRoom,\n away: thermostat.away,\n mode:thermostat.mode,\n active: thermostat.active\n},\n \n {location: \"thermostat\"}\n];\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":400,"y":540,"wires":[["9f6b6139.23881"]]},{"id":"77307f6d.cfc01","type":"function","z":"36b21c99.3c42f4","g":"7745e9a9.8d0398","name":"Room Data to InfluxDB","func":"var rooms = flow.get(\"rooms\");\nvar weather = flow.get(\"weather\");\n\n// get rooms data and format for InfluxDB\n\nvar data = [];\n\nfor (var x = 0; x < rooms.length; x++){\n if(rooms[x].pressure === false){\n rooms[x].pressure = weather.main.pressure;\n }\n \n let roomdata = [{\n \"temp\": rooms[x].temp,\n \"pressure\": rooms[x].pressure,\n \"humidity\": rooms[x].humid},\n {\"room\": rooms[x].room}\n ];\n data.push(roomdata);\n}\n\nmsg.payload = data;\nmsg.measurement = \"rooms\"; \n\nreturn msg;\n","outputs":1,"noerr":0,"initialize":"","finalize":"","x":400,"y":580,"wires":[["9f6b6139.23881"]]},{"id":"ca8283b4.378c7","type":"mqtt in","z":"36b21c99.3c42f4","g":"66accf0a.1210e","name":"Office (Sonoff)","topic":"zigbee2mqtt/TEMP Office","qos":"0","datatype":"json","broker":"6e117ba5.8026e4","x":130,"y":240,"wires":[["ffe81f8a.75979"]]},{"id":"5206c1e0.16c11","type":"mqtt in","z":"36b21c99.3c42f4","g":"66accf0a.1210e","name":"Hall (DHT11 Sonoff)","topic":"thermostat/tele/SENSOR","qos":"0","datatype":"json","broker":"6e117ba5.8026e4","x":150,"y":200,"wires":[["cc289d73.c4d3b"]]},{"id":"6dacfdea.e43aa4","type":"mqtt in","z":"36b21c99.3c42f4","g":"66accf0a.1210e","name":"Kitchen (Aqara)","topic":"zigbee2mqtt/TEMP Kitchen","qos":"0","datatype":"json","broker":"6e117ba5.8026e4","x":140,"y":320,"wires":[["619e42d9.cd281c"]]},{"id":"69e292ad.27800c","type":"mqtt in","z":"36b21c99.3c42f4","g":"66accf0a.1210e","name":"Study (Mi Home)","topic":"zigbee2mqtt/TEMP Study","qos":"0","datatype":"json","broker":"6e117ba5.8026e4","x":140,"y":280,"wires":[["5b4cfff8.8b618"]]},{"id":"a2a4234e.31f84","type":"mqtt in","z":"36b21c99.3c42f4","g":"66accf0a.1210e","name":"Living Room (Aqara)","topic":"zigbee2mqtt/TEMP Living Room","qos":"0","datatype":"json","broker":"6e117ba5.8026e4","x":150,"y":400,"wires":[["c121ba2f.107eb8"]]},{"id":"2ac4f5c3.d97e5a","type":"mqtt in","z":"36b21c99.3c42f4","g":"66accf0a.1210e","name":"Bedroom (Tuya)","topic":"zigbee2mqtt/TEMP Bedroom","qos":"0","datatype":"json","broker":"6e117ba5.8026e4","x":140,"y":360,"wires":[["1a619c76.d311f4"]]},{"id":"c4bfce99.f9f88","type":"change","z":"36b21c99.3c42f4","g":"66accf0a.1210e","name":"Hall","rules":[{"t":"set","p":"room","pt":"msg","to":"Hall","tot":"str"},{"t":"set","p":"temp","pt":"msg","to":"payload.DHT11.Temperature","tot":"msg"},{"t":"set","p":"humid","pt":"msg","to":"payload.DHT11.Humidity","tot":"msg"},{"t":"set","p":"pressure","pt":"msg","to":"false","tot":"bool"},{"t":"set","p":"battery","pt":"msg","to":"false","tot":"bool"},{"t":"set","p":"link","pt":"msg","to":"false","tot":"bool"},{"t":"set","p":"grafana","pt":"msg","to":"{\"grafanaT\":{\"url\":\"http://home.lan:3000/d-solo/xxxxx/rooms-temperature?orgId=1\",\"panelID\":\"7\"},\"grafanaH\":{\"url\":\"http://home.lan:3000/d-solo/xxxxx/rooms-humidity?orgId=1\",\"panelID\":\"7\"},\"grafanaP\":{\"url\":\"http://home.lan:3000/d-solo/xxxxx/rooms-pressure?orgId=1\",\"panelID\":\"7\"}}","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":490,"y":200,"wires":[["28971d8e.b00c92"]]},{"id":"28971d8e.b00c92","type":"function","z":"36b21c99.3c42f4","g":"66accf0a.1210e","name":"Update Room Array","func":"var rooms = flow.get(\"rooms\");\nvar weather = flow.get(\"weather\");\nvar thermostat = flow.get(\"thermostat\");\nvar room = msg.room;\ntime = new Date();\n\nvar sampleRoom = { \"room\": room,\n \"temp\": msg.temp,\n \"humid\": msg.humid,\n \"pressure\": msg.pressure,\n \"link\" : msg.link,\n \"battery\": msg.battery,\n \"grafana\": {\n \"grafanaT\": {\n \"url\": \"\",\n \"panelID\": \"\"\n },\n \"grafanaH\": {\n \"url\": \"\",\n \"panelID\": \"\"\n },\n \"grafanaP\": {\n \"url\": \"\",\n \"panelID\": \"\"}\n }\n };\n \n\n\n\n// search array and update values\n\nvar current = rooms.find((o, i) =>{\n if(o.room === room) {\n rooms[i].room = room;\n rooms[i].temp = msg.temp;\n rooms[i].humid = msg.humid;\n rooms[i].battery = msg.batt;\n rooms[i].pressure = msg.pressure;\n rooms[i].link = msg.link;\n \n rooms[i].grafana = msg.grafana;\n return true;\n }\n }\n );\n \nif( current === undefined){\n rooms.push(sampleRoom);\n}\n\nflow.set(\"rooms\", rooms);\nmsg.payload = rooms;\n\nreturn msg;\n\n\n\n","outputs":1,"noerr":0,"initialize":"","finalize":"","x":810,"y":300,"wires":[["1c4a5d72.c19463"]]},{"id":"8e849ca.78f136","type":"change","z":"36b21c99.3c42f4","g":"66accf0a.1210e","name":"Bedroom","rules":[{"t":"set","p":"room","pt":"msg","to":"Bedroom","tot":"str"},{"t":"set","p":"temp","pt":"msg","to":"payload.temperature","tot":"msg"},{"t":"set","p":"humid","pt":"msg","to":"payload.humidity","tot":"msg"},{"t":"set","p":"pressure","pt":"msg","to":"false","tot":"bool"},{"t":"set","p":"battery","pt":"msg","to":"payload.battery","tot":"msg"},{"t":"set","p":"link","pt":"msg","to":"payload.linkquality","tot":"msg"},{"t":"set","p":"grafana","pt":"msg","to":"{\"grafanaT\":{\"url\":\"http://home.lan:3000/d-solo/xxxxx/rooms-temperature?orgId=1\",\"panelID\":\"3\"},\"grafanaH\":{\"url\":\"http://home.lan:3000/d-solo/xxxxx/rooms-humidity?orgId=1\",\"panelID\":\"5\"},\"grafanaP\":{\"url\":\"http://home.lan:3000/d-solo/xxxxx/rooms-pressure?orgId=1\",\"panelID\":\"5\"}}","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":500,"y":360,"wires":[["28971d8e.b00c92"]]},{"id":"3410ee29.ab43b2","type":"change","z":"36b21c99.3c42f4","g":"66accf0a.1210e","name":"Kitchen","rules":[{"t":"set","p":"room","pt":"msg","to":"Kitchen","tot":"str"},{"t":"set","p":"temp","pt":"msg","to":"payload.temperature","tot":"msg"},{"t":"set","p":"humid","pt":"msg","to":"payload.humidity","tot":"msg"},{"t":"set","p":"pressure","pt":"msg","to":"payload.pressure","tot":"msg"},{"t":"set","p":"battery","pt":"msg","to":"payload.battery","tot":"msg"},{"t":"set","p":"link","pt":"msg","to":"payload.linkquality","tot":"msg"},{"t":"set","p":"grafana","pt":"msg","to":"{\"grafanaT\":{\"url\":\"http://home.lan:3000/d-solo/xxxxx/rooms-temperature?orgId=1\",\"panelID\":\"4\"},\"grafanaH\":{\"url\":\"http://home.lan:3000/d-solo/xxxxx/rooms-humidity?orgId=1\",\"panelID\":\"6\"},\"grafanaP\":{\"url\":\"http://home.lan:3000/d-solo/xxxxx/rooms-pressure?orgId=1\",\"panelID\":\"4\"}}","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":500,"y":320,"wires":[["28971d8e.b00c92"]]},{"id":"5ffec6c6.acffd8","type":"change","z":"36b21c99.3c42f4","g":"66accf0a.1210e","name":"Study","rules":[{"t":"set","p":"room","pt":"msg","to":"Study","tot":"str"},{"t":"set","p":"temp","pt":"msg","to":"payload.temperature","tot":"msg"},{"t":"set","p":"humid","pt":"msg","to":"payload.humidity","tot":"msg"},{"t":"set","p":"pressure","pt":"msg","to":"false","tot":"bool"},{"t":"set","p":"battery","pt":"msg","to":"payload.battery","tot":"msg"},{"t":"set","p":"link","pt":"msg","to":"payload.linkquality","tot":"msg"},{"t":"set","p":"grafana","pt":"msg","to":"{\"grafanaT\":{\"url\":\"http://home.lan:3000/d-solo/xxxxx/rooms-temperature?orgId=1\",\"panelID\":\"6\"},\"grafanaH\":{\"url\":\"http://home.lan:3000/d-solo/xxxxx/rooms-humidity?orgId=1\",\"panelID\":\"2\"},\"grafanaP\":{\"url\":\"http://home.lan:3000/d-solo/xxxxx/rooms-pressure?orgId=1\",\"panelID\":\"2\"}}","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":490,"y":280,"wires":[["28971d8e.b00c92"]]},{"id":"c7465359.89565","type":"change","z":"36b21c99.3c42f4","g":"66accf0a.1210e","name":"Office","rules":[{"t":"set","p":"room","pt":"msg","to":"Office","tot":"str"},{"t":"set","p":"temp","pt":"msg","to":"payload.temperature","tot":"msg"},{"t":"set","p":"humid","pt":"msg","to":"payload.humidity","tot":"msg"},{"t":"set","p":"pressure","pt":"msg","to":"false","tot":"bool"},{"t":"set","p":"battery","pt":"msg","to":"payload.battery","tot":"msg"},{"t":"set","p":"link","pt":"msg","to":"payload.linkquality","tot":"msg"},{"t":"set","p":"grafana","pt":"msg","to":"{\"grafanaT\":{\"url\":\"http://home.lan:3000/d-solo/xxxxx/rooms-temperature?orgId=1\",\"panelID\":\"2\"},\"grafanaH\":{\"url\":\"http://home.lan:3000/d-solo/xxxxx/rooms-humidity?orgId=1\",\"panelID\":\"4\"},\"grafanaP\":{\"url\":\"http://home.lan:3000/d-solo/xxxxx/rooms-pressure?orgId=1\",\"panelID\":\"6\"}}","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":490,"y":240,"wires":[["28971d8e.b00c92"]]},{"id":"88c0de21.674ec","type":"change","z":"36b21c99.3c42f4","g":"66accf0a.1210e","name":"Living Room","rules":[{"t":"set","p":"room","pt":"msg","to":"Living Room","tot":"str"},{"t":"set","p":"temp","pt":"msg","to":"payload.temperature","tot":"msg"},{"t":"set","p":"humid","pt":"msg","to":"payload.humidity","tot":"msg"},{"t":"set","p":"pressure","pt":"msg","to":"payload.pressure","tot":"msg"},{"t":"set","p":"battery","pt":"msg","to":"payload.battery","tot":"msg"},{"t":"set","p":"link","pt":"msg","to":"payload.linkquality","tot":"msg"},{"t":"set","p":"grafana","pt":"msg","to":"{\"grafanaT\":{\"url\":\"http://home.lan:3000/d-solo/xxxxx/rooms-temperature?orgId=1\",\"panelID\":\"5\"},\"grafanaH\":{\"url\":\"http://home.lan:3000/d-solo/xxxxx/rooms-humidity?orgId=1\",\"panelID\":\"3\"},\"grafanaP\":{\"url\":\"http://home.lan:3000/d-solo/xxxxx/rooms-pressure?orgId=1\",\"panelID\":\"3\"}}","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":510,"y":400,"wires":[["28971d8e.b00c92"]]},{"id":"1a619c76.d311f4","type":"delay","z":"36b21c99.3c42f4","g":"66accf0a.1210e","name":"Limit","pauseType":"rate","timeout":"5","timeoutUnits":"seconds","rate":"1","nbRateUnits":"30","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":330,"y":360,"wires":[["8e849ca.78f136"]]},{"id":"cc289d73.c4d3b","type":"delay","z":"36b21c99.3c42f4","g":"66accf0a.1210e","name":"Limit","pauseType":"rate","timeout":"5","timeoutUnits":"seconds","rate":"1","nbRateUnits":"30","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":330,"y":200,"wires":[["c4bfce99.f9f88"]]},{"id":"c121ba2f.107eb8","type":"delay","z":"36b21c99.3c42f4","g":"66accf0a.1210e","name":"Limit","pauseType":"rate","timeout":"5","timeoutUnits":"seconds","rate":"1","nbRateUnits":"30","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":330,"y":400,"wires":[["88c0de21.674ec"]]},{"id":"619e42d9.cd281c","type":"delay","z":"36b21c99.3c42f4","g":"66accf0a.1210e","name":"Limit","pauseType":"rate","timeout":"5","timeoutUnits":"seconds","rate":"1","nbRateUnits":"30","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":330,"y":320,"wires":[["3410ee29.ab43b2"]]},{"id":"5b4cfff8.8b618","type":"delay","z":"36b21c99.3c42f4","g":"66accf0a.1210e","name":"Limit","pauseType":"rate","timeout":"5","timeoutUnits":"seconds","rate":"1","nbRateUnits":"30","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":330,"y":280,"wires":[["5ffec6c6.acffd8"]]},{"id":"ffe81f8a.75979","type":"delay","z":"36b21c99.3c42f4","g":"66accf0a.1210e","name":"Limit","pauseType":"rate","timeout":"5","timeoutUnits":"seconds","rate":"1","nbRateUnits":"30","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":330,"y":240,"wires":[["c7465359.89565"]]},{"id":"1c4a5d72.c19463","type":"link out","z":"36b21c99.3c42f4","g":"66accf0a.1210e","name":"","links":["f9420a41.9bc758"],"x":975,"y":300,"wires":[]},{"id":"4b73a352.57ad4c","type":"inject","z":"36b21c99.3c42f4","g":"87b0b89f.042338","name":"Every 10 min","props":[{"p":"payload"}],"repeat":"600","crontab":"","once":true,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":160,"y":680,"wires":[["573dfa1d.56ddd4"]]},{"id":"f2e9754b.ae5848","type":"http request","z":"36b21c99.3c42f4","g":"87b0b89f.042338","name":"","method":"GET","ret":"obj","paytoqs":"ignore","url":"","tls":"","persist":false,"proxy":"","authType":"","x":550,"y":680,"wires":[["ab83ae24.86c5e"]]},{"id":"ab83ae24.86c5e","type":"change","z":"36b21c99.3c42f4","g":"87b0b89f.042338","name":"","rules":[{"t":"set","p":"weather","pt":"flow","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":760,"y":680,"wires":[[]]},{"id":"573dfa1d.56ddd4","type":"function","z":"36b21c99.3c42f4","g":"87b0b89f.042338","name":"Configure API URL","func":"var lat = global.get('Latitude');\nvar lon = global.get('Longitude');\nvar API = global.get('weatherAPI');\n\n// get weather\nmsg.url= \"api.openweathermap.org/data/2.5/weather?lat=\"+lat+\"&lon=\"+lon+\"&appid=\"+API+\"&units=metric\"\nreturn msg;","outputs":1,"noerr":0,"initialize":"/*\nglobal.set('Latitude', \"XXXXX\");\nglobal.set('Longitude', \"XXXXX\");\nglobal.set('weatherAPI', \"XXXXX\");\n*/","finalize":"","x":350,"y":680,"wires":[["f2e9754b.ae5848"]]},{"id":"bd21e083.8274","type":"inject","z":"36b21c99.3c42f4","g":"7745e9a9.8d0398","name":"every 1 min","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"60","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":150,"y":540,"wires":[["67b3f400.7652fc"]]},{"id":"6e727b09.6db6e4","type":"inject","z":"36b21c99.3c42f4","g":"7745e9a9.8d0398","name":"Every 10 min","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"600","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":160,"y":500,"wires":[["a620940e.c8f9d8"]]},{"id":"6c7f2d7e.ed3f54","type":"link in","z":"36b21c99.3c42f4","g":"a544c709.93b3d8","name":"","links":["f4b436ca.8b4e78","970ce3d1.526a7","febbe3f9.6ead4"],"x":1175,"y":1400,"wires":[["8c2c0718.6f84a8"]]},{"id":"febbe3f9.6ead4","type":"link out","z":"36b21c99.3c42f4","g":"e1c37e19.913ff","name":"","links":["6c7f2d7e.ed3f54","a6671c29.8a21","6287a6ae.41be28"],"x":835,"y":840,"wires":[]},{"id":"f1c766c6.15fac8","type":"ui_template","z":"36b21c99.3c42f4","g":"2e1c0fbc.5dcae","group":"bfe5b33d.a6b41","name":"Rooms Humidity","order":1,"width":15,"height":19,"format":"<html> \n<table class =\"tab\">\n<tbody>\n <tr>\n <td>\n <iframe id=\"myFrame0\" width=\"380px\" height=\"300px\" align=\"center\"></iframe> \n\t\t<script>\n\t\t(function(scope) {\n\t\t\tscope.$watch('msg', function(msg) {\n\t\t\t\tvar x = document.getElementById('myFrame0');\n\t\t\t\tx.setAttribute('src', msg.room1); \n\t\t\t\t});\n\t\t})(scope);\n\t\t</script>\n\t</td>\n <td>\n <iframe id=\"myFrame1\" width=\"380px\" height=\"300px\" align=\"center\"></iframe> \n\t\t<script>\n\t\t(function(scope) { \n\t\t\tscope.$watch('msg', function(msg) { \n\t\t\t\tvar x = document.getElementById('myFrame1');\n\t\t\t\tx.setAttribute('src', msg.room2); \n\t\t\t\t});\n\t\t})(scope);\n\t\t</script>\n\t</td>\n </tr>\n <tr>\n <td>\n <iframe id=\"myFrame2\" width=\"380px\" height=\"300px\" align=\"center\"></iframe> \n\t\t<script>\n\t\t(function(scope) { \n\t\t\tscope.$watch('msg', function(msg) { \n\t\t\t\tvar x = document.getElementById('myFrame2');\n\t\t\t\tx.setAttribute('src', msg.room3); \n\t\t\t\t});\n\t\t})(scope);\n\t\t</script>\n\t</td>\n <td>\n <iframe id=\"myFrame3\" width=\"380px\" height=\"300px\" align=\"center\"></iframe> \n\t\t<script>\n\t\t(function(scope) { \n\t\t\tscope.$watch('msg', function(msg) { \n\t\t\t\tvar x = document.getElementById('myFrame3');\n\t\t\t\tx.setAttribute('src', msg.room4); \n\t\t\t\t});\n\t\t})(scope);\n\t\t</script>\n\t</td>\n </tr>\n <tr>\n <td>\n <iframe id=\"myFrame4\" width=\"380px\" height=\"300px\" align=\"center\" ></iframe> \n\t\t<script> \n\t\t(function(scope) { \n\t\t\tscope.$watch('msg', function(msg) { \n\t\t\t\tvar x = document.getElementById('myFrame4');\n\t\t\t\tx.setAttribute('src', msg.room5); \n\t\t\t\t});\n\t\t})(scope);\n\t\t</script>\n\t</td>\n <td>\n <iframe id=\"myFrame5\" width=\"380px\" height=\"300px\" align=\"center\" ></iframe> \n\t\t<script> \n\t\t(function(scope) { \n\t\t\tscope.$watch('msg', function(msg) { \n\t\t\t\tvar x = document.getElementById('myFrame5');\n\t\t\t\tx.setAttribute('src', msg.room6);\n\t\t\t\t});\n\t\t})(scope);\n\t\t</script>\n\t</td>\n </tr>\n</tbody>\n</table>\n\n\n<style>\n.tab {border-collapse:collapse;}\n.tab .first {border-bottom:1px solid #EEE;}\n.tab .second {border-top:1px solid #CCC;box-shadow: inset 0 1px 0 #CCC;}\n</style>\n\n</html>","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":true,"templateScope":"local","x":1640,"y":1160,"wires":[[]]},{"id":"51b514be.4176ec","type":"ui_template","z":"36b21c99.3c42f4","g":"2e1c0fbc.5dcae","group":"3adece4e.21c712","name":"Rooms Pressure","order":1,"width":15,"height":19,"format":"<html> \n<table class =\"tab\">\n<tbody>\n <tr>\n <td>\n <iframe id=\"myFrame0\" width=\"380px\" height=\"300px\" align=\"center\"></iframe> \n\t\t<script>\n\t\t(function(scope) {\n\t\t\tscope.$watch('msg', function(msg) {\n\t\t\t\tvar x = document.getElementById('myFrame0');\n\t\t\t\tx.setAttribute('src', msg.room1); \n\t\t\t\t});\n\t\t})(scope);\n\t\t</script>\n\t</td>\n <td>\n <iframe id=\"myFrame1\" width=\"380px\" height=\"300px\" align=\"center\"></iframe> \n\t\t<script>\n\t\t(function(scope) { \n\t\t\tscope.$watch('msg', function(msg) { \n\t\t\t\tvar x = document.getElementById('myFrame1');\n\t\t\t\tx.setAttribute('src', msg.room2); \n\t\t\t\t});\n\t\t})(scope);\n\t\t</script>\n\t</td>\n </tr>\n <tr>\n <td>\n <iframe id=\"myFrame2\" width=\"380px\" height=\"300px\" align=\"center\"></iframe> \n\t\t<script>\n\t\t(function(scope) { \n\t\t\tscope.$watch('msg', function(msg) { \n\t\t\t\tvar x = document.getElementById('myFrame2');\n\t\t\t\tx.setAttribute('src', msg.room3); \n\t\t\t\t});\n\t\t})(scope);\n\t\t</script>\n\t</td>\n <td>\n <iframe id=\"myFrame3\" width=\"380px\" height=\"300px\" align=\"center\"></iframe> \n\t\t<script>\n\t\t(function(scope) { \n\t\t\tscope.$watch('msg', function(msg) { \n\t\t\t\tvar x = document.getElementById('myFrame3');\n\t\t\t\tx.setAttribute('src', msg.room4); \n\t\t\t\t});\n\t\t})(scope);\n\t\t</script>\n\t</td>\n </tr>\n <tr>\n <td>\n <iframe id=\"myFrame4\" width=\"380px\" height=\"300px\" align=\"center\" ></iframe> \n\t\t<script> \n\t\t(function(scope) { \n\t\t\tscope.$watch('msg', function(msg) { \n\t\t\t\tvar x = document.getElementById('myFrame4');\n\t\t\t\tx.setAttribute('src', msg.room5); \n\t\t\t\t});\n\t\t})(scope);\n\t\t</script>\n\t</td>\n <td>\n <iframe id=\"myFrame5\" width=\"380px\" height=\"300px\" align=\"center\" ></iframe> \n\t\t<script> \n\t\t(function(scope) { \n\t\t\tscope.$watch('msg', function(msg) { \n\t\t\t\tvar x = document.getElementById('myFrame5');\n\t\t\t\tx.setAttribute('src', msg.room6);\n\t\t\t\t});\n\t\t})(scope);\n\t\t</script>\n\t</td>\n </tr>\n</tbody>\n</table>\n\n\n<style>\n.tab {border-collapse:collapse;}\n.tab .first {border-bottom:1px solid #EEE;}\n.tab .second {border-top:1px solid #CCC;box-shadow: inset 0 1px 0 #CCC;}\n</style>\n\n</html>","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":true,"templateScope":"local","x":1650,"y":1200,"wires":[[]]},{"id":"93c4e267.d9bb8","type":"function","z":"36b21c99.3c42f4","g":"c3668690.b8b078","name":"BuildTemplate","func":"//NOTE, more then one chart on a page, rename in the second and following \n//templates the \"myframe\" variable so that every template has a unique name.\n\npanelid=2;\n\nmsg.payload= \"http://home.lan:3000/d-solo/xxxxx/heating?orgId=1\"+\n\"&refresh=1m\"+\n\"&theme=light\"+\n\"&from=\"+ msg.fromdate +\n\"&to=\"+ msg.enddate +\n\"&panelId=\"+panelid\n\nreturn msg;\n\n","outputs":1,"noerr":0,"initialize":"","finalize":"","x":1320,"y":1020,"wires":[["8c04ac5.a63405"]]},{"id":"c74dac0a.b129e","type":"ui_button","z":"36b21c99.3c42f4","g":"5e8634f8.e933fc","name":"","group":"d3f4c38f.616e3","order":7,"width":3,"height":1,"passthru":true,"label":"24 H","tooltip":"","color":"","bgcolor":"","icon":"","payload":"24","payloadType":"num","topic":"","x":370,"y":1060,"wires":[["2a24b497.1ecd8c"]]},{"id":"681a2c79.be7694","type":"ui_button","z":"36b21c99.3c42f4","g":"5e8634f8.e933fc","name":"","group":"d3f4c38f.616e3","order":5,"width":3,"height":1,"passthru":false,"label":"12 H","tooltip":"","color":"","bgcolor":"","icon":"","payload":"12","payloadType":"num","topic":"","x":370,"y":1100,"wires":[["2a24b497.1ecd8c"]]},{"id":"91ad14d.90f23e8","type":"ui_button","z":"36b21c99.3c42f4","g":"5e8634f8.e933fc","name":"","group":"d3f4c38f.616e3","order":4,"width":3,"height":1,"passthru":false,"label":"1 H","tooltip":"","color":"","bgcolor":"","icon":"","payload":"1","payloadType":"num","topic":"","x":370,"y":1020,"wires":[["2a24b497.1ecd8c"]]},{"id":"2a24b497.1ecd8c","type":"function","z":"36b21c99.3c42f4","g":"5e8634f8.e933fc","name":"SetTimeRange","func":"var p_30d = 1000*60*60*24*30 ; //30 Days\nvar p_7d = 1000*60*60*24*7 ; //7 Days\nvar p_1d = 1000*60*60*24 ; // 1 Day\nvar p_hr = 1000*60*60; //1 Hour\n\nvar d = new Date();\nvar current = d.getTime();\n\n\nmsg.fromdate = \"now-\" + msg.payload +\"h\";\nmsg.enddate = \"now\";\n\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":700,"y":1100,"wires":[["ea9504df.3da778"]]},{"id":"762a4eaa.b24b7","type":"function","z":"36b21c99.3c42f4","g":"5e8634f8.e933fc","name":"SetTimeYesterday","func":"var p_30d = 1000*60*60*24*30 ; //30 Days\nvar p_7d = 1000*60*60*24*7 ; //7 Days\nvar p_1d = 1000*60*60*24 ; // 1 Day\nvar p_hr = 1000*60*60; //1 Hour\n\nvar d = new Date();\nvar current = d.getTime();\nvar today0h = d.setHours(0,0,0,0); //Timestamp midnight\n\nmsg.fromdate = today0h - p_1d\nmsg.enddate = today0h\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":710,"y":1180,"wires":[["43093d89.fa6134"]]},{"id":"97a25797.c16508","type":"ui_button","z":"36b21c99.3c42f4","g":"5e8634f8.e933fc","name":"","group":"d3f4c38f.616e3","order":9,"width":2,"height":1,"passthru":false,"label":"Yesterday","tooltip":"","color":"","bgcolor":"","icon":"","payload":"yesterday","payloadType":"str","topic":"","x":380,"y":1180,"wires":[["762a4eaa.b24b7"]]},{"id":"49422d52.4b46e4","type":"ui_template","z":"36b21c99.3c42f4","g":"5e8634f8.e933fc","group":"fd5ac187.ad263","name":"Page Got Loaded","order":1,"width":0,"height":0,"format":"<script>\n(function() {\n (function(scope) {\n scope.send({payload: \"preload\"}); // this gets sent when the view is opened in the browser\n })(scope);\n})();\n</script>","storeOutMessages":false,"fwdInMessages":false,"resendOnRefresh":false,"templateScope":"local","x":170,"y":1060,"wires":[["c74dac0a.b129e"]]},{"id":"d5383e17.db1f2","type":"function","z":"36b21c99.3c42f4","g":"5e8634f8.e933fc","name":"SetTimeTodaySofar","func":"msg.fromdate = \"now/d\";\nmsg.enddate = \"now\";\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":710,"y":1140,"wires":[["ca1e09ec.975df8"]]},{"id":"8da2a624.245428","type":"ui_button","z":"36b21c99.3c42f4","g":"5e8634f8.e933fc","name":"","group":"d3f4c38f.616e3","order":10,"width":2,"height":1,"passthru":false,"label":"Today","tooltip":"","color":"","bgcolor":"","icon":"","payload":"yesterday","payloadType":"str","topic":"","x":370,"y":1140,"wires":[["d5383e17.db1f2"]]},{"id":"3eb5a6cd.1f6f7a","type":"ui_button","z":"36b21c99.3c42f4","g":"a544c709.93b3d8","name":"Living Room","group":"604a48df.caa088","order":3,"width":6,"height":1,"passthru":false,"label":"{{room}} {{temp}}℃","tooltip":"","color":"","bgcolor":"{{background}}","icon":"fa-television","payload":"true","payloadType":"bool","topic":"Living Room","x":1630,"y":1300,"wires":[["ea281eb2.94679"]]},{"id":"ea281eb2.94679","type":"function","z":"36b21c99.3c42f4","g":"a544c709.93b3d8","name":"","func":"var topic = msg.topic;\nvar value = msg.payload;\nvar thermostat = flow.get(\"thermostat\");\n\nif(value === true){\n thermostat.leadingRoom = topic;\n flow.set(\"thermostat\", thermostat);\n}\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":1860,"y":1400,"wires":[[]]},{"id":"d5100603.469808","type":"ui_button","z":"36b21c99.3c42f4","g":"a544c709.93b3d8","name":"Bedroom","group":"604a48df.caa088","order":6,"width":6,"height":1,"passthru":false,"label":"{{room}} {{temp}}℃","tooltip":"","color":"","bgcolor":"{{background}}","icon":"fa-bed","payload":"true","payloadType":"bool","topic":"Bedroom","x":1620,"y":1420,"wires":[["ea281eb2.94679"]]},{"id":"3f29d200.e4805e","type":"ui_button","z":"36b21c99.3c42f4","g":"a544c709.93b3d8","name":"Kitchen","group":"604a48df.caa088","order":9,"width":6,"height":1,"passthru":false,"label":"{{room}} {{temp}}℃","tooltip":"","color":"","bgcolor":"{{background}}","icon":"fa-cutlery","payload":"true","payloadType":"bool","topic":"Kitchen","x":1620,"y":1460,"wires":[["ea281eb2.94679"]]},{"id":"ced99e49.f1a51","type":"ui_button","z":"36b21c99.3c42f4","g":"a544c709.93b3d8","name":"Office","group":"604a48df.caa088","order":12,"width":6,"height":1,"passthru":false,"label":"{{room}} {{temp}}℃","tooltip":"","color":"","bgcolor":"{{background}}","icon":"fa-briefcase","payload":"true","payloadType":"bool","topic":"Office","x":1610,"y":1380,"wires":[["ea281eb2.94679"]]},{"id":"3d444d9a.2bade2","type":"ui_button","z":"36b21c99.3c42f4","g":"a544c709.93b3d8","name":"Hall","group":"604a48df.caa088","order":18,"width":6,"height":1,"passthru":false,"label":"{{room}} {{temp}}℃","tooltip":"","color":"","bgcolor":"{{background}}","icon":"fa-sign-in","payload":"true","payloadType":"bool","topic":"Hall","x":1610,"y":1500,"wires":[["ea281eb2.94679"]]},{"id":"266d61ac.bb2a0e","type":"ui_button","z":"36b21c99.3c42f4","g":"a544c709.93b3d8","name":"Study","group":"604a48df.caa088","order":15,"width":6,"height":1,"passthru":false,"label":"{{room}} {{temp}}℃","tooltip":"","color":"","bgcolor":"{{background}}","icon":"fa-book","payload":"true","payloadType":"bool","topic":"Study","x":1610,"y":1340,"wires":[["ea281eb2.94679"]]},{"id":"76fe14dc.376ccc","type":"function","z":"36b21c99.3c42f4","g":"2e1c0fbc.5dcae","name":"BuildTemplate","func":"var rooms = flow.get(\"rooms\");\n\nvar data =[];\n\nfor(var x in rooms){\n if(rooms[x].grafana.grafanaT.panelID !== \"\"){\n let url = rooms[x].grafana.grafanaT.url + \"&refresh=1m&theme=light&from=\"+ msg.fromdate + \"&to=\"+ msg.enddate + \"&panelId=\"+ rooms[x].grafana.grafanaT.panelID;\n let message = {payload: url};\n data.push(message);\n }\n}\ntry {\nmsg.room1 = data[0].payload;\n\n} catch (error) {\n msg.room1 = null;\n}\n\ntry {\nmsg.room2 = data[1].payload;\n\n} catch (error) {\n msg.room2 = null;\n}\n\ntry {\nmsg.room3 = data[2].payload;\n\n} catch (error) {\n msg.room3 = null;\n}\n\ntry {\nmsg.room4 = data[3].payload;\n\n} catch (error) {\n msg.room4 = null;\n}\n\ntry {\nmsg.room5 = data[4].payload;\n\n} catch (error) {\n msg.room5 = null;\n}\n\ntry {\nmsg.room6 = data[5].payload;\n\n} catch (error) {\n msg.room6 = null;\n}\n\n\n\nreturn msg;\n\n","outputs":1,"noerr":0,"initialize":"","finalize":"","x":1320,"y":1120,"wires":[["63ab6867.0cbf18"]]},{"id":"63ab6867.0cbf18","type":"ui_template","z":"36b21c99.3c42f4","g":"2e1c0fbc.5dcae","group":"fd5ac187.ad263","name":"Rooms Temp","order":2,"width":15,"height":18,"format":"<html> \n<table class =\"tab\">\n<tbody>\n <tr>\n <td>\n <iframe id=\"myFrame0\" width=\"380px\" height=\"300px\" align=\"center\"></iframe> \n\t\t<script>\n\t\t(function(scope) {\n\t\t\tscope.$watch('msg', function(msg) {\n\t\t\t\tvar x = document.getElementById('myFrame0');\n\t\t\t\tx.setAttribute('src', msg.room1); \n\t\t\t\t});\n\t\t})(scope);\n\t\t</script>\n\t</td>\n <td>\n <iframe id=\"myFrame1\" width=\"380px\" height=\"300px\" align=\"center\"></iframe> \n\t\t<script>\n\t\t(function(scope) { \n\t\t\tscope.$watch('msg', function(msg) { \n\t\t\t\tvar x = document.getElementById('myFrame1');\n\t\t\t\tx.setAttribute('src', msg.room2); \n\t\t\t\t});\n\t\t})(scope);\n\t\t</script>\n\t</td>\n </tr>\n <tr>\n <td>\n <iframe id=\"myFrame2\" width=\"380px\" height=\"300px\" align=\"center\"></iframe> \n\t\t<script>\n\t\t(function(scope) { \n\t\t\tscope.$watch('msg', function(msg) { \n\t\t\t\tvar x = document.getElementById('myFrame2');\n\t\t\t\tx.setAttribute('src', msg.room3); \n\t\t\t\t});\n\t\t})(scope);\n\t\t</script>\n\t</td>\n <td>\n <iframe id=\"myFrame3\" width=\"380px\" height=\"300px\" align=\"center\"></iframe> \n\t\t<script>\n\t\t(function(scope) { \n\t\t\tscope.$watch('msg', function(msg) { \n\t\t\t\tvar x = document.getElementById('myFrame3');\n\t\t\t\tx.setAttribute('src', msg.room4); \n\t\t\t\t});\n\t\t})(scope);\n\t\t</script>\n\t</td>\n </tr>\n <tr>\n <td>\n <iframe id=\"myFrame4\" width=\"380px\" height=\"300px\" align=\"center\" ></iframe> \n\t\t<script> \n\t\t(function(scope) { \n\t\t\tscope.$watch('msg', function(msg) { \n\t\t\t\tvar x = document.getElementById('myFrame4');\n\t\t\t\tx.setAttribute('src', msg.room5); \n\t\t\t\t});\n\t\t})(scope);\n\t\t</script>\n\t</td>\n <td>\n <iframe id=\"myFrame5\" width=\"380px\" height=\"300px\" align=\"center\" ></iframe> \n\t\t<script> \n\t\t(function(scope) { \n\t\t\tscope.$watch('msg', function(msg) { \n\t\t\t\tvar x = document.getElementById('myFrame5');\n\t\t\t\tx.setAttribute('src', msg.room6);\n\t\t\t\t});\n\t\t})(scope);\n\t\t</script>\n\t</td>\n </tr>\n</tbody>\n</table>\n\n\n<style>\n.tab {border-collapse:collapse;}\n.tab .first {border-bottom:1px solid #EEE;}\n.tab .second {border-top:1px solid #CCC;box-shadow: inset 0 1px 0 #CCC;}\n</style>\n\n</html>","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":true,"templateScope":"local","x":1630,"y":1120,"wires":[[]]},{"id":"7e0f18d7.36ce98","type":"function","z":"36b21c99.3c42f4","g":"2e1c0fbc.5dcae","name":"BuildTemplate","func":"var rooms = flow.get(\"rooms\");\n\nvar data =[];\n\nfor(var x in rooms){\n if(rooms[x].grafana.grafanaH.panelID !== \"\"){\n let url = rooms[x].grafana.grafanaH.url + \"&refresh=1m&theme=light&from=\"+ msg.fromdate + \"&to=\"+ msg.enddate + \"&panelId=\"+ rooms[x].grafana.grafanaH.panelID;\n let message = {payload: url};\n data.push(message);\n }\n}\n\ntry {\nmsg.room1 = data[0].payload;\n\n} catch (error) {\n msg.room1 = null;\n}\n\ntry {\nmsg.room2 = data[1].payload;\n\n} catch (error) {\n msg.room2 = null;\n}\n\ntry {\nmsg.room3 = data[2].payload;\n\n} catch (error) {\n msg.room3 = null;\n}\n\ntry {\nmsg.room4 = data[3].payload;\n\n} catch (error) {\n msg.room4 = null;\n}\n\ntry {\nmsg.room5 = data[4].payload;\n\n} catch (error) {\n msg.room5 = null;\n}\n\ntry {\nmsg.room6 = data[5].payload;\n\n} catch (error) {\n msg.room6 = null;\n}\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":1320,"y":1160,"wires":[["f1c766c6.15fac8"]]},{"id":"ccf019a2.dbdf98","type":"function","z":"36b21c99.3c42f4","g":"2e1c0fbc.5dcae","name":"BuildTemplate","func":"var rooms = flow.get(\"rooms\");\n\nvar data =[];\n\nfor(var x in rooms){\n if(rooms[x].grafana.grafanaP.panelID !== \"\"){\n let url = rooms[x].grafana.grafanaP.url + \"&refresh=1m&theme=light&from=\"+ msg.fromdate + \"&to=\"+ msg.enddate + \"&panelId=\"+ rooms[x].grafana.grafanaP.panelID;\n let message = {payload: url};\n data.push(message);\n }\n}\n\ntry {\nmsg.room1 = data[0].payload;\n\n} catch (error) {\n msg.room1 = null;\n}\n\ntry {\nmsg.room2 = data[1].payload;\n\n} catch (error) {\n msg.room2 = null;\n}\n\ntry {\nmsg.room3 = data[2].payload;\n\n} catch (error) {\n msg.room3 = null;\n}\n\ntry {\nmsg.room4 = data[3].payload;\n\n} catch (error) {\n msg.room4 = null;\n}\n\ntry {\nmsg.room5 = data[4].payload;\n\n} catch (error) {\n msg.room5 = null;\n}\n\ntry {\nmsg.room6 = data[5].payload;\n\n} catch (error) {\n msg.room6 = null;\n}\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":1320,"y":1200,"wires":[["51b514be.4176ec"]]},{"id":"a6671c29.8a21","type":"link in","z":"36b21c99.3c42f4","g":"ae59fa39.00c6b8","name":"","links":["f4b436ca.8b4e78","970ce3d1.526a7","febbe3f9.6ead4"],"x":1555,"y":680,"wires":[["dbdcc81c.45bbc8"]]},{"id":"8c04ac5.a63405","type":"ui_template","z":"36b21c99.3c42f4","g":"c3668690.b8b078","group":"604a48df.caa088","name":"Thermostat","order":29,"width":15,"height":6,"format":"<html>\n<iframe id=\"Thermostat\" width=\"700px\" height=\"400px\" style = \"overflow:hidden; margin:auto; border:0px solid green;\"></iframe>\n <script>\n (function(scope) {\n scope.$watch('msg', function(msg) {\n var x = document.getElementById('Thermostat');\n x.setAttribute('src', msg.payload); \n });\n })(scope);\n </script>\n</html>","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":true,"templateScope":"local","x":1610,"y":1020,"wires":[[]]},{"id":"476959d4.554778","type":"ui_template","z":"36b21c99.3c42f4","g":"c3668690.b8b078","group":"604a48df.caa088","name":"Usage day","order":27,"width":5,"height":3,"format":"<html>\n<iframe id=\"Usage day\" width=\"150px\" height=\"150px\" style = \"overflow:hidden; margin:auto; border:0px solid green;\"></iframe>\n <script>\n (function(scope) {\n scope.$watch('msg', function(msg) {\n var x = document.getElementById('Usage day');\n x.setAttribute('src', msg.payload); \n });\n })(scope);\n </script>\n</html>","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":true,"templateScope":"local","x":1710,"y":860,"wires":[[]]},{"id":"d4a40936.45d7b8","type":"ui_template","z":"36b21c99.3c42f4","g":"c3668690.b8b078","group":"604a48df.caa088","name":"Usage hour","order":26,"width":5,"height":3,"format":"<html>\n<iframe id=\"Usage hour\" width=\"150px\" height=\"150px\" style = \"overflow:hidden; margin:auto; border:0px solid green;\"></iframe>\n <script>\n (function(scope) {\n scope.$watch('msg', function(msg) {\n var x = document.getElementById('Usage hour');\n x.setAttribute('src', msg.payload); \n });\n })(scope);\n </script>\n</html>","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":true,"templateScope":"local","x":1710,"y":820,"wires":[[]]},{"id":"9a3a7014.5497d","type":"ui_template","z":"36b21c99.3c42f4","g":"c3668690.b8b078","group":"604a48df.caa088","name":"Usage week","order":28,"width":5,"height":3,"format":"<html>\n<iframe id=\"Usage week\" width=\"150px\" height=\"150px\" style = \"overflow:hidden; margin:auto; border:0px solid green;\"></iframe>\n <script>\n (function(scope) {\n scope.$watch('msg', function(msg) {\n var x = document.getElementById('Usage week');\n x.setAttribute('src', msg.payload); \n });\n })(scope);\n </script>\n</html>","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":true,"templateScope":"local","x":1710,"y":900,"wires":[[]]},{"id":"83fa979b.459908","type":"inject","z":"36b21c99.3c42f4","g":"c3668690.b8b078","name":"","props":[{"p":"payload"}],"repeat":"60","crontab":"","once":true,"onceDelay":0.1,"topic":"","payload":"http://home.lan:3000/d-solo/xxxxx/heating?orgId=1&theme=light&panelId=6","payloadType":"str","x":1290,"y":820,"wires":[["d4a40936.45d7b8"]]},{"id":"889acb23.2ba608","type":"inject","z":"36b21c99.3c42f4","g":"c3668690.b8b078","name":"","props":[{"p":"payload"}],"repeat":"60","crontab":"","once":true,"onceDelay":0.1,"topic":"","payload":"http://home.lan:3000/d-solo/xxxxx/heating?orgId=1&theme=light&panelId=7","payloadType":"str","x":1290,"y":860,"wires":[["476959d4.554778"]]},{"id":"bc4c236e.9ca86","type":"inject","z":"36b21c99.3c42f4","g":"c3668690.b8b078","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"60","crontab":"","once":true,"onceDelay":0.1,"topic":"","payload":"http://home.lan:3000/d-solo/xxxxx/heating?orgId=1&theme=light&panelId=8","payloadType":"str","x":1290,"y":900,"wires":[["9a3a7014.5497d"]]},{"id":"13cae6c.d37c119","type":"ui_button","z":"36b21c99.3c42f4","g":"c3668690.b8b078","name":"","group":"604a48df.caa088","order":24,"width":7,"height":1,"passthru":false,"label":"Turn On","tooltip":"","color":"","bgcolor":"","icon":"","payload":"","payloadType":"str","topic":"on","x":1300,"y":940,"wires":[["a6f01708.d4de48"]]},{"id":"23f14f3d.df47b","type":"ui_button","z":"36b21c99.3c42f4","g":"c3668690.b8b078","name":"","group":"604a48df.caa088","order":25,"width":8,"height":1,"passthru":false,"label":"Set Away","tooltip":"","color":"","bgcolor":"","icon":"","payload":"","payloadType":"str","topic":"away","x":1300,"y":980,"wires":[["a6f01708.d4de48"]]},{"id":"a6f01708.d4de48","type":"function","z":"36b21c99.3c42f4","g":"c3668690.b8b078","name":"thermostat defaults","func":"var thermostat = flow.get(\"thermostat\");\n\nif(msg.topic === \"on\"){\n thermostat.away = false;\n thermostat.temp = 21;\n thermostat.mode = \"heating\";\n thermostat.switch = true;\n thermostat.active = 1;\n}\nif(msg.topic === \"away\"){\n thermostat.away = true;\n thermostat.mode = \"off\";\n thermostat.switch = false;\n thermostat.active = 0;\n}\nflow.set(\"thermostat\", thermostat);\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":1510,"y":960,"wires":[[]]},{"id":"ea9504df.3da778","type":"link out","z":"36b21c99.3c42f4","g":"5e8634f8.e933fc","name":"","links":["ba4edbec.9d8d88","6cc58078.d0289","71a76b4e.e70f94","4d89c2a2.88c4ac"],"x":855,"y":1100,"wires":[]},{"id":"ba4edbec.9d8d88","type":"link in","z":"36b21c99.3c42f4","g":"c3668690.b8b078","name":"","links":["ea9504df.3da778"],"x":1175,"y":1020,"wires":[["93c4e267.d9bb8"]]},{"id":"6cc58078.d0289","type":"link in","z":"36b21c99.3c42f4","g":"2e1c0fbc.5dcae","name":"","links":["ea9504df.3da778","ca1e09ec.975df8","43093d89.fa6134"],"x":1175,"y":1120,"wires":[["76fe14dc.376ccc"]]},{"id":"71a76b4e.e70f94","type":"link in","z":"36b21c99.3c42f4","g":"2e1c0fbc.5dcae","name":"","links":["ea9504df.3da778","ca1e09ec.975df8","43093d89.fa6134"],"x":1175,"y":1160,"wires":[["7e0f18d7.36ce98"]]},{"id":"4d89c2a2.88c4ac","type":"link in","z":"36b21c99.3c42f4","g":"2e1c0fbc.5dcae","name":"","links":["ea9504df.3da778","ca1e09ec.975df8","43093d89.fa6134"],"x":1175,"y":1200,"wires":[["ccf019a2.dbdf98"]]},{"id":"ca1e09ec.975df8","type":"link out","z":"36b21c99.3c42f4","g":"5e8634f8.e933fc","name":"","links":["6cc58078.d0289","71a76b4e.e70f94","4d89c2a2.88c4ac"],"x":855,"y":1140,"wires":[]},{"id":"43093d89.fa6134","type":"link out","z":"36b21c99.3c42f4","g":"5e8634f8.e933fc","name":"","links":["6cc58078.d0289","71a76b4e.e70f94","4d89c2a2.88c4ac"],"x":855,"y":1180,"wires":[]},{"id":"775ca3fd.20495c","type":"nora-thermostat","z":"36b21c99.3c42f4","g":"2477241c.186dac","devicename":"Thermostat","roomhint":"Office","name":"","modes":"off,heat","unit":"C","topic":"","passthru":false,"commandOnly":true,"queryOnly":false,"bufferRangeCelsius":2,"nora":"beababcc.56e388","x":1630,"y":380,"wires":[["d965a399.a3f2d"]]},{"id":"6287a6ae.41be28","type":"link in","z":"36b21c99.3c42f4","g":"2477241c.186dac","name":"","links":["febbe3f9.6ead4"],"x":1255,"y":380,"wires":[["e71b9eba.0c70f"]]},{"id":"d965a399.a3f2d","type":"function","z":"36b21c99.3c42f4","g":"2477241c.186dac","name":"Update thermostat","func":"var thermostat = flow.get(\"thermostat\");\nvar x = msg.payload;\n\nif(x.mode === \"heat\"){\n thermostat.mode = \"heating\";\n thermostat.away = false;\n thermostat.temp = x.setpoint;\n thermostat.active = 1;\n thermostat.low = x.setpointLow;\n thermostat.high = x.setpointHigh;\n}\n\nif(x.mode === \"off\"){\n thermostat.mode = \"off\";\n thermostat.away = true;\n thermostat.temp = x.setpoint;\n thermostat.active = 0;\n thermostat.low = x.setpointLow;\n}\n\nflow.set(\"thermostat\", thermostat);\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":1870,"y":380,"wires":[[]]},{"id":"e71b9eba.0c70f","type":"function","z":"36b21c99.3c42f4","g":"2477241c.186dac","name":"Update Google Home","func":"var thermostat = flow.get(\"thermostat\");\n\n\nvar mode = \"\";\n\nif(thermostat.mode === \"heating\"){\n mode = \"heat\";\n}\nif(thermostat.mode === \"off\"){\n mode = \"off\";\n}\n\n\n\nmsg.payload = {\"mode\": mode,\n \"setpoint\":thermostat.temp,\n \"setpointLow\":thermostat.low,\n \"setpointHigh\":thermostat.high,\n \"temperature\": thermostat.ambient};\n\n\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":1420,"y":380,"wires":[["775ca3fd.20495c"]]},{"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":"d3f4c38f.616e3","type":"ui_group","name":"Data Type","tab":"575b5376.fc1d2c","order":2,"disp":true,"width":15,"collapse":false},{"id":"604a48df.caa088","type":"ui_group","name":"Thermostat","tab":"575b5376.fc1d2c","order":1,"disp":true,"width":15,"collapse":false},{"id":"9d26c7ce.162eb8","type":"alexa-remote-account","name":"","authMethod":"proxy","proxyOwnIp":"10.1.1.217","proxyPort":"3456","cookieFile":"","refreshInterval":"3","alexaServiceHost":"alexa.amazon.co.uk","amazonPage":"amazon.co.uk","acceptLanguage":"en-UK","userAgent":"","useWsMqtt":"on","autoInit":"off"},{"id":"241b578d.91d228","type":"alexa-home-conf","username":"quintaar"},{"id":"6a97c1ce.7814a","type":"influxdb","hostname":"127.0.0.1","port":"8086","protocol":"http","database":"homeautomation","name":"Home Automation DB","usetls":false,"tls":"","influxdbVersion":"1.x","url":"http://localhost:8086","rejectUnauthorized":true},{"id":"bfe5b33d.a6b41","type":"ui_group","name":"Rooms Humidity","tab":"575b5376.fc1d2c","order":5,"disp":true,"width":15,"collapse":false},{"id":"3adece4e.21c712","type":"ui_group","name":"Rooms Pressure","tab":"575b5376.fc1d2c","order":6,"disp":true,"width":15,"collapse":false},{"id":"fd5ac187.ad263","type":"ui_group","name":"Rooms Temp","tab":"575b5376.fc1d2c","order":4,"disp":true,"width":15,"collapse":false},{"id":"beababcc.56e388","type":"nora-config","name":"Nora","group":"","notify":false},{"id":"575b5376.fc1d2c","type":"ui_tab","name":"Heating","icon":"dashboard","order":11,"disabled":false,"hidden":false}]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment