Hi All, sharing a simpler but less powerful or less complete, approach in JavaScript to the excellent Time of Day design pattern found at https://community.openhab.org/t/design-pattern-time-of-day/15407
Why I took this approach:
- I wanted a table-like-looking structure to hold my times, easy to find and quick to read or edit.
- I wanted to use Javascript, not Rules DSL.
- I didn’t need Astro bindings for sunrise, sunset and similar. I suppose I can add it in my code if I later have a use for them.
To implement I have just one vTimeOfDay Item, which holds a String, and a “Set vTimeOfDay” ECMAScript rule, with these triggers:
triggers:
- id: "1"
configuration:
startlevel: 50
type: core.SystemStartlevelTrigger
- id: "2"
configuration:
cronExpression: 0 * * * * ? *
type: timer.GenericCronTrigger
The Script is:
var logger = Java.type('org.slf4j.LoggerFactory').getLogger('org.openhab.rule.' + ctx.ruleUID);
var TimesOfDay = {
week : [
// Special short periods come first
[ 'MIDNIGHT_COOL', '00:05', '00:06'],
[ 'SCHOOL_SOON', '07:30', '07:31'],
[ 'SCHOOL_NOW', '07:42', '07:43'],
[ 'BEDTIME_EDDIE', '20:30', '20:35'],
[ 'BEDTIME_JAMIE', '21:30', '21:35'],
// Regular periods come after
[ 'EARLY', '00:00', '07:05'],
[ 'MORNING', '07:05', '12:00'],
[ 'AFTERNOON', '12:00', '19:00'],
[ 'NIGHT', '19:00', '21:15'],
[ 'LATE', '21:15', '23:00'],
[ 'TOO_LATE', '23:00', '24:00']
],
saturday : [
// Special short periods come first
[ 'MIDNIGHT_COOL', '00:05', '00:06'],
[ 'BEDTIME_EDDIE', '21:30', '21:35'],
[ 'BEDTIME_JAMIE', '22:00', '22:05'],
// Regular periods come after
[ 'EARLY', '00:00', '07:05'],
[ 'MORNING', '07:05', '12:00'],
[ 'AFTERNOON', '12:00', '19:00'],
[ 'NIGHT', '19:00', '21:15'],
[ 'LATE', '21:15', '23:00'],
[ 'TOO_LATE', '23:00', '24:00']
],
sunday: [
// Special short periods come first
[ 'MIDNIGHT_COOL', '00:05', '00:06'],
[ 'BEDTIME_EDDIE', '20:30', '20:35'],
[ 'BEDTIME_JAMIE', '21:30', '21:35'],
// Regular periods come after
[ 'EARLY', '00:00', '07:05'],
[ 'MORNING', '07:05', '12:00'],
[ 'AFTERNOON', '12:00', '19:00'],
[ 'NIGHT', '19:00', '21:15'],
[ 'LATE', '21:15', '23:00'],
[ 'TOO_LATE', '23:00', '24:00']
]
};
// Determine the Minute Of Day for now & weekday
var now = new Date();
var nowMOD = now.getHours()*60 + now.getMinutes();
var weekday = now.getDay();
var table;
// Define which table to use based on weekday
switch (weekday) {
case 0:
table = TimesOfDay.sunday;
break;
case 6:
table = TimesOfDay.saturday;
break;
default:
table = TimesOfDay.week;
}
// Get the current TimeOfDay from Item
var prev = itemRegistry.getItem('vTimeOfDay').getState();
var curr = "UNK"
// Check what should the TimeOfDay be now
var p, pStart, pFinish;
for (p=0; p<table.length; p++) {
pStart = minOfDay(table[p][1]);
pFinish = minOfDay(table[p][2]);
if ((nowMOD >= pStart) && (nowMOD < pFinish)) {
curr=table[p][0];
break;
}
}
// If TimeOfDay has just changed this minute
// update vTimeOfDay Item and log it
if (curr != prev) {
events.sendCommand('vTimeOfDay', curr);
logger.info('vTimeOfDay: ' + curr);
}
// Function to get the number of minutes since
// start of day from a String in HH:MM format
function minOfDay(s) {
var hour=parseInt(s.slice(0,2));
var minute=parseInt(s.slice(3,5));
return hour*60 + minute;
}
As can be seen I have three tables to define the TimesOfDay, one for the work week (M-F), one for Sat and one for Sun. I could have one per day of the week, but right now I don’t need that.
This rule does not care for changes in Daylight Savings Time, so if that is important for you then you would need to add some logic for it. It doesn’t matter for me.
I keep this script that determines vTimeOfDay in OpenHAB rules, but I do almost all of my rules in NodeRED, where I watch for vTimeOfDay changes.
In NodeRED a sample flow looks like this:
Where the change node does msg.timeOfDay = msg.payload, and the switch node is obviously a switch based on msg.timeOfDay.
Why I didn’t do it all in NodeRED? Because I think the table is quicker to see/edit in OpenHAB, but this code could be in there as well in a subflow.
Hope this helps anyone wanting to use Javascript to implement the same Design Pattern, or use it with NodeRED.