From 3b05a85ee96f5eaa285e20920a598aa3973d5e94 Mon Sep 17 00:00:00 2001 From: Jonathan Gilbert Date: Thu, 17 Oct 2019 16:16:54 +1100 Subject: [PATCH] Added initial CommonJS support --- .../javascript/core/PersistenceExtensions.js | 19 +- .../automation/lib/javascript/core/actions.js | 24 +- .../lib/javascript/core/conditions.js | 28 +- Core/automation/lib/javascript/core/init.js | 120 ++++ .../lib/javascript/core/metadata.js | 15 +- Core/automation/lib/javascript/core/osgi.js | 14 +- Core/automation/lib/javascript/core/rules.js | 35 +- .../lib/javascript/core/triggers.js | 59 +- Core/automation/lib/javascript/core/utils.js | 138 +++-- .../lib/javascript/modules/actions.js | 39 ++ .../lib/javascript/modules/conditions.js | 44 ++ .../lib/javascript/modules/loader.js | 64 ++ .../lib/javascript/modules/logutil.js | 23 + .../automation/lib/javascript/modules/osgi.js | 68 ++ .../lib/javascript/modules/rules.js | 157 +++++ .../automation/lib/javascript/modules/test.js | 1 + .../lib/javascript/modules/triggers.js | 171 ++++++ .../lib/javascript/modules/utils.js | 580 ++++++++++++++++++ Script Examples/JavaScript/ActionExamples.js | 50 +- .../JavaScript/HTTPRequestExamples.js | 22 +- Script Examples/JavaScript/HelloWorld.js | 11 +- Script Examples/JavaScript/ItemTest.js | 52 +- .../JavaScript/SimpleRuleExamples.js | 32 +- Script Examples/JavaScript/TimerExample.js | 16 +- 24 files changed, 1589 insertions(+), 193 deletions(-) create mode 100644 Core/automation/lib/javascript/core/init.js create mode 100644 Core/automation/lib/javascript/modules/actions.js create mode 100644 Core/automation/lib/javascript/modules/conditions.js create mode 100644 Core/automation/lib/javascript/modules/loader.js create mode 100644 Core/automation/lib/javascript/modules/logutil.js create mode 100644 Core/automation/lib/javascript/modules/osgi.js create mode 100644 Core/automation/lib/javascript/modules/rules.js create mode 100644 Core/automation/lib/javascript/modules/test.js create mode 100644 Core/automation/lib/javascript/modules/triggers.js create mode 100644 Core/automation/lib/javascript/modules/utils.js diff --git a/Core/automation/lib/javascript/core/PersistenceExtensions.js b/Core/automation/lib/javascript/core/PersistenceExtensions.js index 25cde9a1..a6e29928 100644 --- a/Core/automation/lib/javascript/core/PersistenceExtensions.js +++ b/Core/automation/lib/javascript/core/PersistenceExtensions.js @@ -7,11 +7,18 @@ */ 'use strict'; -var PersistenceExtensions = Java.type("org.eclipse.smarthome.model.persistence.extensions.PersistenceExtensions"); +// START: Backward Compatibility Header +load(Java.type("java.lang.System").getenv("OPENHAB_CONF")+'/automation/lib/javascript/core/init.js'); +// END: Backward Compatibility Header + + //Simplifies spelling for rules. (function(context) { 'use strict'; + + var PersistenceExtensions = Java.type("org.eclipse.smarthome.model.persistence.extensions.PersistenceExtensions"); + context.PersistenceExtensions = PersistenceExtensions; context.pe = PersistenceExtensions; @@ -172,4 +179,12 @@ var PersistenceExtensions = Java.type("org.eclipse.smarthome.model.persistence.e return null; }; -})(this); +})(exports); + +// START: Backward Compatibility Footer +if (typeof ___INIT_STATE___ === 'undefined') { + for (var k in exports) { + this[k] = exports[k]; + } +} +// END: Backward Compatibility Footer \ No newline at end of file diff --git a/Core/automation/lib/javascript/core/actions.js b/Core/automation/lib/javascript/core/actions.js index 4338a38e..7f0f5d3f 100644 --- a/Core/automation/lib/javascript/core/actions.js +++ b/Core/automation/lib/javascript/core/actions.js @@ -1,13 +1,17 @@ 'use strict'; +// START: Backward Compatibility Header +load(Java.type("java.lang.System").getenv("OPENHAB_CONF")+'/automation/lib/javascript/core/init.js'); +// END: Backward Compatibility Header + + (function(context) { 'use strict'; + + var osgi = require('osgi'); - var OPENHAB_CONF = Java.type("java.lang.System").getenv("OPENHAB_CONF"); - load(OPENHAB_CONF + '/automation/lib/javascript/core/osgi.js'); - - var oh1_actions = find_services("org.openhab.core.scriptengine.action.ActionService", null) || []; - var oh2_actions = find_services("org.eclipse.smarthome.model.script.engine.action.ActionService", null) || []; + var oh1_actions = osgi.find_services("org.openhab.core.scriptengine.action.ActionService", null) || []; + var oh2_actions = osgi.find_services("org.eclipse.smarthome.model.script.engine.action.ActionService", null) || []; oh1_actions.concat(oh2_actions).forEach(function (item, index) { context[item.actionClass.simpleName] = item.actionClass.static; @@ -33,4 +37,12 @@ context[item.class.simpleName] = item.class.static; }); -})(this); +})(exports); + +// START: Backward Compatibility Footer +if (typeof ___INIT_STATE___ === 'undefined') { + for (var k in exports) { + this[k] = exports[k]; + } +} +// END: Backward Compatibility Footer \ No newline at end of file diff --git a/Core/automation/lib/javascript/core/conditions.js b/Core/automation/lib/javascript/core/conditions.js index 86833521..d1da8b0d 100644 --- a/Core/automation/lib/javascript/core/conditions.js +++ b/Core/automation/lib/javascript/core/conditions.js @@ -7,6 +7,11 @@ */ 'use strict'; +// START: Backward Compatibility Header +load(Java.type("java.lang.System").getenv("OPENHAB_CONF")+'/automation/lib/javascript/core/init.js'); +// END: Backward Compatibility Header + + scriptExtension.importPreset("RuleSupport"); // Get Triggers and Conditions module output @@ -15,20 +20,25 @@ scriptExtension.importPreset("RuleSupport"); // Examles: // see: org.eclipse.smarthome.automation.sample.extension.java.internal.WelcomeHomeRulesProvider.createLightsRule() -if(ModuleBuilder == undefined)var ModuleBuilder = Java.type("org.eclipse.smarthome.automation.core.util.ModuleBuilder"); + try { + exports.ModuleBuilder = Java.type("org.eclipse.smarthome.automation.core.util.ModuleBuilder"); + } catch(e) { + exports.ModuleBuilder = Java.type("org.openhab.core.automation.util.ModuleBuilder"); + } + // ### stateCondition ### -var ItemStateCondition = function(itemName, state, condName){ +exports.ItemStateCondition = function(itemName, state, condName){ return ModuleBuilder.createCondition().withId(getTrName(condName)).withTypeUID("core.ItemStateCondition").withConfiguration( new Configuration({ "itemName": itemName, "operator": "=", "state": state })).build(); } -var stateCondition = ItemStateCondition; +exports.stateCondition = exports.ItemStateCondition; // ### GenericCompareCondition ### -var GenericCompareCondition = function(itemName, state, operator, condName){ +exports.GenericCompareCondition = function(itemName, state, operator, condName){ return ModuleBuilder.createCondition().withId(getTrName(condName)).withTypeUID("core.GenericCompareCondition").withConfiguration( new Configuration({ "itemName": itemName, "operator": operator,// matches, ==, <, >, =<, => @@ -36,4 +46,12 @@ var GenericCompareCondition = function(itemName, state, operator, condName){ })).build(); } //compareCondition("itemName", OFF, "==", "condNameOfCompareCondition") -var compareCondition = GenericCompareCondition; +exports.compareCondition = exports.GenericCompareCondition; + +// START: Backward Compatibility Footer +if (typeof ___INIT_STATE___ === 'undefined') { + for (var k in exports) { + this[k] = exports[k]; + } +} +// END: Backward Compatibility Footer \ No newline at end of file diff --git a/Core/automation/lib/javascript/core/init.js b/Core/automation/lib/javascript/core/init.js new file mode 100644 index 00000000..8aaed3b1 --- /dev/null +++ b/Core/automation/lib/javascript/core/init.js @@ -0,0 +1,120 @@ +var exports = {}; +var module = {}; + +(function (context) { + 'use strict'; + + var OPENHAB_CONF = Java.type("java.lang.System").getenv("OPENHAB_CONF"); + + var buildEngine = function (){ + var ScriptEngineManager = Java.type('javax.script.ScriptEngineManager'); + var factory = new ScriptEngineManager(); + return factory.getEngineByName("JS"); + }; + + var engine = buildEngine(); + + //(Java)Log - don't depend on standard logging as it depends on the init system + var jLog = Java.type("org.slf4j.LoggerFactory").getLogger("jsr223.javascript.init") + + var init_state = (function(){ + if (typeof ___INIT_STATE___ === 'undefined') { + jLog.debug("Created init runtime") + return { + require_stack: [], + loaded_modules: {} + }; + } else { + return ___INIT_STATE___; + } + })(); + + + var newContext = function (engine) { + var SimpleScriptContext = Java.type('javax.script.SimpleScriptContext'); + var ScriptContext = Java.type('javax.script.ScriptContext'); + + var ctx = new SimpleScriptContext(); + ctx.setBindings(engine.createBindings(), ScriptContext.ENGINE_SCOPE); + ctx.setAttribute("scriptExtension", scriptExtension, ScriptContext.ENGINE_SCOPE); + ctx.setAttribute("exports", exports, ScriptContext.ENGINE_SCOPE); + ctx.setAttribute("module", module, ScriptContext.ENGINE_SCOPE); + ctx.setAttribute("___INIT_STATE___", init_state, ScriptContext.ENGINE_SCOPE); + + return ctx; + }; + + var scriptTemplate = function (id, dir) { + return 'load(Java.type("java.lang.System").getenv("OPENHAB_CONF")+"/automation/lib/javascript/core/init.js");\n' + + 'load("' + OPENHAB_CONF + '/automation/lib/javascript/' + dir + "/" + id + '.js");'; + }; + + var doLoad = function(id) { + var ctx = newContext(engine); + + try { //allow personal to override modules + engine.eval(scriptTemplate(id, "personal"), ctx); + jLog.debug("loaded personal script " + id); + } catch (e) { + if (e.toString().startsWith("javax.script.ScriptException: TypeError: Cannot load script from")) { //script not there; warn only + jLog.debug("No script named " + id + " in personal; falling back to core"); + } else { + jLog.error("Error loading " + id + ": " + e); + } + engine.eval(scriptTemplate(id, "core"), ctx); + jLog.debug("loaded core script " + id); + } + + exports = ctx.getAttribute("exports"); + jLog.debug("retrieved exports: " + Object.keys(exports)); + }; + + context.require = function require(id) { + + jLog.debug("Attempting to retreive module " + id); + + // if currently requiring module 'id', return partial exports + if (init_state.require_stack.indexOf(id) >= 0) { + jLog.debug("Currently requiring module " + require_stack[require_stack.length-1] + ", returning partial exports"); + return init_state.loaded_modules[id].exports; + } + + // if already required module 'id', return finished exports + if (init_state.loaded_modules[id] && init_state.loaded_modules[id].exports) { + jLog.debug("Module already loaded; returning cached version"); + return init_state.loaded_modules[id].exports; + } + + // do the require of module 'id' + // - if currently requiring a module, push global exports/module objects into arguments.callee.modules + if (init_state.require_stack.length > 0) { + var currently_requiring_id = init_state.require_stack[require_stack.length - 1]; + init_state.loaded_modules[currently_requiring_id] = { + exports: exports, + module: module + }; + } + + init_state.require_stack.push(id); + + doLoad(id); + + init_state.loaded_modules[id] = { + exports: exports, + module: module + }; + init_state.require_stack.pop(); + + // restore last required modules' partial exports to the global space, or clear them + if (init_state.require_stack.length > 0) { + var currently_requiring_id = init_state.require_stack[init_state.require_stack.length - 1]; + exports = init_state.loaded_modules[currently_requiring_id].exports; + module = init_state.loaded_modules[currently_requiring_id].module; + } else { + exports = {}; + module = {}; + } + + return init_state.loaded_modules[id].exports; + } +})(this); \ No newline at end of file diff --git a/Core/automation/lib/javascript/core/metadata.js b/Core/automation/lib/javascript/core/metadata.js index 7815750b..2dbd98fb 100644 --- a/Core/automation/lib/javascript/core/metadata.js +++ b/Core/automation/lib/javascript/core/metadata.js @@ -4,6 +4,11 @@ This library provides functions for manipulating Item Metadata. 'use strict'; +// START: Backward Compatibility Header +load(Java.type("java.lang.System").getenv("OPENHAB_CONF")+'/automation/lib/javascript/core/init.js'); +// END: Backward Compatibility Header + + (function(context) { 'use strict'; @@ -242,4 +247,12 @@ This library provides functions for manipulating Item Metadata. } }; -})(this); +})(exports); + +// START: Backward Compatibility Footer +if (typeof ___INIT_STATE___ === 'undefined') { + for (var k in exports) { + this[k] = exports[k]; + } +} +// END: Backward Compatibility Footer \ No newline at end of file diff --git a/Core/automation/lib/javascript/core/osgi.js b/Core/automation/lib/javascript/core/osgi.js index 314ed3d4..b21da9b7 100644 --- a/Core/automation/lib/javascript/core/osgi.js +++ b/Core/automation/lib/javascript/core/osgi.js @@ -3,6 +3,10 @@ This library provides functions for getting, registering, unregistering, and finding OSGi services. */ +// START: Backward Compatibility Header +load(Java.type("java.lang.System").getenv("OPENHAB_CONF")+'/automation/lib/javascript/core/init.js'); +// END: Backward Compatibility Header + 'use strict'; (function(context) { @@ -65,4 +69,12 @@ finding OSGi services. } } -})(this); +})(exports); + +// START: Backward Compatibility Footer +if (typeof ___INIT_STATE___ === 'undefined') { + for (var k in exports) { + this[k] = exports[k]; + } +} +// END: Backward Compatibility Footer \ No newline at end of file diff --git a/Core/automation/lib/javascript/core/rules.js b/Core/automation/lib/javascript/core/rules.js index a1252206..f21e21f5 100644 --- a/Core/automation/lib/javascript/core/rules.js +++ b/Core/automation/lib/javascript/core/rules.js @@ -7,15 +7,18 @@ */ 'use strict'; +// START: Backward Compatibility Header +load(Java.type("java.lang.System").getenv("OPENHAB_CONF")+'/automation/lib/javascript/core/init.js'); +// END: Backward Compatibility Header + scriptExtension.importPreset("RuleSupport"); //https://www.openhab.org/docs/configuration/jsr223.html#overview scriptExtension.importPreset("RuleSimple"); scriptExtension.importPreset("RuleFactories"); scriptExtension.importPreset("default"); -var OPENHAB_CONF = Java.type("java.lang.System").getenv("OPENHAB_CONF"); -load(OPENHAB_CONF+'/automation/lib/javascript/core/utils.js'); -load(OPENHAB_CONF+'/automation/lib/javascript/core/triggers.js'); -load(OPENHAB_CONF+'/automation/lib/javascript/core/conditions.js'); +var utils = require('utils'); +var triggers = require('triggers'); +var conditions = require('conditions'); //https://docs.oracle.com/javase/8/docs/technotes/guides/scripting/nashorn/api.html //var StSimpleRule = Java.type("org.openhab.core.automation.module.script.rulesupport.shared.simple.SimpleRule"); @@ -82,19 +85,21 @@ return RuleBuilder.create(ruleDto.uid) (function (context) { 'use strict'; + var log = require('log').Logger("jsr223.javascript"); + //FROM: https://community.openhab.org/t/port-jsr223-bundle-to-openhab-2/2633/171?u=lewie //Search ruleUID = filter(lambda rule: rule.name == "Alert: TV turn off timer alert", rules.getAll())[0].UID //ruleEngine.setEnabled(ruleUID, True)# enable rule //ruleEngine.setEnabled(ruleUID, False)# disable rule context.setEnabled = function (ruid, enable){ //enable rule - logInfo("################ setEnabled Line: "+__LINE__+" ################# ruid:" + ruid); + log.info("################ setEnabled Line: "+__LINE__+" ################# ruid:" + ruid); RuleManager.setEnabled(ruid, enable); } context.JSRule = function (obj, line) { try{ - var ruid = uuid.randomUUID() + "-" + obj.name.replace(/[^\w]/g, "-"); - logInfo("################ JSRule Line: "+__LINE__+" ################# ruid:" + ruid); + var ruid = utils.uuid.randomUUID() + "-" + obj.name.replace(/[^\w]/g, "-"); + log.info("################ JSRule Line: "+__LINE__+" ################# ruid:" + ruid); //var rule = new SimpleRule({ setUID: function(i) { uid = i; } }) var rule = new SimpleRule(){ execute: obj.execute //DOES THIS WORK? AND IF YES, WHY? => execute is found in implemented SimpleRuleActionHandler @@ -122,7 +127,7 @@ return RuleBuilder.create(ruleDto.uid) //2. OR second option, to add Rules in rulefile. Is not needed. return rule; }catch(err) { - context.logError("JSRule " + __LINE__ + ". obj: '" + obj + "' Error:" + err); + log.error("JSRule " + __LINE__ + ". obj: '" + obj + "' Error:" + err); } return null; }, @@ -131,10 +136,10 @@ return RuleBuilder.create(ruleDto.uid) // or org.openhab.core.automation.sample.extension.java.internal.WelcomeHomeRulesProvider //Missing SimpleRuleActionHandler!! context.JSRuleNew = function (obj, line) { - logInfo("################ JSRuleNew Line: "+__LINE__+" #################"); + log.info("################ JSRuleNew Line: "+__LINE__+" #################"); //2. OR second option, to add Rules in rulefile. Is not needed. var rname = obj.name ? obj.name.replace(/[^\w]/g, "-") : "nameless-generic"; - var ruid = obj.uid ? obj.uid : uuid.randomUUID() + "-" + rname; + var ruid = obj.uid ? obj.uid : utils.uuid.randomUUID() + "-" + rname; var triggers = obj.triggers ? obj.triggers : obj.getEventTrigger(); var execX = new SimpleRule(){execute: obj.execute};//Not good!! return RuleBuilder.create(ruid) @@ -152,4 +157,12 @@ return RuleBuilder.create(ruleDto.uid) .build(); } -}) (this); +}) (exports); + +// START: Backward Compatibility Footer +if (typeof ___INIT_STATE___ === 'undefined') { + for (var k in exports) { + this[k] = exports[k]; + } +} +// END: Backward Compatibility Footer \ No newline at end of file diff --git a/Core/automation/lib/javascript/core/triggers.js b/Core/automation/lib/javascript/core/triggers.js index 760dc873..7a9de604 100644 --- a/Core/automation/lib/javascript/core/triggers.js +++ b/Core/automation/lib/javascript/core/triggers.js @@ -5,7 +5,11 @@ * * @author Helmut Lehmeyer - initial contribution */ -'use strict'; +//'use strict'; + +// START: Backward Compatibility Header +load(Java.type("java.lang.System").getenv("OPENHAB_CONF")+'/automation/lib/javascript/core/init.js'); +// END: Backward Compatibility Header scriptExtension.importPreset("RuleSupport"); scriptExtension.importPreset("RuleFactories"); @@ -16,7 +20,16 @@ scriptExtension.importPreset("RuleFactories"); // Examles: // see: org.eclipse.smarthome.automation.sample.extension.java.internal.WelcomeHomeRulesProvider.createLightsRule() -if(ModuleBuilder == undefined)var ModuleBuilder = Java.type("org.eclipse.smarthome.automation.core.util.ModuleBuilder"); +(function(){ + + var utils = require('utils'); + + var ModuleBuilder; + try { + ModuleBuilder = Java.type("org.eclipse.smarthome.automation.core.util.ModuleBuilder"); + } catch(e) { + ModuleBuilder = Java.type("org.openhab.core.automation.util.ModuleBuilder"); + } //Handlers -> Used Strings for IDs now, so these classes not needed ///if(ChannelEventTriggerHandler == undefined)var ChannelEventTriggerHandler = Java.type("org.openhab.core.automation.internal.module.handler.ChannelEventTriggerHandler"); @@ -76,13 +89,13 @@ automationManager.addTriggerType(new TriggerType( automationManager.addTriggerHandler(STARTUP_MODULE_ID, _StartupTriggerHandlerFactory); */ -var StartupTrigger = function(triggerName){ +exports.StartupTrigger = function(triggerName){ //DOES NOT WORK - TODO: return new Trigger( getTrName(triggerName), "jsr223.StartupTrigger", new Configuration()); } // ### ChannelEventTriggerHandler ### // Works like: ChannelEventTrigger('astro:sun:local:rise#event', 'START') -var ChannelEventTrigger = function(channel, event, triggerName) { +exports.ChannelEventTrigger = function(channel, event, triggerName) { return ModuleBuilder.createTrigger().withId(getTrName(triggerName)).withTypeUID("core.ChannelEventTrigger").withConfiguration( new Configuration({ "channelUID": channel, "event": event @@ -90,59 +103,58 @@ var ChannelEventTrigger = function(channel, event, triggerName) { } // ### ChangedEventTrigger ### -var ItemStateChangeTrigger = function(itemName, oldState, newState, triggerName){ +exports.ItemStateChangeTrigger = function(itemName, oldState, newState, triggerName){ return ModuleBuilder.createTrigger().withId(getTrName(triggerName)).withTypeUID("core.ItemStateChangeTrigger").withConfiguration( new Configuration({ "itemName": itemName, "state": newState, "oldState": oldState })).build(); } -var ChangedEventTrigger = ItemStateChangeTrigger; +exports.ChangedEventTrigger = exports.ItemStateChangeTrigger; // ### UpdatedEventTrigger ### -var ItemStateUpdateTrigger = function(itemName, state, triggerName){ +exports.ItemStateUpdateTrigger = function(itemName, state, triggerName){ return ModuleBuilder.createTrigger().withId(getTrName(triggerName)).withTypeUID("core.ItemStateUpdateTrigger").withConfiguration( new Configuration({ "itemName": itemName, "state": state })).build(); } -var UpdatedEventTrigger = ItemStateUpdateTrigger; +exports.UpdatedEventTrigger = exports.ItemStateUpdateTrigger; // ### CommandEventTrigger ### -var ItemCommandTrigger = function(itemName, command, triggerName){ +exports.ItemCommandTrigger = function(itemName, command, triggerName){ //logWarn("#### ItemCommandTrigger "+__LINE__, triggerName); return ModuleBuilder.createTrigger().withId(getTrName(triggerName)).withTypeUID("core.ItemCommandTrigger").withConfiguration( new Configuration({ "itemName": itemName, "command": command })).build(); } -var CommandEventTrigger = ItemCommandTrigger; +exports.CommandEventTrigger = exports.ItemCommandTrigger; // ### TimerTrigger ### //!!!!!!!! timer.GenericCronTrigger !!!!!!!!!!!!! -var GenericCronTrigger = function(expression, triggerName){ +exports.GenericCronTrigger = function(expression, triggerName){ //logWarn("#### GenericCronTrigger "+__LINE__, expression, getTrName(triggerName), Trigger); // see: org.eclipse.smarthome.automation.sample.extension.java.internal.WelcomeHomeRulesProvider.createLightsRule() return ModuleBuilder.createTrigger().withId(getTrName(triggerName)).withTypeUID("timer.GenericCronTrigger").withConfiguration( new Configuration({ "cronExpression": expression })).build(); } -var TimerTrigger = GenericCronTrigger; - +exports.TimerTrigger = exports.GenericCronTrigger; // ### stateCondition ### -var ItemStateCondition = function(itemName, state, condName){ +exports.ItemStateCondition = function(itemName, state, condName){ return ModuleBuilder.createCondition().withId(getTrName(condName)).withTypeUID("core.ItemStateCondition").withConfiguration( new Configuration({ "itemName": itemName, "operator": "=", "state": state })).build(); } -var stateCondition = ItemStateCondition; +exports.stateCondition = exports.ItemStateCondition; // ### GenericCompareCondition ### -var GenericCompareCondition = function(itemName, state, operator, condName){ +exports.GenericCompareCondition = function(itemName, state, operator, condName){ return ModuleBuilder.createCondition().withId(getTrName(condName)).withTypeUID("core.GenericCompareCondition").withConfiguration( new Configuration({ "itemName": itemName, "operator": operator,// matches, ==, <, >, =<, => @@ -150,11 +162,22 @@ var GenericCompareCondition = function(itemName, state, operator, condName){ })).build(); } //compareCondition("itemName", OFF, "==", "condNameOfCompareCondition") -var compareCondition = GenericCompareCondition; +exports.compareCondition = exports.GenericCompareCondition; var getTrName = function(trn){ - return trn == undefined || trn == null || trn == "" ? uuid.randomUUID() + "-" + me.replace(/[^\w]/g, "-") : trn; + //TODO: replacement for 'me' + return trn == undefined || trn == null || trn == "" ? utils.uuid.randomUUID() : trn; //return trn == undefined || trn == null || trn == "" ? uuid.randomUUID() : trn; } + +})(); + +// START: Backward Compatibility Footer +if (typeof ___INIT_STATE___ === 'undefined') { + for (var k in exports) { + this[k] = exports[k]; + } +} +// END: Backward Compatibility Footer \ No newline at end of file diff --git a/Core/automation/lib/javascript/core/utils.js b/Core/automation/lib/javascript/core/utils.js index 0fc3e984..3061b0ad 100644 --- a/Core/automation/lib/javascript/core/utils.js +++ b/Core/automation/lib/javascript/core/utils.js @@ -7,68 +7,76 @@ */ 'use strict'; - var OPENHAB_CONF = Java.type("java.lang.System").getenv("OPENHAB_CONF"); - var automationPath = OPENHAB_CONF+'/automation/'; - var mainPath = automationPath + 'lib/javascript/core/'; - //https://wiki.shibboleth.net/confluence/display/IDP30/ScriptedAttributeDefinition - var logger = Java.type("org.slf4j.LoggerFactory").getLogger("jsr223.javascript"); - - try { - var RuleBuilder = Java.type("org.openhab.core.automation.util.RuleBuilder"); - } catch(e) { - var RuleBuilder = Java.type("org.eclipse.smarthome.automation.core.util.RuleBuilder"); - } - - try { - var RuleManager = Java.type("org.openhab.core.automation.RuleManager"); - } catch(e) { - var RuleManager = Java.type("org.eclipse.smarthome.automation.RuleManager"); - } +// START: Backward Compatibility Header +load(Java.type("java.lang.System").getenv("OPENHAB_CONF")+'/automation/lib/javascript/core/init.js'); +// END: Backward Compatibility Header - var uuid = Java.type("java.util.UUID"); - var ScriptExecution = Java.type("org.eclipse.smarthome.model.script.actions.ScriptExecution"); - var ScriptServiceUtil = Java.type("org.eclipse.smarthome.model.script.ScriptServiceUtil"); - var ExecUtil = Java.type("org.eclipse.smarthome.io.net.exec.ExecUtil"); - var HttpUtil = Java.type("org.eclipse.smarthome.io.net.http.HttpUtil"); - - - //Other - var Modifier = Java.type("java.lang.reflect.Modifier"); - var InputStream = Java.type("java.io.InputStream"); - var IOUtils = Java.type("org.apache.commons.io.IOUtils"); - - //Types - /* included in "default" preset - var UnDefType = Java.type("org.eclipse.smarthome.core.types.UnDefType"); - var StringListType = Java.type("org.eclipse.smarthome.core.library.types.StringListType"); - var RawType = Java.type("org.eclipse.smarthome.core.library.types.RawType"); - var RewindFastforwardType = Java.type("org.eclipse.smarthome.core.library.types.RewindFastforwardType"); - var PlayPauseType = Java.type("org.eclipse.smarthome.core.library.types.PlayPauseType"); - var NextPreviousType = Java.type("org.eclipse.smarthome.core.library.types.NextPreviousType"); - */ - - //Time JAVA 7 joda - var DateTime = Java.type("org.joda.time.DateTime"); - //Time JAVA 8 - var LocalDate = Java.type("java.time.LocalDate"); - var LocalDateTime = Java.type("java.time.LocalDateTime"); - var FormatStyle = Java.type("java.time.format.FormatStyle"); - var DateTimeFormatter = Java.type("java.time.format.DateTimeFormatter");//https://www.programcreek.com/java-api-examples/?class=java.time.format.DateTimeFormatter&method=ofLocalizedDateTime - var LocalTime = Java.type("java.time.LocalTime"); - var Month = Java.type("java.time.Month"); - var ZoneOffset = Java.type("java.time.ZoneOffset"); - var ZoneId = Java.type("java.time.ZoneId"); - var OffsetDateTime = Java.type("java.time.OffsetDateTime"); - - var Timer = Java.type('java.util.Timer'); - //var QuartzScheduler = Java.type("org.quartz.core.QuartzScheduler"); - load( mainPath + '/PersistenceExtensions.js'); - (function(context) { 'use strict'; + + var OPENHAB_CONF = Java.type("java.lang.System").getenv("OPENHAB_CONF"); + var automationPath = OPENHAB_CONF+'/automation/'; + var mainPath = automationPath + 'lib/javascript/core/'; + //https://wiki.shibboleth.net/confluence/display/IDP30/ScriptedAttributeDefinition + var logger = Java.type("org.slf4j.LoggerFactory").getLogger("jsr223.javascript"); + +//TODO: migrate to CommonJS +load( mainPath + '/PersistenceExtensions.js'); + + try { + context.RuleBuilder = Java.type("org.openhab.core.automation.util.RuleBuilder"); + } catch(e) { + context.RuleBuilder = Java.type("org.eclipse.smarthome.automation.core.util.RuleBuilder"); + } + + try { + context.RuleManager = Java.type("org.openhab.core.automation.RuleManager"); + } catch(e) { + context.RuleManager = Java.type("org.eclipse.smarthome.automation.RuleManager"); + } + + context.uuid = Java.type("java.util.UUID"); + context.ScriptExecution = Java.type("org.eclipse.smarthome.model.script.actions.ScriptExecution"); + context.ScriptServiceUtil = Java.type("org.eclipse.smarthome.model.script.ScriptServiceUtil"); + context.ExecUtil = Java.type("org.eclipse.smarthome.io.net.exec.ExecUtil"); + context.HttpUtil = Java.type("org.eclipse.smarthome.io.net.http.HttpUtil"); + + + //Other + context.Modifier = Java.type("java.lang.reflect.Modifier"); + context.InputStream = Java.type("java.io.InputStream"); + context.IOUtils = Java.type("org.apache.commons.io.IOUtils"); + + + //Types + /* included in "default" preset + var UnDefType = Java.type("org.eclipse.smarthome.core.types.UnDefType"); + var StringListType = Java.type("org.eclipse.smarthome.core.library.types.StringListType"); + var RawType = Java.type("org.eclipse.smarthome.core.library.types.RawType"); + var RewindFastforwardType = Java.type("org.eclipse.smarthome.core.library.types.RewindFastforwardType"); + var PlayPauseType = Java.type("org.eclipse.smarthome.core.library.types.PlayPauseType"); + var NextPreviousType = Java.type("org.eclipse.smarthome.core.library.types.NextPreviousType"); + */ + + //Time JAVA 7 joda + context.DateTime = Java.type("org.joda.time.DateTime"); + //Time JAVA 8 + context.LocalDate = Java.type("java.time.LocalDate"); + context.LocalDateTime = Java.type("java.time.LocalDateTime"); + context.FormatStyle = Java.type("java.time.format.FormatStyle"); + context.DateTimeFormatter = Java.type("java.time.format.DateTimeFormatter");//https://www.programcreek.com/java-api-examples/?class=java.time.format.DateTimeFormatter&method=ofLocalizedDateTime + context.LocalTime = Java.type("java.time.LocalTime"); + context.Month = Java.type("java.time.Month"); + context.ZoneOffset = Java.type("java.time.ZoneOffset"); + context.ZoneId = Java.type("java.time.ZoneId"); + context.OffsetDateTime = Java.type("java.time.OffsetDateTime"); + + context.Timer = Java.type('java.util.Timer'); + + context.automationPath = automationPath; context.mainPath = mainPath; @@ -84,9 +92,7 @@ context.NEXT = NextPreviousType.NEXT; context.PREVIOUS = NextPreviousType.PREVIOUS; */ - - context.uuid = uuid; - + context.logInfo = function(type , value) { logger.info(args(arguments)); }; @@ -444,7 +450,7 @@ * sendHttpDeleteRequest(String url, int timeout) */ - context.HttpUtil = HttpUtil; + //context.HttpUtil = HttpUtil; //sendHttpGetRequest(String url): Sends an GET-HTTP request and returns the result as a String context.sendHttpGetRequest = function(url, timeout) { //logInfo("arguments = " + arguments, arguments.length); @@ -569,8 +575,16 @@ if (v instanceof Function) { return true; } - return false + return false; }; -})(this); +})(exports); + +// START: Backward Compatibility Footer +if (typeof ___INIT_STATE___ === 'undefined') { + for (var k in exports) { + this[k] = exports[k]; + } +} +// END: Backward Compatibility Footer \ No newline at end of file diff --git a/Core/automation/lib/javascript/modules/actions.js b/Core/automation/lib/javascript/modules/actions.js new file mode 100644 index 00000000..17dfd2b4 --- /dev/null +++ b/Core/automation/lib/javascript/modules/actions.js @@ -0,0 +1,39 @@ +'use strict'; + +//CommonJS +load(Java.type("java.lang.System").getenv("OPENHAB_CONF")+'/automation/lib/javascript/personal/loader.js'); + + +(function(context) { + 'use strict'; + + var osgi = require('osgi'); + + var oh1_actions = osgi.find_services("org.openhab.core.scriptengine.action.ActionService", null) || []; + var oh2_actions = osgi.find_services("org.eclipse.smarthome.model.script.engine.action.ActionService", null) || []; + + oh1_actions.concat(oh2_actions).forEach(function (item, index) { + context[item.actionClass.simpleName] = item.actionClass.static; + }); + + try { + var Exec = Java.type('org.openhab.core.model.script.actions.Exec'); + var HTTP = Java.type('org.openhab.core.model.script.actions.HTTP'); + var LogAction = Java.type('org.openhab.core.model.script.actions.LogAction'); + var Ping = Java.type('org.openhab.core.model.script.actions.Ping'); + var ScriptExecution = Java.type('org.openhab.core.model.script.actions.ScriptExecution'); + } catch(e) { + var Exec = Java.type('org.eclipse.smarthome.model.script.actions.Exec'); + var HTTP = Java.type('org.eclipse.smarthome.model.script.actions.HTTP'); + var LogAction = Java.type('org.eclipse.smarthome.model.script.actions.LogAction'); + var Ping = Java.type('org.eclipse.smarthome.model.script.actions.Ping'); + var ScriptExecution = Java.type('org.eclipse.smarthome.model.script.actions.ScriptExecution'); + } + + var static_imports = [Exec, HTTP, LogAction, Ping] + + static_imports.forEach(function (item, index) { + context[item.class.simpleName] = item.class.static; + }); + +})(exports); diff --git a/Core/automation/lib/javascript/modules/conditions.js b/Core/automation/lib/javascript/modules/conditions.js new file mode 100644 index 00000000..371f58e1 --- /dev/null +++ b/Core/automation/lib/javascript/modules/conditions.js @@ -0,0 +1,44 @@ +/** + * Functions for creating Conditions + * + * Copyright (c) 2019 Contributors to the openHAB Scripters project + * + * @author Helmut Lehmeyer - initial contribution + */ +'use strict'; + +scriptExtension.importPreset("RuleSupport"); + +// Get Triggers and Conditions module output +// http://localhost:8080/rest/module-types + +// Examles: +// see: org.eclipse.smarthome.automation.sample.extension.java.internal.WelcomeHomeRulesProvider.createLightsRule() + + try { + exports.ModuleBuilder = Java.type("org.eclipse.smarthome.automation.core.util.ModuleBuilder"); + } catch(e) { + exports.ModuleBuilder = Java.type("org.openhab.core.automation.util.ModuleBuilder"); + } + + +// ### stateCondition ### +exports.ItemStateCondition = function(itemName, state, condName){ + return ModuleBuilder.createCondition().withId(getTrName(condName)).withTypeUID("core.ItemStateCondition").withConfiguration( new Configuration({ + "itemName": itemName, + "operator": "=", + "state": state + })).build(); +} +exports.stateCondition = exports.ItemStateCondition; + +// ### GenericCompareCondition ### +exports.GenericCompareCondition = function(itemName, state, operator, condName){ + return ModuleBuilder.createCondition().withId(getTrName(condName)).withTypeUID("core.GenericCompareCondition").withConfiguration( new Configuration({ + "itemName": itemName, + "operator": operator,// matches, ==, <, >, =<, => + "state": state + })).build(); +} +//compareCondition("itemName", OFF, "==", "condNameOfCompareCondition") +exports.compareCondition = exports.GenericCompareCondition; diff --git a/Core/automation/lib/javascript/modules/loader.js b/Core/automation/lib/javascript/modules/loader.js new file mode 100644 index 00000000..469ac9d0 --- /dev/null +++ b/Core/automation/lib/javascript/modules/loader.js @@ -0,0 +1,64 @@ +var exports = {}; +var module = {}; + +(function(context) { + //'use strict'; + + var OPENHAB_CONF = Java.type("java.lang.System").getenv("OPENHAB_CONF"); + + +context.require = function require(id) { + if ( 'undefined' === typeof arguments.callee.require_stack ) { arguments.callee.require_stack = []; } + var require_stack = arguments.callee.require_stack; + if ( 'undefined' === typeof arguments.callee.modules ) { arguments.callee.modules = {}; } + var modules = arguments.callee.modules; + + // if currently requiring module 'id', return partial exports + if ( require_stack.indexOf(id) >= 0 ) { + return modules[id].exports; + } + + // if already required module 'id', return finished exports + if ( modules[id] && modules[id].exports ) { + return modules[id].exports; + } + + // do the require of module 'id' + // - if currently requiring a module, push global exports/module objects into arguments.callee.modules + if ( require_stack.length > 0 ) { + var currently_requiring_id = require_stack[require_stack.length - 1]; + modules[currently_requiring_id] = { + exports: exports, + module: module + }; + } + + //Java.type("org.slf4j.LoggerFactory").getLogger("loader").error("loading " + id); + + require_stack.push(id); + exports = {}; + module = {}; + load(OPENHAB_CONF+'/automation/lib/javascript/modules/' + id + '.js'); + modules[id] = { + exports: exports, + module: module + }; + require_stack.pop(); + + //Java.type("org.slf4j.LoggerFactory").getLogger("loader").error("loaded " + JSON.stringify(exports)); + + + // restore last required modules' partial exports to the global space, or clear them + if ( require_stack.length > 0 ) { + var currently_requiring_id = require_stack[require_stack.length - 1]; + exports = modules[currently_requiring_id].exports; + module = modules[currently_requiring_id].module; + } else { + exports = {}; + module = {}; + } + + // return arguments.callee.modules[id].exports; + return arguments.callee.modules[id].exports; +} +})(this); \ No newline at end of file diff --git a/Core/automation/lib/javascript/modules/logutil.js b/Core/automation/lib/javascript/modules/logutil.js new file mode 100644 index 00000000..a662ab82 --- /dev/null +++ b/Core/automation/lib/javascript/modules/logutil.js @@ -0,0 +1,23 @@ +exports = { + createLogger: function(name) { + return Java.type("org.slf4j.LoggerFactory").getLogger(name); + }, + logAtLevel: function(logger, level, message) { + switch(level.toUpperCase()) { + case 'DEBUG': + logger.debug(message); + break; + case 'INFO': + logger.info(message); + break; + case 'WARN': + logger.warn(message); + break; + case 'ERROR': + logger.error(message); + break; + default: + logger.error("Failed to log at level " + level); + } + } +} \ No newline at end of file diff --git a/Core/automation/lib/javascript/modules/osgi.js b/Core/automation/lib/javascript/modules/osgi.js new file mode 100644 index 00000000..2605cdc0 --- /dev/null +++ b/Core/automation/lib/javascript/modules/osgi.js @@ -0,0 +1,68 @@ +/* +This library provides functions for getting, registering, unregistering, and +finding OSGi services. +*/ + +'use strict'; + +(function(context) { + 'use strict'; + + var FrameworkUtil = Java.type("org.osgi.framework.FrameworkUtil"); + + var _bundle = FrameworkUtil.getBundle(scriptExtension.class); + var bundle_context = (_bundle !== null) ? _bundle.getBundleContext() : null; + var registered_services = []; + + context.get_service = function(class_or_name) { + if (bundle_context !== null) { + var classname = (typeof class_or_name === "object") ? class_or_name.getName() : class_or_name; + var ref = bundle_context.getServiceReference(classname); + return (ref !== null) ? bundle_context.getService(ref) : null; + } + } + + context.find_services = function(class_name, filter) { + if (bundle_context !== null) { + var refs = bundle_context.getAllServiceReferences(class_name, filter); + if (refs !== null) { + var services = []; + for (var i = 0, size = refs.length; i < size ; i++) { + services.push(bundle_context.getService(refs[i])); + } + return services; + } + } + } + + context.register_service = function(service, interface_names, properties) { + if (properties !== null) { + var util = Java.type("java.util"); + p = util.Hashtable(); + for (var i = 0, size = properties.length; i < size ; i++) { + p.put(k, v); + } + properties = p; + } + else { + properties = null; + } + var reg = bundle_context.registerService(interface_names, service, properties); + for (var i = 0, size = interface_names.length; i < size ; i++) { + registered_services[name] = (service, reg); + } + return reg; + } + + context.unregister_service = function(service) { + var keys = registered_services.keys(); + for (var i = 0, size = keys.length; i < size ; i++) { + var registered_service, reg = registered_services[key]; + if (service == registered_service) { + registered_services.splice(i, keys[i]); + reg.unregister(); + } + } + } + +})(exports); diff --git a/Core/automation/lib/javascript/modules/rules.js b/Core/automation/lib/javascript/modules/rules.js new file mode 100644 index 00000000..064f141c --- /dev/null +++ b/Core/automation/lib/javascript/modules/rules.js @@ -0,0 +1,157 @@ +/** + * Functions for creating rules + * + * Copyright (c) 2019 Contributors to the openHAB Scripters project + * + * @author Helmut Lehmeyer - initial contribution + */ +'use strict'; + +scriptExtension.importPreset("RuleSupport"); //https://www.openhab.org/docs/configuration/jsr223.html#overview +scriptExtension.importPreset("RuleSimple"); +scriptExtension.importPreset("RuleFactories"); +scriptExtension.importPreset("default"); + +var utils = require('utils'); +var triggers = require('triggers'); +var conditions = require('conditions'); +var logutil = require('logutil'); + +//https://docs.oracle.com/javase/8/docs/technotes/guides/scripting/nashorn/api.html +//var StSimpleRule = Java.type("org.openhab.core.automation.module.script.rulesupport.shared.simple.SimpleRule"); +//var StSimpleRuleExt = new StSimpleRule(); +//var ExtendedSimpleRule = Java.extend(SimpleRule, { +// setUID: function(i) { +// //print("Run in separate thread"); +// this.uid = i; +// } +//}); +//var Thread = Java.type("java.lang.Thread"); +//var th = new Thread(new MyRun()); + + +//if(RuleBuilder == undefined)var RuleBuilder = Java.type("org.openhab.core.automation.core.util.RuleBuilder"); + +/* + +if(RuleBuilder == undefined)var RuleBuilder = Java.type("org.openhab.core.automation.core.util.RuleBuilder"); + +In future better do it by org.openhab.core.automation.core.util.RuleBuilder like in +org.openhab.core.automation.core.dto.RuleDTOMapper Don't know +return RuleBuilder.create(ruleDto.uid) + .withActions(ActionDTOMapper.mapDto(ruleDto.actions)) + .withConditions(ConditionDTOMapper.mapDto(ruleDto.conditions)) + .withTriggers(TriggerDTOMapper.mapDto(ruleDto.triggers)) + .withConfiguration(new Configuration(ruleDto.configuration)) + .withConfigurationDescriptions(ConfigDescriptionDTOMapper.map(ruleDto.configDescriptions)) + .withTemplateUID(ruleDto.templateUID) + .withVisibility(ruleDto.visibility) + .withTags(ruleDto.tags) + .withName(ruleDto.name) + .withDescription(ruleDto.description).build(); + +// UNTESTED UNTESTED UNTESTED +//Simplifies spelling for rules. +(function(context) { + 'use strict'; + + context.JSRuleNew = function(obj) { + //logInfo("################ JSRule Line: "+__LINE__+" #################"); + //2. OR second option, to add Rules in rulefile. Is not needed. + var triggers = obj.triggers ? obj.triggers : obj.getEventTrigger(); + return RuleBuilder.create( obj.uid ? obj.uid : uuid.randomUUID()+me.replace(/[^\w]/g, "-")) + .withActions( obj.actions ? obj.actions : null) + .withConditions( obj.conditions ? obj.conditions : null) + .withTriggers( triggers && triggers.length > 0 ? triggers : null) + .withConfiguration(new Configuration(ruleDto.configuration)) + .withConfigurationDescriptions( obj.configurationDescription ? [obj.configurationDescription] : null) + .withTemplateUID( obj.templateUID ? obj.templateUID : null) + .withVisibility( obj.visibility ? obj.visibility : null) + .withTags( obj.tags ? obj.tags : null) + .withName( obj.name ? obj.name : null) + .withDescription(obj.description ? obj.description : null) + .build(); + }; + + })(this); +// UNTESTED UNTESTED UNTESTED +*/ + + +//Simplifies spelling for rules. +(function (context) { + 'use strict'; + + var log = logutil.createLogger("jsr223.javascript"); + + //FROM: https://community.openhab.org/t/port-jsr223-bundle-to-openhab-2/2633/171?u=lewie + //Search ruleUID = filter(lambda rule: rule.name == "Alert: TV turn off timer alert", rules.getAll())[0].UID + //ruleEngine.setEnabled(ruleUID, True)# enable rule + //ruleEngine.setEnabled(ruleUID, False)# disable rule + context.setEnabled = function (ruid, enable){ //enable rule + log.info("################ setEnabled Line: "+__LINE__+" ################# ruid:" + ruid); + RuleManager.setEnabled(ruid, enable); + } + + context.JSRule = function (obj, line) { + try{ + var ruid = utils.uuid.randomUUID() + "-" + obj.name.replace(/[^\w]/g, "-"); + log.info("################ JSRule Line: "+__LINE__+" ################# ruid:" + ruid); + //var rule = new SimpleRule({ setUID: function(i) { uid = i; } }) + var rule = new SimpleRule(){ + execute: obj.execute //DOES THIS WORK? AND IF YES, WHY? => execute is found in implemented SimpleRuleActionHandler + }; + var triggers = obj.triggers ? obj.triggers : obj.getEventTrigger(); + + rule.setTemplateUID(ruid); + + if (obj.description) { + rule.setDescription(obj.description); + } + if (obj.name) { + rule.setName(obj.name); + } + + //1. Register rule here + if (triggers && triggers.length > 0) { + rule.setTriggers(triggers); + automationManager.addRule(rule); + } + + //rule.setUID( ruid); //I must not set... :-( + //logInfo("################ JSRule Line: "+__LINE__+" ################# getUid:" + rule.getUID()); + //logInfo("################ JSRule Line: "+__LINE__+" ################# templateUID:" + rule.getTemplateUID()); + //2. OR second option, to add Rules in rulefile. Is not needed. + return rule; + }catch(err) { + log.error("JSRule " + __LINE__ + ". obj: '" + obj + "' Error:" + err); + } + return null; + }, + + //TODO like in org.openhab.core.automation.core.dto.RuleDTOMapper + // or org.openhab.core.automation.sample.extension.java.internal.WelcomeHomeRulesProvider + //Missing SimpleRuleActionHandler!! + context.JSRuleNew = function (obj, line) { + log.info("################ JSRuleNew Line: "+__LINE__+" #################"); + //2. OR second option, to add Rules in rulefile. Is not needed. + var rname = obj.name ? obj.name.replace(/[^\w]/g, "-") : "nameless-generic"; + var ruid = obj.uid ? obj.uid : utils.uuid.randomUUID() + "-" + rname; + var triggers = obj.triggers ? obj.triggers : obj.getEventTrigger(); + var execX = new SimpleRule(){execute: obj.execute};//Not good!! + return RuleBuilder.create(ruid) + .withActions(execX.getActions() ? execX.getActions() : null) + //.withActions(obj.execute ? [obj.execute] : null) //org.openhab.core.automation.module.script.rulesupport.shared.ScriptedAutomationManager L164 + ////.withConditions(obj.conditions ? obj.conditions : []) + .withTriggers(triggers && triggers.length > 0 ? triggers : null) + //.withConfiguration(new Configuration(obj.configuration)) + //.withConfigurationDescriptions(obj.configurationDescription ? [obj.configurationDescription] : null) + //.withTemplateUID(obj.templateUID ? obj.templateUID : ruid) + .withVisibility(obj.visibility ? obj.visibility : null) + //.withTags(obj.tags ? obj.tags : null) + .withName(obj.name ? obj.name : null) + .withDescription(obj.description ? obj.description : null) + .build(); + } + +}) (exports); diff --git a/Core/automation/lib/javascript/modules/test.js b/Core/automation/lib/javascript/modules/test.js new file mode 100644 index 00000000..e3b14204 --- /dev/null +++ b/Core/automation/lib/javascript/modules/test.js @@ -0,0 +1 @@ +exports.test = "ok!" \ No newline at end of file diff --git a/Core/automation/lib/javascript/modules/triggers.js b/Core/automation/lib/javascript/modules/triggers.js new file mode 100644 index 00000000..707ce442 --- /dev/null +++ b/Core/automation/lib/javascript/modules/triggers.js @@ -0,0 +1,171 @@ +/** + * Functions for creating Triggers + * + * Copyright (c) 2019 Contributors to the openHAB Scripters project + * + * @author Helmut Lehmeyer - initial contribution + */ +//'use strict'; + +scriptExtension.importPreset("RuleSupport"); +scriptExtension.importPreset("RuleFactories"); + +// Get Triggers and Conditions module output +// http://localhost:8080/rest/module-types + +// Examles: +// see: org.eclipse.smarthome.automation.sample.extension.java.internal.WelcomeHomeRulesProvider.createLightsRule() + +(function(){ + + var utils = require('utils'); + + var ModuleBuilder; + try { + ModuleBuilder = Java.type("org.eclipse.smarthome.automation.core.util.ModuleBuilder"); + } catch(e) { + ModuleBuilder = Java.type("org.openhab.core.automation.util.ModuleBuilder"); + } + +//Handlers -> Used Strings for IDs now, so these classes not needed +///if(ChannelEventTriggerHandler == undefined)var ChannelEventTriggerHandler = Java.type("org.openhab.core.automation.internal.module.handler.ChannelEventTriggerHandler"); +///if(CompareConditionHandler == undefined)var CompareConditionHandler = Java.type("org.openhab.core.automation.internal.module.handler.CompareConditionHandler"); +/////if(GenericEventConditionHandler == undefined)var GenericEventConditionHandler = Java.type("org.openhab.core.automation.internal.module.handler.GenericEventConditionHandler"); +/////if(GenericEventTriggerHandler == undefined)var GenericEventTriggerHandler = Java.type("org.openhab.core.automation.internal.module.handler.GenericEventTriggerHandler"); +/////if(ItemCommandActionHandler == undefined)var ItemCommandActionHandler = Java.type("org.openhab.core.automation.internal.module.handler.ItemCommandActionHandler"); +///if(ItemCommandTriggerHandler == undefined)var ItemCommandTriggerHandler = Java.type("org.openhab.core.automation.internal.module.handler.ItemCommandTriggerHandler"); +///if(ItemStateConditionHandler == undefined)var ItemStateConditionHandler = Java.type("org.openhab.core.automation.internal.module.handler.ItemStateConditionHandler"); +///if(ItemStateTriggerHandler == undefined)var ItemStateTriggerHandler = Java.type("org.openhab.core.automation.internal.module.handler.ItemStateTriggerHandler"); +/////if(RuleEnablementActionHandler == undefined)var RuleEnablementActionHandler = Java.type("org.openhab.core.automation.internal.module.handler.RuleEnablementActionHandler"); +/////if(RunRuleActionHandler == undefined)var RunRuleActionHandler = Java.type("org.openhab.core.automation.internal.module.handler.RunRuleActionHandler"); +/////if(DayOfWeekConditionHandler == undefined)var DayOfWeekConditionHandler = Java.type("org.openhab.core.automation.internal.module.handler.DayOfWeekConditionHandler"); +///if(GenericCronTriggerHandler == undefined)var GenericCronTriggerHandler = Java.type("org.openhab.core.automation.internal.module.handler.GenericCronTriggerHandler"); +/////if(TimeOfDayTriggerHandler == undefined)var TimeOfDayTriggerHandler = Java.type("org.openhab.core.automation.internal.module.handler.TimeOfDayTriggerHandler"); + +// ### StartupTrigger ### DOES NOT WORK!! TODO?! +/* +//if(Visibility == undefined)var Visibility = Java.type("org.eclipse.smarthome.automation.Visibility");//RuleSimple preset includes this +if(HashSet == undefined)var HashSet = Java.type("java.util.HashSet"); +if(TriggerHandler == undefined)var TriggerHandler = Java.type("org.openhab.core.automation.handler.TriggerHandler"); +if(Trigger == undefined)var Trigger = Java.type("org.eclipse.smarthome.automation.Trigger"); + +var _StartupTriggerHandlerFactory = new TriggerHandlerFactory(){ + get: function(trigger){ + logWarn(" -#### #### #### #### #### get trigger "+__LINE__, trigger); + //return _StartupTriggerHandlerFactory.handler(trigger); + return new TriggerHandler(){ + setRuleEngineCallback: function(rule_engine_callback){ + logWarn(" -#### TriggerHandler setRuleEngineCallback "+__LINE__, " setRuleEngineCallback "); + rule_engine_callback.triggered(trigger, {}); + }, + dispose: function(){ + logWarn(" -#### TriggerHandler dispose "+__LINE__, " dispose "); + } + }; + }, + ungetHandler: function( module, ruleUID, handler){ + logWarn(" -#### ungetHandler "+__LINE__, module); + logWarn(" -#### ungetHandler "+__LINE__, ruleUID); + logWarn(" -#### ungetHandler "+__LINE__, handler); + }, + dispose: function(){ + logWarn(" -#### dispose "+__LINE__, " dispose "); + } +}; +var STARTUP_MODULE_ID = "jsr223.StartupTrigger"; + +automationManager.addTriggerType(new TriggerType( + STARTUP_MODULE_ID, + [], + "the rule is activated", + "Triggers when a rule is activated the first time", + new HashSet(), + Visibility.VISIBLE, + [])); + +automationManager.addTriggerHandler(STARTUP_MODULE_ID, _StartupTriggerHandlerFactory); +*/ +exports.StartupTrigger = function(triggerName){ + //DOES NOT WORK - TODO: return new Trigger( getTrName(triggerName), "jsr223.StartupTrigger", new Configuration()); +} + +// ### ChannelEventTriggerHandler ### +// Works like: ChannelEventTrigger('astro:sun:local:rise#event', 'START') +exports.ChannelEventTrigger = function(channel, event, triggerName) { + return ModuleBuilder.createTrigger().withId(getTrName(triggerName)).withTypeUID("core.ChannelEventTrigger").withConfiguration( new Configuration({ + "channelUID": channel, + "event": event + })).build(); +} + +// ### ChangedEventTrigger ### +exports.ItemStateChangeTrigger = function(itemName, oldState, newState, triggerName){ + return ModuleBuilder.createTrigger().withId(getTrName(triggerName)).withTypeUID("core.ItemStateChangeTrigger").withConfiguration( new Configuration({ + "itemName": itemName, + "state": newState, + "oldState": oldState + })).build(); +} +exports.ChangedEventTrigger = exports.ItemStateChangeTrigger; + + +// ### UpdatedEventTrigger ### +exports.ItemStateUpdateTrigger = function(itemName, state, triggerName){ + return ModuleBuilder.createTrigger().withId(getTrName(triggerName)).withTypeUID("core.ItemStateUpdateTrigger").withConfiguration( new Configuration({ + "itemName": itemName, + "state": state + })).build(); +} +exports.UpdatedEventTrigger = exports.ItemStateUpdateTrigger; + + +// ### CommandEventTrigger ### +exports.ItemCommandTrigger = function(itemName, command, triggerName){ + //logWarn("#### ItemCommandTrigger "+__LINE__, triggerName); + return ModuleBuilder.createTrigger().withId(getTrName(triggerName)).withTypeUID("core.ItemCommandTrigger").withConfiguration( new Configuration({ + "itemName": itemName, + "command": command + })).build(); +} +exports.CommandEventTrigger = exports.ItemCommandTrigger; + +// ### TimerTrigger ### +//!!!!!!!! timer.GenericCronTrigger !!!!!!!!!!!!! +exports.GenericCronTrigger = function(expression, triggerName){ + //logWarn("#### GenericCronTrigger "+__LINE__, expression, getTrName(triggerName), Trigger); // see: org.eclipse.smarthome.automation.sample.extension.java.internal.WelcomeHomeRulesProvider.createLightsRule() + return ModuleBuilder.createTrigger().withId(getTrName(triggerName)).withTypeUID("timer.GenericCronTrigger").withConfiguration( new Configuration({ + "cronExpression": expression + })).build(); +} +exports.TimerTrigger = exports.GenericCronTrigger; + +// ### stateCondition ### +exports.ItemStateCondition = function(itemName, state, condName){ + return ModuleBuilder.createCondition().withId(getTrName(condName)).withTypeUID("core.ItemStateCondition").withConfiguration( new Configuration({ + "itemName": itemName, + "operator": "=", + "state": state + })).build(); +} +exports.stateCondition = exports.ItemStateCondition; + +// ### GenericCompareCondition ### +exports.GenericCompareCondition = function(itemName, state, operator, condName){ + return ModuleBuilder.createCondition().withId(getTrName(condName)).withTypeUID("core.GenericCompareCondition").withConfiguration( new Configuration({ + "itemName": itemName, + "operator": operator,// matches, ==, <, >, =<, => + "state": state + })).build(); +} +//compareCondition("itemName", OFF, "==", "condNameOfCompareCondition") +exports.compareCondition = exports.GenericCompareCondition; + + + +var getTrName = function(trn){ + //TODO: replacement for 'me' + return trn == undefined || trn == null || trn == "" ? utils.uuid.randomUUID() : trn; + //return trn == undefined || trn == null || trn == "" ? uuid.randomUUID() : trn; +} + +})(); \ No newline at end of file diff --git a/Core/automation/lib/javascript/modules/utils.js b/Core/automation/lib/javascript/modules/utils.js new file mode 100644 index 00000000..71d7b053 --- /dev/null +++ b/Core/automation/lib/javascript/modules/utils.js @@ -0,0 +1,580 @@ +/** + * Utility functions and variables + * + * Copyright (c) 2019 Contributors to the openHAB Scripters project + * + * @author Helmut Lehmeyer - initial contribution + */ +'use strict'; + + + + + //var QuartzScheduler = Java.type("org.quartz.core.QuartzScheduler"); + +(function(context) { + 'use strict'; + + var OPENHAB_CONF = Java.type("java.lang.System").getenv("OPENHAB_CONF"); + var automationPath = OPENHAB_CONF+'/automation/'; + var mainPath = automationPath + 'lib/javascript/core/'; + //https://wiki.shibboleth.net/confluence/display/IDP30/ScriptedAttributeDefinition + var logger = Java.type("org.slf4j.LoggerFactory").getLogger("jsr223.javascript"); + +//TODO: migrate to CommonJS +load( mainPath + '/PersistenceExtensions.js'); + + try { + context.RuleBuilder = Java.type("org.openhab.core.automation.util.RuleBuilder"); + } catch(e) { + context.RuleBuilder = Java.type("org.eclipse.smarthome.automation.core.util.RuleBuilder"); + } + + try { + context.RuleManager = Java.type("org.openhab.core.automation.RuleManager"); + } catch(e) { + context.RuleManager = Java.type("org.eclipse.smarthome.automation.RuleManager"); + } + + context.uuid = Java.type("java.util.UUID"); + context.ScriptExecution = Java.type("org.eclipse.smarthome.model.script.actions.ScriptExecution"); + context.ScriptServiceUtil = Java.type("org.eclipse.smarthome.model.script.ScriptServiceUtil"); + context.ExecUtil = Java.type("org.eclipse.smarthome.io.net.exec.ExecUtil"); + context.HttpUtil = Java.type("org.eclipse.smarthome.io.net.http.HttpUtil"); + + + //Other + context.Modifier = Java.type("java.lang.reflect.Modifier"); + context.InputStream = Java.type("java.io.InputStream"); + context.IOUtils = Java.type("org.apache.commons.io.IOUtils"); + + + //Types + /* included in "default" preset + var UnDefType = Java.type("org.eclipse.smarthome.core.types.UnDefType"); + var StringListType = Java.type("org.eclipse.smarthome.core.library.types.StringListType"); + var RawType = Java.type("org.eclipse.smarthome.core.library.types.RawType"); + var RewindFastforwardType = Java.type("org.eclipse.smarthome.core.library.types.RewindFastforwardType"); + var PlayPauseType = Java.type("org.eclipse.smarthome.core.library.types.PlayPauseType"); + var NextPreviousType = Java.type("org.eclipse.smarthome.core.library.types.NextPreviousType"); + */ + + //Time JAVA 7 joda + context.DateTime = Java.type("org.joda.time.DateTime"); + //Time JAVA 8 + context.LocalDate = Java.type("java.time.LocalDate"); + context.LocalDateTime = Java.type("java.time.LocalDateTime"); + context.FormatStyle = Java.type("java.time.format.FormatStyle"); + context.DateTimeFormatter = Java.type("java.time.format.DateTimeFormatter");//https://www.programcreek.com/java-api-examples/?class=java.time.format.DateTimeFormatter&method=ofLocalizedDateTime + context.LocalTime = Java.type("java.time.LocalTime"); + context.Month = Java.type("java.time.Month"); + context.ZoneOffset = Java.type("java.time.ZoneOffset"); + context.ZoneId = Java.type("java.time.ZoneId"); + context.OffsetDateTime = Java.type("java.time.OffsetDateTime"); + + context.Timer = Java.type('java.util.Timer'); + + + context.automationPath = automationPath; + context.mainPath = mainPath; + + /* included in "default" preset + //Todo missing: + context.UnDefType = UnDefType; + context.OPEN = OpenClosedType.OPEN; + context.CLOSED = OpenClosedType.CLOSED; + context.REWIND = RewindFastforwardType.REWIND; + context.FASTFORWARD = RewindFastforwardType.FASTFORWARD; + context.PLAY = PlayPauseType.PLAY; + context.PAUSE = PlayPauseType.PAUSE; + context.NEXT = NextPreviousType.NEXT; + context.PREVIOUS = NextPreviousType.PREVIOUS; + */ + + context.logInfo = function(type , value) { + logger.info(args(arguments)); + }; + context.logWarn = function(type , value) { + logger.warn(args(arguments)); + }; + context.logDebug = function(type , value) { + logger.debug(args(arguments)); + }; + context.logError = function(type , value) { + logger.error(args(arguments)); + }; + context.logTrace = function(type , value) { + logger.trace(args(arguments)); + }; + + + context.console = {}; + context.console.info = context.logInfo; + context.console.warn = context.logWarn; + context.console.debug = context.logDebug; + context.console.error = context.logError; + + context.console.log = function(value) { + logger.info("console.log", value); + }; + + context.isUndefined = function(item) { + return isUndefinedState(item.state); + }; + context.isUndefinedStr = function(itemStr) { + return itemRegistry.getItem(itemStr) ? isUndefinedState(itemRegistry.getItem(itemStr).state) : true; + }; + + context.isUndefinedState = function(itemState) { + if(itemState.toString() == "Uninitialized" || itemState.toString() == "Undefined")return true; + return false; + }; + + context.getItem = function(it) { + try { + //print("################## "+itemRegistry.getItem(it)); + return (typeof it === 'string' || it instanceof String) ? itemRegistry.getItem(it) : it; + }catch(err) { + context.logError("getItem "+__LINE__, err); + } + return null; + }; + context.getItem.sendCommand = context.sendCommand; + context.isUninitialized = function(it) { + try { + var item = context.getItem(it); + if(item == null || item.state instanceof UnDefType || item.state.toString() == "Undefined" || item.state.toString() == "Uninitialized" )return true; + }catch(err) { + context.logError("isUninitialized "+__LINE__, err); + return true; + } + return false; + }; + + //returns item if exists, if got a value and this is not set, it will be updated + context.updateIfUninitialized = function(it, val, getFromDB) { + try { + var item = context.getItem(it); + /* + context.logInfo("|-|-updateIfUninitialized "+__LINE__, item +" -> "+val); //val -> undefined + context.logInfo("|-|-updateIfUninitialized "+__LINE__, isUninitialized(it)); //true + context.logInfo("|-|-updateIfUninitialized "+__LINE__, val == undefined); //true + context.logInfo("|-|-updateIfUninitialized "+__LINE__, val == "undefined"); //false + context.logInfo("|-|-updateIfUninitialized "+__LINE__, val === null); //false + context.logInfo("|-|-updateIfUninitialized "+__LINE__, val == null); //true + if(val){context.logInfo("|-|-updateIfUninitialized "+__LINE__, "val is defined!!!!")}; + if(item){context.logInfo("|-|-updateIfUninitialized "+__LINE__, "item is defined!!!!")}; //item is defined!!!! + + if(item && item.state instanceof UnDefType){ + if(item.type == + } + */ + if(item == undefined || item == null){ + context.error("updateIfUninitialized item not found "+__LINE__ + " item=" + item); + return item; + } + if(getFromDB && isUninitialized(it)){ + var it_histval = historicState(it, now()); + if(it_histval != undefined){ + postUpdate( it, it_histval); + context.logInfo("updateIfUninitialized use DB history "+__LINE__ + " it_histval=" + it_histval); + return item; + } + } + if( isUninitialized(it) && val != undefined){ + postUpdate( it, val); + context.logInfo("updateIfUninitialized use gotten val "+__LINE__ + " val=" + val); + return item; + } + return item; + }catch(err) { + context.logError("updateIfUninitialized "+__LINE__, err); + return null; + } + return null; + }; + + context.sendMail = function(mail, subject, message) { + getAction("Mail").static.sendMail(mail, subject, message); + }; + context.sendXMPP = function(mail, message) { + getAction("XMPP").static.sendXMPP(mail, message); + }; + context.transform = function(type, script, value) { + //var myList = transform("JS", "wunderground.js", wundergr);//returns String + //https://www.openhab.org/docs/configuration/transformations.html#usage + context.logInfo("|-|-transform "+__LINE__, "type:" + type, "script:" + script, "content:" + value.substring(0, 40)); + var t = getAction("Transformation").static.transform; + context.logInfo("|-|-transform "+__LINE__, "transform:" + t); + + getAction("Transformation").static.transform(type, script, value); + }; + + context.postUpdate = function(item, value) { + try { + events.postUpdate(item, value); + }catch(err) { + context.logError("utils.js postUpdate " + __LINE__ + ". Item: '" + item + "' with value: '" + value + "' ' Error:" + err); + } + }; + + context.sendCommand = function(item, value) { + try { + events.sendCommand(item, value); + }catch(err) { + context.logError("utils.js sendCommand " + __LINE__ + ". Item: '" + item + "' with value: '" + value + "' ' Error:" + err); + } + }; + + context.sendCommandLater = function(item, value, millis) { + var zfunc = function(args){ + sendCommand(""+args[0], args[1]); + }; + setTimeout( zfunc, millis || 1000, [item, value]); + }; + + //NOT TESTED YET: storeStates(Item...); + context.storeStates = function(item) { + events.storeStates((typeof item === 'string' || item instanceof String) ? itemRegistry.getItem(item) : item); + }; + //NOT TESTED YET: restoreStates(Map); + context.restoreStates = function(mapArray) { + events.restoreStates(mapArray); + }; + + context.createTimer = function(time, runnable) { + try{ + return ScriptExecution.createTimer(time, runnable); + }catch(err) { + context.logError("utils.js createTimer " + __LINE__ + " Error:" + err); + } + }; + + //https://blog.codecentric.de/en/2014/06/project-nashorn-javascript-jvm-polyglott/ + context.timerObject = { + timerCount: 0, + evLoops:[] + }; + context.setTimeout = function(fn, millis, arg) { + try{ + if( isFunction(fn) ){ //use + var t = context.timerObject; + if(t.timerCount > 999) t.timerCount = 0; + var tCountLocal = t.timerCount + 1; + t.timerCount = tCountLocal; + t.evLoops[t.timerCount] = new Timer('jsEventLoop'+t.timerCount, false); + t.evLoops[t.timerCount].schedule(function() { + fn(arg); + try{ + //cancel and purge itself + if(t.evLoops[tCountLocal]){ + t.evLoops[tCountLocal].cancel(); + t.evLoops[tCountLocal].purge(); + } + }catch(err) { + context.logError("utils.js setTimeout " + __LINE__ + " Error:" + err); + } + }, millis); + return t.evLoops[t.timerCount]; + }else{ + context.logWarn("utils.js setTimeout " + __LINE__ + "Please use like: setTimeout(function, milliseconds, arguments)"); + } + }catch(err) { + context.logError("utils.js setTimeout " + __LINE__ + " Error:" + err); + } + }; + + //round(ungerundeter Wert, Stellen nach dem Komma); round(6,66666, 2); -> 6,67 + context.round = function( x, p) { return(Math.round(Math.pow(10, p)*x)/Math.pow(10, p));}; + + //Joda for Java 7 and openHAB2 !!!!!!NICHT AUF LocalDateTime UMSCHALTEN!!!!!! + //https://github.com/JodaOrg/joda-time/issues/81 + context.now = function() { return DateTime.now();}; + //Java8: + //context.now = function() { return LocalDateTime.now(); }; + context.zoneOffset = function() { return OffsetDateTime.now().getOffset(); }; // +02:00 + context.isoDateTimeString = function() { return context.now() + (""+context.zoneOffset()).split(":").join(""); }; // '2018-09-11T12:39:40.004+0200' + context.dateString = function(kind) { + //https://www.programcreek.com/java-api-examples/?class=java.time.format.DateTimeFormatter&method=ofLocalizedDateTime + //return DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT, FormatStyle.SHORT).ISO_LOCAL_DATE_TIME; + //var n = LocalDateTime.now(); + //System.out.println("Before : " + n); + //// DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + //var formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm:ss"); + //var formatDateTime = n.format(formatter); + //System.out.println("After : " + formatDateTime); + if(kind == "short")return LocalDateTime.now().format(DateTimeFormatter.ofPattern("dd.MM.yy HH:mm:ss")); + return LocalDateTime.now().format(DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm:ss")); + }; + + context.getObjectProperties = function(obj) { + for (var key in obj) { + if (obj.hasOwnProperty(key)) { + context.logInfo("", key+" = "+obj[""+key]); + } + } + }; + + //### getTriggeredData ### + context.getTriggeredData = function(input) { + + //https://stackoverflow.com/questions/679915/how-do-i-test-for-an-empty-javascript-object + //context.logInfo(typeof input); + //context.logInfo(typeof input === "function"); + //context.logInfo(typeof input === "boolean"); + //context.logInfo(typeof input === "string"); + //context.logInfo(typeof input === "number"); + //context.logInfo(typeof input === "symbol"); + //context.logInfo(typeof input === "undefined"); + //context.logInfo(typeof input === "object"); + //context.logInfo("isEmpty: JSON.stringify(obj)="+JSON.stringify(input)); + //context.logInfo("isEmpty: JSON.stringify(obj)="+JSON.parse(input)); + //context.logInfo(isEmpty(input)); + + context.logInfo("input", input); + var ev = input.get("event")+""; + context.logInfo("event",ev.split("'").join("").split("Item ").join("").split(" ")); + var evArr = []; + if(context.strIncludes(ev, "triggered")){ + var atmp = ev.split(" triggered "); //astro:sun:local:astroDawn#event triggered START + evArr = [atmp[0], "triggered", atmp[1]]; + }else{ + evArr = ev.split("'").join("").split("Item ").join("").split(" "); //Item 'benqth681_switch' received command ON + } + + var d = { + //size: input.size(), + oldState: input.get("oldState")+"", + newState: input.get("newState")+"", + receivedCommand: null, + receivedState: null, + receivedTrigger: null, + itemName: evArr[0] + }; + + switch (evArr[1]) { + case "received": + d.eventType = "command"; + d.triggerType = "ItemCommandTrigger"; + d.receivedCommand = input.get("command")+""; + break; + case "updated": + d.eventType = "update"; + d.triggerType = "ItemStateUpdateTrigger"; + d.receivedState = input.get("state")+""; + break; + case "changed": + d.eventType = "change"; + d.triggerType = "ItemStateChangeTrigger"; + break; + case "triggered": + d.eventType = "triggered"; + d.triggerType = "ChannelEventTrigger"; + d.receivedTrigger = evArr[2]; + break; + default: + if(input.size() == 0){ + d.eventType = "time"; + d.triggerType = "GenericCronTrigger"; + d.triggerTypeOld = "TimerTrigger"; + }else{ + d.eventType = ""; + d.triggerType = ""; + } + } + return d; + }; + + //### getActions ### + context.getActions = function() { + if(actions == null){ + actions = {}; + var services = ScriptServiceUtil.getActionServices(); + if (services != null) { + for (var actionService in services) { + var cn = services[actionService].getActionClassName(); + var className = cn.substring(cn.lastIndexOf(".") + 1); + actions[className] = services[actionService]; + actionList[actionService] = className; + } + } + } + logInfo("actions = " + actions); + logInfo("actionList = " + actionList); + return actions; + }; + context.getActionList = function(str) { + if(actions == null){ + actions = getActions(); + } + return actionList; + }; + context.getAction = function(str) { + if(actions == null){ + actions = getActions(); + } + return actions[str].getActionClass(); + }; + + //### ExecUtil ### + context.executeCommandLine = function(commandLine) { + if(commandLine == null || commandLine == "" ){ + return null; + } + return ExecUtil.executeCommandLine(commandLine); + }; + context.executeCommandLineAndWaitResponse = function(commandLine, timeout) { + if(commandLine == null || commandLine == "" ){ + return null; + } + return ExecUtil.executeCommandLineAndWaitResponse(commandLine, timeout); + }; + + + + /** + * SIEHE ### getActions ### in utils.js + * sendHttpGetRequest(String url) + * sendHttpGetRequest(String url, int timeout) + * sendHttpPutRequest(String url) + * sendHttpPutRequest(String url, int timeout) + * sendHttpPutRequest(String url, String contentType, String content) + * sendHttpPutRequest(String url, String contentType, String content, int timeout) + * sendHttpPostRequest(String url) + * sendHttpPostRequest(String url, int timeout) + * sendHttpPostRequest(String url, String contentType, String content) + * sendHttpPostRequest(String url, String contentType, String content, int timeout) + * sendHttpDeleteRequest(String url) + * sendHttpDeleteRequest(String url, int timeout) + */ + + //context.HttpUtil = HttpUtil; + //sendHttpGetRequest(String url): Sends an GET-HTTP request and returns the result as a String + context.sendHttpGetRequest = function(url, timeout) { + //logInfo("arguments = " + arguments, arguments.length); + return context.executeUrl("GET", url, timeout); + }; + //sendHttpPutRequest(String url, Sting contentType, String content): Sends a PUT-HTTP request with the given content and returns the result as a String + //sendHttpPutRequest(String url): Sends a PUT-HTTP request and returns the result as a String + context.sendHttpPutRequest = function(url, timeout) { + return context.executeUrl("PUT", url, timeout); + }; + //sendHttpPostRequest(String url, String contentType, String content): Sends a POST-HTTP request with the given content and returns the result as a String + //sendHttpPostRequest(String url): Sends a POST-HTTP request and returns the result as a String + context.sendHttpPostRequest = function(url, timeout) { + return context.executeUrl("POST", url, timeout); + }; + //sendHttpDeleteRequest(String url): Sends a DELETE-HTTP request and returns the result as a String + context.sendHttpDeleteRequest = function(url, timeout) { + return context.executeUrl("DELETE", url, timeout); + }; + context.executeUrl = function(httpMethod, url, timeout) { + if(url == undefined || url == null || url == "" ){ return null; } + if(timeout == undefined ){ timeout = 5000; } + return HttpUtil.executeUrl(httpMethod, url, timeout); + }; + //like getAction("Lewi").static.sendHttpPostRequest(posturl, header, "", timeout); + // NOW => executeUrlPostWithContent(posturl, "", header, timeout); + // BETTER => executeUrlWithContent("POST", posturl, null, "", header, timeout); + //context.executeUrlPostWithContent = function(url, content, contentType, timeout) { + // return context.executeUrlWithContent("POST", url, null, content, contentType, timeout); + //}; + //executeUrl(String httpMethod, String url, Properties httpHeaders, InputStream content, String contentType, int timeout) + context.executeUrlWithContent = function(httpMethod, url, httpHeaders, content, contentType, timeout) { + logInfo("httpMethod = " + httpMethod); + logInfo("url = " + url); + logInfo("httpHeaders = " + httpHeaders); + logInfo("content = " + content); + logInfo("contentType = " + contentType); + logInfo("timeout = " + timeout); + if(httpMethod == undefined || httpMethod == null){ httpMethod = "POST"; } + if(url == undefined || url == null || url == "" ){ return null; } + if(httpHeaders == undefined ){ httpHeaders = null; } + if(content == undefined || content == null ){ content = ""; } + if(contentType == undefined || contentType == null ){ contentType = ""; } + if(timeout == undefined || timeout == null ){ timeout = 5000; } + return HttpUtil.executeUrl(httpMethod, url, httpHeaders, IOUtils.toInputStream(content), contentType, timeout); + }; + + /** STRING FUNCTIONS **/ + context.endTrim = function(x) { + return x.replace(/\s*$/,''); + } + context.endTrim = function(x) { + return x.replace(/^\s+/g, ''); + } + context.endAndStartTrim = function(x) { + return x.replace(/^\s+|\s+$/gm,''); + } + context.allTrim = function(x) { + return x.replace(/^\s+|\s+$/gm,''); + } + context.strIncludes = function(str, x) { + return str.indexOf(x) != -1 ? true : false; + } + + /** JAVA COLLECTION TO ARRAY **/ + context.javaCollectionToArray = function( jCollection){ + try{ + var jsArray = []; + jCollection.forEach(function(key) { + jsArray.push(key); + }); + return jsArray; + }catch(err) { + context.logError("utils.js javaCollectionToArray " + __LINE__ + " Error:" + err); + } + return null; + + } + context.includes = function( obj, val ){ + try{ + for (var key in obj) { + if(val != undefined && val == key+"")return true; + }; + }catch(err) { + context.logError("utils.js includes " + __LINE__ + " Error:" + err); + return false; + } + return false; + } + + //### Locals vars/functions + var actions = null; + var actionList = []; + + var args = function(a) { + var um = a.length > 1 ? "\n" : ""; + var s1 = ""; + for(var i in a){ + if(i == 0){ + s1 = "|" + a[i] +"| "; + }else{ + s1 += um + i + ":'" + a[i] +"' "; + } + } + return s1 + um; + }; + + // Is Object empty? + var isEmpty = function(obj) { + for(var prop in obj) { + if(obj.hasOwnProperty(prop)){ + context.logInfo("isEmpty: prop="+prop); + return false; + } + } + context.logInfo("isEmpty: JSON.stringify(obj)="+JSON.stringify(obj)); + context.logInfo("isEmpty: JSON.stringify({})="+JSON.stringify({})); + return JSON.stringify(obj) === JSON.stringify({}); + } + + var isFunction = function(v) { + if (v instanceof Function) { + return true; + } + return false + }; + + +})(exports); diff --git a/Script Examples/JavaScript/ActionExamples.js b/Script Examples/JavaScript/ActionExamples.js index 313b50c2..c62e3241 100644 --- a/Script Examples/JavaScript/ActionExamples.js +++ b/Script Examples/JavaScript/ActionExamples.js @@ -7,13 +7,17 @@ */ 'use strict'; -var OPENHAB_CONF = Java.type("java.lang.System").getenv("OPENHAB_CONF"); // most this is /etc/openhab2 -load(OPENHAB_CONF+'/automation/lib/javascript/core/rules.js'); +load(Java.type("java.lang.System").getenv("OPENHAB_CONF")+'/automation/lib/javascript/core/init.js'); + +var rules = require('rules'); +var triggers = require('triggers'); +var actions = require('actions'); +var utils = require('utils'); + -var me = "ActionExamples.js"; logInfo("################# "+me+" ##################"); -var myRule = JSRule({ +var myRule = rules.JSRule({ name: me+" Busevents", description: "TEST L:"+__LINE__, triggers: [ @@ -52,7 +56,7 @@ var myRule = JSRule({ // Run Timer var runme = function(){logWarn(" runme ", "runme");}; - createTimer(now().plusSeconds(2), runme); + utils.createTimer(now().plusSeconds(2), runme); //getAction("XMPP").static.sendXMPP("helmutl@lewi-cleantech.net", "automation XMPP :-)"); //sendXMPP("helmutl@lewi-cleantech.net", "automation XMPP :-)"); @@ -98,7 +102,7 @@ var myRule = JSRule({ * storeStates(Item...) * restoreStates(Map) */ -JSRule({ +rules.JSRule({ name: me+" Busevents", description: "TEST L:"+__LINE__, triggers: [ @@ -107,7 +111,7 @@ JSRule({ execute: function( module, input){ logInfo("################ "+me+" Line: "+__LINE__+" #################"); - var it = getItem("errors_in_logs"); + var it = utils.getItem("errors_in_logs"); //sendCommand(it, String); //sendCommand(it, Number); @@ -139,7 +143,7 @@ JSRule({ /** * getActions to see which actions are available */ -JSRule({ +rules.JSRule({ name: me+" getActions", description: "TEST L:"+__LINE__, triggers: [ @@ -147,8 +151,8 @@ JSRule({ ], execute: function( module, input){ logInfo("################ "+me+" Line: "+__LINE__+" #################"); - var a = getActions(); - var aList = getActionList(); + var a = utils.getActions(); + var aList = utils.getActionList(); print("getActionList: " + JSON.stringify( aList )); for(var i=0; i