Design Pattern: Separation of Behaviors

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 .rules files by a diverse and varied collection of Rules. Such things 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.

Sometimes one can implement this sort of thing in a lambda but lambdas can only be called from Rules in the same .rules file as the lambda, forcing you to put everything in one file or duplicating your lambdas across multiple .rules files, violating DRY (Don’t Repeat Yourself). Another alternative is to use Scripts but one cannot pass arguments to Scripts which limits their usefulness to this use case.

Concept


Set up a Design Pattern: Proxy Item and send commands to that Item to update its state and 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 the best choice for the Proxy Item as it is able to represent a lot of different types of data and it is easily parsable into multiple arguments if needed.

There are two sides to this design pattern. One side implements something akin to a function call that a Rule initiates by sending a command to the Proxy Item. This would be useful for cases like alerting where the Rules have a message they send to the Proxy to be dealt with. The first simple example below is this sort of implementation.

The second is to have a rule that triggers on its own which populates the Proxy Item with the result of a calculation. The second example below which determines if it is cloudy is this sort of implementation. In this case the Rules check the Proxy Item to determine what the current state is and adjust its behavior based on the current state.

Simple Example 1: Alerting

This is an alerting example. It allows Rules to distinguish between different types of alerts and do something different based on the alert type and the time of day. Some ancillary Items are not shown below.

Items

String Notification_Proxy_Info
String Notification_Proxy_Alarm

JSR 223 Jython with Helper Library

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 aAlert received command")
@when("Item aInfo received command")
def send_alert(event):
    if event.itemName == "aAlert":
        send_alert.log.warn(event.itemCommand)
    else:
        send_alert.log.info(event.itemCommand)

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

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

Rules DSL

rule "Send message"
when
  Item aAlert received command or
  Item aInfo received command
then
  if(triggeringItem.name == "aAlert") logWarn(logName, receivedCommand.toString)
  else logInfo(logName, receivedCommand.toString)

  val night = if(vTimeOfDay.state.toString == "NIGHT" || vTimeOfDay.state.toString == "BED") true else false
  var broadcast = if(triggeringItem.name == "aAlert" && !night) true else false

  if(broadcast) {
    sendBroadcastNotification(receivedCommand.toString)
    sendMail("5555555555@sms.com", "", receivedCommand.toString) // fake SMS email address
  }
  else {
    sendNotification("myemail@email.com", receivedCommand.toString) // fake email
    sendMail("myemail@email.com", "openHAB Message", receivedCommand.toString) // fake email
  }

end

Theory of Operation

In the above, alerts are logged to openhab.log as warnings, info are logged as info. Then we determine whether we should broadcast the alert or only inform the administrator (me). We only broadcast if it’s an alert and it isn’t night.

In the Jython version, we store the email addresses in configuration.py which is where specific and sensitive information should go. This lets you check in and share the code without worrying about redacting that information.

JSR223 Python Module

The need for this design pattern is less pronounced for JSR223 Rules. An equally valid solution many times is to create a library function that each Rule directly calls. The main purpose of this DP is to deal with the fact that Rules DSL does not provide such a mechanism.

In particular, use a module if the actions taken by the function is different every time is called. If the function performs a calculation that can be reused (see below), this DP still applies.

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)

Theory of Operation

In JSR223 we have access to all the constructs of a “normal” language. This means we can put instantaneous code like the above into a personal library (stored in $OH_CONF/automation/lib/python/personal) and import and call them from your Rules. In this case we create two functions, one for alerts and another for info. Notice how we gain access to Items and other core OH stuff using the imported scope.

Simple Example 2: Is it Cloudy?

This example checks the current weather conditions to determine whether it is cloudy or not. See Comprehensive Wunderground using HTTP Binding Example for how the Items below get populated and the contents of the weather.map which is used to map the current conditions to a cloudiness state.

Item

Switch      vIsCloudy       "Conditions are Cloudy [%s]" <rain>

Rules DSL

rule "Is it cloudy outside?"
when
	Item vWeather_Conditions changed
