Determine properties like holiday, business day, weekend, etc at the moment when message is received.

In combination with great node BigTimer by Peter Scargill I needed something to determine whether if its business day at that moment, if its holiday, which weekday it is, regarding energy consumption if its lower or higher tariff etc. So I wrote a function and decided to share it so anyone could use it for its own purposes. The code naturally includes our national (Slovenian) holiday sets. Ofcourse modificaitions are needed for use in any other country which has its own set of holidays and energy consumption tariff rules.

Im using it in combination with BigTimer to turn on the light in the morning when its time to get up but only if its business day :) I also pass messages to it from energy meter and then calculate energy consumption in kWh for lower and higher tariff. And water heater is turned off in higher tariff at 20:00 so water is not heated during showering time but gets heated when lower tariff kicks in at 22:00. I hope anyone else could benefit using this stuff. Im also open for suggestions and improvements!

Public gist: https://gist.github.com/mrizvic/f8c6b1db1bd815d49d76657cf6977e4a

Screenshot: http://imgur.com/a/LZniM

[{"id":"b6b597a8.bfa978","type":"function","z":"f2b4a9c7.254388","name":"append date properties","func":"/*\n\n * ----------------------------------------------------------------------------\n * \"THE BEER-WARE LICENSE\" (Revision 42):\n * github.com/mrizvic wrote this file.  As long as you retain this notice you\n * can do whatever you want with this stuff. If we meet some day, and you think\n * this stuff is worth it, you can buy me a beer in return.   M.Rizvic\n * ----------------------------------------------------------------------------\n\n## This function will pass incoming message to multiple outputs based on following conditions:\n## output 1 - unconditional\n## output 2 - if its holiday\n## output 3 - if its business day\n## output 4 - if its weeekend\n## output 5 - if its leap year\n## output 6 - if its high tariff time regarding energy consumption\n## output 7 - if its low tariff time regarding energy consumption\n\n## Holidays are defined in a matter of if..else if sentences as shown below in USER SPECIFIC DATES section. Some holidays are variable and must be calculated each time (e.g. easter)\n## Some properties will be appended to original message in case some would like to use them. Below is an example:\n\n_msgid: \"78a5e9f0.a318e8\"\ntopic: \"\"\npayload: \"power on\"\ndate: \"2017-02-23T15:59:59.401Z\"\ntariff: \"vt\"\nholiday: false\nbusinessday: true\nweekend: false\nweekday: 4\nleapyear: false\nproperties: \"tariff=vt,holiday=false,businessday=true,weekend=false,weekday=4,leapyear=false\"\n\nweekday numbers are in range from 1 to 7 where is 1 for monday, 2 for tuesday, ... and 7 for sunday\ntariff can be 'vt' (high tariff) or 'mt' (low tariff)\n*/\n\n// take current timestamp\nvar date = new Date();\n\nvar getEasterDate = function(year) {\n  var a = year % 19;\n  var b = Math.floor(year / 100);\n  var c = year % 100;\n  var d = Math.floor(b / 4); \n  var e = b % 4;\n  var f = Math.floor((b + 8) / 25);\n  var g = Math.floor((b - f + 1) / 3); \n  var h = (19 * a + b - d - g + 15) % 30;\n  var i = Math.floor(c / 4);\n  var k = c % 4;\n  var l = (32 + 2 * e + 2 * i - h - k) % 7;\n  var m = Math.floor((a + 11 * h + 22 * l) / 451);\n  var n0 = (h + l + 7 * m + 114);\n  var n = Math.floor(n0 / 31) - 1;\n  var p = n0 % 31 + 1;\n  var date = new Date(year,n,p);\n  return date; \n};\n\nDate.prototype.addDays = function(days)\n{\n    var dat = new Date(this.valueOf());\n    dat.setDate(dat.getDate() + days);\n    return dat;\n};\n\nvar weekday = date.getDay();\nif (weekday === 0) { weekday = 7; }\n\nvar year = date.getFullYear();\nvar month = date.getMonth() + 1;\nvar day = date.getDate();\nvar hour = date.getHours();\n\nvar isHoliday = false;\nvar holidayString = \"\";\nvar isLeapYear = new Date(year, 1, 29).getMonth() == 1;\n\n// sunday or saturday\nvar isWeekend = (weekday > 5);\nvar isBusinessDay = ! isWeekend;\n\n\n// USER SPECIFIC DATES - BEGIN\n\n// calculate some variable holiday dates\n// EASTER SUNDAY\nvar easterDate = getEasterDate(year);\nvar ed1 = easterDate.getDate();\nvar em1 = easterDate.getMonth() + 1;\n\n// EASTER MONDAY\nvar easterMonday = easterDate.addDays(1);\nvar ed2 = easterMonday.getDate();\nvar em2 = easterMonday.getMonth() + 1;\n\n// BINKOSTNA NEDELJA = (EASTER SUNDAY + 49) - 50 DAN PO VELIKI NOCI\nvar binkost1 = easterDate.addDays(49);\nvar bd1 = binkost1.getDate();\nvar bm1 = binkost1.getMonth() + 1;\n\n// BINKOSTNI PONEDELJEK\nvar binkost2 = easterDate.addDays(50);\nvar bd2 = binkost2.getDate();\nvar bm2 = binkost2.getMonth() + 1;\n\n// set date specific properties\n\n     if ( (month == 1)   && (day == 1)   ) { isHoliday = true; isBusinessDay = isBusinessDay && false; holidayString = \"Novo leto\"; }\nelse if ( (month == 1)   && (day == 2)   ) { isHoliday = true; isBusinessDay = isBusinessDay && false; holidayString = \"Novo leto\"; }\nelse if ( (month == 2)   && (day == 8)   ) { isHoliday = true; isBusinessDay = isBusinessDay && false; holidayString = \"Prešernov dan\"; }\nelse if ( (month == em1) && (day == ed1) ) { isHoliday = true; isBusinessDay = isBusinessDay && false; holidayString = \"Velika noč\"; }\nelse if ( (month == em2) && (day == ed2) ) { isHoliday = true; isBusinessDay = isBusinessDay && false; holidayString = \"Velikončni ponedeljek\"; }\nelse if ( (month == 4)   && (day == 27)  ) { isHoliday = true; isBusinessDay = isBusinessDay && false; holidayString = \"Dan boja proti okupatorju\"; }\nelse if ( (month == 5)   && (day == 1)   ) { isHoliday = true; isBusinessDay = isBusinessDay && false; holidayString = \"Praznik dela\"; }\nelse if ( (month == 5)   && (day == 2)   ) { isHoliday = true; isBusinessDay = isBusinessDay && false; holidayString = \"Praznik dela\"; }\nelse if ( (month == bm1) && (day == bd1) ) { isHoliday = true; isBusinessDay = isBusinessDay && false; holidayString = \"Binkoštna nedelja\"; }\nelse if ( (month == bm2) && (day == bd2) ) { isHoliday = true; isBusinessDay = isBusinessDay && true;  holidayString = \"Binkoštni ponedeljek\"; }\nelse if ( (month == 6)   && (day == 8)   ) { isHoliday = true; isBusinessDay = isBusinessDay && true;  holidayString = \"Dan Primoža Trubarja\";}\nelse if ( (month == 6)   && (day == 25)  ) { isHoliday = true; isBusinessDay = isBusinessDay && false; holidayString = \"Dan državnosti\"; }\nelse if ( (month == 8)   && (day == 15)  ) { isHoliday = true; isBusinessDay = isBusinessDay && false; holidayString = \"Marijino vnebovzetje\"; }\nelse if ( (month == 8)   && (day == 17)  ) { isHoliday = true; isBusinessDay = isBusinessDay && true;  holidayString = \"Združitev prekmurskih Slovencev z matičnim narodom\";}\nelse if ( (month == 9)   && (day == 15)  ) { isHoliday = true; isBusinessDay = isBusinessDay && true;  holidayString = \"Vrnitev Primorske k matični domovini\";}\nelse if ( (month == 10)  && (day == 25)  ) { isHoliday = true; isBusinessDay = isBusinessDay && true;  holidayString = \"Dan suverenosti\"; }\nelse if ( (month == 10)  && (day == 31)  ) { isHoliday = true; isBusinessDay = isBusinessDay && false; holidayString = \"Dan reformacije\"; }\nelse if ( (month == 11)  && (day == 1)   ) { isHoliday = true; isBusinessDay = isBusinessDay && false; holidayString = \"Dan spomina na mrtve\"; }\nelse if ( (month == 11)  && (day == 23)  ) { isHoliday = true; isBusinessDay = isBusinessDay && true;  holidayString = \"Dan Rudolfa Maistra\"; }\nelse if ( (month == 12)  && (day == 25)  ) { isHoliday = true; isBusinessDay = isBusinessDay && false; holidayString = \"Božič\"; }\nelse if ( (month == 12)  && (day == 26)  ) { isHoliday = true; isBusinessDay = isBusinessDay && false; holidayString = \"Dan samostojnosti in enotnosti\"; }\n\n// USER SPECIFIC DATES - END\n\n\n// determine energy consumption tariff\n// low tariff if not business day or between 22:00 and 06:00\nvar mt = ! isBusinessDay || (hour >= 22) || (hour < 6);\nvar vt = ! mt;\n\nvar tariff = mt ? \"mt\" : \"vt\";\n\n\n\n// preserve original message\nvar result = msg;\nmsg.date = date;\n\n// add our properties\nresult.tariff = tariff;\nresult.holiday = isHoliday;\nresult.businessday = isBusinessDay;\nresult.weekend = isWeekend;\nresult.weekday = weekday;\nresult.leapyear = isLeapYear;\nif (holidayString.length > 0) {\n  result.holiday_name = holidayString;\n}\n\n// generate string of properties so one could\n// parse using switch node\nresult.properties = '';\nresult.properties += 'tariff=' + tariff + ',';\nresult.properties += 'holiday=' + isHoliday + ',';\nresult.properties += 'businessday=' + isBusinessDay + ',';\nresult.properties += 'weekend=' + isWeekend + ',';\nresult.properties += 'weekday=' + weekday + ',';\nresult.properties += 'leapyear=' + isLeapYear;\n\n// generate conditional outputs\nmsg1 = result;\nmsg2 = isHoliday ? result : null;\nmsg3 = isBusinessDay ? result : null;\nmsg4 = isWeekend ? result : null;\nmsg5 = isLeapYear ? result : null;\nmsg6 = vt ? result : null;\nmsg7 = mt ? result : null;\n\nreturn [ msg1, msg2, msg3, msg4, msg5, msg6, msg7 ];","outputs":"1","noerr":0,"x":541,"y":267,"wires":[["95ca14de.7d3678","a44c1e4.2ca26e","35e1f48e.bbc83c","e877217f.a039a","e032dc8a.1202b","9bdec0a1.eb1b2","77c7fc4b.23c3f4"]]},{"id":"95ca14de.7d3678","type":"function","z":"f2b4a9c7.254388","name":"is businessday","func":"if (msg.businessday === true) { return msg; }","outputs":1,"noerr":0,"x":851,"y":344,"wires":[[]]},{"id":"a44c1e4.2ca26e","type":"function","z":"f2b4a9c7.254388","name":"is weekend","func":"if (msg.weekend === true) { return msg; }","outputs":1,"noerr":0,"x":840.5,"y":297,"wires":[[]]},{"id":"35e1f48e.bbc83c","type":"function","z":"f2b4a9c7.254388","name":"is low tariff","func":"if (msg.tariff === \"mt\") { return msg; }","outputs":1,"noerr":0,"x":840.5,"y":247,"wires":[[]]},{"id":"e877217f.a039a","type":"function","z":"f2b4a9c7.254388","name":"is high tariff","func":"if (msg.tariff === \"vt\") { return msg; }","outputs":1,"noerr":0,"x":841.5,"y":198,"wires":[[]]},{"id":"5f69b490.e8d33c","type":"inject","z":"f2b4a9c7.254388","name":"emit \"power on\" message on start","topic":"","payload":"power on","payloadType":"str","repeat":"","crontab":"","once":true,"x":228,"y":267,"wires":[["b6b597a8.bfa978"]]},{"id":"e032dc8a.1202b","type":"function","z":"f2b4a9c7.254388","name":"is holiday","func":"if (msg.holiday === true) { return msg; }","outputs":1,"noerr":0,"x":831,"y":396,"wires":[[]]},{"id":"9bdec0a1.eb1b2","type":"function","z":"f2b4a9c7.254388","name":"is leap year","func":"if (msg.leapyear === true) { return msg; }","outputs":1,"noerr":0,"x":841,"y":447,"wires":[[]]},{"id":"77c7fc4b.23c3f4","type":"switch","z":"f2b4a9c7.254388","name":"properties router","property":"properties","propertyType":"msg","rules":[{"t":"cont","v":"weekend=true","vt":"str"},{"t":"cont","v":"weekend=false","vt":"str"},{"t":"cont","v":"businessday=true","vt":"str"},{"t":"cont","v":"businessday=false","vt":"str"},{"t":"cont","v":"holiday=true","vt":"str"},{"t":"cont","v":"holiday=false","vt":"str"},{"t":"cont","v":"leapyear=true","vt":"str"},{"t":"cont","v":"leapyear=false","vt":"str"},{"t":"cont","v":"tariff=vt","vt":"str"},{"t":"cont","v":"tariff=mt","vt":"str"},{"t":"cont","v":"holiday_string=Velikončni ponedeljek","vt":"str"},{"t":"else"}],"checkall":"true","outputs":12,"x":861,"y":697,"wires":[["14f54e6b.749882"],["14f54e6b.749882"],[],[],[],[],[],[],[],[],[],[]]},{"id":"14f54e6b.749882","type":"debug","z":"f2b4a9c7.254388","name":"","active":true,"console":"false","complete":"true","x":1149,"y":627,"wires":[]},{"id":"24d8c2b2.b8379e","type":"comment","z":"f2b4a9c7.254388","name":"event initiator","info":"You should place a node here that emits an event (MQTT in, websocket in, tcp/udp in,...). I suggest to check out BigTimer by Peter Scargill.","x":159,"y":215,"wires":[]},{"id":"f2330c9f.2b9db","type":"comment","z":"f2b4a9c7.254388","name":"determine date properties","info":"This function determines current time and determines whether it is business day, weekend, a weekday number etc...\nIt appends these properties to a message so take care that this function does not override your original properties.\n\n`payload`, `topic` and `_msgid` properties are not modified. Everything below that is added or modified by the function.\n\nAn example message:\n```\npayload: \"power on\"\ntopic: \"\"\n_msgid: \"6ab0f9a.f954f08\"\nholiday: false\nbusinessday: true\nweekend: false\nweekday: 4\nleapyear: false\ntariff: vt\n```\n\n","x":540,"y":211,"wires":[]},{"id":"217f97ba.4eeb38","type":"comment","z":"f2b4a9c7.254388","name":"message filter","info":"Below are examples of how messages can be filtered or passed depending on their properties.\n","x":841,"y":145,"wires":[]},{"id":"95ff2eb6.486a9","type":"comment","z":"f2b4a9c7.254388","name":"message router","info":"Messages can be routed using switch node by parsing `msg.properties`\n","x":851,"y":575,"wires":[]}]
mrizvic

Flow Info

created 3 months, 1 week ago

Node Types

Core
  • comment (x4)
  • debug (x1)
  • function (x7)
  • inject (x1)
  • switch (x1)

Tags

  • timestamp
  • holiday
  • weekend
  • tariff
  • energy
  • power
  • timer
  • date
  • time
  • meter
Copy this flow JSON to your clipboard and then import into Node-RED using the Import From > Clipboard (Ctrl-I) menu option