Design Pattern: Separation of Behaviors

Edit: Updated for OH 4.

Please Design Pattern: What is a Design Pattern and How Do I Use Them for more information on what a DP is and how to use them.

Problem Statement

Often one will have certain cross cutting code that is used across a many diverse and varied collection of Rules. Such code can include things like calculating time of day to control the behavior of a rule, sending alerts, calculating state to drive a state machine, etc. For example, Lighting, blind/rollershutter controls and HVAC may all care whether it is cloudy or not.


There are three difference concepts that can be applied in this design pattern.

  1. Using an Item to trigger a rule or store the result of a calculation
  2. Using a library
  3. Calling other rules

Concept 1: Item

Set up a Design Pattern: Proxy Item and send commands to that Item to kick off a Rule to implement the cross cutting logic. The value sent to the Item represents the argument(s) for the cross cutting logic to operate on.

A String Item makes a good choice for the proxy Item as it is able to represent a lot of different types of data and it can be relatively easily parsable into multiple arguments if needed.

There are two slightly different ways to implement this approach.

Command Item

This way simulates something like a function call. The “function” is a rule triggered when the proxy Item receives a command and to “call” that “function” you send a command to the proxy Item. Any data needed by the triggered rule gets encoded in the command sent to the proxy Item.

The advantage of this approach is the “calls” to the rule will be queued so one does not have multiple other rules trying to execute the code at the same time which can be a problem with other approaches (e.g. the Script and Scenes examples).

This approach is best when there is not much that needs to be sent to the rule to operate, such as an alerting rule that just needs to know the message to send in an alert but may do something different based on the time of day.

Items:

String Notification_Proxy_Info
String Notification_Proxy_Alarm

To send an alert command either of these two Items with the message to send as part of the alert.
Both of these Items are used to trigger the rule on received command.

Blockly

If the alert is to the info Item and it’s DAY time send the alert as an email. If it’s the alert Item, send the alert as a notification any time of day. In either case, log the message also.

JS Scripting

if(event.itemName.endsWith('Info') && items.TimeOfDay.state == 'DAY') {
  actions.Things.getActions('mail', 'mail:smtp:gmail').sendMail('me@domain.tld', 'openHAB Alert', event.itemCommand);
}
else if(event.itemName.endsWith('Alert')) {
  actions.NotificationAction.sendBroadcastNotification(event.itemCommand, 'alarm', 'important');
}
console.info(event.itemCommand);

Rules DSL

if(triggeringItemName.endsWith('Info')) {
    getActions('mail', 'main:smtp:gmail').sendMain('me@domain.tld', 'openHAB Alert', receivedCommand.toString)
}
else if(triggeringItemName.endsWith('Alert')) {
    sendBroadcastNotification(receivedCommand.toString, 'alarm', 'important')
}
logInfo('Alerting', receivedCommand.toString)

Jython with Helper Library (expect changes in the future)

I don’t know how well Jython works in UI rules so I’m showing a file based rule here.

from core.rules import rule
from core.triggers import when
from core.actions import NotificationAction, Mail
from configuration import admin_email, alert_email

@rule("Publish alerts and info", description="Centralizes alerting logic.", tags=["admin"])
@when("Item Notification_Proxy_Info received command")
@when("Item Notification_Proxy_Alert received command")
def send_alert(event):
    if event.itemName == "Notification_Proxy_Info":
        Mail.sendMail("me@domain.tld", "openHAB Alert", event.itemCommand)
    else:
        NotificationAction.sendBroadcastNotification(event.itemCommand, 'alarm', 'important')

    
    night = True if items.vTimeOfDay == "NIGHT" or items.vTimeOfDay == "BED" else False
    broadcast = True if event.itemName == "aAlert" and night else False

    if broadcast:
        
        Mail.sendMail(alert_email, "", event.itemCommand)
    else:
        NotificationAction.sendNotification(admin_email, str(event.itemCommand))
        Mail.sendMail(admin_email, "openHAB Info", str(event.itemCommand))
    send_alert.log.info(event.itemCommand)

Store Result

The second way to use an Item in this design pattern is to calculate some state (e.g. time of day, how cloudy it is, a complicated boolean expression, etc.) and store the result of that calculation in an Item. Other rules just need to check the Item instead of needing to redo the calculation in multiple places.