then
	logDebug(logName, "New weather conditions: " + vWeather_Conditions.state.toString)
		    
	val isCloudy = transform("MAP", "weather.map", vWeather_Conditions.state.toString)
	val newState = if(isCloudy === null || isCloudy == "false") OFF else ON
		
	if(newState != vIsCloudy.state) logInfo(logName, "Setting isCloudy to " + newState.toString) 

	vIsCloudy.postUpdate(newState)
end

rule "Some random rule that cares about cloudy"
when
    Item vIsCloudy changed
then
    if(vIsCloudy.state == ON) {
        // do stuff now that it is cloudy
    }
    else {
        // do stuff now that it isn't cloudy
    }
end

NOTE: Since Wunderground shut down their API, here is an example of the Rule using OpenWeatherMap, which is actually much simpler. OpenWeatherMap provides cloudiness as a percent so there is no need to map the conditions to a cloudiness.

rule "Is it cloudy outside?"
when
	Item vCloudiness changed // OpenWeatherMap cloudiness Item
then
    val newState = if(vCloudiness.state > 50) ON else OFF
    if(newState != vIsCloudy.state) vIsCloudyState.postUpdate(newState)
end

Theory of Operation

When the current weather conditions changes, use a map file which returns true if the contidion indicates it is cloudy (snow, rain, partly cloudy, etc) and false otherwise. Then, if the current cloudy conditions are different from vIsCloudy, update vIsCloudy.

Any rule that needs to do something different if it is cloudy just need to check vIsCloudy. Any Rule that needs to do something in response to it becoming cloudy can trigger off of vIsCloudy.

JSR223 Python using the Helper Library

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(" %", "")) > 50.0 else "OFF"
    is_cloudy.log.info("new state is " + newState)
    command_if_different("vIsCloudy", newState)

Theory of Operation

The above Python version of the Rule does the same as the OpenWeatherMap version of the Rules DSL version. Because we can create libraries of useful functions in JSR223, I’ve created a little function that only sends a command (there is an update version too) if the new state is different from the current state of the Item.

As with the above versions, this Rule sends a command to vIsCloudy when the cloudiness changes. Rules that need to check if it’s cloudy need only check vIsCloudy. Rules that need to trigger when it becomes cloudy can trigger off of vIsCloudy. Even though JSR223 Rules have the ability to create functions, this is a good use of this Design Pattern.

Advantages and Limitations

The major advantage this DP provides is centralizing of otherwise cross cutting logic. As a result the cross cutting logic can be more complex yet easier to maintain. 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 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 (if using JSR223 Rules), 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.

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.

