How to design a good rule

Hi,

I have been running Openhab for some years now, mostly for switching lights on/off based on motion sensors. I am also controlling a central fan which is based on the humidity on 3 rooms, and if someone request it vent a room (the kitchen). It should also go into low power mode at night. For this is I have created three items called auto, vent and night. When someone request it to vent I turn off auto mode (controlled by a zigbee button), auto mode is other wise on. At night I switch the night item on (controlled by a cron rule), otherwise off. If high humidity is detected (zigbee sensors) on the three other rooms, the vent item is switched on.

Controlling these three items (switches items) works fine, the problem is the rule that control the fan. I seems to have some concurrency problems. I use item.state when I check the state of the items in my rule, but it seems like the rule is triggered before the state is updated. I know about receivedCommand and triggereingItem, but it seems like it will make my rule very messy if I should use them. I also tried to use a timer that would trigger 1 second after the rule was triggered, but it seemed to use the states that existed when the rule was triggered. I am an embedded C programmer by trade, and it that may no help how I design my rules. So I was wondering if someone could give me some pointers for how I should do this the correct way.

rule "Update fanspeed"
when
        Item Fancontrol_automode received update or
        Item Fancontrol_nightmode received update or
        Item Fancontrol_venting received update
then
        if (Fancontrol_automode.state == ON) {
                if (Fancontrol_nightmode.state == OFF) {
                        if (Fancontrol_venting.state == ON) {
                                SonoffiFan03_Fanspeed.sendCommand(3)
                        } else {
                                SonoffiFan03_Fanspeed.sendCommand(2)
                        }
                } else {
                        SonoffiFan03_Fanspeed.sendCommand(2)
                }
        } else {
                SonoffiFan03_Fanspeed.sendCommand(3)
        }
end

Don’t see any race issues with your rule.
Maybe the updates are coming when you don’t expect them (‘received update’ includes updates-to-same-state i.e.no change)

Find out -

rule "Update fanspeed"
when
        Item Fancontrol_automode received update or
        Item Fancontrol_nightmode received update or
        Item Fancontrol_venting received update
then
   logInfo("diagnostic", "My rule is triggered")
   logInfo("diagnostic", "auto " + Fancontrol_automode.state.toString)
   logInfo("diagnostic", "night " + Fancontrol_nightmode.state.toString)
   logInfo("diagnostic", "vent " + Fancontrol_venting.state.toString)
   ...

You’ve not told us what problem you actually observe.

Using the implicit variables almost always makes the rule shorter and clearer than the alternatives.

I’m not certain that it’s relevant in this case though.

Looking at the rule, you probably only want it to run when an Item changes state, not a mere update, so I’d start by changing the triggers to changed as @rossko57 suggests. That will constrain slightly when the rule triggers and should make it easier to track what’s going on (events.log doesn’t log out updates to Items, only changes and commands).

That’s not really how it’s supposed to work so we would need to see the code to understand more.

Rules like this tend to become easier to read and simpler if you use my Design Pattern: How to Structure a Rule DP.

rule "Update fanspeed"
when
    Item Fancontrol_automode changed or
    Item Fancontrol_nightmode changed or
    Item Fancontrol_venting changed
then
    var speed = 3;

    if(Fancontrol_automode.state == OFF) speed = 2
    else if(Fancontrol_nightmode.state == ON) speed = 2
    else if(Fancontrol_nightmode.state == OFF && Fancontrol_venting.state == OFF) speed = 2

    SonoffiFan03_Fanspeed.sendCommand(speed);
end

Obviously you would structure the conditions as desired (it might help future you understand what’s going on if you list out all the possibilities instead of defaulting to 3 and only checking for the 2 states). But by separating the sendCommand from the conditions it’s really easy to add stuff. For example, add some logging which will help us understand what’s going on, or a check to only send the new speed to the fan if the new speed is actually different, add some hysteresis (more important for a sensor driven rule), etc.

Anyway, when you call MyItem.state, you get the state of that Item right now. Where one runs into trouble is right now may not be completely up to date, especially with commands. Or the Item might have already changed state when the rule starts running which also can cause problems.

