/**
* Copyright (c) 2021 Florian Hotze
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
const { items, rules, triggers } = require('openhab');
/**
* Provides the alarm clock rule with QUARTZ cron trigger.
* Do not call directly, instead call {@link rulesx.createAlarmClock}.
*
* Needs settings Items that must follow a given naming scheme.
* The cron expression is build based on settings items.
* When no day is selected, send command OFF to alarmSwitch and do not return rule.
* When hour/minute are NaN, return no rule and set them to defaults.
*
* @private
* @param {string} switchItem name of Item to switch the alarm on/off
* @param {*} alarmFunc function to execute when the rule runs
*/
function _createClockRule (switchItem, alarmFunc) {
// Get Items' states for time configuration.
const hour = parseInt(items.getItem(switchItem + '_H').state);
const minute = parseInt(items.getItem(switchItem + '_M').state);
// If hour or minute is NaN, return and initialize default values.
if (isNaN(hour) || isNaN(minute)) {
items.getItem(switchItem + '_H').postUpdate('7');
items.getItem(switchItem + '_M').postUpdate('0');
items.getItem(switchItem + '_Time').postUpdate('07:00');
console.info('Not adding clock rule for ' + switchItem + ' due to missing time configuration.');
return;
}
// Post time string.
items.getItem(switchItem + '_Time').postUpdate(((hour < 10) ? '0' : '') + hour.toString() + ':' + ((minute < 10) ? '0' : '') + minute.toString());
// If switchItem is OFF, return.
if (items.getItem(switchItem).state !== 'ON') {
console.info('Not adding clock rule for ' + switchItem + ' because alarm is switched off.');
return;
}
// Generate Array for days of week.
const days = [];
if (items.getItem(switchItem + '_MON').state === 'ON') days.push('MON');
if (items.getItem(switchItem + '_TUE').state === 'ON') days.push('TUE');
if (items.getItem(switchItem + '_WED').state === 'ON') days.push('WED');
if (items.getItem(switchItem + '_THU').state === 'ON') days.push('THU');
if (items.getItem(switchItem + '_FRI').state === 'ON') days.push('FRI');
if (items.getItem(switchItem + '_SAT').state === 'ON') days.push('SAT');
if (items.getItem(switchItem + '_SUN').state === 'ON') days.push('SUN');
// If no day is selected, return and turn of the switchItem.
if (days.length === 0) {
items.getItem(switchItem).sendCommand('OFF');
console.info('Not adding clock rule for ' + switchItem + ' because no day is enabled.');
return;
}
// Generate the QUARTZ cron expression.
const quartz = '0 ' + minute + ' ' + hour + ' ? * ' + days.join(',') + ' *';
// Return the JSRule.
rules.JSRule({
name: 'Alarm Clock ' + switchItem,
description: 'The Alarm Clock itself, created by the manager rule.',
triggers: [triggers.GenericCronTrigger(quartz)],
execute: alarmFunc,
id: 'alarmClock-for-' + switchItem,
tags: ['@hotzware/openhab-tools', 'createAlarmClock', 'Schedule'],
overwrite: true
});
}
/**
* Creates an alarm clock with time and days configurable over Items, therefore compatible with Sitemaps.
*
* The manager rule that creates and updates the alarm clock rule {@link _createClockRule} on change of settings Items.
* Also creates and removes the alarm clock rule on command ON/OFF of switchItem.
*
* @example
* rulesx.createAlarmClock('Florian_alarm1', data => { console.log('Successfully tested alarm clock.'); });
*
* @memberof rulesx
* @param {string} switchItem name of Item to switch the alarm on/off
* @param {function} alarmFunc function to execute when the alarm clock fires
*/
function createAlarmClock (switchItem, alarmFunc) {
rules.JSRule({
name: 'Alarm Clock Manager ' + switchItem,
triggers: [
triggers.ItemStateChangeTrigger(switchItem),
triggers.ItemStateChangeTrigger(switchItem + '_H'),
triggers.ItemStateChangeTrigger(switchItem + '_M'),
triggers.ItemStateChangeTrigger(switchItem + '_MON'),
triggers.ItemStateChangeTrigger(switchItem + '_TUE'),
triggers.ItemStateChangeTrigger(switchItem + '_WED'),
triggers.ItemStateChangeTrigger(switchItem + '_THU'),
triggers.ItemStateChangeTrigger(switchItem + '_FRI'),
triggers.ItemStateChangeTrigger(switchItem + '_SAT'),
triggers.ItemStateChangeTrigger(switchItem + '_SUN')
],
execute: (event) => {
rules.removeRule('alarmClock-for-' + switchItem);
_createClockRule(switchItem, alarmFunc);
},
id: 'alarmClock-manager-for-' + switchItem,
tags: ['@hotzware/openhab-tools', 'createAlarmClock']
});
_createClockRule(switchItem, alarmFunc);
}
/**
* Creates all required Items for an alarm clock.
*
* @memberof rulesx
* @param {String} switchItemName name of Item to switch alarm on/off
* @param {String} switchItemLabel label of Item to switch alarm on/off
* @param {String} persistenceGroup name of group whose members are persisted & restored on startup
* @param {Boolean} [sitemapSnippet=false] whether to output a Sitemap snippet for alarm configuration
* @param {String[]} [weekdaysLabels=['Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag', 'Sonntag']] names of weekdays in your language, starting with Monday & ending with Sunday
*/
function createAlarmClockItems (switchItemName, switchItemLabel, persistenceGroup, sitemapSnippet = false, weekdaysLabels = ['Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag', 'Sonntag']) {
function createItemAndSetState (itemConfig, state) {
try {
items.addItem(itemConfig);
} catch (error) {
console.warn(`Failed to create Item ${itemConfig.name}: ${error}`);
}
items.getItem(itemConfig.name).postUpdate(state);
}
// Create switchItem
createItemAndSetState({
type: 'Switch',
name: switchItemName,
label: switchItemLabel,
category: 'time',
groups: [persistenceGroup]
}, 'OFF');
// Create weekday Items
const weekdaysNames = ['_MON', '_TUE', '_WED', '_THU', '_FRI', '_SAT', '_SUN'];
for (const i in weekdaysNames) {
createItemAndSetState({
type: 'Switch',
name: switchItemName + weekdaysNames[i],
label: weekdaysLabels[i],
category: 'switch',
groups: [persistenceGroup]
}, 'OFF');
}
// Create hour & minute Items
createItemAndSetState({
type: 'Number',
name: switchItemName + '_H',
label: 'Stunde',
category: 'time',
groups: [persistenceGroup],
metadata: {
stateDescription: {
config: {
pattern: '%d'
}
}
}
}, '7');
createItemAndSetState({
type: 'Number',
name: switchItemName + '_M',
label: 'Minute',
category: 'time',
groups: [persistenceGroup],
metadata: {
stateDescription: {
config: {
pattern: '%d'
}
}
}
}, '0');
// Create state Item
createItemAndSetState({
type: 'String',
name: switchItemName + '_Time',
label: '',
category: 'time',
groups: [persistenceGroup],
metadata: {
stateDescription: {
config: {
pattern: '%s'
}
}
}
}, '07:00');
const sitemapText =
`Text label="Wecker 1 [%s]" item=${switchItemName}_Time icon="time" valuecolor=[${switchItemName}==ON="green", ${switchItemName}==OFF="grey"] {
Default item=${switchItemName}
Frame label="Zeit" {
Setpoint item=${switchItemName}_H minValue=0 maxValue=23 step=1
Setpoint item=${switchItemName}_M minValue=0 maxValue=55 step=5
}
Frame label="Wochentage" {
Switch item=${switchItemName}_MON
Switch item=${switchItemName}_TUE
Switch item=${switchItemName}_WED
Switch item=${switchItemName}_THU
Switch item=${switchItemName}_FRI
Switch item=${switchItemName}_SAT
Switch item=${switchItemName}_SUN
}
}`;
if (sitemapSnippet === true) console.info(`alarm clock configuration Sitemap snippet: \n${sitemapText}`);
}
module.exports = {
createAlarmClock,
createAlarmClockItems
};