Snippets

Peter Scargill Node-Red Stat 6

Created by Peter Scargill last modified
[{"id":"c690fee8.ee841","type":"ui_template","z":"c552e8d2.712b48","group":"968be961.f344c8","name":"css etc","order":10,"width":"0","height":"0","format":"<style>\n\n.cellGreen \n{\nbackground-color: #ffdddd !important;\n}\n\n  .filled { \n      height: 100% !important;\n\n      padding: 0 !important;\n      margin: 0 !important;\n  }\n  .nr-dashboard-template {\n      padding: 0;\n      margin: 0;\n  }\n  \n  .rounded {\n  border-radius: 12px 12px 12px 12px;\n}\n \n   .bigfont {\n  font-size: 18px;\n}\n\n   .smallfont {\n  font-size: 12px;\n}\n \n\n  \n.zui-table {\n    border: solid 1px #DDEEEE;\n    border-collapse: collapse;\n    border-spacing: 0;\n    font: normal 10px Arial, sans-serif;\n    outline: none;\n}\n.zui-table thead th {\n    width: 100%;\n    height:50%;\n    background-color: #99bbff;\n    border: solid 1px #DDEEEE;\n    color: #336B6B;\n    padding: 7px 3px 5px 3px;\n    text-align: center;\n    text-shadow: 1px 1px 1px #fff;\n}\n.zui-table tbody td {\n    width: 100%;\n    height:50%;\n    border: solid 1px #333;\n    color: #333;\n    text-align: center;\n    padding: 6px 3px 9px 3px;\n    text-shadow: 1px 1px 1px #fff;\n}\n.zui-table-rounded {\n    border: none;\n}\n.zui-table-rounded thead th {\n    background-color: #77aaff;\n    border: none;\n    text-shadow: 1px 1px 1px #ccc;\n    color: #333;\n}\n.zui-table-rounded thead th:first-child {\n    border-radius: 10px 0 0 0;\n}\n.zui-table-rounded thead th:last-child {\n    border-radius: 10px 10px 0px 0px;\n}\n.zui-table-rounded tbody td {\n    border: none;\n    border-top: solid 1px #957030;\n    background-color: #aaddff;\n}\n.zui-table-rounded tbody tr:last-child td:first-child {\n    border-radius: 10px 10px 0 0;\n}\n.zui-table-rounded tbody tr:last-child td:last-child {\n    border-radius: 0 0 10px 10px;\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    \nvar myStatus=\"Nowt\";\n</script>","storeOutMessages":true,"fwdInMessages":true,"x":540,"y":60,"wires":[[]]},{"id":"7ea72e65.22713","type":"ui_template","z":"c552e8d2.712b48","group":"968be961.f344c8","name":"Settings page","order":2,"width":"6","height":"6","format":"<style>\n.thedays { vertical-align:bottom; height:54px; }\n.the2px  { background-color:black; height:2px; }\n.theblocks {width:100%; height:0%; background-color:green; }\n.greybuttons { background-color:#dddddd !important; width:48px; }\n.thetemps { font-size:70%; color:#888888 !important; }\n.smallheadings { color:black; font-size:80%; }\n\n</style>\n\n<script>\nvar thedays = [\"SUNDAY\", \"MONDAY\", \"TUESDAY\", \"WEDNESDAY\", \"THURSDAY\", \"FRIDAY\", \"SATURDAY\"];\n\nvar last = 1;\n\nfunction bar(mm, val) {\n  if (val == 14) {\n    $(mm).height(\"12%\");\n    $(mm).css('background-color', '#6666ff');\n  } //blue\n  if (val == 15) {\n    $(mm).height(\"16%\");\n    $(mm).css('background-color', '#5577ff');\n  }\n  if (val == 16) {\n    $(mm).height(\"20%\");\n    $(mm).css('background-color', '#5599ff');\n  }\n  if (val == 17) {\n    $(mm).height(\"24%\");\n    $(mm).css('background-color', '#55ccdd');\n  } // cyan\n  if (val == 18) {\n    $(mm).height(\"28%\");\n    $(mm).css('background-color', '#55ddaa');\n  }\n  if (val == 19) {\n    $(mm).height(\"32%\");\n    $(mm).css('background-color', '#55dd55');\n  }\n  if (val == 20) {\n    $(mm).height(\"36%\");\n    $(mm).css('background-color', '#55dd55');\n  } // green\n  if (val == 21) {\n    $(mm).height(\"40%\");\n    $(mm).css('background-color', '#55dd55');\n  }\n  if (val == 22) {\n    $(mm).height(\"44%\");\n    $(mm).css('background-color', '#aadd55');\n  }\n  if (val == 23) {\n    $(mm).height(\"48%\");\n    $(mm).css('background-color', '#dddd55');\n  } // yellow\n  if (val == 24) {\n    $(mm).height(\"52%\");\n    $(mm).css('background-color', '#ffaa55');\n  }\n  if (val == 25) {\n    $(mm).height(\"56%\");\n    $(mm).css('background-color', '#ff8855');\n  }\n  if (val == 26) {\n    $(mm).height(\"60%\");\n    $(mm).css('background-color', '#ff7777');\n  } // red\n\n}\n\nfunction selec(val, sta) {\n  var w = \"#td\" + val;\n  if (sta) $(w).css('background-color', 'magenta');\n  else $(w).css('background-color', 'black');\n}\n\n(function(scope) {\n  scope.$watch('msg', function(msg) {\n    selec(last, 0);\n    last = msg.selector;\n    selec(last, 1);\n    for (var x = 0; x < 24; x++) {\n      var w = \"#t\" + x;\n      bar(w, msg.timing[((msg.days - 1) * 24) + x]);\n      var v = \"#v\" + x;\n      $(v).text(msg.timing[((msg.days - 1) * 24) + x] + \"C\")\n    }\n    for (var x = 0; x < 2; x++) {\n      var w = \"#s\" + x;\n      $(w).text(msg.timing[168 + x] + \"C\");\n    }\n    $(\"#s2\").text(msg.timing[170] + \"%\");\n    \n    $(\"#d0\").text(thedays[msg.days - 1]);\n    if ((last > 4) && (last < 29))\n      $(\"#current\").text(msg.timing[((msg.days - 1) * 24) + last - 5] + \"C\");\n    else\n      $(\"#current\").text(\"-\");\n\n   myStatus=msg.myStatus;\n   if (msg.foryou != \"\")\n   {\n       $(\"#info\").text(msg.foryou);\n       var tm = setTimeout(function() {\n             $(\"#info\").text(myStatus);\n             clearTimeout(tm);\n       }, 3000);\n    }\n  });\n})(scope);\n\n</script>\n<table width=\"100%\">\n  <tr style=\"height:2px\">\n    <td colspan=12 style=\"background-color:black;height:5px;\"></td>\n  </tr>\n\n  <tr>\n    <td colspan=6>\n      <center><span class=\"smallheadings\">Day</span></center>\n    </td>\n    <td colspan=2>\n      <center><span class=\"smallheadings\">Frost</span></center>\n    </td>\n    <td colspan=2>\n      <center><span class=\"smallheadings\">Away</span></center>\n    </td>\n    <td colspan=2>\n      <center><span class=\"smallheadings\">Dehum</span></center>\n    </td>\n  </tr>\n\n  <tr>\n    <td ng-click=\"send({payload: '29'})\" colspan=6>\n      <center><span id=\"d0\" style=\"color:blue;font-size:110%\">MONDAY</span></center>\n    </td>\n    <td ng-click=\"send({payload: '1'})\" colspan=2>\n      <center><span id=\"s0\" style=\"color:blue;font-size:110%\">14</span></center>\n    </td>\n    <td ng-click=\"send({payload: '2'})\" colspan=2>\n      <center><span id=\"s1\" style=\"color:blue;font-size:110%\">20</span></center>\n    </td>\n    <td ng-click=\"send({payload: '30'})\" colspan=2>\n      <center><span id=\"s2\" style=\"color:blue;font-size:110%\">40</span></center>\n    </td>\n  </tr>\n\n  <tr style=\"height:2px\">\n    <td id=\"td29\" colspan=6 style=\"background-color:black;height:2px;\"></td>\n    <td id=\"td1\" colspan=2 style=\"background-color:black;height:2px;\"></td>\n    <td id=\"td2\" colspan=2 style=\"background-color:black;height:2px;\"></td>\n    <td id=\"td30\" colspan=2 style=\"background-color:black;height:2px;\"></td>\n  </tr>\n\n  <tr>\n    <td ng-click=\"send({payload: '5'})\" class=\"thedays\"><span id=\"v0\" class=\"thetemps\"></span>\n      <div id=\"t0\" class=\"theblocks\"></div>\n    </td>\n    <td ng-click=\"send({payload: '6'})\" class=\"thedays\"><span id=\"v1\" class=\"thetemps\"></span>\n      <div id=\"t1\" class=\"theblocks\"></div>\n    </td>\n    <td ng-click=\"send({payload: '7'})\" class=\"thedays\"><span id=\"v2\" class=\"thetemps\"></span>\n      <div id=\"t2\" class=\"theblocks\"></div>\n    </td>\n    <td ng-click=\"send({payload: '8'})\" class=\"thedays\"><span id=\"v3\" class=\"thetemps\"></span>\n      <div id=\"t3\" class=\"theblocks\"></div>\n    </td>\n    <td ng-click=\"send({payload: '9'})\" class=\"thedays\"><span id=\"v4\" class=\"thetemps\"></span>\n      <div id=\"t4\" class=\"theblocks\"></div>\n    </td>\n    <td ng-click=\"send({payload: '10'})\" class=\"thedays\"><span id=\"v5\" class=\"thetemps\"></span>\n      <div id=\"t5\" class=\"theblocks\"></div>\n    </td>\n    <td ng-click=\"send({payload: '11'})\" class=\"thedays\"><span id=\"v6\" class=\"thetemps\"></span>\n      <div id=\"t6\" class=\"theblocks\"></div>\n    </td>\n    <td ng-click=\"send({payload: '12'})\" class=\"thedays\"><span id=\"v7\" class=\"thetemps\"></span>\n      <div id=\"t7\" class=\"theblocks\"></div>\n    </td>\n    <td ng-click=\"send({payload: '13'})\" class=\"thedays\"><span id=\"v8\" class=\"thetemps\"></span>\n      <div id=\"t8\" class=\"theblocks\"></div>\n    </td>\n    <td ng-click=\"send({payload: '14'})\" class=\"thedays\"><span id=\"v9\" class=\"thetemps\"></span>\n      <div id=\"t9\" class=\"theblocks\"></div>\n    </td>\n    <td ng-click=\"send({payload: '15'})\" class=\"thedays\"><span id=\"v10\" class=\"thetemps\"></span>\n      <div id=\"t10\" class=\"theblocks\"></div>\n    </td>\n    <td ng-click=\"send({payload: '16'})\" class=\"thedays\"><span id=\"v11\" class=\"thetemps\"></span>\n      <div id=\"t11\" class=\"theblocks\"></div>\n    </td>\n  </tr>\n\n  <tr style=\"height:2px\">\n    <td id=\"td5\" class=\"the2px\"></td>\n    <td id=\"td6\" class=\"the2px\"></td>\n    <td id=\"td7\" class=\"the2px\"></td>\n    <td id=\"td8\" class=\"the2px\"></td>\n    <td id=\"td9\" class=\"the2px\"></td>\n    <td id=\"td10\" class=\"the2px\"></td>\n    <td id=\"td11\" class=\"the2px\"></td>\n    <td id=\"td12\" class=\"the2px\"></td>\n    <td id=\"td13\" class=\"the2px\"></td>\n    <td id=\"td14\" class=\"the2px\"></td>\n    <td id=\"td15\" class=\"the2px\"></td>\n    <td id=\"td16\" class=\"the2px\"></td>\n  </tr>\n\n  <tr>\n    <td>0</td>\n    <td>1</td>\n    <td>2</td>\n    <td>3</td>\n    <td>4</td>\n    <td>5</td>\n    <td>6</td>\n    <td>7</td>\n    <td>8</td>\n    <td>9</td>\n    <td>10</td>\n    <td>11</td>\n  </tr>\n\n  <tr>\n    <td ng-click=\"send({payload: '17'})\" class=\"thedays\"><span id=\"v12\" class=\"thetemps\"></span>\n      <div id=\"t12\" class=\"theblocks\"></div>\n    </td>\n    <td ng-click=\"send({payload: '18'})\" class=\"thedays\"><span id=\"v13\" class=\"thetemps\"></span>\n      <div id=\"t13\" class=\"theblocks\"></div>\n    </td>\n    <td ng-click=\"send({payload: '19'})\" class=\"thedays\"><span id=\"v14\" class=\"thetemps\"></span>\n      <div id=\"t14\" class=\"theblocks\"></div>\n    </td>\n    <td ng-click=\"send({payload: '20'})\" class=\"thedays\"><span id=\"v15\" class=\"thetemps\"></span>\n      <div id=\"t15\" class=\"theblocks\"></div>\n    </td>\n    <td ng-click=\"send({payload: '21'})\" class=\"thedays\"><span id=\"v16\" class=\"thetemps\"></span>\n      <div id=\"t16\" class=\"theblocks\"></div>\n    </td>\n    <td ng-click=\"send({payload: '22'})\" class=\"thedays\"><span id=\"v17\" class=\"thetemps\"></span>\n      <div id=\"t17\" class=\"theblocks\"></div>\n    </td>\n    <td ng-click=\"send({payload: '23'})\" class=\"thedays\"><span id=\"v18\" class=\"thetemps\"></span>\n      <div id=\"t18\" class=\"theblocks\"></div>\n    </td>\n    <td ng-click=\"send({payload: '24'})\" class=\"thedays\"><span id=\"v19\" class=\"thetemps\"></span>\n      <div id=\"t19\" class=\"theblocks\"></div>\n    </td>\n    <td ng-click=\"send({payload: '25'})\" class=\"thedays\"><span id=\"v20\" class=\"thetemps\"></span>\n      <div id=\"t20\" class=\"theblocks\"></div>\n    </td>\n    <td ng-click=\"send({payload: '26'})\" class=\"thedays\"><span id=\"v21\" class=\"thetemps\"></span>\n      <div id=\"t21\" class=\"theblocks\"></div>\n    </td>\n    <td ng-click=\"send({payload: '27'})\" class=\"thedays\"><span id=\"v22\" class=\"thetemps\"></span>\n      <div id=\"t22\" class=\"theblocks\"></div>\n    </td>\n    <td ng-click=\"send({payload: '28'})\" class=\"thedays\"><span id=\"v23\" class=\"thetemps\"></span>\n      <div id=\"t23\" class=\"theblocks\"></div>\n    </td>\n  </tr>\n\n  <tr style=\"height:2px\">\n    <td id=\"td17\" class=\"the2px\"></td>\n    <td id=\"td18\" class=\"the2px\"></td>\n    <td id=\"td19\" class=\"the2px\"></td>\n    <td id=\"td20\" class=\"the2px\"></td>\n    <td id=\"td21\" class=\"the2px\"></td>\n    <td id=\"td22\" class=\"the2px\"></td>\n    <td id=\"td23\" class=\"the2px\"></td>\n    <td id=\"td24\" class=\"the2px\"></td>\n    <td id=\"td25\" class=\"the2px\"></td>\n    <td id=\"td26\" class=\"the2px\"></td>\n    <td id=\"td27\" class=\"the2px\"></td>\n    <td id=\"td28\" class=\"the2px\"></td>\n  </tr>\n\n  <tr>\n    <td>12</td>\n    <td>13</td>\n    <td>14</td>\n    <td>15</td>\n    <td>16</td>\n    <td>17</td>\n    <td>18</td>\n    <td>19</td>\n    <td>20</td>\n    <td>21</td>\n    <td>22</td>\n    <td>23</td>\n  </tr>\n  \n  <tr height=\"4px\">\n    <td colspan=\"12\"></td>\n  </tr>\n\n\n  <tr height=\"22px\">\n    <td colspan=2 bgcolor=\"#dddddd\"><span class=\"smallheadings\">&nbsp;Status:</span></td>\n\n    <td colspan=10 bgcolor=\"#dddddd\">\n      <center><span id=\"info\" class=\"smallheadings\">OK</span></center>\n    </td>\n  </tr>\n\n  <tr height=\"6px\">\n    <td colspan=\"12\"></td>\n  </tr>\n\n  <tr style=\"height:48px\">\n    <td colspan=2>\n      <md-button class=\"vibrate filled touched smallfont rounded greybuttons\" ng-click=\"send({payload: 'd'})\">\n        <img style=\"outline : none;\" ng-src=\"{{(msg.payload)?'/myicons/png/48x48/actions/arrow-left-double-2.png':'/myicons/png/48x48/actions/arrow-left-double-2.png'}}\" height=\"36px\" />\n      </md-button>\n    </td>\n\n    <td colspan=2>\n      <center><span id=\"current\" style=\"color:black;font-size:120%\">-</span></center>\n    </td>\n\n    <td colspan=2>\n      <md-button class=\"vibrate filled touched smallfont rounded greybuttons\" ng-click=\"send({payload: 'u'})\">\n        <img style=\"outline : none;\" ng-src=\"{{(msg.payload)?'/myicons/png/48x48/actions/arrow-right-double-2.png':'/myicons/png/48x48/actions/arrow-right-double-2.png'}}\" height=\"36px\" />\n      </md-button>\n    </td>\n\n    <td colspan=2>\n      <md-button class=\"vibrate filled touched smallfont rounded greybuttons\" ng-click=\"send({payload: 'r'})\">\n        <img style=\"outline : none;\" ng-src=\"{{(msg.payload)?'/myicons/png/48x48/actions/edit-copy-4.png':'/myicons/png/48x48/actions/edit-copy-4.png'}}\" height=\"36px\" />\n      </md-button>\n    </td>\n\n    <td colspan=2>\n      <md-button class=\"vibrate filled touched smallfont rounded greybuttons\" ng-click=\"send({payload: 's'})\">\n        <img style=\"outline : none;\" ng-src=\"{{(msg.payload)?'/myicons/png/48x48/actions/document-save-5.png':'/myicons/png/48x48/actions/document-save-5.png'}}\" height=\"36px\" />\n      </md-button>\n    </td>\n\n    <td colspan=2>\n      <md-button class=\"vibrate filled touched smallfont rounded greybuttons\" ng-click=\"send({payload: 'c'})\">\n        <img style=\"outline : none;\" ng-src=\"{{(msg.payload)?'/myicons/png/48x48/actions/dialog-cancel-5.png':'/myicons/png/48x48/actions/dialog-cancel-5.png'}}\" height=\"36px\" />\n      </md-button>\n    </td>\n    <td colspan=1></td>\n  </tr>\n</table>\n\n","storeOutMessages":false,"fwdInMessages":false,"x":780,"y":40,"wires":[["7503d67.3703628","510345b4.def36c","99b5322a.b16c9"]]},{"id":"7503d67.3703628","type":"function","z":"c552e8d2.712b48","name":"Process controls","func":"if ( typeof context.days == 'undefined' ) context.days=1;\nif ( typeof context.selector == 'undefined' ) context.selector=1;\nif ( typeof context.saving == 'undefined' ) context.saving=0;\nif ( typeof context.global.incomingTemperature == 'undefined' ) context.global.incomingTemperature=0;\nif ( typeof context.global.incomingHumidity == 'undefined' ) context.global.incomingHumidity=40;\nif ( typeof context.global.hold == 'undefined' ) context.global.hold=0;\nif ( typeof context.global.away == 'undefined' ) context.global.away=0;\nif ( typeof context.global.manual == 'undefined' ) context.global.manual=0;\nif ( typeof context.global.setTemperature == 'undefined' ) context.global.setTemperature=0;\nif ( typeof context.global.manualTimer == 'undefined' ) context.global.manualTimer=0;\nif ( typeof context.global.myStatus== 'undefined')  context.global.myStatus=\"\";\nif ( typeof context.global.timing == 'undefined' ) \n    {\n        context.global.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                        8,14,40,0\n                        ];\n        context.saving=0;  \n        msg.payload=\"anything\";  msg.foryou=\"Restoring\"; return([null,null,msg]);\n    }\nvar timing=global.get(\"timing\");\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]++; \n                    if (timing[((context.days-1)*24)+context.selector-5]>26) timing[((context.days-1)*24)+context.selector-5]=26;\n                    msg.foryou=\"Incremented temperature\";\n                }\n                if (context.selector==1) { if (timing[168]<26) {  timing[168]++; msg.foryou=\"Incremented frost setting 1 degree\"; } else msg.foryou=\"Hit limit\"; }\n                if (context.selector==2) { if (timing[169]<26) {  timing[169]++; msg.foryou=\"Incremented away setting 1 degree\"; } else msg.foryou=\"Hit limit\"; }\n                if (context.selector==29) { if (context.days<7) { context.days++; msg.foryou=\"Forward one day\";} else msg.foryou=\"End of days!!\"; }\n                if (context.selector==30) { if (timing[170]<60) {  timing[170]++; msg.foryou=\"Incremented humidity setting 1%\"; } else msg.foryou=\"Hit limit\"; }\n\n                break;\n    case \"d\" :  if ((context.selector>4)&&(context.selector<29))\n                {\n                    timing[((context.days-1)*24)+context.selector-5]--; \n                    if (timing[((context.days-1)*24)+context.selector-5]<14) timing[((context.days-1)*24)+context.selector-5]=14;\n                    msg.foryou=\"Decremented temperature\";\n                }\n                if (context.selector==1) { if (timing[168]>8) { timing[168]--; msg.foryou=\"Decremented frost setting 1 degree\"; } else msg.foryou=\"Hit limit\"; }\n                if (context.selector==2) { if (timing[169]>8) { timing[169]--; msg.foryou=\"Decremented away setting 1 degree\"; } else msg.foryou=\"Hit limit\"; }\n                if (context.selector==29) { if (context.days>1) { context.days--;  msg.foryou=\"Backward one day\";} else msg.foryou=\"Beginning of days!!\";  }\n                if (context.selector==30) { if (timing[170]>30) { timing[170]--; msg.foryou=\"Decremented humidity setting 1%\"; } else msg.foryou=\"Hit limit\"; }\n\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=\"Copied settings to the next hour slot\";\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=\"Copied a complete day's settings\";\n                        }\n                break;\n    case 's': context.saving=0;  msg.foryou=\"Settings saved to disk\"; 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':\n    case '30': context.selector=parseInt(msg.payload);\n               if (msg.payload=='1') msg.foryou=\"Frost temperature selection\"; \n               else if (msg.payload=='2') msg.foryou=\"Away temperature selection\";\n               else if (msg.payload=='29') msg.foryou=\"Day selection\";\n               else if (msg.payload=='30') msg.foryou=\"Humidity selection\";\n               else  msg.foryou=\"Selected hour period \" + (parseInt(msg.payload)-4);\n    break;\n    case 'c' : msg.payload=\"anything\";  msg.foryou=\"Changes cancelled\"; node.send([null,null,msg]);\n    }\n\nmsg.temperatures=context.temperatures;\nmsg.timing=timing;\nmsg.days=context.days;\nmsg.selector=context.selector;\n\n\nmsg.myStatus=context.global.myStatus;\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=\"\";\n","outputs":"3","noerr":0,"x":790,"y":100,"wires":[["7ea72e65.22713"],["be40f55e.3f6778"],["cb16bca.ae59c4"]]},{"id":"94173a25.bc5c98","type":"inject","z":"c552e8d2.712b48","name":"Once only","topic":"","payload":"","payloadType":"str","repeat":"","crontab":"","once":true,"x":560,"y":100,"wires":[["7503d67.3703628","cb16bca.ae59c4"]]},{"id":"402882aa.db283c","type":"inject","z":"c552e8d2.712b48","name":"Every minute","topic":"","payload":"","payloadType":"str","repeat":"60","crontab":"","once":false,"x":580,"y":200,"wires":[["510345b4.def36c","f0bb67c6.e12508","7503d67.3703628"]]},{"id":"510345b4.def36c","type":"function","z":"c552e8d2.712b48","name":"Process heat","func":"var timing=global.get(\"timing\");\nvar now = new Date();\nmsg.payload=timing[(now.getDay()*24)+now.getHours()];\nmsg.frost=timing[168];\nmsg.away=timing[169];\nmsg.setHumidity=timing[170];\n\nmsg.temperature=global.get(\"incomingTemperature\");\nmsg.humidity=global.get(\"incomingHumidity\");\n\nmsg.set=msg.payload;\nif (global.get(\"manualTimer\")) global.set(\"manualTimer\",global.get(\"manualTimer\")-1);\nelse global.set(\"manual\",0);\nmsg.desired=msg.set;\nglobal.set(\"setTemperature\",msg.desired);\nmsg.desired+=global.get(\"manual\");\nif (global.get(\"frost\")) { msg.desired=global.get(\"timing\")[168]; global.set(\"frost\",global.get(\"frost\")-1); }\nif (global.get(\"away\")) { msg.desired=global.get(\"timing\")[169]; global.set(\"away\",global.get(\"away\")-1); }\n\nif (msg.desired>msg.temperature) msg.heatRelay=1; else msg.heatRelay=0;\nif (msg.humidity>msg.setHumidity) msg.humidityRelay=1; else msg.humidityRelay=0;\n\n//context.global.myStatus=\"Heating: \" + ((msg.heatRelay)? \"ON\":\"OFF\") + \" Dehumidifier: \" + ((msg.humidityRelay)? \"ON\":\"OFF\");\nglobal.set(\"myStatus\",\"-\");\n\nnode.status({fill:\"blue\",shape:\"dot\",text:\"Set point \" + msg.desired + \"c - Actual \" + msg.temperature +\"c\"});\n\nif ( typeof msg.value == 'undefined' ) msg.value=global.get(\"incomingTemperature\");\n\nnode.send(msg);\n\n\n\n\n\n","outputs":"1","noerr":0,"x":770,"y":200,"wires":[["ca92fea0.f2192","12fba98.fdffd57","33b0f2e3.5a52de","cca4335c.f3a09","223f9d0f.f87852"]]},{"id":"be40f55e.3f6778","type":"file","z":"c552e8d2.712b48","name":"backup","filename":"/home/pi/petesstatlog.log","appendNewline":true,"createDir":true,"overwriteFile":"true","x":1000,"y":60,"wires":[]},{"id":"cb16bca.ae59c4","type":"file in","z":"c552e8d2.712b48","name":"Restore","filename":"/home/pi/petesstatlog.log","format":"utf8","x":1000,"y":120,"wires":[["c0e50aeb.94a498"]]},{"id":"c0e50aeb.94a498","type":"function","z":"c552e8d2.712b48","name":"Restore data from SD","func":"context.global.timing=JSON.parse(msg.payload);\nmsg.payload=\"\";\nreturn msg;","outputs":1,"noerr":0,"x":800,"y":160,"wires":[["7503d67.3703628"]]},{"id":"9fede730.9ba208","type":"inject","z":"c552e8d2.712b48","name":"incoming humidity 40%","topic":"","payload":"40","payloadType":"str","repeat":"","crontab":"","once":false,"x":160,"y":120,"wires":[["a2825399.e1a35"]]},{"id":"7f9a723e.3410ac","type":"inject","z":"c552e8d2.712b48","name":"incoming humidity 50%","topic":"","payload":"50","payloadType":"str","repeat":"","crontab":"","once":false,"x":160,"y":160,"wires":[["a2825399.e1a35"]]},{"id":"d6b9fc13.9f3a2","type":"function","z":"c552e8d2.712b48","name":"Store temperature","func":"global.set(\"incomingTemperature\",msg.payload);","outputs":"0","noerr":0,"x":370,"y":60,"wires":[]},{"id":"a2825399.e1a35","type":"function","z":"c552e8d2.712b48","name":"Store humidity","func":"global.set(\"incomingHumidity\",msg.payload);","outputs":"0","noerr":0,"x":360,"y":140,"wires":[]},{"id":"a3ab35cf.676788","type":"inject","z":"c552e8d2.712b48","name":"Test \"Away\" 2 minutes","topic":"","payload":"2","payloadType":"str","repeat":"","crontab":"","once":false,"x":160,"y":200,"wires":[["416ade9b.6aa75"]]},{"id":"cfb283df.1710e","type":"inject","z":"c552e8d2.712b48","name":"Test \"Away\" clear","topic":"","payload":"0","payloadType":"str","repeat":"","crontab":"","once":false,"x":140,"y":240,"wires":[["416ade9b.6aa75"]]},{"id":"140a0db9.49f692","type":"inject","z":"c552e8d2.712b48","name":"Test \"Frost\" 2 minutes","topic":"","payload":"2","payloadType":"str","repeat":"","crontab":"","once":false,"x":160,"y":280,"wires":[["12f72a6.fa27fd6"]]},{"id":"728e2650.93fc28","type":"inject","z":"c552e8d2.712b48","name":"Test \"Frost\" clear","topic":"","payload":"0","payloadType":"str","repeat":"","crontab":"","once":false,"x":140,"y":320,"wires":[["12f72a6.fa27fd6"]]},{"id":"12f72a6.fa27fd6","type":"function","z":"c552e8d2.712b48","name":"Store \"Hold\"","func":"global.set(\"frost\",msg.payload);","outputs":"0","noerr":0,"x":350,"y":320,"wires":[]},{"id":"416ade9b.6aa75","type":"function","z":"c552e8d2.712b48","name":"Store \"Away\"","func":"global.set(\"away\",msg.payload);","outputs":"0","noerr":0,"x":350,"y":220,"wires":[]},{"id":"c0c8a0f9.85b36","type":"inject","z":"c552e8d2.712b48","name":"sample forecast","topic":"","payload":"Dry, 2c with chance of snow","payloadType":"str","repeat":"","crontab":"","once":false,"x":140,"y":360,"wires":[["174a8efb.6436b1"]]},{"id":"535b8149.e2db6","type":"inject","z":"c552e8d2.712b48","name":"Sample forecast","topic":"","payload":"Wet, 12c, possibly rain tonight","payloadType":"str","repeat":"","crontab":"","once":false,"x":140,"y":400,"wires":[["174a8efb.6436b1"]]},{"id":"174a8efb.6436b1","type":"function","z":"c552e8d2.712b48","name":"Store forecast","func":"global.set(\"forecast\",msg.payload);","outputs":"0","noerr":0,"x":360,"y":380,"wires":[]},{"id":"fe37d17b.b1d9f","type":"function","z":"c552e8d2.712b48","name":"Heat relay","func":"if (msg.heatRelay==1)\nnode.status({fill:\"red\",shape:\"dot\",text:\"Heat ON\"});\nelse\nnode.status({fill:\"black\",shape:\"dot\",text:\"Heat OFF\"});\n","outputs":"0","noerr":0,"x":1070,"y":220,"wires":[]},{"id":"e6ca09fc.945898","type":"function","z":"c552e8d2.712b48","name":"Handle SET","func":"// here we set manual override controls - valid for 60 minutes after last change.\n\nif (global.get(\"away\")===0)\n{\n    if (msg.payload==\"u\") { global.set(\"manualTimer\",60); if (global.get(\"manual\")<10) global.set(\"manual\",global.get(\"manual\")+1); }\n    if (msg.payload==\"d\") { global.set(\"manualTimer\",60); if (global.get(\"manual\")>-10) global.set(\"manual\",global.get(\"manual\")-1); }\n    if (msg.payload==\"a\") { global.set(\"manualTimer\",0); global.set(\"manual\",0); }\n}\n\nif (global.get(\"manual\")===0) msg.colour=\"#aaddff\"; else msg.colour=\"#aaffaa\";\n\nmsg.desired= global.get(\"setTemperature\") + global.get(\"manual\");\nif (global.get(\"frost\")) { msg.desired=global.get(\"timing\")[168]; msg.colour=\"#ffbbbb\"; }\nif (global.get(\"away\"))  { msg.desired=global.get(\"timing\")[169];msg.colour=\"#ffbbbb\";  }\nmsg.value=msg.desired;\n\nreturn msg;","outputs":1,"noerr":0,"x":770,"y":380,"wires":[["12fba98.fdffd57","510345b4.def36c"]]},{"id":"f0249ce.5c8b26","type":"ui_template","z":"c552e8d2.712b48","group":"968be961.f344c8","name":"up","order":4,"width":"1","height":"1","format":"  <md-button  class=\"vibrate filled touched smallfont rounded greybuttons\" ng-click=\"send({payload: 'u'})\"> \n                <img style=\"outline : none;\" \n                             ng-src=\"{{(msg.payload)?'/myicons/png/48x48/actions/arrow-right-2.png':'/myicons/png/48x48/actions/arrow-right-2.png'}}\" \n                              height=\"36px\"\n                />\n</md-button> ","storeOutMessages":false,"fwdInMessages":false,"x":530,"y":380,"wires":[["e6ca09fc.945898","de91f758.6226b8"]]},{"id":"ddc93996.6c52a8","type":"ui_template","z":"c552e8d2.712b48","group":"968be961.f344c8","name":"down","order":3,"width":"1","height":"1","format":"  <md-button  class=\"vibrate filled touched smallfont rounded greybuttons\" ng-click=\"send({payload: 'd'})\"> \n                <img style=\"outline : none;\" \n                             ng-src=\"{{(msg.payload)?'/myicons/png/48x48/actions/arrow-down-2.png':'/myicons/png/48x48/actions/arrow-left-2.png'}}\" \n                              height=\"36px\"\n                />\n</md-button> ","storeOutMessages":false,"fwdInMessages":false,"x":530,"y":420,"wires":[["e6ca09fc.945898","de91f758.6226b8"]]},{"id":"51b41303.edda9c","type":"function","z":"c552e8d2.712b48","name":"Handle AWAY","func":"// here we set manual override controls - valid for 60 minutes after last change.\nif (msg.payload==\"u\") {  global.set(\"away\",global.get(\"away\")+1); }\nif (msg.payload==\"uu\") { global.set(\"away\",global.get(\"away\")+24); }\nif (msg.payload==\"a\") { global.set(\"away\",0);  }\nmsg.away=global.get(\"away\");\n\nif (global.get(\"away\")===0) msg.colour=\"#aaddff\"; else msg.colour=\"#aaffaa\";\n\nvar t=parseInt(msg.away);\nif (t>23) t=((t/24).toFixed(1))+\"d\"; else t=t+\"h\";\nmsg.away=t;\n  \nmsg.payload=\"\";\nreturn msg;","outputs":1,"noerr":0,"x":780,"y":440,"wires":[["e6ca09fc.945898","eee62274.b8525"]]},{"id":"a3ffa1.f19c706","type":"ui_template","z":"c552e8d2.712b48","group":"968be961.f344c8","name":"more","order":6,"width":"1","height":"1","format":"  <md-button  class=\"vibrate filled touched smallfont rounded greybuttons\" ng-click=\"send({payload: 'u'})\"> \n                <img style=\"outline : none;\" \n                             ng-src=\"{{(msg.payload)?'/myicons/png/48x48/actions/arrow-right-2.png':'/myicons/png/48x48/actions/arrow-right-2.png'}}\" \n                              height=\"36px\"\n                />\n</md-button> ","storeOutMessages":false,"fwdInMessages":false,"x":530,"y":460,"wires":[["51b41303.edda9c","de91f758.6226b8"]]},{"id":"dbe0bda4.379","type":"ui_template","z":"c552e8d2.712b48","group":"968be961.f344c8","name":"mmore","order":7,"width":"1","height":"1","format":"  <md-button  class=\"vibrate filled touched smallfont rounded greybuttons\" ng-click=\"send({payload: 'uu'})\"> \n                <img style=\"outline : none;\" \n                             ng-src=\"{{(msg.payload)?'/myicons/png/48x48/actions/arrow-left-double-2.png':'/myicons/png/48x48/actions/arrow-right-double-2.png'}}\" \n                              height=\"36px\"\n                />\n</md-button> ","storeOutMessages":false,"fwdInMessages":false,"x":540,"y":500,"wires":[["51b41303.edda9c","de91f758.6226b8"]]},{"id":"ca92fea0.f2192","type":"ui_template","z":"c552e8d2.712b48","group":"968be961.f344c8","name":"newergauge","order":1,"width":"3","height":"3","format":"<script type=\"text/javascript\" src=\"/myjs/gauge.min.js\"></script>\n<script>\n\n\n   (function(scope){\n        scope.$watch('msg', function(msg) {\n           gauge.value=msg.value;\n           gauge.heat=msg.heatRelay;\n           gauge.humidity=msg.humidityRelay;\n           gauge.draw();\n        });\n    })(scope);\n    \nvar gauge = new RadialGauge({\n    renderTo: 'canvas-id',\n    width: 160,\n    height: 160,\n    heat: 0,\n    humidity: 0,\n    units: \"Degrees C\",\n    title: \"Heating\",\n    minValue: 10,\n    maxValue: 30,\n    majorTicks: [\n        '10',\n        '15',\n        '20',\n        '25',\n        '30'\n    ],\n    minorTicks: 5,\n    strokeTicks: true,\n   highlights  : [\n        { from : 10,  to : 15, color : '#8888ff' },\n        { from : 15, to : 20, color :  '#88ff88' },\n        { from : 20, to : 25, color :  '#ffff00' },\n        { from : 25, to : 30, color :  '#ff8888' }\n    ],\n\n    colorPlate: \"#fff\",\n    borderShadowWidth: 0,\n    borders: true,\n    needleType: \"arrow\",\n    valueInt: 2,\n    valueDec:0,\n    needleWidth: 2,\n    fontTitleSize: 42,\n    needleCircleSize: 14,\n    needleCircleOuter: true,\n    needleCircleInner: false,\n    animationDuration: 500,\n    animationRule: \"linear\"\n}).draw();\n\n\ngauge.on('beforeNeedle', function () {\n        // getting canvas 2d drawing context\n        var context = this.canvas.context;\n        // we can use gauge context special 'max' property which represents\n        // gauge radius in a real pixels and calculate size of relative pixel\n        // for our drawing needs\n        var pixel = context.max / 100;\n        // step out our circle center coordinate by 30% of its radius from\n        // gauge center\n        var centerX = 36 * pixel;\n        // stay in center by Y-coordinate\n        var centerY = 0;\n        // use circle radius equal to 5%\n        var radius = 10 * pixel;\n        // save previous context state\n        context.save();\n        \n        // draw circle using canvas JS API\n        context.beginPath();\n        context.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);\n        context.fillStyle = (this.heat) ? '#ff0000' : '#8888';\n        context.fill();\n        context.closePath();\n\n        context.beginPath();\n        context.arc(centerX-(72 * pixel), centerY, radius, 0, 2 * Math.PI, false);\n        context.fillStyle = (this.humidity) ? '#00dd88' : '#888888';\n        context.fill();\n        context.closePath();\n        // restore previous context state to prevent break of\n        // further drawings        \n        \n        context.restore();\n       // context.draw();\n    });\n\ngauge.value = 18;\n\n\n</script>\n<canvas style=\"outline: none;\" ng-click=\"send({payload: ' '})\" id=\"canvas-id\">\n</canvas>","storeOutMessages":false,"fwdInMessages":false,"x":1030,"y":500,"wires":[["510345b4.def36c","99b5322a.b16c9"]]},{"id":"12fba98.fdffd57","type":"ui_template","z":"c552e8d2.712b48","group":"968be961.f344c8","name":"SET","order":5,"width":"1","height":"1","format":"<script>\n   (function(scope){\n        scope.$watch('msg', function(msg) {\n             if (msg.desired!=\"\") $(\"#infor\").text(msg.desired+\"C\");\n             if (msg.colour!=\"\") $(\"#infor\").css(\"background-color\",msg.colour);\n        });\n \n    })(scope);\n</script>\n<table  ng-click=\"send({payload: 'a'})\" width=100% height=100% class=\"vibrate zui-table zui-table-rounded\">\n    <thead>\n        <tr>\n            <th>SET</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr >\n            <td id=\"infor\"></td>\n        </tr>\n\n    </tbody>\n</table>\n","storeOutMessages":false,"fwdInMessages":false,"x":1010,"y":540,"wires":[["e6ca09fc.945898","de91f758.6226b8"]]},{"id":"eee62274.b8525","type":"ui_template","z":"c552e8d2.712b48","group":"968be961.f344c8","name":"AWAY","order":8,"width":"1","height":"1","format":"<script>\n   (function(scope){\n        scope.$watch('msg', function(msg) {\n             if (msg.away!=\"\") $(\"#awaytable\").text(msg.away);\n             if (msg.colour!=\"\") $(\"#awaytable\").css(\"background-color\",msg.colour);\n        });\n \n    })(scope);\n</script>\n\n<table ng-click=\"send({payload: 'a'})\" width=100% height=100% class=\"vibrate zui-table zui-table-rounded\">\n    <thead>\n        <tr>\n            <th>AWAY</th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr>\n            <td id=\"awaytable\"></td>\n    \n        </tr>\n\n    </tbody>\n</table>","storeOutMessages":false,"fwdInMessages":false,"x":1010,"y":580,"wires":[["51b41303.edda9c","de91f758.6226b8"]]},{"id":"3ec413a4.5c623c","type":"ui_template","z":"c552e8d2.712b48","group":"968be961.f344c8","name":"STATUS","order":9,"width":"3","height":"1","format":"<script>\n   (function(scope){\n        scope.$watch('msg', function(msg) {\n             if (msg.topic!=\"\") $(\"#hdr1\").text(msg.topic);\n             if (msg.payload!=\"\") $(\"#bod1\").text(msg.payload);\n        });\n    })(scope);\n</script>\n\n<table ng-click=\"send({payload: 'a'})\" width=100% height=100% class=\"zui-table zui-table-rounded\">\n    <thead>\n        <tr>\n            <th id=\"hdr1\">></th>\n        </tr>\n    </thead>\n    <tbody>\n        <tr>\n            <td id=\"bod1\"></td>\n    \n        </tr>\n\n    </tbody>\n</table>","storeOutMessages":false,"fwdInMessages":false,"x":1020,"y":620,"wires":[[]]},{"id":"f0bb67c6.e12508","type":"function","z":"c552e8d2.712b48","name":"show humidity","func":"function theNewDate()\n{\n   var d = new Date(),\n    minutes = d.getMinutes().toString().length == 1 ? '0'+d.getMinutes() : d.getMinutes();\n    hours = d.getHours().toString().length == 1 ? '0'+d.getHours() : d.getHours();\n    ampm = d.getHours() >= 12 ? 'pm' : 'am';\n    months = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];\n    days = ['Sun','Mon','Tue','Wed','Thu','Fri','Sat'];\n    var m= days[d.getDay()]+' '+months[d.getMonth()]+' '+d.getDate()+' '+d.getFullYear()+' '+hours+':'+minutes+ampm;\n    return m;\n}\n\nmsg.topic=theNewDate();\nmsg.payload=\"Humidity: \" + global.get(\"incomingHumidity\") +\"%\" ;\nreturn msg;","outputs":1,"noerr":0,"x":780,"y":500,"wires":[["3ec413a4.5c623c"]]},{"id":"de91f758.6226b8","type":"function","z":"c552e8d2.712b48","name":"Showing settings","func":"msg.payload=\"Showing settings\";\nreturn msg;","outputs":1,"noerr":0,"x":790,"y":560,"wires":[["3ec413a4.5c623c"]]},{"id":"99b5322a.b16c9","type":"function","z":"c552e8d2.712b48","name":"Showing actual","func":"msg.payload=\"Showing actual\";\nreturn msg;","outputs":1,"noerr":0,"x":780,"y":620,"wires":[["3ec413a4.5c623c"]]},{"id":"eb0f3261.2613d","type":"function","z":"c552e8d2.712b48","name":"Dehum relay","func":"if (msg.humidityRelay==1)\nnode.status({fill:\"red\",shape:\"dot\",text:\"Dehumidifier ON\"});\nelse\nnode.status({fill:\"black\",shape:\"dot\",text:\"Dehumidifier OFF\"});\n","outputs":"0","noerr":0,"x":1070,"y":280,"wires":[]},{"id":"e0faeb04.f1c718","type":"inject","z":"c552e8d2.712b48","name":"incoming heat 27c","topic":"","payload":"27","payloadType":"str","repeat":"","crontab":"","once":false,"x":150,"y":40,"wires":[["d6b9fc13.9f3a2"]]},{"id":"4823dd31.779ad4","type":"inject","z":"c552e8d2.712b48","name":"incoming heat 18c","topic":"","payload":"18","payloadType":"str","repeat":"","crontab":"","once":false,"x":150,"y":80,"wires":[["d6b9fc13.9f3a2"]]},{"id":"33b0f2e3.5a52de","type":"trigger","z":"c552e8d2.712b48","op1":"","op2":"","op1type":"nul","op2type":"payl","duration":"1","extend":true,"units":"min","reset":"","name":"","x":1070,"y":160,"wires":[["fe37d17b.b1d9f","eb0f3261.2613d"]]},{"id":"cca4335c.f3a09","type":"function","z":"c552e8d2.712b48","name":"Heat test","func":"if (msg.heatRelay==1)\nnode.status({fill:\"red\",shape:\"dot\",text:\"Heat ON\"});\nelse\nnode.status({fill:\"black\",shape:\"dot\",text:\"Heat OFF\"});\n","outputs":"0","noerr":0,"x":1060,"y":340,"wires":[]},{"id":"223f9d0f.f87852","type":"function","z":"c552e8d2.712b48","name":"Dehum test","func":"if (msg.humidityRelay==1)\nnode.status({fill:\"red\",shape:\"dot\",text:\"Dehumidifier ON\"});\nelse\nnode.status({fill:\"black\",shape:\"dot\",text:\"Dehumidifier OFF\"});\n","outputs":"0","noerr":0,"x":1070,"y":400,"wires":[]},{"id":"968be961.f344c8","type":"ui_group","z":"","name":"Stat","tab":"c675fdae.9cea1","disp":false,"width":"6"},{"id":"c675fdae.9cea1","type":"ui_tab","z":"","name":"Stat","icon":"dashboard"}]

Comments (4)

  1. Peter Scargill

    Ok, changes this morning.

    When changing humidity level I realised that the indicator was not immediately reflecting this - so I've added some more wires to ensure this happens - but in the process realised that outputs to relays could now change more frequently than every minute. Accordingly I've added a TRIGGER node and test functions so you can see changes - but they won't end up on relays for a minute. The DELAY function seemed ideal for that but the description is somewhat misleading - limiting rate and dropping intermediate messages does NOT result in the last message coming out - it results in the FIRST one coming out and subsequent messages during the delay being dumped. Fortunately you can obtain the result I needed with the TRIGGER node. If one minute maximum messages is too short or long for you - adjust that node.

  2. Otis Jame

    Use Emoji Kitchen mashups that suit the context of your conversation. Whether you're conveying a mood, a holiday spirit, or just having fun, the right combination can make your messages more impactful.

  3. Eveline Anders

    In this block-based sandbox, players gather resources, craft items, and build structures to survive. Miniblox emphasizes creativity and strategic planning, challenging you to explore diverse environments and expand your territory. The game allows you to shape your surroundings and achieve your goals through innovative construction.

HTTPS SSH

You can clone a snippet to your computer for local editing. Learn more.