The major disadvantage is this DP requires at least one extra unbound Item to store the state.

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
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
Design Pattern: Human Readable Names in Messages
Design Pattern: Gate Keeper
Comprehensive Wunderground using HTTP Binding Example
Reusable Functions: A simple lambda example with copious notes
Can a rule trigger another rule
Motion detection -> lights on - if it's dark and within time period, with timer - Help needed
How can I get the initial state of an MQTT switch?
[SOLVED] Rules Syntax : Select into Select
Passing parameters to a script
How to access to .cfg defined vars?
Keep 'when Item received update' rules from running during RestoreOnStartup
Support to distinguish between human- and machine "agent" induced events
[SOLVED] Rules / xtend syntax for arrays and lambda's
Journey to JSR223 Python 1 of 9
[JSR223][Jython] Error during evaluation of script 'file:/openhab/conf/automation/jsr223/python/core/components/100_DirectoryTrigger.py': ImportError: No module name d configuration in <script> at line number 21
How to calculate the time of a specific azimuth
Doing it smarter - help with rule code rollershutter automation
Getting Fancy with my Tower Timers - Separation of Behaviors
[SOLVED] myOpenHab app different screens per user?
No Global Variables? Time to use Node-Red
Enable/Disable Alexa Voice Control
Removal of the OH 1.x Compatibility Layer
Sonoff dual to control shutters
[SOLVED] Is it possible to write some Java functions in rules
HSBType Equality for Phillips Hue
Design Pattern: DRY, How Not to Repeat Yourself in Rules DSL
Migrating MQTT1 items to MQTT2.4 items
Detect Item state type
[SOLVED] Lambda calling other lambda? (JSR223/JYTHON)
Presence rule with reed switch state & time
Design Patterns: Generic Is Alive
Accessing variables in lambda
Finally not called -> deadlock
Roadmap to Happiness - What is missing in the core framework
Using Thread to wait until some condition happens
Getting rule name in rule
Lambda functions fail (not thread safe?)
Lambda functions fail (not thread safe?)
Arraylist
Timers in functions not possible?
[SOLVED] MQTT populating temperature values - no it is not!
Design Pattern: Associated Items
Rules to only fire when its :00 or :30
File Include
Difference between scripts and rules
Rules / functions / scripts: best approach
OpenHAB or HAAS
[SOLVED] Openhab 2 Contact Sensor Time Rule
Notifymyandroid is dead - alternatives?
[SOLVED] Is there a better way to code this?
Android openhab app quick question
What are your top 3 automations
Rule for Rollershutters - with proxy items and reed-contacts
Inactivity of items // no updates // automatically tracking
myopenHAB Mobile Notifications Temporarily Disabled
Lambda Procedure error: java.lang.NullPointerException
Stop timer and reset to null. Structure of rule okay?
Use variable for item
Rule to activate another rule
Presence detection via iPhone's mDNS Entry. How to integrate into OH2?
How to find out if binding stopped working?
Rule optimization: Window OPEN reminder
Sending Notifications to Fire TV/Android TV
Can I get a Phone location within my house?
Can I call a rule from within a rule?
Rule Push Message to iOS App when Window longer Open
Iterating over a group, want to check an alternate item, sometimes
Send SMS via VoIP provider API
Global functions for use in rules
Include external script in rule file
How to get notification for sensor alarm using openhab2
Triggering a rule when user navigates (back to parent level) in Basic/Classic UI
Making Decisions Based on Time of Day
Decoupling notification service
Timed lights, Alerts to push notification?
Help with Rules please
"First Time" Rule
Best practice for .rules
sendHttpGetRequest - TimeoutException
Design Pattern: Manual Trigger Detection
Notifications in group design pattern
Design Pattern: Expire Binding Based Timers
Blinking LED - how to implement it correctly?
New Binding - Timer/Scheduling Binding
Effective use of Timers in Rules
Current and Correct Documentation of Syntax for Things and Items Needed
OpenHab send sensor notification to iOS/Android using IFTTT
Best way to control timer from more than one .rules file?
Reusable Functions: A simple lambda example with copious notes
Whole house lighting
[OH2] Rule help to play a random sound file
Set last tripped/alarm date, or last action date to an item - best practice?
Boxcar Notification - rule to notify, can a rule execute a rule?
Is there a way to create functions/routines in openhab?
Automation/Orchestration Design Patterns
[Deprecated] Design Pattern: Time Of Day
Making group rules/scripts for FlowerCare/Miflora sensors in OH3
DSL rule with received command on two items does not have triggeringItem
Writing jython scripts and accessing personal modules
Validation issue in a rule
Implementing a Script/Rule
How to define global variables in oh3 for DSL rule in main UI
Could I simplify Mail command in OH 2.5?
Parts of Code as a Variable in rules
Issues with implicit variables newState and triggeringItem in 3.0.0
Is Notification of an Event using a Dummy Switch a good method?
Complex Notification system
Collection of Strings item
Accessing OS environment variables in rules
Rule to switch on Christmas Lights between 1. Advent and "Heilig Dreikönig"
Reusable Functions: A simple lambda example with copious notes
Reusable Functions: A simple lambda example with copious notes
[SOLVED] Put rule code into method and call it in different rules
Start a rule in a rule
Design Pattern: Working with Groups in Rules
Complex Rule optimization

@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.