Open 5iver opened 5 years ago
Working EXAMPLE, based on openhab2-javascript/jslib/triggersAndConditions.js:
'use strict';
load('/etc/openhab2/automation/jsr223/jslib/JSRule.js');
var me = "itemTest.js";
logInfo("################# "+me+" ##################");
JSRule({
name: me+" L"+__LINE__,
description: "SwiGroup Sender"+__LINE__,
triggers: [
TimerTrigger("0/5 * * * * ?")
],
execute: function( module, input){
logInfo("################ SwiGroup "+me+" Line: "+__LINE__+" #################");
//postUpdate("SwiGroup", getRandom2str([ON,OFF])); //Does not trigger
sendCommand("SwiGroup", getRandom2str([ON,OFF])); //triggers
}
});
JSRule({
name: me+" L"+__LINE__,
description: "SwiGroup Receiver"+__LINE__,
triggers: [
CommandEventTrigger("SwiGroup"),
ItemStateChangeTrigger("SwiGroup")
],
execute: function( module, input){
logInfo("################ SwiGroup "+me+" Line: "+__LINE__+" #################");
var SwiGroup = getItem("SwiGroup");
logInfo("SwiGroup SwiGroup.state = " + SwiGroup.state);
}
});
var getRandom2str = function(str){
return Math.random() > 0.5 ? str[0] : str[1];
}
Related log:
2018-10-07 08:04:25.009 [INFO ] [lesupport.internal.shared.SimpleRule] - |################ SwiGroup itemTest.js Line: 14 #################|
2018-10-07 08:04:25.010 [INFO ] [lesupport.internal.shared.SimpleRule] - |################ SwiGroup itemTest.js Line: 27 #################|
2018-10-07 08:04:25.013 [INFO ] [lesupport.internal.shared.SimpleRule] - |SwiGroup SwiGroup.state = ON|
2018-10-07 08:04:25.014 [ome.event.ItemCommandEvent] - Item 'SwiGroup' received command ON
2018-10-07 08:04:25.015 [ome.event.ItemCommandEvent] - Item 'SwiGroup_Switch_1' received command ON
2018-10-07 08:04:25.015 [ome.event.ItemCommandEvent] - Item 'SwiGroup_Switch_2' received command ON
2018-10-07 08:04:25.015 [ome.event.ItemCommandEvent] - Item 'SwiGroup_Switch_3' received command ON
2018-10-07 08:04:25.016 [vent.ItemStateChangedEvent] - SwiGroup_Switch_1 changed from OFF to ON
2018-10-07 08:04:25.016 [vent.ItemStateChangedEvent] - SwiGroup_Switch_2 changed from OFF to ON
2018-10-07 08:04:25.016 [vent.ItemStateChangedEvent] - SwiGroup_Switch_3 changed from OFF to ON
Thank you, but your rule is using ItemStateChangeTrigger, which does work for me as well. The issue is with ItemStateUpdateTrigger. This works for items but not for groups.
I went a little deeper. My first script only responded to ItemCommandTrigger (named: CommandEventTrigger).
Only three triggers are working yet: ItemCommandTrigger ItemStateUpdateTrigger GenericCronTrigger
Not working tested Triggers are: ItemStateChangeTrigger ItemStateCondition GenericCompareCondition
ChannelEventTrigger I did not test.
LOGGER:
2018-10-07 15:14:20.005 [INFO ] [lesupport.internal.shared.SimpleRule] - |################ SwiGroup itemTriggerTest.js Line: 213 #################|
2018-10-07 15:14:20.008 [INFO ] [lesupport.internal.shared.SimpleRule] - |################ SwiGroup ItemCommandTrigger itemTriggerTest.js Line: 225 #################|
2018-10-07 15:14:20.009 [INFO ] [lesupport.internal.shared.SimpleRule] - |################ SwiGroup ItemStateUpdateTrigger itemTriggerTest.js Line: 235 #################|
A full working example file for testing:
'use strict';
var me = "itemTriggerTest.js";
se.importPreset("RuleSupport");
se.importPreset("RuleSimple");
se.importPreset("RuleFactories");
se.importPreset("default");
var logger = Java.type("org.slf4j.LoggerFactory").getLogger("org.eclipse.smarthome.automation.module.script.rulesupport.internal.shared.SimpleRule");
var uuid = Java.type("java.util.UUID");
if(ModuleBuilder == undefined)var ModuleBuilder = Java.type("org.eclipse.smarthome.automation.core.util.ModuleBuilder");
//Handlers
if(ChannelEventTriggerHandler == undefined)var ChannelEventTriggerHandler = Java.type("org.eclipse.smarthome.automation.module.core.handler.ChannelEventTriggerHandler");
if(CompareConditionHandler == undefined)var CompareConditionHandler = Java.type("org.eclipse.smarthome.automation.module.core.handler.CompareConditionHandler");
//if(GenericEventConditionHandler == undefined)var GenericEventConditionHandler = Java.type("org.eclipse.smarthome.automation.module.core.handler.GenericEventConditionHandler");
//if(GenericEventTriggerHandler == undefined)var GenericEventTriggerHandler = Java.type("org.eclipse.smarthome.automation.module.core.handler.GenericEventTriggerHandler");
//if(ItemCommandActionHandler == undefined)var ItemCommandActionHandler = Java.type("org.eclipse.smarthome.automation.module.core.handler.ItemCommandActionHandler");
if(ItemCommandTriggerHandler == undefined)var ItemCommandTriggerHandler = Java.type("org.eclipse.smarthome.automation.module.core.handler.ItemCommandTriggerHandler");
if(ItemStateConditionHandler == undefined)var ItemStateConditionHandler = Java.type("org.eclipse.smarthome.automation.module.core.handler.ItemStateConditionHandler");
if(ItemStateTriggerHandler == undefined)var ItemStateTriggerHandler = Java.type("org.eclipse.smarthome.automation.module.core.handler.ItemStateTriggerHandler");
//if(RuleEnablementActionHandler == undefined)var RuleEnablementActionHandler = Java.type("org.eclipse.smarthome.automation.module.core.handler.RuleEnablementActionHandler");
//if(RunRuleActionHandler == undefined)var RunRuleActionHandler = Java.type("org.eclipse.smarthome.automation.module.core.handler.RunRuleActionHandler");
//if(DayOfWeekConditionHandler == undefined)var DayOfWeekConditionHandler = Java.type("org.eclipse.smarthome.automation.module.timer.handler.DayOfWeekConditionHandler");
if(GenericCronTriggerHandler == undefined)var GenericCronTriggerHandler = Java.type("org.eclipse.smarthome.automation.module.timer.handler.GenericCronTriggerHandler");
//if(TimeOfDayTriggerHandler == undefined)var TimeOfDayTriggerHandler = Java.type("org.eclipse.smarthome.automation.module.timer.handler.TimeOfDayTriggerHandler");
//#####################
//##### HELPERS ######
//#####################
(function(context) {
'use strict';
context.uuid = uuid;
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.postUpdate = function(item, value) {
try {
events.postUpdate(item, value);
}catch(err) {
context.logError("helper.js postUpdate " + __LINE__ + ". Item: '" + item + "' with value: '" + value + "' ' Error:" + err);
}
};
context.sendCommand = function(item, value) {
try {
events.sendCommand(item, value);
}catch(err) {
context.logError("helper.js sendCommand " + __LINE__ + ". Item: '" + item + "' with value: '" + value + "' ' Error:" + err);
}
};
context.getRandom2str = function(str){
return Math.random() > 0.5 ? str[0] : str[1];
}
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;
};
})(this);
//####################################
//##### JSRule uses SimpleRule ######
//####################################
(function (context) {
'use strict';
context.JSRule = function (obj, line) {
try{
var ruid = uuid.randomUUID() + "-" + obj.name.replace(/[^\w]/g, "-");
//logInfo("################ 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) {
context.logError("JSRule " + __LINE__ + ". obj: '" + obj + "' Error:" + err);
}
return null;
}
}) (this);
//##################################
//##### HANDLER AND TRIGGERS ######
//##################################
// ### ChannelEventTriggerHandler ###
// TODO: test this: https://community.openhab.org/t/two-trigger-with-a-condition-each-in-one-single-rule/30225/17?u=lewie
// ‘astro:sun:home:rise#event’ triggered event -> START
// https://github.com/lewie/openhab2-javascript/issues/1
var ChannelEventTrigger = function(channel, event, triggerName) {
return ModuleBuilder.createTrigger().withId(getTrName(triggerName)).withTypeUID(ChannelEventTriggerHandler.MODULE_TYPE_ID).withConfiguration( new Configuration({
"channelUID": channel,
"event": event
})).build();
}
// ### ChangedEventTrigger ###
var ItemStateChangeTrigger = function(itemName, oldState, newState, triggerName){
return ModuleBuilder.createTrigger().withId(getTrName(triggerName)).withTypeUID(ItemStateTriggerHandler.CHANGE_MODULE_TYPE_ID).withConfiguration( new Configuration({
"itemName": itemName,
"state": newState,
"oldState": oldState
})).build();
}
// ### UpdatedEventTrigger ###
var ItemStateUpdateTrigger = function(itemName, state, triggerName){
return ModuleBuilder.createTrigger().withId(getTrName(triggerName)).withTypeUID(ItemStateTriggerHandler.UPDATE_MODULE_TYPE_ID).withConfiguration( new Configuration({
"itemName": itemName,
"state": state
})).build();
}
// ### CommandEventTrigger ###
var ItemCommandTrigger = function(itemName, command, triggerName){
return ModuleBuilder.createTrigger().withId(getTrName(triggerName)).withTypeUID(ItemCommandTriggerHandler.MODULE_TYPE_ID).withConfiguration( new Configuration({
"itemName": itemName,
"command": command
})).build();
}
// ### TimerTrigger ###
var GenericCronTrigger = function(expression, triggerName){
return ModuleBuilder.createTrigger().withId(getTrName(triggerName)).withTypeUID(GenericCronTriggerHandler.MODULE_TYPE_ID).withConfiguration( new Configuration({
"cronExpression": expression
})).build();
}
// ### stateCondition ###
var ItemStateCondition = function(itemName, state, condName){
return ModuleBuilder.createCondition().withId(getTrName(condName)).withTypeUID(ItemStateConditionHandler.ITEM_STATE_CONDITION).withConfiguration( new Configuration({
"itemName": itemName,
"operator": "=",
"state": state
})).build();
}
// ### GenericCompareCondition ###
var GenericCompareCondition = function(itemName, state, operator, condName){
return ModuleBuilder.createCondition().withId(getTrName(condName)).withTypeUID(CompareConditionHandler.MODULE_TYPE).withConfiguration( new Configuration({
"itemName": itemName,
"operator": operator,// matches, ==, <, >, =<, =>
"state": state
})).build();
}
//GenericCompareCondition("itemName", OFF, "==", "condNameOfCompareCondition")
var getTrName = function(trn){
return trn == undefined || trn == null || trn == "" ? uuid.randomUUID() + "-" + me.replace(/[^\w]/g, "-") : trn;
//return trn == undefined || trn == null || trn == "" ? uuid.randomUUID() : trn;
}
//####################################################
//##### JSRULES, TESTING HANDLERS AND TRIGGERS ######
//####################################################
logInfo("################# "+me+" ##################");
JSRule({
name: me+" L"+__LINE__,
description: "SwiGroup Sender"+__LINE__,
triggers: [
GenericCronTrigger("0/5 * * * * ?")
],
execute: function( module, input){
logInfo("################ SwiGroup "+me+" Line: "+__LINE__+" #################");
//postUpdate("SwiGroup", getRandom2str([ON,OFF]));
sendCommand("SwiGroup", getRandom2str([ON,OFF]));
}
});
JSRule({
name: me+" L"+__LINE__,
description: "SwiGroup Receiver of ItemCommandTrigger"+__LINE__,
triggers: [
ItemCommandTrigger("SwiGroup")
],
execute: function( module, input){
logInfo("################ SwiGroup ItemCommandTrigger "+me+" Line: "+__LINE__+" #################");
}
});
JSRule({
name: me+" L"+__LINE__,
description: "SwiGroup Receiver ItemStateUpdateTrigger"+__LINE__,
triggers: [
ItemStateUpdateTrigger("SwiGroup")
],
execute: function( module, input){
logInfo("################ SwiGroup ItemStateUpdateTrigger "+me+" Line: "+__LINE__+" #################");
}
});
JSRule({
name: me+" L"+__LINE__,
description: "SwiGroup Receiver of ItemStateChangeTrigger"+__LINE__,
triggers: [
ItemStateChangeTrigger("SwiGroup", "ON", "OFF")
],
execute: function( module, input){
logInfo("################ SwiGroup ItemStateChangeTrigger "+me+" Line: "+__LINE__+" #################");
}
});
JSRule({
name: me+" L"+__LINE__,
description: "SwiGroup Receiver ItemStateCondition"+__LINE__,
triggers: [
ItemStateCondition("SwiGroup", "ON")
],
execute: function( module, input){
logInfo("################ SwiGroup ItemStateCondition "+me+" Line: "+__LINE__+" #################");
}
});
JSRule({
name: me+" L"+__LINE__,
description: "SwiGroup Receiver GenericCompareCondition"+__LINE__,
triggers: [
GenericCompareCondition("SwiGroup", "ON", "==" )
],
execute: function( module, input){
logInfo("################ SwiGroup GenericCompareCondition "+me+" Line: "+__LINE__+" #################");
}
});
I'n not sure if it matters, but I can confirm that it also does not work with PaperUI generated Rules.
Given
Group:Switch:OR(ON,OFF) TestGroup
Switch Test "Test" (TestGroup)
and "an item received and update" trigger on TestGroup the resultant Action will not execute if I change the state of Test. I didn't try to sendUpdate to TestGroup directly.
If I use "an item changed state" trigger on TestGroup and change the state of Test, the Action executes as expected.
@openhab-5iver , from reading @lewie 's working test code (mind you, I don't know javascript), it seems that the "state" key in the trigger configuration created in ItemStateUpdateTrigger is always present, even if the corresponding value isn't provided to ItemStateUpdateTrigger. I'm assuming the value of a missing argument in the invocation of ItemStateUpdateTrigger is the javascript equivalent of python's None. The corresponding code from openhab/triggers.py does not add a "state" key when the ItemStateUpdate class is instantiated with its state parameter set to None.
I tested this with the latest version of openhab/triggers.py. My test rule is never triggered. only when the update is to OFF. I also tested with the when expression "Item myGroup received update ON". Item myGroup comprises a group of three dimmer items and its base type is Dimmer. I tested by issuing various commands to the three dimmer items that are members of myGroup. [I later found that an existing DSL rule did not update myGroup directly using postUpdate().]
I also tested with the test for state is not None in ItemStateUpdateTrigger commented out. The results were the same, my test rule was onlynever triggered. when myGroup was updated to OFF.
[Update] It seems one of my existing production DSL rules was issuing an OFF command to myGroup, so my results were the same as those reported below by @openhab-5iver.
I did some more testing, and found that the trigger does fire for groups, if an update is sent directly to the group. When originally reported, I was only testing member Item updates, and finding that these were not causing the trigger to fire. This is still the case. I've updated the title of the issue to reflect this.
This may be a more general issue, where group states are not being updated with member updates, but I have not yet tested that hypothesis.
@ScottKinSF , thank you for pointing this out. In testing I found that including the state, with a value or null (I do my tests in JS with the raw API to make it easier for the devs to reproduce), produced the same result (no trigger).
I can confirm that this is not working from Jython
I can confirm, commands and updates sent directly to a Group Item will trigger the Rule with JSON Rules as well. But updates to the Group caused by changes or updates to a Group's members do not trigger the Rule.
it seems that the "state" key in the trigger configuration created in ItemStateUpdateTrigger is always present, even if the corresponding value isn't provided to ItemStateUpdateTrigger. I'm assuming the value of a missing argument in the invocation of ItemStateUpdateTrigger is the javascript equivalent of python's None. The corresponding code from openhab/triggers.py does not add a "state" key when the ItemStateUpdate class is instantiated with its state parameter set to None.
Based on my testing, event.state will only be defined for a ItemStateUpdateTrigger. All other triggers give event.state == undefined
which I would say is similar to None. I'm no JS expert but it seems that JS is a bit looser than Python when it comes to this sort of thing. Python will give you a different error when a variable is defined but not set and when a variable isn't even defined. JS gives you undefined
in both cases.
Has this been resolved?
Take a look at #6464 for some more info. This appears to be by design.
A more accurate title might be "ItemStateUpdateTrigger only fires for a group when the update is sent directly to the group". I see the same behavior in JS, Jython, and PaperUI. The same rule will trigger if the target is changed to a non-group item. I'm currently using OH snapshot 1405.
Event.log
org.eclipse.smarthome.automation