A changed trigger won’t occur until the Item has actually changed so that first problem shouldn’t be a problem if you change the triggers. It used to be the case that a received update trigger would not happen until after the Item was updated too. I’m not so sure that’s still the case, though it doesn’t make sense otherwise. I’m pretty sure it’s the Item itself that generates the event.

Thanks for really quick response. Seems like changing to “changed” did the tick.

What I was observing was that the fanspeed was starting to toggle “opposite” of what I expected. So for instance in the case where vent was off, and night was off, typically the it would start out correct with auto = on, fanspeed = 2. But when I toggled auto a few times it would start to be auto = on, fanspeed = 3. This would only happen if I operated the auto item with the zigbee button, but not if I changed the state in the openhab GUI. Which probably confirms that updates was coming when I didn’t expect them? Would give a different timing on the even I guess.

I think the reason I mixed in concurrency is that I was triggering on “received command” in an earlier version of the rule. And I read that in that case the rule can be triggered before the state is actually changed. Will that not be the case when using changed?

I am struggling a bit to understand the difference between postUpdate, sendCommand, received command, received Update, changed, etc. I have found some documentation, but I don’t think they have been very enlightening for what the practical difference is. Do you have a link to any documentation that can help me understand this better?

I know for Zwave the devices will periodically phone home with their current state and each of those will result in an update to the Item. The same author wrote the Zigbee binding so perhaps it does the same. Note this is for mains powered devices though. Battery powered devices are not so chatty.

Think of it like this.

  • Command: a request to have a device do something. A command may or may not result in an Item updating its state. If the Item does update, it could be quite some time if it’s configured such that the Item doesn’t update until after the device reports “I followed your command and am now X”. Remember, we’re dealing with real devices in the real world. It can take some time for a device to act upon a command.

  • Change: an Item was once one state and it just now moved to a different state.

  • Update: an Item’s state was refreshed; it may or may not have changed.

You would never receive a changed event before the Item actually changed. The Item changes then the changed event is emitted to the bus.

I think the same goes for updates. The Item updates and then the update event is emitted to the bus.

A command may or may not result in a change or an update so commands need to be treated completely separately from the Item’s state. In fact, many commands cannot be an Item’s state (e.g. INCREASE/DECREASE).

  • postUpdate: update the state of this Item to X. X may or may not be different from the Item’s current state. If it’s different, a changed event will occur. The new Item’s state does not get sent to the binding and out to the devices. It’s internal to OH only.

  • sendCommand: ask a device to do Y. It can be the same as a state (e.g. change the setpoint on the thermostat to 68 °F), or it can be more abstract (e.g. INCREASE the light level of that Dimmer). Commands go out to the end device. The Item may or may not update or change state in response to the command (e.g. the device is down, the device is already in the right state like you’ve sent an ON command to a light that’s already ON, etc). If it changes state, the new state may not resemble the command (e.g. an INCREASE on a Dimmer may result in a change to 75).

  • received command: a command was sent to this Item

  • received update: this Item was updated, it may or may not have been in response to a command, it may or may not have changed

  • changed: this Item changed state after an update.

If an Item receives a command that causes the Item to change state, all three events will occur. First the command, then an update and if the Item changed state in response to the update a changed event.

There is one wrinkle though. By default there is a service in OH called “autoupdate”. This service will see that an Item has received a command and, unless overridden by the binding, will attempt to guess what the new state of the Item will be in response to the command and update the Item accordingly. This makes the Item state change before the device receives the command and acts upon it. Weird stuff can happen if autoupdate is on and, for example, a Dimmer gradually dims down until OFF, reporting it’s new states along the way. You’ll see the Dimmer receive an OFF command, change to 0, then change to 50, then change to 40, and so on.

1 Like

Really thanks for the quick and good answers. I think I have a much better understanding now. I guess this is really the basics, but google haven’t been able to come up with good information, but of course the information you get is only as good as the queries you feed it.