Features for Rules that work with Groups

Introduction

This post provides an overview of two features that have been added to openHAB recently to make it easier to write rules that work with groups of items. These features only apply to rules defined in .rules files (also know as DSL Rules), and not any other types of rules/scripts such as those for the Experimental Rule Engine or JSR223 Scripting.

The following sections will provide examples of the usage of each feature. These examples will be based on the items shown here.

Group AllLights
Group SwitchLights (AllLights)
Group DimmerLights (AllLights)
Switch SwitchLight01 (SwitchLights)
Switch SwitchLight02 (SwitchLights)
Dimmer DimmerLight01 (DimmerLights)
Dimmer DimmerLight02 (DimmerLights)

Feature: triggeringItem Implicit Variable

“triggeringItem” is an implicit variable that is available within rules that are triggered by item based events. Item based events use one or more of the following trigger formats.

Item <item> received command [<command>]
Item <item> received update [<state>]
Item <item> changed [from <state>] [to <state>]

The “triggeringItem” implicit variable by itself does not directly add group support, but it is a first step that allows a rule to easily determine which item caused the rule to execute.
This feature replaces the need to use a persistence based workaround to identify the item. (I believe this workaround was a creative solution to the problem that has served the community for a long time. Thank you, @rlkoshak)

Availability

“triggeringItem” is available in the openHAB 2.2.0 Release Build.

Examples

rule "OrCommandExample"
when
    Item SwitchLight01 received command or
    Item SwitchLight02 received command
then
    logInfo("RuleExamples", "The item " + triggeringItem.name + " received command " + receivedCommand)
end

rule "OrChangedExample"
when
    Item SwitchLight01 changed or
    Item SwitchLight02 changed or
    Item DimmerLight01 changed or
    Item DimmerLight02 changed
then
    logInfo("RuleExamples", "The item " + triggeringItem.name + " changed state from " + previousState + " to " + triggeringItem.state)
end

In these examples the “triggeringItem” implicit variable will be the item that actually triggered the rule (SwitchLight01, SwitchLight02, DimmerLight01, or DimmerLight02).

Limitations

As mentioned above, “triggeringItem” does not add group support on its own. In the rule below the “triggeringItem” implicit variable will always be the group SwitchLights.

rule "TriggeringItemLimitation"
when
    Item SwitchLights changed 
then
    logInfo("RuleExamples", "The item " + triggeringItem.name + " changed state from " + previousState + " to " + triggeringItem.state)
end

Feature: “Member of” Rule Triggers

New rule trigger options have been added that allow rules to operate on items that are members of groups. Group member based events use one or more of the following trigger formats.

Member of <group> received command [<command>]
Member of <group> received update [<state>]
Member of <group> changed [from <state>] [to <state>]

When you combine the “triggeringItem” implicit variable with “Member of” triggers you have true group support for rules.

Availability

“Member of” is an openHAB 2.3 feature. It is not available in any current release build. It is available in snapshot builds starting with openHAB 2.3.0 Build #1212.
Snapshot builds should not be considered as reliable/stable as release builds. Please do not switch to a snapshot just to get this feature unless you understand the risks and are willing to deal with them.

Examples

rule "MemberOfCommandExample"
when
    Member of SwitchLights received command
then
    logInfo("RuleExamples", "The item " + triggeringItem.name + " received command " + receivedCommand)
end

rule "MemberOfChangedExample"
when
    Member of SwitchLights changed or
    Member of DimmerLights changed
then
    logInfo("RuleExamples", "The item " + triggeringItem.name + " changed state from " + previousState + " to " + triggeringItem.state)
end

In these examples the “triggeringItem” implicit variable will be the item that actually triggered the rule (SwitchLight01, SwitchLight02, DimmerLight01, or DimmerLight02).

Advantages

If you compare the “Member of” examples with the “triggeringItem” examples you will notice that only the “when” sections have changed. The two sets of rule examples are functionally equivalent. The advantages provided by “Member of” are:

  • For large groups it is easier to write Member of <group> [condition] than Item <item1> [condition] or Item <item2> [condition] or Item <item3> [condition] or ...
  • You can add items to and/or remove items from the group without modifying the rule

Limitations

“Member of” only works on items that are direct members of a group. It does not traverse nested groups. In the rule below the “triggeringItem” implicit variable will be one of the groups that are nested within AllLights (SwitchLights or DimmerLights) and not the base items (SwitchLight01, SwitchLight02, DimmerLight01, or DimmerLight02).

rule "MemberOfLimitation"
when
    Member of AllLights changed 
then
    logInfo("RuleExamples", "The item " + triggeringItem.name + " changed state from " + previousState + " to " + triggeringItem.state)
end

Side Note

There is a topic that has come up several times in discussions around “triggeringItem” that I thought would be worth mentioning here. It is not an issue with “triggeringItem”, but the use of “triggeringItem” appears to have made it more common for people to run into the situation.

If you have a rule that is triggered based on an item receiving a command (Item <item> received command [<command>] or Member of <group> received command [<command>]), you should not use the state of that item within the rule. It does not matter how you access the state (triggeringItem.state, ActualItemName.state, or SomeGroup.members.<filter>.state), it should be considered non-deterministic at this point. There is a GitHub issue that goes into some detail about why this is.

You can use the implicit variable “receivedCommand” within the rule to determine what command was issued to the item.

28 Likes

Thanks a lot for this implementation.

Will help a lot.

No one is happier than I that the persistence hack is no longer necessary.

Fantastic! I’ve been looking for this to go live. I’m going to have to go back and rewrite almost all of my design patterns before 2.3 release.

Thank you for mentioning this. It is very important that we all understand how it works.

Thank you for the write up! I see no reason why this can’t be added with only minor changes (accounting for the fact that the implicit variables are discussed after the triggers) to the Docs.

Wow! Thank you very much for these new features and the excellent documentation and examples.

This will shorten and improve my rules significantly and I can also get rid of the (only 99% reliable) persistence hack. My first tests show that this works with all events (also ‘received update’) so I will have to rewrite some rules now.

This is a REAL improvement with a large leverage for coding rules.

This sounds exciting. I have yet to migrate an OH1 service with lots of grouped lighting and presence sensing, it sounds like restructuring to exploit this new feature will make it worthwhile. Thankyou devs !!