For example, lets create a rule to keep track of whether it’s cloudy or not. We use a Cloudiness Item (a percent) and will store the result of the is cloudy calculation in a Switch Item. The rule triggers when the cloudiness value changes.

Rules that need to do something based on the cloudiness level simple need to use the IsCloudy Item’s state.

Blockly

JS Scripting

console.debug('New cloudiness percent: ' + event.itemState);
var newCloudiness = (Quantity(event.itemState).greaterThan(Quantity('45 %'))) ? 'ON' : 'OFF';
if(newCloudiness != items.IsCloudy.state) console.info('Setting isCloudy to ' + newCloudiness);
items.IsCloudy.postUpdate(newCloudiness);

Rules DSL

rule "Is it cloudy outside?"
when
	Item Cloudiness changed
then
	logDebug(logName, "New cloudiness percent: " + newState)
	val newCloudiness = if(newState > | 45 %) ON else OFF		
	if(newCloudiness != IsCloudy.state) logInfo(logName, "Setting isCloudy to " + newCloudiness.toString) 
	IsCloudy.postUpdate(newCloudiness)
end

### Jython using the Helper Library

```python
from core.rules import rule
from core.triggers import when
import personal.util 
reload(personal.util)
from personal.util import command_if_different

@rule("Is Cloudy", description="Generates an event when it's cloudy or not", tags=["weather"])
@when("Item vCloudiness changed")
def is_cloudy(event):
    is_cloudy.log.info(str(items["vCloudiness"]).replace(" %", ""))
    newState = "ON" if float(str(items["vCloudiness"]).replace(" %", "")) > 45.0 else "OFF"
    is_cloudy.log.info("new state is " + newState)
    command_if_different("vIsCloudy", newState)

Concept 2: Libraries

Most of the rules languages support libraries. Rules DSL is the primary notable exception.

A library is a collection of code: functions, classes, data structures, etc, that can be imported into another library of a rule. For example, a library can be used to replace a block of code that would otherwise be repeated across multiple rules with a simple import and function call.

For the example here we will use the same alerting example from above.

An advantage of this approach is that the library code actually gets imported into the rule where it’s running so there is no chance of undesirable interactions between rules. However, a library (except for Block libraries) cannot be created through the UI and must be done through text files on the host.

Blockly

Unfortunately Blockly libraries are not easy to create. There are two choices: create a block library, create a JS node module and use the inline script block to import and call the library functions.

Block Library

Explaining how to create a block library is beyond the scope of this tutorial. See Tutorial: How To Write Block Libraries for details.

At a high level you’ll use Developer Tools → Block Libraries to create your very own Blockly Block(s) which can be used in you rules like any other block. See Block Libraries - openHAB Community for a number of published examples.

JS Scripting

See JavaScript Scripting - Automation | openHAB for instructions on how to install third party libraries or how to create your own personal library. Assuming we put the alerting code from above into a personal library function the code would look something like this:

exports.sendAlert = function(message) {
    actions.NotificationAction.sendBroadcastNotification(message, 'alarm', 'important');
    console.info(message);
}

exports.sendInfo = function(message) {
    actions.Things.getActions('mail', 'mail:smtp:gmail').sendMail('me@domain.tld', 'openHAB Alert', event.itemCommand);
    console.info(message);
}

In a rule calling the library functions looks like (assuming the personal library is “rlk_personal” and the functions are exported under “alerting”):

var {alerting} = require('rlk_personal');
alerting.sendAlert('Attempting to trigger a garage door but the controller is not online!');

Jython Module

See the Helper Library Docs for details on creating a module.

util.py

from core.jsr223 import scope
from core.log import logging, LOG_PREFIX
from core.actions import NotificationAction, Mail
from configuration import admin_email, alert_email

def send_info(message):
    out = str(message)
    logging.getLogger("{}.alert".format(LOG_PREFIX)).info(out.format(5 + 5))
    NotificationAction.sendNotification(admin_email, out)
    Mail.sendMail(admin_email, "openHAB Info", out)

def send_alert(message):
    out = str(message)
    night = True if scope.items.vTimeOfDay == "NIGHT" or scope.items.vTimeOfDay == "BED" else False

    if not night:
        logging.getLogger("{}.alert".format(LOG_PREFIX)).warning(out.format(5 + 5))
        NotificationAction.sendBroadcastNotification(out)
        Mail.sendMail(alert_email, "", out)
    else:
        send_info(message)

Example of use:

from core.rules import rule
from core.triggers import when
import personal.util
reload(personal.util)
from personal.util import send_info, send_alert

@rule("Publish alerts and info", description="Centralizes alerting logic.", tags=["admin"])
@when("Item aAlert received command")
@when("Item aInfo received command")
def send_alert_rule(event):
    if event.itemName == "aAlert":
        send_alert(event.itemCommand)
    else:
        send_info(event.itemCommand)

Concept 3: Rules Calling Other Rules

For some time OH has supported the ability for rules to call another rule. In addition, OH 4 introduced the concept of “Scenes” in addition to the concept of “Scripts”, both of which are a special type of rule but still callable as a rule.

Scenes let you list a bunch of Items and the states you want those Items to be commanded to.

A script is a rule consisting of only a single Script Action. See Rules | openHAB.

All of these are rules and all of them can be called from another rule in most languages with the exception of Rules DSL.

“Arguments” can be passed into the rule in many cases (a Rules DSL rule can be called from another rule, but it cannot access the passed in data so the sharedCache would need to be used instead).

When a rule calls another “regular” rule that has conditions, you can set a flag to control whether the condition is applied or not. For example, if a condition causes the rule not to run if Foo is ON, if you pass the flag to apply Conditions when the rule is called it won’t execute and immediately return while Foo is ON. If you pass false the called rule will run even if Foo is ON.

Simple UI Rules

Add an Action to the Rule and choose “Scenes, Scripts, and Rules” for the Action Type.

image

Fill in something meaningful for the name and description. Keep “run” selected, select the rule to call and decide whether or not the rule conditions should be applied.

When this rule is triggered and it’s conditions allow the rule to run, it will call the selected rule.

There is no way to pass additional data to the called rule in this way.

Blockly

Use the “run rule or script with context” block to call another rule. In the called rule, you can access the passed in context using the “get contextual attribute” block.

Because Blockly converts to JS Scripting, note the limitations identified below for JS Scripting.

JS Scripting

There are some limitations with JS Scripting when rules call other rules. GraalVM JS which underlies the JS Scripting add-on does not allow multithreaded access to the context of any given script. The JS Scripting add-on implements a number of locks to prevent this from happening in the normal course of events (rule triggers, timers, etc.). However, there are no locks in place when a JS Scripting rule is called. Consequently, if two rules call the same rule at the same time, a “Multi-threaded access” exception will be thrown and the second call will fail.

Because of this, calling JS Scripting rules or Blockly rules should be the exception rather than the normal way to consider implementing separation of behaviors. If can be very useful in some cases but not all (e.g. it would be a terrible way to centralize your alerting logic). It is great for calling Scenes though as those execute very fast and are unlikely to be called from two different rules at the same time.

To call another rule from a JS Scripting rule, use rules.runRule(ruleUID, dict, conditions) where

  • ruleUID: is a string representation of the rule UID of the rule to call
  • dict: is a JavaScript dictionary of key/value pairs (e.g. { "foo": "bar", "baz": "biz" })
  • conditions: when true the called rule will only run it’s action scripts if the conditions are true

For an example from Thing Status Reporting [4.0.0.0;4.9.9.9]

var {helpers} = require('openhab_rules_tools');
console.loggerName = 'org.openhab.automation.rules_tools.Thing Status';
// osgi.getService('org.apache.karaf.log.core.LogService').setLevel(console.loggerName, 'DEBUG');

helpers.validateLibraries('4.1.0', '2.0.0');

console.debug('ThingStatusInfoChangedEvent:' + event.toString());

var parsed = JSON.parse(event.payload);

var data = {};
data['thingID'] = event.topic.split('/')[2];;
data['thing'] = things.getThing(data['thingID']);
data['oldStatus'] = parsed[1].status;
data['oldDetail'] = parsed[1].statusDetail;
data['newStatus'] = parsed[0].status;
data['newDetail'] = parsed[0].statusDetail;

rules.runRule("thing-status-proc", data, true);

The contents of data get inserted into the called rule as variables. The thing-status-proc rule I use looks like this:

console.debug('Thing ' + thingID + ' changed from ' + oldStatus + ' (' + oldDetail + ') to ' 
              + newStatus + '(' + newDetail + ')');

var itemName = cache.shared.get(ruleUID+'_thingToItem')[thingID];
var newState = (newStatus == 'ONLINE') ? 'ON' : 'OFF';

console.debug(cache.shared.get(ruleUID+'_thingToItem'));
console.debug('Thing status update: ' + itemName + ' ' + newState);
items[itemName].postUpdate(newState);

You can see the variables passed from the calling rule are accessed directly.

Advantages and Limitations

The major advantage this DP provides is centralizing of otherwise cross cutting logic, improving Don’t Repeat Yourself (DRY) and making the long term maintenance of your rules easier. If, for example, I decided to use a different notification service for my alerts, I would only have to change it in one place because I used one of the concepts in this DP.

It also has the advantage that it can more efficiently calculate certain states. For example, if we had put the Is Cloudy example above into a function, every time that any Rule needs to determine if it is cloudy that Rule will need to redo the same calculation over and over again and come up with the same answer every time. By centralizing the calculation, it only needs to be done when the cloudiness actually changes.

It can greatly reduce the number of times certain rules trigger as well. For example, again using the Is Cloudy example, if we have a few Rules that need to do something in response to the cloudiness changing, all of those Rules would have to trigger based on vCloudiness which updates every few minutes even though all the Rule cares about is if the value falls above or below a certain threshold. This DP allows us to centralize these triggers into one simpler Rule and all the rest only trigger when they need to.

Related Design Patterns

Design Pattern How It’s Used
Design Pattern: Unbound Item (aka Virtual Item) Notification_Proxy_Info and Notification_Proxy_Alarm are both examples of Virtual Items.
Design Pattern: Proxy Item Notification_Proxy_Info and Notification_Proxy_Alarm are both examples of Proxy Items
Comprehensive Wunderground using HTTP Binding Example Not a DP but the cloudy rule depends on this code
Design Pattern: Gate Keeper Gate Keeper is a specific implementation of this DB
[Deprecated] Design Pattern: Time Of Day Time of Day is a specific implementation of this DP
Design Pattern: Human Readable Names in Messages Used to map the current conditions to true/false depending on whether the conditions indicated that it is cloudy or not
Design Pattern: Sensor Aggregation ois a specific implementation of this DP
12 Likes

@rlkoshak Thanks for all of your design patterns.
I like all these ideas, which make things easy to overlook and to maintain.

I adapted the pattern above and i found out that I get old messages during system start.
… yeah because of the update event from the persistence.

So I changed to the received command trigger.
… and accidently I got older messages, because of the delay between receive and update.

So once again the question was raised when to use a which trigger:

ItemCommandTrigger, ItemStateUpdateTrigger, ItemStateChangeTrigger

vice versa when to use what

postUpdate, sendCommand

I’ve looked for a comprehensive explanation but I didn’t found one.
I’ve made a homemade explanation … but struggling for the optimum.

It is a huge topic with lots of special cases and knowledge of the specifics of your system that simply cannot be generalized.

At a high level:

  • command when you want the Rule to trigger when the Item is specifically commanded
  • update when you want the Rule to trigger anytime the Item is “touched” whether or not the Item actually changed
  • changed when you want to Rule to trigger when the Item changes state

Seems simple enough but what about side effects?

  • command will only trigger if the Item is specifically commanded (from the sitemap, a binding, or another Rule) and if that Item is linked to a Channel or binding that command will almost certainly go out to the device as well. Is that acceptable in your case? I can’t say, only you know your system.

  • update will trigger anytime the Item is updated or commanded but this means the Rule will trigger when the Item is populated using restoreOnStartup as well as from updates caused by bindings, sitemaps, and rules. Does this matter? It depends on the specifics on this Item and how it is used and populated.

  • changed will trigger anytime the Item’s state changes but this means the Rule will trigger when the Item goes from NULL to a restoreOnStartup state on startup. Does this cause problems? I can’t say, it depends on how the Item is used.

So as you can see, given a very specific scenario, I can easily tell you what Rule trigger would be most appropriate, but I can’t give simple advice that is generally applicable because it depends on the specific details about how the Items in question are defined, how they are updated and commanded, and what the Rule is supposed to do.

This sentence as written does not make sense. Care to elaborate?

4 Likes

First of all: very nice and understandable explanation.
(Maybe it could be added to the general documentation.)

Second - some deeper dive in my logfiles -hopefully not to detailed…

I refer to your:

The sequence was:

  1. use the washing machine
  2. ready
  3. dispatch info: washing is ready
  4. use the dryer
  5. ready
  6. dispatch info: dryer is ready → this went wrong.
    I received two times “washing is ready”.

The essence of my logfiles …
openhab.log says:

2018-01-23 09:16:43.496 [INFO ] [.smarthome.model.script.Notification] - Dispatch info: washing ready!
2018-01-23 09:18:33.433 [INFO ] [eclipse.smarthome.model.script.dryer] - dryer_StateMachine: STATE_OFF -> STATE_ACTIVE [11.696A]
2018-01-23 09:21:39.602 [INFO ] [marthome.model.script.washingMachine] - washingMachine_StateMachine: STATE_FINISHED -> STATE_OFF [0.057A]
2018-01-23 10:17:36.020 [INFO ] [eclipse.smarthome.model.script.dryer] - dryer_StateMachine: STATE_ACTIVE -> STATE_FINISHED [0.843A]
2018-01-23 10:17:36.058 [INFO ] [.smarthome.model.script.Notification] - Dispatch info: washing ready!

here the events.log:

2018-01-23 10:17:36.047 [ome.event.ItemCommandEvent] - Item 'Notification_Info' received command dryer is ready!
2018-01-23 10:17:36.051 [vent.ItemStateChangedEvent] - dryer_OpStateDebounceTimer changed from OFF to ON
2018-01-23 10:17:36.063 [vent.ItemStateChangedEvent] - Notification_Info changed from washing ready! to dryer is ready!

By the timestamps there is a small gap between
‘Notification_Info’ received command
and the change of the state
Notification_Info changed

So my rule, which was triggered by the “received command”, fetched the old item.state at this time.

That confuses me because if this happens every now and then …???

I have never seen nor heard of this happening or being reported on the log. It makes me think that either there is something else going on or this is a very new bug.

Are you on the snapshot?

Does it consistently get the wrong state or only sometimes?

What happens when you put a Thread::sleep for 20 msec or so in your alerting rule, does that fix it?

When using received command (which IMHO is the correct trigger in this case) what is the value of the implicit variable receivedCommand?

All things considered, were I to write Example 1 again today I would have:

rule "Dispatch Info Notification"
when
        Item Notification_Proxy_Info received command
then
        val String msg = receivedCommand.toString
        logInfo("InfoNotif", msg)
        if(TimeOfDay.state != "Night") notifyMyAndroid(msg)
end

rule "Dispatch Alarm Notification"
when
        Item Notification_Proxy_Alarm received command
then
        val String msg = receivedCommand.toString
        logError("AlarmNotif", msg)
        if(TimeOfDay.state == "Night") notifyMyAndroid(msg) else sendNotification("email", msg)
end

rule "Some random rule"
when
    // something happens
then
    // do some stuff
    Notification_Proxy_Alarm.sendCommand("I have a serious alert!")
end

If there is a timing problem that should fix it because receivedCommand gets populated before the Rule itself gets triggered. Calling Notification.state would fail sometimes as populating the Item state happens in parallel with the Rule triggering and apparently in this case the Rule runs before the Item gets populated (again, assuming the problem really is one of timing).

I too experienced the same thing recently with the notification sending the previous value. I’m not positive, but I believe it was after updating to the latest snapshot a couple weeks ago. The rule had been working fine for some time.
I added a 25ms sleep before parsing the string and that seems to have fixed it.

1 Like

Since you can pinpoint much more specifically when the problem showed up and have a minimal configuration that works, would you mind posting an Issue?

Search first to make sure there isn’t one already.

I believe this is a regression and it either needs to be addressed or the new behavior needs to be documented.

Just to verify, is receivedCommand correct or does it contain the old value as well?

Like I said, it has been a couple weeks at least since these changes. I had updated my rules to use receivedCommand rather than update, around the same time as updating to the latest snapshot I believe.

I went back and tried a few different version of the rules to narrow down the issue.

Using post/received update, both the event log and the sent notification are correct without a sleep.

Using send/received command, the events log shows the proxy item both receiving the command and changing from the previous to new value correctly. The notification that gets sent contains whatever was in the proxy item previously, however.

Adding a 25ms sleep to the beginning of the notification rule fixes the issue and the correct notification is sent. I tested each case several times and it was 100% repeatable.

I’m not sure on the timing of when I changed to using update instead of command vs when I updated to the latest snapshot so I can’t say with certainty that the issue was introduced with the snapshot. I will still work on filing an issue though since it’s clearly not the expected behavior.

I did some additional investigating and would like to get your thoughts @rlkoshak whether this is an appropriate issue to file under ESH, or just an unfortunate effect of timings.

In this case the Item state is updating 19ms after the command was received. The rule is triggering on upon the command being received, however, which I guess is the expected behavior. The delay is sometimes as small as 1-3ms, but still enough to cause an issue.

What’s curious to me is that it doesn’t seem to manifest when using “update.”

Event log

24 15:23:29.072 [ome.event.ItemCommandEvent] - Item 'Notification_Proxy_Info' received command Laundry;Dryer Done
2018-01-24 15:23:29.091 [vent.ItemStateChangedEvent] - Notification_Proxy_Info changed from Laundry;Washer Done to Laundry;Dryer Done

Openhab log

2018-01-24 15:23:29.073 [INFO ] [pse.smarthome.model.script.InfoNotif] - Notification rule start
2018-01-24 15:23:29.073 [INFO ] [pse.smarthome.model.script.InfoNotif] - Washer Done

Rule

rule "Send Info Notification"
when
        Item Notification_Proxy_Info received command
then
        logInfo("InfoNotif", "Notification rule start")
//      Thread::sleep(25)
        val msg = Notification_Proxy_Info.state.toString.split(";")
        val String subject = msg.get(0)
        val String message = msg.get(1)
        logInfo("InfoNotif", message)
        pushNotification(subject, message)
end

I think it certainly is worth opening an issue to at least open the discussion. The expected behavior, and the observed behavior to this point, is that when the Rule triggers, the Item will already have the new state.

Or maybe this has been a problem all along and because it is a rare race condition it has been rarely seen or reported until now.

I agree with your description of the expected behavior. I’m still learning what components are part of ESH and which are OH specific so I wasn’t sure where rules fall in.

Edit: Issue has been raised https://github.com/eclipse/smarthome/issues/4981

1 Like

Rules are ESH. These days there is very little that is part of the core that is OH 2 specific beyond Karaf. But it is always good to look and ask if you are unsure.

It doesn’t look like the issue is going anywhere. There was also another issue for it, but I forgot to search through closed issues. Woops.

I still think that, since sendCommand does trigger a state update, the expected behavior would be for the rule to act upon the new state. I guess knowing there is a problem at least lets us deal with it.

I remember now why I changed to received command instead of received update. With update I was getting notifications every time OH started due to restore on startup. I guess there’s a few ways to deal with this scenario.

  1. Use received command with a short sleep.
  2. Use received update, but only execute the rule if the previous state was not null.
  3. Don’t restore your notification proxy item.

…or

  1. use the Item <itemname> changed trigger for that purpose, if you are interested only in item state changes

@rlkoshak gave very to-the-point explanation above.

Just some additional words hopefully clarify the misunderstanding: a “command” event basically reflects the intention to change something in “real world” and is directed towards the bindings. It may take pretty long until the binding really reached out to the device and gets back the new, real state (for some devices even minutes). Once the binding receives back the new device state, it will then broadcast it as an item “state” event in openHAB. This is not a problem, but rather a design decision :smile:

2 Likes
  1. Use the receivedCommand implicit variable.

For this particular case that really won’t be a good solution because it is possible if not likely that the one will want to send the same notification twice or more in a row. That would be impossible with a changed trigger.

I’m on openHAB 2.2.0-1 (Release Build).

Even on a switch-item I get two different timestamps for the events.
(as pointed out by Kai in the github issue - there is an asynchronous state update.)

2018-01-25 20:36:58.613 [ome.event.ItemCommandEvent] - Item 'AlarmClock_Sunday_Active' received command ON

2018-01-25 20:36:58.633 [vent.ItemStateChangedEvent] - AlarmClock_Sunday_Active changed from OFF to ON

So a rule triggered by the “received command” and checking the state of that command in the rule could go wrong every now and then.
(As “user” I would expected a consistency when the rule is triggered but things are as they are. see here)

… That was a bit my question in the first place… how to use these different types of triggers.

…Yes

  • Now I would avoid a “received command” trigger without specification.
  • Only on switch items I would “received command ON” or “received command OFF”
    I wouldn’t recommend a sleep.
  • On analog values and strings I could easily live with the received update trigger
    … you only have to know. :hushed:

Kai’s explanation of the state being updated not by the command being received, but by auto update on the item makes a whole lot more sense of this. It may still catch some users by surprise, but at least we can hopefully point them to a better explanation of what is happening.

Frist, thanks for all the very helpful desing patterns!

I have a issue for which I have no good solution so far: I set up proxy items to send messages via matrix protocol, refer to [1] and the OpenHAB files below, however: After a while, the proxy rules do not fire anymore if the proxy items change. I have no clue so far except one observation: If I force a “reload” of the rules file, the proxy rules fire again… so what I do currently is enforcing a reload of the rules via cron every hour but I want to fix this correctly now. Any ideas? Thanks!

[1] GitHub - mm28ajos/OpenHABMatrixIntegration: Docker based OpenHAB matrix protocol integration with end to end encrypted messages.

proxy.items

String MatrixMessage
String MatrixMessageAdmin
String MatrixMessageBell
String MatrixMessageMail
String MatrixMessageFire

sendmatrix.rules

rule "Send Matrix Message Admin"
when 
    Item MatrixMessageAdmin received command
then
    logInfo("logger", "Started sending of matrix message admin.")  // I do not see this in the logs
    executeCommandLine("/bin/bash", "-c", "echo \"docker run --rm -v /home/matrixcommander:/data:z matrixcommander/matrix-commander:6 -m \'"+ MatrixMessageAdmin.state.toString +"\'\" > /openhab/hostpipe" )
end

rule "Send Matrix Message Bell"
when
    Item MatrixMessageBell received command
then
    logInfo("logger", "Started sending of matrix message bell.") 
    executeCommandLine("/bin/bash", "-c", "echo \"docker run --rm -v /home/matrixcommander:/data:z matrixcommander/matrix-commander:6 -r \'#group:fqdn\' -m \'"+ MatrixMessageBell.state.toString +"\'\" > /openhab/hostpipe" )
end

rule "Send Matrix Message Normal"
when
    Item MatrixMessage received command
then
    logInfo("logger", "Started sending of matrix message.") 
    executeCommandLine("/bin/bash", "-c", "echo \"docker run --rm -v /home/matrixcommander:/data:z matrixcommander/matrix-commander:6 -r \'#group:fqdn\' -m \'"+ MatrixMessage.state.toString +"\'\" > /openhab/hostpipe" )
end

rule "Send Matrix Message Mail"
when
    Item MatrixMessageMail received command
then
    logInfo("logger", "Started sending of matrix message mail.") 
    executeCommandLine("/bin/bash", "-c", "echo \"docker run --rm -v /home/matrixcommander:/data:z matrixcommander/matrix-commander:6 -r \'#group:fqdn\' -m \'"+ MatrixMessageMail.state.toString +"\'\" > /openhab/hostpipe" )
end

rule "Send Matrix Message Fire"
when
    Item MatrixMessageFire received command
then
    logInfo("logger", "Started sending of matrix message fire.") 
    executeCommandLine("/bin/bash", "-c", "echo \"docker run --rm -v /home/matrixcommander:/data:z matrixcommander/matrix-commander:6 -r \'#group:fqdn\' -m \'"+ MatrixMessageFire.state.toString +"\'\" > /openhab/hostpipe" )
end 

test.rules

rule "test_switch update"
when
    Item test_switch received update
then
    logInfo("logger", "Matrix message you be sent"")  // I see this in the logs 
    MatrixMessageAdmin.sendCommand("Hello world!")
end

This might be best as a separate post as I don’t think the problem here has to do with this Design Pattern.

The first thing I’d do is add some logging after the executeCommandLines. If that call is never returning for some reason, the rule will be blocked from running ever again. Only one instance of a rule can run at a given time and if it gets blocked it will not trigger again until it becomes unblocked.

That seems to match the behavior shown.

If that’s the case, add the Duration argument to the call and see if that fixes it.

Note, the rule triggers on the command before the Item has updated it’s state. It will only be a trick of timing if MatrixMessageMail.state has the new state caused by the command inside the rule. Use receivedCommand instead.

1 Like

Thanks a lot! Applied the two hints and it works!