|
[ |
|
{ |
|
"id": "8850e193.e1712", |
|
"type": "subflow", |
|
"name": "SaveChart", |
|
"info": "", |
|
"category": "", |
|
"in": [ |
|
{ |
|
"x": 80, |
|
"y": 140, |
|
"wires": [ |
|
{ |
|
"id": "40784bb1.204934" |
|
} |
|
] |
|
} |
|
], |
|
"out": [ |
|
{ |
|
"x": 820, |
|
"y": 120, |
|
"wires": [ |
|
{ |
|
"id": "a6525d2.cb354a", |
|
"port": 0 |
|
} |
|
] |
|
} |
|
] |
|
}, |
|
{ |
|
"id": "a0f72417.ea2838", |
|
"type": "file", |
|
"z": "8850e193.e1712", |
|
"name": "backup", |
|
"filename": "", |
|
"appendNewline": false, |
|
"createDir": true, |
|
"overwriteFile": "true", |
|
"x": 700, |
|
"y": 160, |
|
"wires": [ |
|
[] |
|
] |
|
}, |
|
{ |
|
"id": "70a2db09.6ff354", |
|
"type": "file in", |
|
"z": "8850e193.e1712", |
|
"name": "restore", |
|
"filename": "", |
|
"format": "utf8", |
|
"sendError": true, |
|
"x": 530, |
|
"y": 120, |
|
"wires": [ |
|
[ |
|
"a6525d2.cb354a" |
|
] |
|
] |
|
}, |
|
{ |
|
"id": "922d4285.5f7e1", |
|
"type": "json", |
|
"z": "8850e193.e1712", |
|
"name": "", |
|
"property": "payload", |
|
"action": "str", |
|
"pretty": false, |
|
"x": 530, |
|
"y": 160, |
|
"wires": [ |
|
[ |
|
"a0f72417.ea2838" |
|
] |
|
] |
|
}, |
|
{ |
|
"id": "a6525d2.cb354a", |
|
"type": "json", |
|
"z": "8850e193.e1712", |
|
"name": "", |
|
"property": "payload", |
|
"action": "str", |
|
"pretty": false, |
|
"x": 690, |
|
"y": 120, |
|
"wires": [ |
|
[] |
|
] |
|
}, |
|
{ |
|
"id": "40784bb1.204934", |
|
"type": "function", |
|
"z": "8850e193.e1712", |
|
"name": "LoadSave", |
|
"func": "var strSafe=msg.topic;\nif(strSafe)\n{\n msg.filename =\"/share/chart.save\";\n var loaded=context.get(strSafe)||0;\n \n if(0===loaded||strSafe==\"restore\")\n {\n //node.warn(\"Loading chart\");\n msg.payload=\"load\";\n context.set(strSafe,1);\n }\n else\n {\n //node.warn(\"Writing chart\");\n //node.warn(msg.payload);\n }\n return msg;\n \n}\nreturn null;", |
|
"outputs": 1, |
|
"noerr": 0, |
|
"initialize": "", |
|
"finalize": "", |
|
"x": 230, |
|
"y": 140, |
|
"wires": [ |
|
[ |
|
"51fb3038.7afb6" |
|
] |
|
] |
|
}, |
|
{ |
|
"id": "51fb3038.7afb6", |
|
"type": "switch", |
|
"z": "8850e193.e1712", |
|
"name": "Load data", |
|
"property": "payload", |
|
"propertyType": "msg", |
|
"rules": [ |
|
{ |
|
"t": "eq", |
|
"v": "load", |
|
"vt": "str" |
|
}, |
|
{ |
|
"t": "else" |
|
} |
|
], |
|
"checkall": "false", |
|
"repair": false, |
|
"outputs": 2, |
|
"x": 380, |
|
"y": 140, |
|
"wires": [ |
|
[ |
|
"70a2db09.6ff354" |
|
], |
|
[ |
|
"922d4285.5f7e1" |
|
] |
|
] |
|
}, |
|
{ |
|
"id": "c7e7982a.89e5f8", |
|
"type": "tab", |
|
"label": "The Ultimate Thermostat v3.4 ITA - giuseppeg88", |
|
"disabled": false, |
|
"info": "GitHub:\nhttps://github.com/giuseppeg88/node-red-contrib-thermostat-scheduler\n\nLICENSE:\nGNU General Public License v3.0\nPermissions of this strong copyleft license are conditioned on making available complete source code of licensed works and modifications, which include larger works using a licensed work, under the same license. Copyright and license notices must be preserved. Contributors provide an express grant of patent rights." |
|
}, |
|
{ |
|
"id": "b5b4d03.75d053", |
|
"type": "ui_template", |
|
"z": "c7e7982a.89e5f8", |
|
"group": "77b849cb.094c08", |
|
"name": "css etc", |
|
"order": 3, |
|
"width": 0, |
|
"height": 0, |
|
"format": "<style>\n\n.filled { height: 38px !important;padding: 0 !important; margin: 0 !important;}\n.nr-dashboard-template { padding: 0; margin: 0;}\n.rounded { border-radius: 12px 12px 12px 12px;}\n.bigfont { font-size: 18px;}\n.smallfont { font-size: 12px;}\n.thedays { cursor:pointer; vertical-align:bottom; height:38px; }\n.the2px { background-color: #9E9E9E; height:2px; }\n.theblocks {width:100%; height:0%; background-color:#4CAF50; }\n.greybuttons { background-color:#009688 !important; width:38px; border: none;}\n.thetemps { cursor:pointer; font-size:70%; color:#9E9E9E !important; }\n.smallheadings { color:white; font-size:80%; }\n\n</style>\n\n<script>\nvar current=1;\n\n$('.vibrate').on('click', function() {\n navigator.vibrate(100);\n});\n\nfunction restore_bg(x) {\n $(this).css(\"background-color\", x);\n };\n\n$('.touched').on('mousedown', function() {\n \n var x= $(this).css(\"background-color\");\n $(this).css(\"background-color\", \"yellow\");\n \n setTimeout(restore_bg.bind(this,x),50);\n navigator.vibrate(80);\n });\n \n</script>", |
|
"storeOutMessages": false, |
|
"fwdInMessages": true, |
|
"resendOnRefresh": false, |
|
"templateScope": "local", |
|
"x": 260, |
|
"y": 80, |
|
"wires": [ |
|
[] |
|
] |
|
}, |
|
{ |
|
"id": "a0aab4d8.8b6498", |
|
"type": "ui_template", |
|
"z": "c7e7982a.89e5f8", |
|
"group": "77b849cb.094c08", |
|
"name": "Settings page", |
|
"order": 1, |
|
"width": 8, |
|
"height": 5, |
|
"format": "<script>\nvar thedays=[\"DOMENICA\",\"LUNEDI\",\"MARTEDI\",\"MERCOLEDI\",\"GIOVEDI\",\"VENERDI\",\"SABATO\"];\nvar ID = \"AA\";\n\nvar last=29;\n\nfunction bar(mm,val)\n{\nif (val>=12 && val<13) { $(mm).height(\"12%\"); $(mm).css('background-color', '#1E88E5'); } //blue\nif (val>=13 && val<14) { $(mm).height(\"16%\"); $(mm).css('background-color', '#039BE5'); }\nif (val>=14 && val<15) { $(mm).height(\"20%\"); $(mm).css('background-color', '#00ACC1'); } \nif (val>=15 && val<16) { $(mm).height(\"24%\"); $(mm).css('background-color', '#039BE5'); } // cyan\nif (val>=16 && val<17) { $(mm).height(\"28%\"); $(mm).css('background-color', '#00ACC1'); }\nif (val>=17 && val<18) { $(mm).height(\"32%\"); $(mm).css('background-color', '#00897B'); } \nif (val>=18 && val<19) { $(mm).height(\"36%\"); $(mm).css('background-color', '#388E3C'); } // green\nif (val>=19 && val<20) { $(mm).height(\"40%\"); $(mm).css('background-color', '#689F38'); }\nif (val>=20 && val<21) { $(mm).height(\"44%\"); $(mm).css('background-color', '#C0CA33'); }\nif (val>=21 && val<22) { $(mm).height(\"48%\"); $(mm).css('background-color', '#FDD835'); } // yellow\nif (val>=22 && val<23) { $(mm).height(\"52%\"); $(mm).css('background-color', '#FBC02D'); }\nif (val>=23 && val<24) { $(mm).height(\"56%\"); $(mm).css('background-color', '#FFA000'); }\nif (val>=24) { $(mm).height(\"60%\"); $(mm).css('background-color','#E64A19'); } // red\n}\n\n//function bar(mm,val)\n//{\n//if (val==14 || val==14.5) { $(mm).height(\"12%\"); $(mm).css('background-color', '#1E88E5'); } //blue\n//if (val==15 || val==15.5) { $(mm).height(\"16%\"); $(mm).css('background-color', '#039BE5'); }\n//if (val==16 || val==16.5) { $(mm).height(\"20%\"); $(mm).css('background-color', '#00ACC1'); } \n//if (val==17 || val==17.5) { $(mm).height(\"24%\"); $(mm).css('background-color', '#039BE5'); } // cyan\n//if (val==18 || val==18.5) { $(mm).height(\"28%\"); $(mm).css('background-color', '#00ACC1'); }\n//if (val==19 || val==19.5) { $(mm).height(\"32%\"); $(mm).css('background-color', '#00897B'); } \n//if (val==20 || val==20.5) { $(mm).height(\"36%\"); $(mm).css('background-color', '#388E3C'); } // green\n//if (val==21 || val==21.5) { $(mm).height(\"40%\"); $(mm).css('background-color', '#689F38'); }\n//if (val==22 || val==22.5) { $(mm).height(\"44%\"); $(mm).css('background-color', '#C0CA33'); }\n//if (val==23 || val==23.5) { $(mm).height(\"48%\"); $(mm).css('background-color', '#FDD835'); } // yellow\n//if (val==24 || val==24.5) { $(mm).height(\"52%\"); $(mm).css('background-color', '#FBC02D'); }\n//if (val==25 || val==25.5) { $(mm).height(\"56%\"); $(mm).css('background-color', '#FFA000'); }\n//if (val==26) { $(mm).height(\"60%\"); $(mm).css('background-color','#E64A19'); } // red\n//}\n\nfunction stat(text)\n{\n$(\"#info\"+ID).text(text);\nvar tm=setTimeout(function(){ $(\"#info\"+ID).text(\"Ok\"); clearTimeout(tm);}, 3000);\n}\n\nfunction selec(val,sta)\n{\nvar w=\"#td\"+val+ID;\n if (sta) $(w).css('background-color','#4CAF50'); else $(w).css('background-color','#FFC107');\n}\n\n (function(scope){\n scope.ID = ID;\n scope.send({payload: '29'})\n scope.$watch('msg', function(msg) {\n selec(last,0); last=msg.selector; selec(last,1);\n for (var x=0; x<24; x++) \n { \n var w=\"#t\"+x+ID; bar(w,msg.timing[((msg.days-1)*24)+x].toFixed(1)); \n var v=\"#v\"+x+ID; $(v).text(msg.timing[((msg.days-1)*24)+x].toFixed(1)+\"°\")\n } \n for (var x=0; x<2; x++) { var w=\"#s\"+x+ID; $(w).text(msg.timing[168+x].toFixed(1)+\"°\"); }\n $(\"#d0\"+ID).text(thedays[msg.days-1]);\n if ((last>4) &&(last<29))\n $(\"#current\"+ID).text(msg.timing[((msg.days-1)*24)+last-5].toFixed(1) + \"°\");\n else\n $(\"#current\"+ID).text(\"-\");\n \n if (msg.foryou!=\"\") { stat(msg.foryou); }\n \n \n });\n \n })(scope);\n \n\n</script>\n<table width=\"100%\">\n \n <tr>\n <td colspan=3> </td>\n <td colspan=6><center><span class=\"smallheadings\" >Giorno</span></center></td>\n <!--<td colspan=3><center><span class=\"smallheadings\">Clima</span></center></td> -->\n <td colspan=3><center><span class=\"smallheadings\">AWAY</span></center></td> \n </tr>\n \n <tr>\n <td colspan=3> </td>\n <td ng-click=\"send({payload: '29'})\" colspan=6><center><span id=\"{{ 'd0' + ID }}\" style=\"cursor:pointer;color:white;font-size:100%\">LUNEDI</span></center></td>\n <!-- <td ng-click=\"send({payload: '1'})\" colspan=3><center><span id=\"{{'s0' + ID }}\" style=\"color:white;font-size:100%\">14</span></center></td> -->\n <td ng-click=\"send({payload: '2'})\" colspan=3><center><span id=\"{{'s1' + ID }}\" style=\"cursor:pointer;color:white;font-size:100%\">17</span></center></td> \n </tr>\n \n <tr style=\"height:2px\">\n <td colspan=3 style=\"background-color:#9E9E9E;height:2px;\"></td> \n <td id=\"{{ 'td29' + ID }}\" colspan=6 style=\"background-color:#9E9E9E;height:2px;\"></td> \n <!-- <td id=\"{{'td1' + ID }}\" colspan=3 style=\"background-color:#9E9E9E;height:2px;\"></td> -->\n <td id=\"{{'td2 + ID '}}\" colspan=3 style=\"background-color:#9E9E9E;height:2px;\"></td> \n </tr> \n\n <tr>\n <td ng-click=\"send({payload: '5'})\" class=\"thedays\"><span id=\"{{ 'v0' + ID }}\" class=\"thetemps\"></span><div id=\"{{ 't0' + ID }}\" class=\"theblocks\"></div></td>\n <td ng-click=\"send({payload: '6'})\" class=\"thedays\"><span id=\"{{ 'v1' + ID }}\" class=\"thetemps\"></span><div id=\"{{ 't1' + ID }}\" class=\"theblocks\"></div></td>\n <td ng-click=\"send({payload: '7'})\" class=\"thedays\"><span id=\"{{ 'v2' + ID }}\" class=\"thetemps\"></span><div id=\"{{ 't2' + ID }}\" class=\"theblocks\"></div></td>\n <td ng-click=\"send({payload: '8'})\" class=\"thedays\"><span id=\"{{ 'v3' + ID }}\" class=\"thetemps\"></span><div id=\"{{ 't3' + ID }}\" class=\"theblocks\"></div></td>\n <td ng-click=\"send({payload: '9'})\" class=\"thedays\"><span id=\"{{ 'v4' + ID }}\" class=\"thetemps\"></span><div id=\"{{ 't4' + ID }}\" class=\"theblocks\"></div></td>\n <td ng-click=\"send({payload: '10'})\" class=\"thedays\"><span id=\"{{ 'v5' + ID }}\" class=\"thetemps\"></span><div id=\"{{ 't5' + ID }}\" class=\"theblocks\"></div></td>\n <td ng-click=\"send({payload: '11'})\" class=\"thedays\"><span id=\"{{ 'v6' + ID }}\" class=\"thetemps\"></span><div id=\"{{ 't6' + ID }}\" class=\"theblocks\"></div></td>\n <td ng-click=\"send({payload: '12'})\" class=\"thedays\"><span id=\"{{ 'v7' + ID }}\" class=\"thetemps\"></span><div id=\"{{ 't7' + ID }}\" class=\"theblocks\"></div></td>\n <td ng-click=\"send({payload: '13'})\" class=\"thedays\"><span id=\"{{ 'v8' + ID }}\" class=\"thetemps\"></span><div id=\"{{ 't8' + ID }}\" class=\"theblocks\"></div></td>\n <td ng-click=\"send({payload: '14'})\" class=\"thedays\"><span id=\"{{ 'v9' + ID }}\" class=\"thetemps\"></span><div id=\"{{ 't9' + ID }}\" class=\"theblocks\"></div></td>\n <td ng-click=\"send({payload: '15'})\" class=\"thedays\"><span id=\"{{ 'v10' + ID }}\" class=\"thetemps\"></span><div id=\"{{ 't10' + ID }}\" class=\"theblocks\"></div></td>\n <td ng-click=\"send({payload: '16'})\" class=\"thedays\"><span id=\"{{ 'v11' + ID }}\" class=\"thetemps\"></span><div id=\"{{ 't11' + ID }}\" class=\"theblocks\"></div></td>\n </tr> \n \n <tr style=\"height:2px\">\n <td id=\"{{ 'td5' + ID }}\" class=\"the2px\"></td>\n <td id=\"{{ 'td6' + ID }}\" class=\"the2px\"></td>\n <td id=\"{{ 'td7' + ID }}\" class=\"the2px\"></td>\n <td id=\"{{ 'td8' + ID }}\" class=\"the2px\"></td>\n <td id=\"{{ 'td9' + ID }}\" class=\"the2px\"></td>\n <td id=\"{{ 'td10' + ID }}\" class=\"the2px\"></td>\n <td id=\"{{ 'td11' + ID }}\" class=\"the2px\"></td>\n <td id=\"{{ 'td12' + ID }}\" class=\"the2px\"></td>\n <td id=\"{{ 'td13' + ID }}\" class=\"the2px\"></td>\n <td id=\"{{ 'td14' + ID }}\" class=\"the2px\"></td>\n <td id=\"{{ 'td15' + ID }}\" class=\"the2px\"></td>\n <td id=\"{{ 'td16' + ID }}\" class=\"the2px\"></td>\n </tr> \n \n <tr>\n <td align=\"center\">0</td>\n <td align=\"center\">1</td>\n <td align=\"center\">2</td>\n <td align=\"center\">3</td>\n <td align=\"center\">4</td>\n <td align=\"center\">5</td>\n <td align=\"center\">6</td>\n <td align=\"center\">7</td>\n <td align=\"center\">8</td>\n <td align=\"center\">9</td>\n <td align=\"center\">10</td>\n <td align=\"center\">11</td>\n </tr> \n \n <tr>\n <td ng-click=\"send({payload: '17'})\" class=\"thedays\"><span id=\"{{ 'v12' + ID }}\" class=\"thetemps\"></span><div id=\"{{ 't12' + ID }}\" class=\"theblocks\"></div></td>\n <td ng-click=\"send({payload: '18'})\" class=\"thedays\"><span id=\"{{ 'v13' + ID }}\" class=\"thetemps\"></span><div id=\"{{ 't13' + ID }}\" class=\"theblocks\"></div></td>\n <td ng-click=\"send({payload: '19'})\" class=\"thedays\"><span id=\"{{ 'v14' + ID }}\" class=\"thetemps\"></span><div id=\"{{ 't14' + ID }}\" class=\"theblocks\"></div></td>\n <td ng-click=\"send({payload: '20'})\" class=\"thedays\"><span id=\"{{ 'v15' + ID }}\" class=\"thetemps\"></span><div id=\"{{ 't15' + ID }}\" class=\"theblocks\"></div></td>\n <td ng-click=\"send({payload: '21'})\" class=\"thedays\"><span id=\"{{ 'v16' + ID }}\" class=\"thetemps\"></span><div id=\"{{ 't16' + ID }}\" class=\"theblocks\"></div></td>\n <td ng-click=\"send({payload: '22'})\" class=\"thedays\"><span id=\"{{ 'v17' + ID }}\" class=\"thetemps\"></span><div id=\"{{ 't17' + ID }}\" class=\"theblocks\"></div></td>\n <td ng-click=\"send({payload: '23'})\" class=\"thedays\"><span id=\"{{ 'v18' + ID }}\" class=\"thetemps\"></span><div id=\"{{ 't18' + ID }}\" class=\"theblocks\"></div></td>\n <td ng-click=\"send({payload: '24'})\" class=\"thedays\"><span id=\"{{ 'v19' + ID }}\" class=\"thetemps\"></span><div id=\"{{ 't19' + ID }}\" class=\"theblocks\"></div></td>\n <td ng-click=\"send({payload: '25'})\" class=\"thedays\"><span id=\"{{ 'v20' + ID }}\" class=\"thetemps\"></span><div id=\"{{ 't20' + ID }}\" class=\"theblocks\"></div></td>\n <td ng-click=\"send({payload: '26'})\" class=\"thedays\"><span id=\"{{ 'v21' + ID }}\" class=\"thetemps\"></span><div id=\"{{ 't21' + ID }}\" class=\"theblocks\"></div></td>\n <td ng-click=\"send({payload: '27'})\" class=\"thedays\"><span id=\"{{ 'v22' + ID }}\" class=\"thetemps\"></span><div id=\"{{ 't22' + ID }}\" class=\"theblocks\"></div></td>\n <td ng-click=\"send({payload: '28'})\" class=\"thedays\"><span id=\"{{ 'v23' + ID }}\" class=\"thetemps\"></span><div id=\"{{ 't23' + ID }}\" class=\"theblocks\"></div></td>\n </tr> \n \n <tr style=\"height:2px\">\n <td id=\"{{ 'td17' + ID }}\" class=\"the2px\"></td>\n <td id=\"{{ 'td18' + ID }}\" class=\"the2px\"></td>\n <td id=\"{{ 'td19' + ID }}\" class=\"the2px\"></td>\n <td id=\"{{ 'td20' + ID }}\" class=\"the2px\"></td>\n <td id=\"{{ 'td21' + ID }}\" class=\"the2px\"></td>\n <td id=\"{{ 'td22' + ID }}\" class=\"the2px\"></td>\n <td id=\"{{ 'td23' + ID }}\" class=\"the2px\"></td>\n <td id=\"{{ 'td24' + ID }}\" class=\"the2px\"></td>\n <td id=\"{{ 'td25' + ID }}\" class=\"the2px\"></td>\n <td id=\"{{ 'td26' + ID }}\" class=\"the2px\"></td>\n <td id=\"{{ 'td27' + ID }}\" class=\"the2px\"></td>\n <td id=\"{{ 'td28' + ID }}\" class=\"the2px\"></td>\n </tr> \n \n <tr>\n <td align=\"center\">12</td>\n <td align=\"center\">13</td>\n <td align=\"center\">14</td>\n <td align=\"center\">15</td>\n <td align=\"center\">16</td>\n <td align=\"center\">17</td>\n <td align=\"center\">18</td>\n <td align=\"center\">19</td>\n <td align=\"center\">20</td>\n <td align=\"center\">21</td>\n <td align=\"center\">22</td>\n <td align=\"center\">23</td>\n </tr> \n \n <tr height=\"5px\">\n <td colspan=\"12\"></td>\n </tr>\n \n <tr height=\"20px\"> \n <td colspan=2 class=\"smallheadings\"><center> Azioni: </center></td> \n\n <td colspan=10 ><center><span id=\"{{ 'info' + ID }}\" class=\"smallheadings\" ></span></center></td>\n\n </tr>\n \n <tr height=\"5px\">\n <td colspan=\"12\"></td>\n </tr>\n\n <tr style=\"height:48px\">\n <td colspan=2> <center>\n <button class=\"vibrate filled touched smallfont rounded greybuttons\" ng-click=\"send({payload: 'd'})\"> \n <ng-md-icon style=\"color: #fff;\" icon=\"keyboard_arrow_down\">\n <!--<md-tooltip md-direction=\"bottom\">DECREMENTA</md-tooltip>-->\n </ng-md-icon>\n </button> </center>\n </td>\n \n <td colspan=2><center><span id=\"{{ 'current' + ID }}\" style=\"color:white;font-size:120%\"> - </span></center></td>\n\n <td colspan=2> <center>\n <button class=\"vibrate filled touched smallfont rounded greybuttons\" ng-click=\"send({payload: 'u'})\"> \n <ng-md-icon style=\"color: #fff;\" icon=\"keyboard_arrow_up\">\n <!--<md-tooltip md-direction=\"bottom\">INCREMENTA</md-tooltip>-->\n </ng-md-icon>\n </button> </center>\n </td>\n\n <td colspan=2> <center>\n <button class=\"vibrate filled touched smallfont rounded greybuttons\" ng-click=\"send({payload: 'r'})\"> \n <ng-md-icon style=\"color: #fff;\" icon=\"content_copy\">\n <!--<md-tooltip md-direction=\"bottom\">COPIA</md-tooltip>-->\n </ng-md-icon>\n </button> </center>\n </td>\n\n\n <td colspan=2> <center>\n <button class=\"vibrate filled touched smallfont rounded greybuttons\" ng-click=\"send({payload: 's'})\"> \n <ng-md-icon style=\"color: #fff;\" icon=\"save\">\n <!--<md-tooltip md-direction=\"bottom\">SALVA</md-tooltip>-->\n </ng-md-icon>\n </button> </center>\n </td>\n\n <td colspan=2> <center>\n <button class=\"vibrate filled touched smallfont rounded greybuttons\" ng-click=\"send({payload: 'c'})\"> \n <ng-md-icon style=\"color: #fff;\" icon=\"cancel\">\n <!--<md-tooltip md-direction=\"bottom\">ANNULLA</md-tooltip>-->\n </ng-md-icon>\n </button> </center>\n </td>\n </tr>\n\n</table>", |
|
"storeOutMessages": false, |
|
"fwdInMessages": false, |
|
"resendOnRefresh": false, |
|
"templateScope": "local", |
|
"x": 290, |
|
"y": 140, |
|
"wires": [ |
|
[ |
|
"9773ea79.6d18f8" |
|
] |
|
] |
|
}, |
|
{ |
|
"id": "9773ea79.6d18f8", |
|
"type": "function", |
|
"z": "c7e7982a.89e5f8", |
|
"name": "Process controls", |
|
"func": "if ( typeof context.days == 'undefined' || flow.get(\"resetday\")) \n{\n var date = new Date();\n var daynum = date.getDay();\n context.days= daynum+1;\n flow.set(\"resetday\",false);\n}\n\nif ( typeof (flow.get(\"thermostat_mode\")) == 'undefined') \n{\n flow.set(\"thermostat_mode\",\"off\");\n}\n\nif ( typeof context.selector == 'undefined' ) context.selector=29;\nif ( typeof context.saving == 'undefined' ) context.saving=1;\n\nlet timing = global.get(\"timing\");\nif ( !timing || !Array.isArray(timing) ) \n {\n timing=[\n 14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,\n 14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,\n 14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,\n 14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,\n 14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,\n 14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,\n 14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,\n 6,14\n ];\n context.saving=1;\n global.set(\"timing\",timing);\n }\n//if ( typeof global.get(\"days\") != 'undefined' ) context.days=global.get(\"days\");\n\nswitch (msg.payload)\n {\n case \"u\" : if ((context.selector>4)&&(context.selector<29))\n {\n timing[((context.days-1)*24)+context.selector-5]+=0.5; \n if (timing[((context.days-1)*24)+context.selector-5]>24){ timing[((context.days-1)*24)+context.selector-5]=24; msg.foryou=\"Limite raggiunto\";}\n else msg.foryou=\"Temperatura aumentata\";\n }\n if (context.selector==1) { if (timing[168+(context.selector-1)]<24) { timing[168+(context.selector-1)]+=0.5; msg.foryou=\"Temperatura clima aumentata di 0.5°C\"; } else msg.foryou=\"Limite raggiunto\"; }\n if (context.selector==2) { if (timing[168+(context.selector-1)]<24) { timing[168+(context.selector-1)]+=0.5; msg.foryou=\"Temperatura fuori casa aumentata di 0.5°C\"; } else msg.foryou=\"Limite raggiunto\"; }\n if (context.selector==29) { msg.foryou=\"Giorno successivo\"; context.days++; if (context.days>7) { context.days = 1; } }\n break;\n case \"d\" : if ((context.selector>4)&&(context.selector<29))\n {\n timing[((context.days-1)*24)+context.selector-5]-=0.5; \n if (timing[((context.days-1)*24)+context.selector-5]<14){ timing[((context.days-1)*24)+context.selector-5]=14; msg.foryou=\"Limite raggiunto\";}\n else msg.foryou=\"Temperatura decrementata\";\n }\n if (context.selector==1) { if (timing[168+(context.selector-1)]>12) { timing[168+(context.selector-1)]-=0.5; msg.foryou=\"Temperatura clima diminuita di 0.5°C\"; } else msg.foryou=\"Limite raggiunto\"; }\n if (context.selector==2) { if (timing[168+(context.selector-1)]>12) { timing[168+(context.selector-1)]-=0.5; msg.foryou=\"Temperatura fuori casa diminuita di 0.5°C\"; } else msg.foryou=\"Limite raggiunto\"; }\n if (context.selector==29) { msg.foryou=\"Giorno precedente\"; context.days--; if (context.days < 1) { context.days = 7; } }\n break;\n case 'r' : if ((context.selector>=5)&&(context.selector<28))\n {\n timing[((context.days-1)*24)+context.selector-4]=timing[((context.days-1)*24)+context.selector-5]; \n context.selector++;\n msg.foryou=\"Temperatura copiata nello slot successivo\";\n }\n if ((context.selector==29)&&(context.days<7))\n {\n for (var a=0;a<24;a++)\n {\n timing[((context.days)*24)+a]=timing[((context.days-1)*24)+a]; \n }\n context.days++;\n msg.foryou=\"Impostazioni copiate nel giorno successivo\";\n }\n else if(context.days==7)\n msg.foryou=\"Fine della settimana raggiunto!\";\n break;\n case 's': context.saving=0; msg.foryou=\"Impostazioni salvate\"; break;\n case '1':\n case '2':\n case '3':\n case '4':\n case '5':\n case '6':\n case '7':\n case '8':\n case '9':\n case '10':\n case '11':\n case '12':\n case '13':\n case '14':\n case '15':\n case '16':\n case '17':\n case '18':\n case '19':\n case '20':\n case '21':\n case '22':\n case '23':\n case '24':\n case '25':\n case '26':\n case '27':\n case '28':\n case '29': context.selector=parseInt(msg.payload);\n if (msg.payload=='1') msg.foryou=\"Temperatura clima selezionata\"; \n else if (msg.payload=='2') msg.foryou=\"Temperatura fuori casa selezionata\";\n else if (msg.payload=='29') msg.foryou=\"Giorno selezionato\";\n else msg.foryou=\"Regolazione temperatura ore: \" + (parseInt(msg.payload)-5);\n break;\n case 'c' : msg.payload=\"niente\"; msg.foryou=\"Cambiamenti annullati\"; node.send([null,null,msg]);\n }\n\nmsg.temperatures=context.temperatures;\nmsg.timing=timing;\nmsg.days=context.days;\nmsg.selector=context.selector;\n\nnode.send([msg,null,null]);\n\nif (context.saving===0) \n { \n msg.topic=\"\";\n msg.timing=\"\";\n msg.payload=JSON.stringify(timing);\n node.send([null,msg,null]); \n context.saving=1;\n }\n msg.foryou=\"\"", |
|
"outputs": "3", |
|
"noerr": 0, |
|
"initialize": "", |
|
"finalize": "", |
|
"libs": [], |
|
"x": 560, |
|
"y": 200, |
|
"wires": [ |
|
[ |
|
"e0fd4ef8.cf0b3" |
|
], |
|
[ |
|
"780ced4a.7679d4" |
|
], |
|
[ |
|
"20ded924.9b9306" |
|
] |
|
] |
|
}, |
|
{ |
|
"id": "c128a3ee.22a46", |
|
"type": "inject", |
|
"z": "c7e7982a.89e5f8", |
|
"name": "Once only", |
|
"props": [ |
|
{ |
|
"p": "payload", |
|
"v": "", |
|
"vt": "str" |
|
}, |
|
{ |
|
"p": "topic", |
|
"v": "", |
|
"vt": "string" |
|
} |
|
], |
|
"repeat": "", |
|
"crontab": "", |
|
"once": true, |
|
"topic": "", |
|
"payload": "", |
|
"payloadType": "str", |
|
"x": 298, |
|
"y": 237, |
|
"wires": [ |
|
[ |
|
"9773ea79.6d18f8", |
|
"a0408ce0.f23a8" |
|
] |
|
] |
|
}, |
|
{ |
|
"id": "74fef445.d62e9c", |
|
"type": "inject", |
|
"z": "c7e7982a.89e5f8", |
|
"name": "Every minute", |
|
"props": [ |
|
{ |
|
"p": "payload" |
|
}, |
|
{ |
|
"p": "topic", |
|
"vt": "str" |
|
} |
|
], |
|
"repeat": "60", |
|
"crontab": "", |
|
"once": true, |
|
"onceDelay": "", |
|
"topic": "", |
|
"payload": "", |
|
"payloadType": "str", |
|
"x": 320, |
|
"y": 480, |
|
"wires": [ |
|
[ |
|
"7ba12336.80a24c", |
|
"266cc8e.7387c38" |
|
] |
|
] |
|
}, |
|
{ |
|
"id": "a805343b.fe6d88", |
|
"type": "function", |
|
"z": "c7e7982a.89e5f8", |
|
"name": "Process heat", |
|
"func": "if (flow.get(\"thermostat_mode\") != \"schedule\") {\n return null;\n}\n\nlet timing=global.get(\"timing\");\nvar now = new Date(msg.time);\n\nvar fixed_temperature = timing[(now.getDay()*24)+now.getHours()];\nvar away_temperature = timing[169];\nvar away_mode = flow.get(\"away_mode\");\n\nif (away_mode) {\n msg.payload = (fixed_temperature > away_temperature ? away_temperature : fixed_temperature);\n msg.awayMode = true;\n} else {\n msg.payload = fixed_temperature;\n msg.awayMode = false;\n}\n\nnode.status({fill:\"blue\",shape:\"dot\",text: \"Actual: \" + flow.get(\"ambient_temperature\") + \" - Set point: \" + msg.payload + \"°C\" + \" [away mode: \" + away_mode + \"]\"});\n\n\nreturn msg;", |
|
"outputs": 1, |
|
"noerr": 0, |
|
"initialize": "", |
|
"finalize": "", |
|
"libs": [], |
|
"x": 890, |
|
"y": 480, |
|
"wires": [ |
|
[ |
|
"f0e9bddf.11ad3" |
|
] |
|
] |
|
}, |
|
{ |
|
"id": "780ced4a.7679d4", |
|
"type": "file", |
|
"z": "c7e7982a.89e5f8", |
|
"name": "backup", |
|
"filename": "/share/thermo_scheduler.save", |
|
"appendNewline": true, |
|
"createDir": true, |
|
"overwriteFile": "true", |
|
"x": 750, |
|
"y": 200, |
|
"wires": [ |
|
[] |
|
] |
|
}, |
|
{ |
|
"id": "a0408ce0.f23a8", |
|
"type": "file in", |
|
"z": "c7e7982a.89e5f8", |
|
"name": "Restore", |
|
"filename": "/share/thermo_scheduler.save", |
|
"format": "utf8", |
|
"sendError": true, |
|
"x": 530, |
|
"y": 280, |
|
"wires": [ |
|
[ |
|
"5cdbcb09.d2b184" |
|
] |
|
] |
|
}, |
|
{ |
|
"id": "5cdbcb09.d2b184", |
|
"type": "function", |
|
"z": "c7e7982a.89e5f8", |
|
"name": "Restore data from SD", |
|
"func": "let timing = global.get(\"timing\");\ntiming=JSON.parse(msg.payload);\nglobal.set(\"timing\",timing);\nmsg.payload=\"\";\nreturn msg;", |
|
"outputs": 1, |
|
"noerr": 0, |
|
"initialize": "", |
|
"finalize": "", |
|
"libs": [], |
|
"x": 750, |
|
"y": 280, |
|
"wires": [ |
|
[ |
|
"8cc70579.6ac458" |
|
] |
|
] |
|
}, |
|
{ |
|
"id": "645bd732.1d8128", |
|
"type": "moment", |
|
"z": "c7e7982a.89e5f8", |
|
"name": "", |
|
"topic": "", |
|
"input": "payload", |
|
"inputType": "msg", |
|
"inTz": "Europe/Rome", |
|
"adjAmount": "0", |
|
"adjType": "hours", |
|
"adjDir": "add", |
|
"format": "dddd DD MMMM YYYY - HH:mm", |
|
"locale": "it_IT", |
|
"output": "payload", |
|
"outputType": "msg", |
|
"outTz": "Europe/Rome", |
|
"x": 620, |
|
"y": 560, |
|
"wires": [ |
|
[ |
|
"5a3f0ac6.23d634" |
|
] |
|
] |
|
}, |
|
{ |
|
"id": "5a3f0ac6.23d634", |
|
"type": "ui_text", |
|
"z": "c7e7982a.89e5f8", |
|
"group": "317e9d9c.dea8e2", |
|
"order": 2, |
|
"width": 6, |
|
"height": 1, |
|
"name": "Time", |
|
"label": "", |
|
"format": "{{msg.payload}}", |
|
"layout": "col-center", |
|
"x": 870, |
|
"y": 560, |
|
"wires": [] |
|
}, |
|
{ |
|
"id": "eb3fb3aa.cba34", |
|
"type": "link in", |
|
"z": "c7e7982a.89e5f8", |
|
"name": "restore", |
|
"links": [ |
|
"20ded924.9b9306" |
|
], |
|
"x": 351.5, |
|
"y": 288, |
|
"wires": [ |
|
[ |
|
"a0408ce0.f23a8" |
|
] |
|
] |
|
}, |
|
{ |
|
"id": "20ded924.9b9306", |
|
"type": "link out", |
|
"z": "c7e7982a.89e5f8", |
|
"name": "restore", |
|
"links": [ |
|
"eb3fb3aa.cba34", |
|
"93466115.e953e" |
|
], |
|
"x": 711.5, |
|
"y": 236, |
|
"wires": [] |
|
}, |
|
{ |
|
"id": "106201b7.f5bb7e", |
|
"type": "link in", |
|
"z": "c7e7982a.89e5f8", |
|
"name": "restoreSD", |
|
"links": [ |
|
"8cc70579.6ac458", |
|
"8e1afd82.fc23f", |
|
"aa45f621.310328" |
|
], |
|
"x": 351, |
|
"y": 189, |
|
"wires": [ |
|
[ |
|
"9773ea79.6d18f8" |
|
] |
|
] |
|
}, |
|
{ |
|
"id": "8cc70579.6ac458", |
|
"type": "link out", |
|
"z": "c7e7982a.89e5f8", |
|
"name": "restoreSD", |
|
"links": [ |
|
"106201b7.f5bb7e" |
|
], |
|
"x": 945, |
|
"y": 280, |
|
"wires": [] |
|
}, |
|
{ |
|
"id": "e0fd4ef8.cf0b3", |
|
"type": "link out", |
|
"z": "c7e7982a.89e5f8", |
|
"name": "setSettings", |
|
"links": [ |
|
"1a23cdc.2ee0b32" |
|
], |
|
"x": 712.5, |
|
"y": 160, |
|
"wires": [] |
|
}, |
|
{ |
|
"id": "1a23cdc.2ee0b32", |
|
"type": "link in", |
|
"z": "c7e7982a.89e5f8", |
|
"name": "setSettings", |
|
"links": [ |
|
"e0fd4ef8.cf0b3" |
|
], |
|
"x": 157.5, |
|
"y": 137, |
|
"wires": [ |
|
[ |
|
"a0aab4d8.8b6498" |
|
] |
|
] |
|
}, |
|
{ |
|
"id": "7ba12336.80a24c", |
|
"type": "moment", |
|
"z": "c7e7982a.89e5f8", |
|
"name": "time", |
|
"topic": "", |
|
"input": "", |
|
"inputType": "date", |
|
"inTz": "Europe/Rome", |
|
"adjAmount": "0", |
|
"adjType": "hours", |
|
"adjDir": "add", |
|
"format": "", |
|
"locale": "it_IT", |
|
"output": "time", |
|
"outputType": "msg", |
|
"outTz": "Europe/Rome", |
|
"x": 610, |
|
"y": 480, |
|
"wires": [ |
|
[ |
|
"a805343b.fe6d88" |
|
] |
|
] |
|
}, |
|
{ |
|
"id": "64c9da3e.3127b4", |
|
"type": "function", |
|
"z": "c7e7982a.89e5f8", |
|
"name": "Store away state", |
|
"func": "msg.topic = 'awayMode';\nvar awayMode = false;\n\nif(msg.payload == \"armed_away\"){\n awayMode = true; \n}\n\nflow.set(\"away_mode\",awayMode);\nnode.status({fill:\"red\",shape:\"dot\",text:\"away mode: \" + awayMode}); \n\nreturn msg;\n", |
|
"outputs": 1, |
|
"noerr": 0, |
|
"x": 510, |
|
"y": 780, |
|
"wires": [ |
|
[ |
|
"f8f19df4.f2fd7" |
|
] |
|
] |
|
}, |
|
{ |
|
"id": "f0e9bddf.11ad3", |
|
"type": "api-call-service", |
|
"z": "c7e7982a.89e5f8", |
|
"name": "", |
|
"server": "41108723.0bf848", |
|
"version": 3, |
|
"debugenabled": false, |
|
"service_domain": "climate", |
|
"service": "set_temperature", |
|
"entityId": "climate.termostato", |
|
"data": "{\"temperature\": \"{{payload}}\", \"hvac_mode\": \"heat\"}", |
|
"dataType": "json", |
|
"mergecontext": "", |
|
"mustacheAltTags": false, |
|
"outputProperties": [ |
|
{ |
|
"property": "payload", |
|
"propertyType": "msg", |
|
"value": "", |
|
"valueType": "data" |
|
} |
|
], |
|
"queue": "none", |
|
"x": 1160, |
|
"y": 560, |
|
"wires": [ |
|
[] |
|
] |
|
}, |
|
{ |
|
"id": "a2f11a6d.ff7e28", |
|
"type": "api-call-service", |
|
"z": "c7e7982a.89e5f8", |
|
"name": "", |
|
"server": "41108723.0bf848", |
|
"version": 3, |
|
"service_domain": "climate", |
|
"service": "turn_on", |
|
"entityId": "climate.termostato", |
|
"data": "{\"entity_id\": \"climate.termostato\"}", |
|
"dataType": "json", |
|
"mergecontext": "", |
|
"mustacheAltTags": false, |
|
"outputProperties": [], |
|
"queue": "none", |
|
"x": 900, |
|
"y": 1020, |
|
"wires": [ |
|
[] |
|
] |
|
}, |
|
{ |
|
"id": "180c3495.1167cb", |
|
"type": "api-call-service", |
|
"z": "c7e7982a.89e5f8", |
|
"name": "", |
|
"server": "41108723.0bf848", |
|
"version": 3, |
|
"service_domain": "climate", |
|
"service": "turn_off", |
|
"entityId": "climate.termostato", |
|
"data": "{\"entity_id\": \"climate.termostato\"}", |
|
"dataType": "json", |
|
"mergecontext": "", |
|
"mustacheAltTags": false, |
|
"outputProperties": [], |
|
"queue": "none", |
|
"x": 900, |
|
"y": 960, |
|
"wires": [ |
|
[] |
|
] |
|
}, |
|
{ |
|
"id": "c5a858fe.e4ae98", |
|
"type": "server-state-changed", |
|
"z": "c7e7982a.89e5f8", |
|
"name": "Away from Alarm", |
|
"server": "41108723.0bf848", |
|
"version": 3, |
|
"entityidfilter": "alarm_control_panel.allarme_casa", |
|
"entityidfiltertype": "exact", |
|
"outputinitially": true, |
|
"state_type": "str", |
|
"haltifstate": "", |
|
"halt_if_type": "str", |
|
"halt_if_compare": "is", |
|
"outputs": 1, |
|
"output_only_on_state_change": true, |
|
"for": "0", |
|
"forType": "num", |
|
"forUnits": "minutes", |
|
"outputProperties": [ |
|
{ |
|
"property": "payload", |
|
"propertyType": "msg", |
|
"value": "", |
|
"valueType": "entityState" |
|
}, |
|
{ |
|
"property": "data", |
|
"propertyType": "msg", |
|
"value": "", |
|
"valueType": "eventData" |
|
}, |
|
{ |
|
"property": "topic", |
|
"propertyType": "msg", |
|
"value": "", |
|
"valueType": "triggerId" |
|
} |
|
], |
|
"x": 260, |
|
"y": 780, |
|
"wires": [ |
|
[ |
|
"64c9da3e.3127b4" |
|
] |
|
] |
|
}, |
|
{ |
|
"id": "95403a92.332ff8", |
|
"type": "inject", |
|
"z": "c7e7982a.89e5f8", |
|
"name": "Every second", |
|
"props": [ |
|
{ |
|
"p": "payload", |
|
"v": "", |
|
"vt": "date" |
|
}, |
|
{ |
|
"p": "topic", |
|
"v": "", |
|
"vt": "string" |
|
} |
|
], |
|
"repeat": "1", |
|
"crontab": "", |
|
"once": true, |
|
"onceDelay": "", |
|
"topic": "", |
|
"payload": "", |
|
"payloadType": "date", |
|
"x": 320, |
|
"y": 560, |
|
"wires": [ |
|
[ |
|
"645bd732.1d8128" |
|
] |
|
] |
|
}, |
|
{ |
|
"id": "97c4518e.c0731", |
|
"type": "ui_template", |
|
"z": "c7e7982a.89e5f8", |
|
"group": "317e9d9c.dea8e2", |
|
"name": "Nest", |
|
"order": 4, |
|
"width": 5, |
|
"height": 5, |
|
"format": "<div id=\"thermostat\"></div>\n\n<style>\n\n@import url(https://fonts.googleapis.com/css?family=Open+Sans:300);\n\n#thermostat {\n margin: 0 0;\n overflow: hidden;\n -webkit-tap-highlight-color: rgba(0, 0, 0, 0);\n}\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.off .dial__ico__leaf {\n visibility: hidden;\n}\n.dial.off .dial__lbl--target {\n visibility: hidden;\n}\n.dial.off .dial__lbl--target--half {\n visibility: hidden;\n}\n.dial.off .dial__lbl--off {\n opacity: 1;\n}\n.dial .dial__shape {\n -webkit-transition: fill 0.5s;\n transition: fill 0.5s;\n}\n.dial path.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-rule: evenodd;\n opacity: 0;\n -webkit-transition: opacity 0.5s;\n transition: opacity 0.5s;\n}\n.dial--edit path.dial__editableIndicator {\n fill: white;\n}\n.dial--edit .dial__editableIndicator {\n opacity: 1;\n}\n.dial--state--off .dial__shape {\n fill: #3d3c3c;\n}\n.dial--state--idle .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 .dial__ticks path {\n fill: rgba(255, 255, 255, 0.3);\n}\n.dial .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--off {\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\t//function roundHalf(num) {\n\t//\treturn Math.round(num*10)/10;\n\t//}\n\t\n\t// Round a number to tenth's 0.1\n\tfunction roundHalf(num) {\n\t\treturn Math.round(num*10)/10;\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 || 380,\n\t\t\tminValue: options.minValue || 14, // Minimum value for target temperature\n\t\t\tmaxValue: options.maxValue || 24, // 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: ['idle', '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\toff: 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\tfunction str2bool(strvalue){\n return (strvalue && typeof strvalue == 'string') ? (strvalue.toLowerCase() == 'true') : (strvalue == true);\n }\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 = !!str2bool(val);\n\t\t\t\trender();\n\t\t\t}\n\t\t});\n\t\tObject.defineProperty(this,'off',{\n\t\t\tget: function() {\n\t\t\t\treturn state.off;\n\t\t\t},\n\t\t\tset: function(val) {\n\t\t\t\tstate.off = !!str2bool(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: '95%', //options.diameter+'px',\n\t\t\theight: '95%', //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 lbloff = createSVGElement('text',{\n\t\t\tx: properties.radius,\n\t\t\ty: properties.radius,\n\t\t\tclass: 'dial__lbl dial__lbl--off'\n\t\t},svg);\n\t\tvar lbloff_text = document.createTextNode('OFF');\n\t\tlbloff.appendChild(lbloff_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\trenderOff();\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.off) {\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 = self.ambient_temperature;\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', true);\n\t\t\tlblTargetHalf_text.nodeValue = (self.target_temperature % 1).toFixed(1).substring(2);\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 - off\n\t\t */\n\t\tfunction renderOff() {\n\t\t\tsvg.classList[self.off ? 'add' : 'remove']('off');\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/* ==== */\nvar initializing = true;\n\n(function(scope) {\n var nest = new thermostatDial(document.getElementById('thermostat'),{\n \tonSetTargetTemperature: function(v) {\n \t var p = {\n \t \"ambient_temperature\":nest.ambient_temperature,\n \t \"target_temperature\":v,\n \t \"hvac_state\":nest.hvac_state,\n \t \"has_leaf\": nest.has_leaf,\n \t \"off_view\":nest.off\n \t };\n \t\tscope.send({topic: \"target_temperature\", payload: p});\n \t}\n });\n \n scope.$watch('msg', function(data) {\n if (initializing) {\n initializing = false;\n } else {\n nest.ambient_temperature = data.payload.ambient_temperature || 0;\n nest.target_temperature = data.payload.target_temperature || 0;\n nest.hvac_state = data.payload.hvac_state || \"off\";\n nest.has_leaf = data.payload.has_leaf || false;\n nest.off = data.payload.off_view || false;\n }\n \n });\n})(scope);\n\n</script>", |
|
"storeOutMessages": true, |
|
"fwdInMessages": false, |
|
"resendOnRefresh": true, |
|
"templateScope": "local", |
|
"x": 630, |
|
"y": 640, |
|
"wires": [ |
|
[ |
|
"8f7013c0.fc602" |
|
] |
|
] |
|
}, |
|
{ |
|
"id": "f8f19df4.f2fd7", |
|
"type": "function", |
|
"z": "c7e7982a.89e5f8", |
|
"name": "Data", |
|
"func": "msg.topic = \"update\";\n\nvar msg2 = {};\nmsg2.payload = flow.get(\"thermostat_mode\");\n\nvar data = {\n 'ambient_temperature': flow.get(\"ambient_temperature\") || 20,\n 'target_temperature': flow.get(\"target_temperature\") || 14,\n 'hvac_state': flow.get(\"hvac_action\") || 'off',\n 'has_leaf': flow.get(\"away_mode\") || false,\n 'off_view': flow.get(\"off_view\") || false\n}\nmsg.payload = data;\nnode.status({fill:\"red\",shape:\"dot\",text: \"ambient_temperature: \" + data.ambient_temperature + \" / target_temperature: \" + data.target_temperature + \" / away_mode: \" + data.has_leaf + \" / climate_state: \" + flow.get(\"climate_state\") + \" / hvac_state: \" + data.hvac_state + \" / thermostat_mode: \" + msg2.payload});\n\nvar msg3 = {};\nif (msg2.payload == \"off\")\n{\n msg3.payload = false;\n}\nelse if (msg2.payload == \"countdown\")\n{\n msg3.payload = true;\n}\nelse\n{\n msg3 = null;\n}\n\nreturn [msg,msg2,msg3];", |
|
"outputs": 3, |
|
"noerr": 0, |
|
"initialize": "", |
|
"finalize": "", |
|
"x": 750, |
|
"y": 760, |
|
"wires": [ |
|
[ |
|
"97c4518e.c0731", |
|
"f774f7fb.980448" |
|
], |
|
[ |
|
"e80beafb.960048", |
|
"f21ea4a8.3d7e28" |
|
], |
|
[ |
|
"8d3e7ccb.05e8a" |
|
] |
|
] |
|
}, |
|
{ |
|
"id": "8f7013c0.fc602", |
|
"type": "function", |
|
"z": "c7e7982a.89e5f8", |
|
"name": "New setpoint from UI", |
|
"func": "if (msg.topic == \"target_temperature\") {\n msg.payload = msg.payload.target_temperature;\n flow.set(\"target_temperature\", msg.payload);\n node.status({fill:\"red\",shape:\"dot\",text:\"target_temperature: \" + msg.payload}); \n return msg;\n}\n", |
|
"outputs": 1, |
|
"noerr": 0, |
|
"x": 860, |
|
"y": 640, |
|
"wires": [ |
|
[ |
|
"f0e9bddf.11ad3" |
|
] |
|
] |
|
}, |
|
{ |
|
"id": "85c35de5.000d", |
|
"type": "server-state-changed", |
|
"z": "c7e7982a.89e5f8", |
|
"name": "Climate", |
|
"server": "41108723.0bf848", |
|
"version": 3, |
|
"entityidfilter": "climate.termostato", |
|
"entityidfiltertype": "exact", |
|
"outputinitially": true, |
|
"state_type": "str", |
|
"haltifstate": "", |
|
"halt_if_type": "str", |
|
"halt_if_compare": "is", |
|
"outputs": 1, |
|
"output_only_on_state_change": false, |
|
"for": "0", |
|
"forType": "num", |
|
"forUnits": "minutes", |
|
"outputProperties": [ |
|
{ |
|
"property": "payload", |
|
"propertyType": "msg", |
|
"value": "", |
|
"valueType": "entityState" |
|
}, |
|
{ |
|
"property": "data", |
|
"propertyType": "msg", |
|
"value": "", |
|
"valueType": "eventData" |
|
}, |
|
{ |
|
"property": "topic", |
|
"propertyType": "msg", |
|
"value": "", |
|
"valueType": "triggerId" |
|
} |
|
], |
|
"x": 230, |
|
"y": 720, |
|
"wires": [ |
|
[ |
|
"d81ec755.7a8988", |
|
"8190067a.0d5ff8" |
|
] |
|
] |
|
}, |
|
{ |
|
"id": "f774f7fb.980448", |
|
"type": "debug", |
|
"z": "c7e7982a.89e5f8", |
|
"name": "climate_debug", |
|
"active": false, |
|
"tosidebar": true, |
|
"console": false, |
|
"tostatus": false, |
|
"complete": "true", |
|
"targetType": "full", |
|
"x": 940, |
|
"y": 740, |
|
"wires": [] |
|
}, |
|
{ |
|
"id": "d81ec755.7a8988", |
|
"type": "function", |
|
"z": "c7e7982a.89e5f8", |
|
"name": "Store climate state", |
|
"func": "msg.topic = 'climate';\n\nflow.set(\"ambient_temperature\", msg.data.new_state.attributes.current_temperature);\nflow.set(\"target_temperature\",msg.data.new_state.attributes.temperature);\nflow.set(\"climate_state\",msg.payload);\nflow.set(\"off_view\",msg.payload == \"off\" ? true : false);\nflow.set(\"hvac_action\",msg.data.new_state.attributes.hvac_action);\n\nnode.status({fill:\"red\",shape:\"dot\",text:msg.payload}); \n\nreturn msg;", |
|
"outputs": 1, |
|
"noerr": 0, |
|
"initialize": "", |
|
"finalize": "", |
|
"x": 510, |
|
"y": 720, |
|
"wires": [ |
|
[ |
|
"f8f19df4.f2fd7" |
|
] |
|
] |
|
}, |
|
{ |
|
"id": "30695c3e.d68cc4", |
|
"type": "ui_switch", |
|
"z": "c7e7982a.89e5f8", |
|
"name": "", |
|
"label": "", |
|
"tooltip": "", |
|
"group": "317e9d9c.dea8e2", |
|
"order": 3, |
|
"width": 1, |
|
"height": 1, |
|
"passthru": false, |
|
"decouple": "true", |
|
"topic": "", |
|
"style": "", |
|
"onvalue": "true", |
|
"onvalueType": "bool", |
|
"onicon": "", |
|
"oncolor": "", |
|
"offvalue": "false", |
|
"offvalueType": "bool", |
|
"officon": "", |
|
"offcolor": "", |
|
"x": 430, |
|
"y": 1000, |
|
"wires": [ |
|
[ |
|
"8d3e7ccb.05e8a" |
|
] |
|
] |
|
}, |
|
{ |
|
"id": "8d3e7ccb.05e8a", |
|
"type": "switch", |
|
"z": "c7e7982a.89e5f8", |
|
"name": "", |
|
"property": "payload", |
|
"propertyType": "msg", |
|
"rules": [ |
|
{ |
|
"t": "false" |
|
}, |
|
{ |
|
"t": "true" |
|
} |
|
], |
|
"checkall": "true", |
|
"repair": false, |
|
"outputs": 2, |
|
"x": 590, |
|
"y": 1000, |
|
"wires": [ |
|
[ |
|
"180c3495.1167cb", |
|
"cef71c8c.a9bc5" |
|
], |
|
[ |
|
"a2f11a6d.ff7e28" |
|
] |
|
] |
|
}, |
|
{ |
|
"id": "8190067a.0d5ff8", |
|
"type": "function", |
|
"z": "c7e7982a.89e5f8", |
|
"name": "sync switch", |
|
"func": "var msg2 = {};\n\nif (msg.payload == \"off\"){\n msg.payload = false;\n flow.set(\"thermostat_mode\",\"off\");\n msg2.payload = \"off\";\n}\nelse {\n msg.payload = true;\n if (flow.get(\"thermostat_mode\") == \"off\") {\n flow.set(\"thermostat_mode\",\"schedule\");\n msg2.payload = \"schedule\";\n }\n else {\n msg2.payload = flow.get(\"thermostat_mode\");\n }\n}\n\nreturn [msg, msg2];\n", |
|
"outputs": 2, |
|
"noerr": 0, |
|
"initialize": "", |
|
"finalize": "", |
|
"x": 210, |
|
"y": 960, |
|
"wires": [ |
|
[ |
|
"30695c3e.d68cc4" |
|
], |
|
[ |
|
"f21ea4a8.3d7e28" |
|
] |
|
] |
|
}, |
|
{ |
|
"id": "4803668a.123128", |
|
"type": "ui_button", |
|
"z": "c7e7982a.89e5f8", |
|
"name": "", |
|
"group": "77b849cb.094c08", |
|
"order": 2, |
|
"width": 8, |
|
"height": 1, |
|
"passthru": false, |
|
"label": "Torna alla home", |
|
"tooltip": "", |
|
"color": "{{colour}}", |
|
"bgcolor": "{{payload}}", |
|
"icon": "", |
|
"payload": "{\"group\":{\"hide\":[\"Cronotermostato_Programmazione\"],\"show\":[\"Cronotermostato_Nest\"]}}", |
|
"payloadType": "json", |
|
"topic": "", |
|
"x": 640, |
|
"y": 1340, |
|
"wires": [ |
|
[ |
|
"fa178067.0ef11", |
|
"df7585f3.52b3d8" |
|
] |
|
] |
|
}, |
|
{ |
|
"id": "fa178067.0ef11", |
|
"type": "ui_ui_control", |
|
"z": "c7e7982a.89e5f8", |
|
"name": "", |
|
"events": "all", |
|
"x": 900, |
|
"y": 1360, |
|
"wires": [ |
|
[] |
|
] |
|
}, |
|
{ |
|
"id": "8a7e776.5e09688", |
|
"type": "ui_chart", |
|
"z": "c7e7982a.89e5f8", |
|
"name": "", |
|
"group": "eaea6ba8.f76288", |
|
"order": 1, |
|
"width": 8, |
|
"height": 5, |
|
"label": "Grafico cronologico", |
|
"chartType": "line", |
|
"legend": "true", |
|
"xformat": "HH:mm", |
|
"interpolate": "bezier", |
|
"nodata": "empty", |
|
"dot": false, |
|
"ymin": "", |
|
"ymax": "", |
|
"removeOlder": "6", |
|
"removeOlderPoints": "", |
|
"removeOlderUnit": "3600", |
|
"cutout": 0, |
|
"useOneColor": false, |
|
"useUTC": false, |
|
"colors": [ |
|
"#d62728", |
|
"#1f77b4", |
|
"#ff7f0e", |
|
"#2ca02c", |
|
"#98df8a", |
|
"#aec7e8", |
|
"#ff9896", |
|
"#9467bd", |
|
"#c5b0d5" |
|
], |
|
"outputs": 1, |
|
"x": 690, |
|
"y": 2100, |
|
"wires": [ |
|
[ |
|
"b8478180.cc3d2", |
|
"8fa4fc95.6ccb" |
|
] |
|
] |
|
}, |
|
{ |
|
"id": "d9362c57.332e", |
|
"type": "function", |
|
"z": "c7e7982a.89e5f8", |
|
"name": "Data to chart", |
|
"func": "var msg1 = {};\nmsg1.topic = \"target\";\nmsg1.payload = flow.get(\"target_temperature\");\n\nvar msg2 = {};\nmsg2.topic = \"ambient\";\nmsg2.payload = flow.get(\"ambient_temperature\");\n\nreturn [msg1, msg2];", |
|
"outputs": 2, |
|
"noerr": 0, |
|
"x": 450, |
|
"y": 2100, |
|
"wires": [ |
|
[ |
|
"8a7e776.5e09688" |
|
], |
|
[ |
|
"8a7e776.5e09688" |
|
] |
|
] |
|
}, |
|
{ |
|
"id": "3c197bdb.d59684", |
|
"type": "ui_button", |
|
"z": "c7e7982a.89e5f8", |
|
"name": "", |
|
"group": "eaea6ba8.f76288", |
|
"order": 2, |
|
"width": 8, |
|
"height": 1, |
|
"passthru": false, |
|
"label": "Torna alla home", |
|
"tooltip": "", |
|
"color": "{{colour}}", |
|
"bgcolor": "{{payload}}", |
|
"icon": "", |
|
"payload": "{\"group\":{\"hide\":[\"Cronotermostato_Grafico\"],\"show\":[\"Cronotermostato_Nest\"]}}", |
|
"payloadType": "json", |
|
"topic": "", |
|
"x": 640, |
|
"y": 1440, |
|
"wires": [ |
|
[ |
|
"fa178067.0ef11", |
|
"df7585f3.52b3d8" |
|
] |
|
] |
|
}, |
|
{ |
|
"id": "4faba555.b954dc", |
|
"type": "ui_button", |
|
"z": "c7e7982a.89e5f8", |
|
"name": "", |
|
"group": "317e9d9c.dea8e2", |
|
"order": 1, |
|
"width": 1, |
|
"height": 1, |
|
"passthru": false, |
|
"label": "", |
|
"tooltip": "", |
|
"color": "{{colour}}", |
|
"bgcolor": "transparent", |
|
"icon": "fa-area-chart", |
|
"payload": "{\"group\":{\"show\":[\"Cronotermostato_Grafico\"],\"hide\":[\"Cronotermostato_Nest\"]}}", |
|
"payloadType": "json", |
|
"topic": "", |
|
"x": 610, |
|
"y": 1380, |
|
"wires": [ |
|
[ |
|
"fa178067.0ef11", |
|
"7d9d27e5.6bd938" |
|
] |
|
] |
|
}, |
|
{ |
|
"id": "37ae5a89.01cd36", |
|
"type": "inject", |
|
"z": "c7e7982a.89e5f8", |
|
"name": "Every minute", |
|
"props": [ |
|
{ |
|
"p": "payload", |
|
"v": "", |
|
"vt": "str" |
|
}, |
|
{ |
|
"p": "topic", |
|
"v": "", |
|
"vt": "string" |
|
} |
|
], |
|
"repeat": "60", |
|
"crontab": "", |
|
"once": true, |
|
"onceDelay": "", |
|
"topic": "", |
|
"payload": "", |
|
"payloadType": "str", |
|
"x": 240, |
|
"y": 2100, |
|
"wires": [ |
|
[ |
|
"d9362c57.332e", |
|
"7af169ef.9510a8" |
|
] |
|
] |
|
}, |
|
{ |
|
"id": "b8478180.cc3d2", |
|
"type": "subflow:8850e193.e1712", |
|
"z": "c7e7982a.89e5f8", |
|
"name": "", |
|
"env": [], |
|
"x": 870, |
|
"y": 2100, |
|
"wires": [ |
|
[ |
|
"b7aa55dc.b434c8" |
|
] |
|
] |
|
}, |
|
{ |
|
"id": "7d9d27e5.6bd938", |
|
"type": "function", |
|
"z": "c7e7982a.89e5f8", |
|
"name": "restore chart", |
|
"func": "msg.topic=\"restore\"\nreturn msg;", |
|
"outputs": 1, |
|
"noerr": 0, |
|
"x": 850, |
|
"y": 1520, |
|
"wires": [ |
|
[] |
|
] |
|
}, |
|
{ |
|
"id": "8fa4fc95.6ccb", |
|
"type": "debug", |
|
"z": "c7e7982a.89e5f8", |
|
"name": "grafico_debug", |
|
"active": false, |
|
"tosidebar": true, |
|
"console": false, |
|
"tostatus": false, |
|
"complete": "true", |
|
"targetType": "full", |
|
"x": 880, |
|
"y": 2040, |
|
"wires": [] |
|
}, |
|
{ |
|
"id": "634ced23.8751e4", |
|
"type": "function", |
|
"z": "c7e7982a.89e5f8", |
|
"name": "show today", |
|
"func": "flow.set(\"resetday\",true);\n\nreturn msg;", |
|
"outputs": 1, |
|
"noerr": 0, |
|
"initialize": "", |
|
"finalize": "", |
|
"x": 870, |
|
"y": 1280, |
|
"wires": [ |
|
[ |
|
"fa178067.0ef11" |
|
] |
|
] |
|
}, |
|
{ |
|
"id": "3ad37bad.3b6564", |
|
"type": "change", |
|
"z": "c7e7982a.89e5f8", |
|
"name": "", |
|
"rules": [ |
|
{ |
|
"t": "set", |
|
"p": "yves", |
|
"pt": "global", |
|
"to": "payload[0]", |
|
"tot": "msg" |
|
} |
|
], |
|
"action": "", |
|
"property": "", |
|
"from": "", |
|
"to": "", |
|
"reg": false, |
|
"x": 1220, |
|
"y": 2100, |
|
"wires": [ |
|
[] |
|
] |
|
}, |
|
{ |
|
"id": "b7aa55dc.b434c8", |
|
"type": "switch", |
|
"z": "c7e7982a.89e5f8", |
|
"name": "", |
|
"property": "payload", |
|
"propertyType": "msg", |
|
"rules": [ |
|
{ |
|
"t": "istype", |
|
"v": "undefined", |
|
"vt": "undefined" |
|
}, |
|
{ |
|
"t": "else" |
|
} |
|
], |
|
"checkall": "true", |
|
"repair": false, |
|
"outputs": 2, |
|
"x": 1030, |
|
"y": 2100, |
|
"wires": [ |
|
[], |
|
[ |
|
"3ad37bad.3b6564" |
|
] |
|
] |
|
}, |
|
{ |
|
"id": "7af169ef.9510a8", |
|
"type": "change", |
|
"z": "c7e7982a.89e5f8", |
|
"name": "global.yves", |
|
"rules": [ |
|
{ |
|
"t": "set", |
|
"p": "payload", |
|
"pt": "msg", |
|
"to": "yves", |
|
"tot": "global" |
|
} |
|
], |
|
"action": "", |
|
"property": "", |
|
"from": "", |
|
"to": "", |
|
"reg": false, |
|
"x": 450, |
|
"y": 2160, |
|
"wires": [ |
|
[ |
|
"8a7e776.5e09688" |
|
] |
|
] |
|
}, |
|
{ |
|
"id": "5021393b.a4a638", |
|
"type": "ui_button", |
|
"z": "c7e7982a.89e5f8", |
|
"name": "", |
|
"group": "e767a130.9c455", |
|
"order": 7, |
|
"width": 2, |
|
"height": 1, |
|
"passthru": true, |
|
"label": "Stop", |
|
"tooltip": "", |
|
"color": "", |
|
"bgcolor": "", |
|
"icon": "fa-clock-o", |
|
"payload": "{ \"payload\": \"stop\" }", |
|
"payloadType": "str", |
|
"topic": "", |
|
"x": 370, |
|
"y": 1680, |
|
"wires": [ |
|
[ |
|
"e3e8f114.0795b" |
|
] |
|
] |
|
}, |
|
{ |
|
"id": "e356a4a.bc2a558", |
|
"type": "function", |
|
"z": "c7e7982a.89e5f8", |
|
"name": "Seconds to minutes & refresh state", |
|
"func": "var msg2 = {};\nmsg2.payload = msg.payload;\n\nvar msg3 = {};\n\nvar minutes = msg.payload /60;\nmsg.payload=minutes;\n\nif (msg.state > 0)\n{\n if (flow.get(\"thermostat_mode\") != 'countdown')\n {\n flow.set(\"thermostat_mode\", \"countdown\");\n }\n else\n {\n msg2 = null;\n }\n \n if (minutes < 1)\n {\n msg3.payload = \"Secondi rimanenti: \" + (minutes*60).toFixed(0);\n }\n else\n {\n msg3.payload = \"Minuti rimanenti: \" + minutes.toFixed(0);\n }\n}\nelse if (msg2.payload == -1 || (msg2.payload == 0 && flow.get(\"countdown_preflag\") != 'off'))\n{\n flow.set(\"thermostat_mode\", flow.get(\"countdown_followed_by\"));\n}\nelse\n{\n msg2 = null;\n}\n\nflow.set(\"countdown_preflag\", msg.flag);\n\nreturn [msg, msg2, msg3];", |
|
"outputs": 3, |
|
"noerr": 0, |
|
"initialize": "", |
|
"finalize": "", |
|
"x": 1020, |
|
"y": 1920, |
|
"wires": [ |
|
[ |
|
"bb3cc3ca.9642a" |
|
], |
|
[ |
|
"3a1c4056.fd71a" |
|
], |
|
[ |
|
"66c9691b.d63478" |
|
] |
|
] |
|
}, |
|
{ |
|
"id": "bb3cc3ca.9642a", |
|
"type": "ui_gauge", |
|
"z": "c7e7982a.89e5f8", |
|
"name": "Countdown Timer", |
|
"group": "e767a130.9c455", |
|
"order": 1, |
|
"width": 6, |
|
"height": 4, |
|
"gtype": "donut", |
|
"title": "", |
|
"label": "Minuti", |
|
"format": "{{value | number:0}}", |
|
"min": 0, |
|
"max": "60", |
|
"colors": [ |
|
"#ff2600", |
|
"#e6e600", |
|
"#00f900" |
|
], |
|
"seg1": "", |
|
"seg2": "", |
|
"x": 1230, |
|
"y": 1800, |
|
"wires": [] |
|
}, |
|
{ |
|
"id": "a6f16c.5d5d8e98", |
|
"type": "function", |
|
"z": "c7e7982a.89e5f8", |
|
"name": "Minutes to seconds", |
|
"func": "var seconds = msg.payload * 60;\n\nif(seconds==0) \n{\n msg.payload= \"stop\";\n return msg;\n}\n\nmsg.payload=\"{\\\"payload\\\": \\\"on\\\", \\\"timeout\\\":\" + seconds + \", \\\"warning\\\": 30}\"\n\nreturn msg;", |
|
"outputs": 1, |
|
"noerr": 0, |
|
"initialize": "", |
|
"finalize": "", |
|
"x": 450, |
|
"y": 1880, |
|
"wires": [ |
|
[ |
|
"b693b186.25f61" |
|
] |
|
] |
|
}, |
|
{ |
|
"id": "601e97b7.a9d318", |
|
"type": "ui_slider", |
|
"z": "c7e7982a.89e5f8", |
|
"name": "", |
|
"label": "Minuti", |
|
"tooltip": "Timer avviato al rilascio", |
|
"group": "e767a130.9c455", |
|
"order": 6, |
|
"width": 6, |
|
"height": 1, |
|
"passthru": true, |
|
"outs": "end", |
|
"topic": "", |
|
"min": "0", |
|
"max": "120", |
|
"step": 1, |
|
"x": 230, |
|
"y": 1840, |
|
"wires": [ |
|
[ |
|
"a6f16c.5d5d8e98", |
|
"dc8ecafd.2056b8" |
|
] |
|
] |
|
}, |
|
{ |
|
"id": "146358ea.a1b987", |
|
"type": "ui_toast", |
|
"z": "c7e7982a.89e5f8", |
|
"position": "top left", |
|
"displayTime": "1", |
|
"highlight": "#e83a2c", |
|
"sendall": true, |
|
"outputs": 0, |
|
"ok": "OK", |
|
"cancel": "", |
|
"raw": false, |
|
"topic": "", |
|
"name": "", |
|
"x": 960, |
|
"y": 1840, |
|
"wires": [] |
|
}, |
|
{ |
|
"id": "b693b186.25f61", |
|
"type": "mytimeout", |
|
"z": "c7e7982a.89e5f8", |
|
"name": "Timer 1-120 Minutes", |
|
"outtopic": "", |
|
"outsafe": "", |
|
"outwarning": "Il Countdown è quasi finito", |
|
"outunsafe": "Countdown terminato", |
|
"warning": "", |
|
"timer": "", |
|
"debug": false, |
|
"ndebug": true, |
|
"ignoreCase": false, |
|
"repeat": false, |
|
"again": false, |
|
"x": 720, |
|
"y": 1880, |
|
"wires": [ |
|
[ |
|
"146358ea.a1b987" |
|
], |
|
[ |
|
"e356a4a.bc2a558" |
|
] |
|
] |
|
}, |
|
{ |
|
"id": "dc8ecafd.2056b8", |
|
"type": "function", |
|
"z": "c7e7982a.89e5f8", |
|
"name": "Set min&max", |
|
"func": "var minuti = msg.payload;\n\nif(minuti==0) \n{\n minuti=1;\n}\n\nmsg.ui_control = {\"min\":0,\"max\":minuti}\n\nreturn msg;", |
|
"outputs": 1, |
|
"noerr": 0, |
|
"initialize": "", |
|
"finalize": "", |
|
"x": 430, |
|
"y": 1800, |
|
"wires": [ |
|
[ |
|
"bb3cc3ca.9642a" |
|
] |
|
] |
|
}, |
|
{ |
|
"id": "e3e8f114.0795b", |
|
"type": "function", |
|
"z": "c7e7982a.89e5f8", |
|
"name": "Reset Slider", |
|
"func": "msg.payload = 0;\n\nreturn msg;", |
|
"outputs": 1, |
|
"noerr": 0, |
|
"initialize": "", |
|
"finalize": "", |
|
"x": 570, |
|
"y": 1680, |
|
"wires": [ |
|
[ |
|
"601e97b7.a9d318" |
|
] |
|
] |
|
}, |
|
{ |
|
"id": "5b0d0cf.c059ef4", |
|
"type": "ui_button", |
|
"z": "c7e7982a.89e5f8", |
|
"name": "", |
|
"group": "e767a130.9c455", |
|
"order": 8, |
|
"width": 8, |
|
"height": 1, |
|
"passthru": false, |
|
"label": "Torna alla home", |
|
"tooltip": "", |
|
"color": "{{colour}}", |
|
"bgcolor": "{{payload}}", |
|
"icon": "", |
|
"payload": "{\"group\":{\"hide\":[\"Cronotermostato_Countdown\"],\"show\":[\"Cronotermostato_Nest\"]}}", |
|
"payloadType": "json", |
|
"topic": "", |
|
"x": 640, |
|
"y": 1500, |
|
"wires": [ |
|
[ |
|
"fa178067.0ef11", |
|
"df7585f3.52b3d8" |
|
] |
|
] |
|
}, |
|
{ |
|
"id": "f21ea4a8.3d7e28", |
|
"type": "ui_dropdown", |
|
"z": "c7e7982a.89e5f8", |
|
"name": "", |
|
"label": "", |
|
"tooltip": "", |
|
"place": "Select mode", |
|
"group": "317e9d9c.dea8e2", |
|
"order": 5, |
|
"width": 3, |
|
"height": 1, |
|
"passthru": false, |
|
"multiple": false, |
|
"options": [ |
|
{ |
|
"label": "Spento", |
|
"value": "off", |
|
"type": "str" |
|
}, |
|
{ |
|
"label": "Programma", |
|
"value": "schedule", |
|
"type": "str" |
|
}, |
|
{ |
|
"label": "Countdown", |
|
"value": "countdown", |
|
"type": "str" |
|
}, |
|
{ |
|
"label": "Manuale", |
|
"value": "manual", |
|
"type": "str" |
|
} |
|
], |
|
"payload": "", |
|
"topic": "", |
|
"x": 280, |
|
"y": 1100, |
|
"wires": [ |
|
[ |
|
"52b5f34a.e5438c", |
|
"e80beafb.960048" |
|
] |
|
] |
|
}, |
|
{ |
|
"id": "52b5f34a.e5438c", |
|
"type": "function", |
|
"z": "c7e7982a.89e5f8", |
|
"name": "Mode selection", |
|
"func": "switch (msg.payload){\ncase 'off':\n flow.set(\"thermostat_mode\",\"off\")\n return [msg,null,null,null]\n\ncase 'schedule':\n msg.payload = {\"group\":{\"show\":[\"Cronotermostato_Programmazione\"],\"hide\":[\"Cronotermostato_Nest\"]}};\n flow.set(\"thermostat_mode\",\"schedule\")\n return [null,msg,null,null]\n\ncase 'countdown':\n msg.payload = {\"group\":{\"show\":[\"Cronotermostato_Countdown\"],\"hide\":[\"Cronotermostato_Nest\"]}};\n return [null,null,msg,null]\n\ncase 'manual':\n flow.set(\"thermostat_mode\",\"manual\")\n return [null,null,null,msg]\n}\n\nreturn [null,null,null,null];", |
|
"outputs": 4, |
|
"noerr": 0, |
|
"initialize": "", |
|
"finalize": "", |
|
"x": 500, |
|
"y": 1100, |
|
"wires": [ |
|
[ |
|
"180c3495.1167cb", |
|
"cef71c8c.a9bc5" |
|
], |
|
[ |
|
"634ced23.8751e4", |
|
"a2f11a6d.ff7e28", |
|
"cef71c8c.a9bc5" |
|
], |
|
[ |
|
"fa178067.0ef11", |
|
"2111533e.56fbec" |
|
], |
|
[ |
|
"a2f11a6d.ff7e28", |
|
"cef71c8c.a9bc5", |
|
"f90c64e4.b6bd58" |
|
] |
|
], |
|
"outputLabels": [ |
|
"off", |
|
"schedule", |
|
"countdown", |
|
"manual" |
|
] |
|
}, |
|
{ |
|
"id": "76d7a3ad.82706c", |
|
"type": "ui_text", |
|
"z": "c7e7982a.89e5f8", |
|
"group": "317e9d9c.dea8e2", |
|
"order": 7, |
|
"width": 3, |
|
"height": 3, |
|
"name": "", |
|
"label": "", |
|
"format": "{{msg.payload}}", |
|
"layout": "row-left", |
|
"x": 910, |
|
"y": 1600, |
|
"wires": [] |
|
}, |
|
{ |
|
"id": "548f9ce2.872cb4", |
|
"type": "ui_button", |
|
"z": "c7e7982a.89e5f8", |
|
"name": "", |
|
"group": "317e9d9c.dea8e2", |
|
"order": 6, |
|
"width": 3, |
|
"height": 1, |
|
"passthru": false, |
|
"label": "{{msg.label}}", |
|
"tooltip": "", |
|
"color": "", |
|
"bgcolor": "transparent", |
|
"icon": "", |
|
"payload": "setting_link", |
|
"payloadType": "flow", |
|
"topic": "", |
|
"x": 590, |
|
"y": 1200, |
|
"wires": [ |
|
[ |
|
"fa178067.0ef11", |
|
"634ced23.8751e4" |
|
] |
|
] |
|
}, |
|
{ |
|
"id": "46acbaca.a27cb4", |
|
"type": "ui_dropdown", |
|
"z": "c7e7982a.89e5f8", |
|
"name": "", |
|
"label": "", |
|
"tooltip": "", |
|
"place": "After", |
|
"group": "e767a130.9c455", |
|
"order": 4, |
|
"width": 2, |
|
"height": 1, |
|
"passthru": false, |
|
"multiple": false, |
|
"options": [ |
|
{ |
|
"label": "Spento", |
|
"value": "off", |
|
"type": "str" |
|
}, |
|
{ |
|
"label": "Programma", |
|
"value": "schedule", |
|
"type": "str" |
|
} |
|
], |
|
"payload": "", |
|
"topic": "", |
|
"x": 1060, |
|
"y": 1140, |
|
"wires": [ |
|
[ |
|
"f6e4894d.68e478" |
|
] |
|
] |
|
}, |
|
{ |
|
"id": "604038e5.65ef58", |
|
"type": "ui_text", |
|
"z": "c7e7982a.89e5f8", |
|
"group": "e767a130.9c455", |
|
"order": 3, |
|
"width": 2, |
|
"height": 1, |
|
"name": "", |
|
"label": "Seguito dalla modalità:", |
|
"format": "{{msg.payload}}", |
|
"layout": "col-center", |
|
"x": 1100, |
|
"y": 1100, |
|
"wires": [] |
|
}, |
|
{ |
|
"id": "df7585f3.52b3d8", |
|
"type": "link out", |
|
"z": "c7e7982a.89e5f8", |
|
"name": "RefreshNest", |
|
"links": [ |
|
"582b7fce.e50f6" |
|
], |
|
"x": 875, |
|
"y": 1440, |
|
"wires": [] |
|
}, |
|
{ |
|
"id": "582b7fce.e50f6", |
|
"type": "link in", |
|
"z": "c7e7982a.89e5f8", |
|
"name": "RefreshNest", |
|
"links": [ |
|
"df7585f3.52b3d8", |
|
"3a1c4056.fd71a" |
|
], |
|
"x": 655, |
|
"y": 820, |
|
"wires": [ |
|
[ |
|
"f8f19df4.f2fd7" |
|
] |
|
] |
|
}, |
|
{ |
|
"id": "d0e07eaf.acadd", |
|
"type": "link in", |
|
"z": "c7e7982a.89e5f8", |
|
"name": "StopCountdown", |
|
"links": [ |
|
"cef71c8c.a9bc5" |
|
], |
|
"x": 255, |
|
"y": 1640, |
|
"wires": [ |
|
[ |
|
"5021393b.a4a638" |
|
] |
|
] |
|
}, |
|
{ |
|
"id": "cef71c8c.a9bc5", |
|
"type": "link out", |
|
"z": "c7e7982a.89e5f8", |
|
"name": "StopCountdown", |
|
"links": [ |
|
"d0e07eaf.acadd" |
|
], |
|
"x": 855, |
|
"y": 1080, |
|
"wires": [] |
|
}, |
|
{ |
|
"id": "715a16df.299d68", |
|
"type": "inject", |
|
"z": "c7e7982a.89e5f8", |
|
"name": "Once only", |
|
"props": [ |
|
{ |
|
"p": "payload" |
|
} |
|
], |
|
"repeat": "", |
|
"crontab": "", |
|
"once": true, |
|
"onceDelay": "", |
|
"topic": "", |
|
"payload": "off", |
|
"payloadType": "str", |
|
"x": 470, |
|
"y": 1840, |
|
"wires": [ |
|
[ |
|
"b693b186.25f61" |
|
] |
|
] |
|
}, |
|
{ |
|
"id": "2111533e.56fbec", |
|
"type": "function", |
|
"z": "c7e7982a.89e5f8", |
|
"name": "sync followed by", |
|
"func": "if (typeof (flow.get(\"countdown_followed_by\")) == 'undefined') \n{\n flow.set(\"countdown_followed_by\",\"off\");\n}\n\nmsg.payload = flow.get(\"countdown_followed_by\");\n\nreturn msg;", |
|
"outputs": 1, |
|
"noerr": 0, |
|
"initialize": "", |
|
"finalize": "", |
|
"x": 880, |
|
"y": 1140, |
|
"wires": [ |
|
[ |
|
"46acbaca.a27cb4" |
|
] |
|
] |
|
}, |
|
{ |
|
"id": "f6e4894d.68e478", |
|
"type": "function", |
|
"z": "c7e7982a.89e5f8", |
|
"name": "store followed by", |
|
"func": "switch (msg.payload){\ncase 'off':\n flow.set(\"countdown_followed_by\",\"off\")\n return msg;\n\ncase 'schedule':\n flow.set(\"countdown_followed_by\",\"schedule\")\n return msg;\n}\n\nreturn msg;", |
|
"outputs": 1, |
|
"noerr": 0, |
|
"initialize": "", |
|
"finalize": "", |
|
"x": 1270, |
|
"y": 1140, |
|
"wires": [ |
|
[ |
|
"63502f69.e7ed8" |
|
] |
|
] |
|
}, |
|
{ |
|
"id": "63502f69.e7ed8", |
|
"type": "debug", |
|
"z": "c7e7982a.89e5f8", |
|
"name": "followed_by_debug", |
|
"active": false, |
|
"tosidebar": true, |
|
"console": false, |
|
"tostatus": false, |
|
"complete": "true", |
|
"targetType": "full", |
|
"statusVal": "", |
|
"statusType": "auto", |
|
"x": 1490, |
|
"y": 1140, |
|
"wires": [] |
|
}, |
|
{ |
|
"id": "e80beafb.960048", |
|
"type": "function", |
|
"z": "c7e7982a.89e5f8", |
|
"name": "Update setting button", |
|
"func": "var button_link = {};\nbutton_link.group = {};\n\nvar msg2 = {};\n\nswitch (msg.payload){\ncase 'off':\n msg.ui_control = {\"icon\": \"\"};\n msg.label = \"\";\n msg.enabled = false;\n button_link.group.show = [];\n button_link.group.hide = [];\n msg2.payload = \"\";\n break;\ncase 'schedule':\n msg.ui_control = {\"icon\": \"fa-calendar\"};\n msg.label = \"Imposta programma\";\n msg.enabled = true;\n button_link.group.show = [\"Cronotermostato_Programmazione\"];\n button_link.group.hide = [\"Cronotermostato_Nest\"];\n msg2.payload = \"\";\n break;\ncase 'countdown':\n msg.ui_control = {\"icon\": \"timer\"};\n msg.label = \"Imposta Countdown\";\n msg.enabled = true; \n button_link.group.show = [\"Cronotermostato_Countdown\"];\n button_link.group.hide = [\"Cronotermostato_Nest\"];\n msg2 = null;\n break;\ncase 'manual':\n msg.ui_control = {\"icon\": \"\"};\n msg.label = \"\";\n msg.enabled = false;\n button_link.group.show = [];\n button_link.group.hide = [];\n msg2.payload = \"(Ricordarsi di spegnere il termostato)\";\n break;\n}\n\nflow.set(\"setting_link\", button_link);\nreturn [msg, msg2];", |
|
"outputs": 2, |
|
"noerr": 0, |
|
"initialize": "", |
|
"finalize": "", |
|
"x": 380, |
|
"y": 1220, |
|
"wires": [ |
|
[ |
|
"548f9ce2.872cb4" |
|
], |
|
[ |
|
"265b809.020228", |
|
"266cc8e.7387c38" |
|
] |
|
], |
|
"outputLabels": [ |
|
"off", |
|
"" |
|
] |
|
}, |
|
{ |
|
"id": "f90c64e4.b6bd58", |
|
"type": "ui_toast", |
|
"z": "c7e7982a.89e5f8", |
|
"position": "top left", |
|
"displayTime": "1", |
|
"highlight": "#e83a2c", |
|
"sendall": true, |
|
"outputs": 0, |
|
"ok": "OK", |
|
"cancel": "", |
|
"raw": false, |
|
"topic": "", |
|
"name": "", |
|
"x": 900, |
|
"y": 1200, |
|
"wires": [] |
|
}, |
|
{ |
|
"id": "3a1c4056.fd71a", |
|
"type": "link out", |
|
"z": "c7e7982a.89e5f8", |
|
"name": "RefreshNest", |
|
"links": [ |
|
"582b7fce.e50f6" |
|
], |
|
"x": 1255, |
|
"y": 1920, |
|
"wires": [] |
|
}, |
|
{ |
|
"id": "d14b2224.e583", |
|
"type": "link in", |
|
"z": "c7e7982a.89e5f8", |
|
"name": "set_infotext", |
|
"links": [ |
|
"66c9691b.d63478", |
|
"40dd5def.7dbcb4", |
|
"265b809.020228" |
|
], |
|
"x": 815, |
|
"y": 1600, |
|
"wires": [ |
|
[ |
|
"76d7a3ad.82706c" |
|
] |
|
] |
|
}, |
|
{ |
|
"id": "66c9691b.d63478", |
|
"type": "link out", |
|
"z": "c7e7982a.89e5f8", |
|
"name": "set_infotext", |
|
"links": [ |
|
"d14b2224.e583" |
|
], |
|
"x": 1255, |
|
"y": 1960, |
|
"wires": [] |
|
}, |
|
{ |
|
"id": "40dd5def.7dbcb4", |
|
"type": "link out", |
|
"z": "c7e7982a.89e5f8", |
|
"name": "set_infotext", |
|
"links": [ |
|
"d14b2224.e583" |
|
], |
|
"x": 1095, |
|
"y": 420, |
|
"wires": [] |
|
}, |
|
{ |
|
"id": "4014445.26c60bc", |
|
"type": "function", |
|
"z": "c7e7982a.89e5f8", |
|
"name": "Show next hour temperature", |
|
"func": "if (flow.get(\"thermostat_mode\") != \"schedule\") {\n return null;\n}\n\nlet timing=global.get(\"timing\");\nvar nexthour = new Date(msg.time);\n\nvar fixed_temperature = timing[(nexthour.getDay()*24)+nexthour.getHours()];\n\nmsg.payload = \"Temperatura programmata per la prossima ora: \" + fixed_temperature + \"°\";\n\nreturn msg;", |
|
"outputs": 1, |
|
"noerr": 0, |
|
"initialize": "", |
|
"finalize": "", |
|
"libs": [], |
|
"x": 940, |
|
"y": 420, |
|
"wires": [ |
|
[ |
|
"40dd5def.7dbcb4" |
|
] |
|
] |
|
}, |
|
{ |
|
"id": "266cc8e.7387c38", |
|
"type": "moment", |
|
"z": "c7e7982a.89e5f8", |
|
"name": "time + 1", |
|
"topic": "", |
|
"input": "", |
|
"inputType": "date", |
|
"inTz": "Europe/Rome", |
|
"adjAmount": "1", |
|
"adjType": "hours", |
|
"adjDir": "add", |
|
"format": "", |
|
"locale": "it_IT", |
|
"output": "time", |
|
"outputType": "msg", |
|
"outTz": "Europe/Rome", |
|
"x": 620, |
|
"y": 420, |
|
"wires": [ |
|
[ |
|
"4014445.26c60bc" |
|
] |
|
] |
|
}, |
|
{ |
|
"id": "265b809.020228", |
|
"type": "link out", |
|
"z": "c7e7982a.89e5f8", |
|
"name": "set_infotext", |
|
"links": [ |
|
"d14b2224.e583" |
|
], |
|
"x": 555, |
|
"y": 1240, |
|
"wires": [] |
|
}, |
|
{ |
|
"id": "1583662b.eaa1ea", |
|
"type": "comment", |
|
"z": "c7e7982a.89e5f8", |
|
"name": "set this", |
|
"info": "", |
|
"x": 130, |
|
"y": 720, |
|
"wires": [] |
|
}, |
|
{ |
|
"id": "90b52d0f.173c8", |
|
"type": "comment", |
|
"z": "c7e7982a.89e5f8", |
|
"name": "set this", |
|
"info": "", |
|
"x": 130, |
|
"y": 780, |
|
"wires": [] |
|
}, |
|
{ |
|
"id": "f32ca0ec.42264", |
|
"type": "comment", |
|
"z": "c7e7982a.89e5f8", |
|
"name": "set this", |
|
"info": "", |
|
"x": 1050, |
|
"y": 960, |
|
"wires": [] |
|
}, |
|
{ |
|
"id": "e2603d04.10a1e", |
|
"type": "comment", |
|
"z": "c7e7982a.89e5f8", |
|
"name": "set this", |
|
"info": "", |
|
"x": 1050, |
|
"y": 1020, |
|
"wires": [] |
|
}, |
|
{ |
|
"id": "6882e6f4.346418", |
|
"type": "comment", |
|
"z": "c7e7982a.89e5f8", |
|
"name": "set this", |
|
"info": "", |
|
"x": 1330, |
|
"y": 560, |
|
"wires": [] |
|
}, |
|
{ |
|
"id": "81a71617.0969f8", |
|
"type": "ui_ui_control", |
|
"z": "c7e7982a.89e5f8", |
|
"name": "ui_control on connect", |
|
"events": "connect", |
|
"x": 400, |
|
"y": 1280, |
|
"wires": [ |
|
[ |
|
"d3918875.9486b8" |
|
] |
|
] |
|
}, |
|
{ |
|
"id": "d3918875.9486b8", |
|
"type": "function", |
|
"z": "c7e7982a.89e5f8", |
|
"name": "hide groups", |
|
"func": "msg.payload = {\"group\":{\"hide\":[\"Cronotermostato_Programmazione\",\"Cronotermostato_Grafico\",\"Cronotermostato_Countdown\"],\"show\":[\"Cronotermostato_Nest\"]}}\n\nreturn msg;", |
|
"outputs": 1, |
|
"noerr": 0, |
|
"initialize": "", |
|
"finalize": "", |
|
"x": 630, |
|
"y": 1280, |
|
"wires": [ |
|
[ |
|
"fa178067.0ef11" |
|
] |
|
] |
|
}, |
|
{ |
|
"id": "af7851fa.ee551", |
|
"type": "comment", |
|
"z": "c7e7982a.89e5f8", |
|
"name": "set your Timezone in these three nodes", |
|
"info": "", |
|
"x": 610, |
|
"y": 380, |
|
"wires": [] |
|
}, |
|
{ |
|
"id": "77b849cb.094c08", |
|
"type": "ui_group", |
|
"name": "Programmazione", |
|
"tab": "5d954e3e.9339b", |
|
"order": 2, |
|
"disp": false, |
|
"width": 8, |
|
"collapse": false |
|
}, |
|
{ |
|
"id": "317e9d9c.dea8e2", |
|
"type": "ui_group", |
|
"name": "Nest", |
|
"tab": "5d954e3e.9339b", |
|
"order": 1, |
|
"disp": false, |
|
"width": 8, |
|
"collapse": false |
|
}, |
|
{ |
|
"id": "41108723.0bf848", |
|
"type": "server", |
|
"name": "Home Assistant", |
|
"version": 2, |
|
"addon": true, |
|
"rejectUnauthorizedCerts": true, |
|
"ha_boolean": "y|yes|true|on|home|open", |
|
"connectionDelay": true, |
|
"cacheJson": true, |
|
"heartbeat": false, |
|
"heartbeatInterval": 30 |
|
}, |
|
{ |
|
"id": "eaea6ba8.f76288", |
|
"type": "ui_group", |
|
"name": "Grafico", |
|
"tab": "5d954e3e.9339b", |
|
"order": 3, |
|
"disp": false, |
|
"width": 8, |
|
"collapse": false |
|
}, |
|
{ |
|
"id": "e767a130.9c455", |
|
"type": "ui_group", |
|
"name": "Countdown", |
|
"tab": "5d954e3e.9339b", |
|
"order": 4, |
|
"disp": false, |
|
"width": "8", |
|
"collapse": false |
|
}, |
|
{ |
|
"id": "5d954e3e.9339b", |
|
"type": "ui_tab", |
|
"name": "Cronotermostato", |
|
"icon": "dashboard", |
|
"order": 1, |
|
"disabled": false, |
|
"hidden": false |
|
} |
|
] |
Thanks for sharing all this work! I hope you'll continue to share updates as I am having issues viewing it. Also, if you have any suggestions how a beginner might go about editing to get from celcius to farenheit, it'd be appreciated. I'll drop a clue only applicable to those trying to view the dashboard in hass.io, the root is in a bit of a different place: https://ipaddress:1880/endpoint/ui/