Adding a few more point examples. I have these as a Scripts for future reference.
Create a rule from a rule
The rule will disappear when OH restarts unless this code is run again. You cannot set the UID when using builder
as far as I can tell. Deleting the rule does not appear to work.
// Delete doesn't work
const { ruleRegistry } = require('@runtime/RuleSupport');
let RuleManager = osgi.getService("org.openhab.core.automation.RuleManager");
console.info('Creating a rule');
// rule builder
var ruleBuilder = function() {
rules.when().item('aTestSwitch').receivedCommand().then(event => {
console.log(event);
}).build("Test rule from rule", "Test rule from rule");
}
var ruleJSRule = function() {
rules.JSRule({
name: 'Test rule from rule2',
description: 'Test rule from rule2',
id: ruleUID+'_test_jsrule',
triggers: [triggers.ItemCommandTrigger('aTestSwitch')],
execute: event => {
console.log(event);
}
});
}
//ruleBuilder();
ruleJSRule();
// See JS Scripting docs.
console.info("Triggering created rule");
items.getItem('aTestSwitch').sendCommand('ON');
console.info('Deleting the rule');
var allRules = utils.javaSetToJsArray(ruleRegistry.getAll());
var uids = allRules.filter(r => r.getName() == "Test rule from rule2");
if(uids.length > 0) {
console.info('Found some rules', uids.length, uids[0].getUID());
const rval = ruleRegistry.remove(uids[0].getUID());
if(!rval) console.error("failed to remove rule!", rval);
}
var status = RuleManager.getStatus(uids[0].getUID());
if(status) {
console.info(status);
}
else {
console.info("Rule no longer exists");
}
Disable/Enable another rule
const { ruleRegistry } = require('@runtime/RuleSupport');
let RuleManager = osgi.getService("org.openhab.core.automation.RuleManager");
var logger = log('examples');
// Get all the rules
var allRules = utils.javaSetToJsArray(ruleRegistry.getAll());
logger.info('There are {} rules', allRules.length);
for each (let r in allRules) {
logger.info('Rule name = {} Rule UID = {}', r.getName(), r.getUID());
}
logger.info("This rule's UID = {}", ruleUID);
// Disable this rule
logger.info('Enabled status before: {}', RuleManager.isEnabled(ruleUID));
RuleManager.setEnabled(ruleUID, false);
logger.info('Enabled status after: {}', RuleManager.isEnabled(ruleUID));
Ephemeris
let logger = log('ephemeris example');
logger.info('About to test Ephemeris');
logger.info((actions.Ephemeris.isWeekend()) ? "It's the weekend" : 'Get back to work!');
executeCommandLine
var results = actions.Exec.executeCommandLine(time.Duration.ofSeconds(1), 'echo', 'hello');
console.info(results);
Working with QuantityTypes
var QT = Java.type('org.openhab.core.library.types.QuantityType');
let cloudiness = items.getItem('vCloudiness');
console.info('Cloudiness.rawState.class = ' + cloudiness.rawState.class.toString());
console.info('Cloudiness.state = ' + cloudiness.state); // string
console.info('Cloudiness.rawState = ' + cloudiness.rawState); // QuantityType
console.info('Cloudiness as number = ' + cloudiness.rawState.floatValue()); // float
console.info('Compare to 50%: ' + (cloudiness.rawState.compareTo(QT.valueOf('50 %')) < 0));
Run another rule
let RuleManager = osgi.getService("org.openhab.core.automation.RuleManager");
RuleManager.runNow('tocall');
var map = { 'test_data': 'Passed data to called rule' }
RuleManager.runNow('tocall', true, map);
In tocall
the passed in test_data
is available as test_data
.
Here’s tocall
var logger = Java.type("org.slf4j.LoggerFactory").getLogger("org.openhab.model.script.Run From");
logger.info("Map is: " + context.getAttribute("test_data"));
Complex coordination with timing
JS Scripting doesn’t support Thread::sleep, nor does it support having more than one thread running at the same time. This means you cannot have the script running at the same time as a timer nor can you have two timers running at the same time from the same script. Here is one way to work around that which I’ve used in my “unit tests” I’ve created for one of my libraries.
This is testing the Gatekeeper class.
Note it also shows examples for creating Timers.
var {gatekeeper, testUtils} = require('openhab_rules_tools');
var logger = log('rules_tools.Gatekeeper Tests');
var testFunGen = (test, num) => {
logger.debug('generating function for {} run{}', test, num);
return () => {
logger.debug('{}: Test {} ran', test, num);
cache.put(test+'_run'+num, time.ZonedDateTime.now());
};
}
logger.info('Starting Gatekeeper tests');
var reset = (test) => {
logger.debug('resetting {}');
cache.put(test, null);
logger.debug('resetting {}', test+'_start');
cache.put(test+'_start', null);
for(var i = 1; i <= 4; i++ ) {
logger.debug('resetting {}', test+'_run'+1)
cache.put(test+'_run'+i, null);
}
}
// Test 1: Scheduling
var gk1 = new gatekeeper.Gatekeeper();
var TEST1 = ruleUID+'_test1';
reset(TEST1);
cache.put(TEST1+'_start', time.ZonedDateTime.now());
gk1.addCommand('1s', testFunGen(TEST1, 1));
gk1.addCommand('2s', testFunGen(TEST1, 2));
gk1.addCommand('3s', testFunGen(TEST1, 3));
gk1.addCommand(500, testFunGen(TEST1, 4));
actions.ScriptExecution.createTimer(time.ZonedDateTime.now().plus(6500, time.ChronoUnit.MILLIS), () => {
var success = true;
const start = cache.get(TEST1+'_start');
const run1 = cache.get(TEST1+'_run1');
const run2 = cache.get(TEST1+'_run2');
const run3 = cache.get(TEST1+'_run3');
const run4 = cache.get(TEST1+'_run4');
if(start === null) {
logger.error('{} Failed to get starting timestamp', TEST1);
success = false;
}
if(success && run1 === null) {
logger.error('{} run1 failed to run!', TEST1);
success = false;
}
if(success && run2 === null) {
logger.error('{} run2 failed to run!', TEST1);
success = false;
}
if(success && run3 === null) {
logger.error('{} run3 failed to run!', TEST1);
success = false;
}
if(success && run4 === null) {
logger.error('{} run4 failed to run!', TEST1);
success = false;
}
if(success) {
logger.info('\n{}\n{}\n{}\n{}\n{}', start.toString(), run1.toString(), run2.toString(), run3.toString(), run4.toString());
const dur1 = time.Duration.between(run1, run2).seconds();
const dur2 = time.Duration.between(run2, run3).seconds();
const dur3 = time.Duration.between(run3, run4).seconds();
if(start.isAfter(run1)) {
logger.error('{} failed, run1 ran before start!', TEST1);
success = false;
}
if(success && dur1 != 1) {
logger.error('{} failed, time between run1 and run2 is {} seconds.', dur1);
success = false;
}
if(success && dur2 != 2) {
logger.error('{} failed, time between run2 and run3 is {} seconds', dur2);
success = false;
}
if(success && dur3 != 3) {
logger.error('{} failed, time between run3 and run4 is {} seconds', dur3);
}
if(success) {
logger.info('Gatekeeper test 1 success!');
}
}
});
// Test 2: cancelAll
var gk2 = new gatekeeper.Gatekeeper();
var TEST2 = ruleUID+'_test2'
reset(TEST2);
gk2.addCommand('1s 500z', testFunGen(TEST2, 1));
gk2.addCommand('2s', testFunGen(TEST2, 2));
gk2.addCommand('3s', testFunGen(TEST2, 3));
gk2.addCommand(500, testFunGen(TEST2, 4));
actions.ScriptExecution.createTimer(time.ZonedDateTime.now().plus(2750, time.ChronoUnit.MILLIS), () => {
var success = true;
const run1 = cache.get(TEST2+'_run1');
const run2 = cache.get(TEST2+'_run2');
const run3 = cache.get(TEST2+'_run3');
const run4 = cache.get(TEST2+'_run4');
if(!run1) {
logger.error('{} failed, run1 did not run', TEST2);
success = false;
}
if(success && !run2) {
logger.error('{} failed, run2 did not run', TEST2);
success = false;
}
if(success && run3) {
logger.error('{} failed, run3 ran too soon', TEST2);
success = false;
}
if(success && run4) {
logger.error('{} failed, run4 ran too soon', TEST2);
success = false;
}
if(success) {
gk2.cancelAll();
actions.ScriptExecution.createTimer(time.ZonedDateTime.now().plus(4000, time.ChronoUnit.MILLIS), () => {
var success = true;
const run3 = cache.get(TEST2+'_run3');
const run4 = cache.get(TEST2+'_run4');
if(run3) {
logger.error('{} failed, run3 ran after being cancelled');
success = false;
}
if(success && run4) {
logger.error('{} failed, run4 ran after being cancelled');
}
if(success){
logger.info('Gatekeeper test 2 success!')
}
});
}
});