Delay when setting items in OpenHAB

delay
Tags: #<Tag:0x00007fe057626508>

(Torsten) #1

Hi,

I have rules that turn on and off my hallway lights and especially change the brightness. I am using - additionally to the items that control the lamps directly - also artificial items to make sure that brightness changes are also tracked when the lights are currently not on but come on later (then with the correct brightness). For example, I have this rule:

rule “Dim lights”
when
Time cron “0 45 19 ? * *”
then
I_ART_Flurlampe_vorne.sendCommand(15)
I_ART_Flurlampe_hinten.sendCommand(15)
if (I_ART_Anwesenheit.state == ON) {
I_FL_Deckenlampe_vorn_Dimmer.sendCommand(I_ART_Flurlampe_vorne.state)
I_FL_Deckenlampe_hinten_Dimmer.sendCommand(I_ART_Flurlampe_hinten.state)
}
end

However, this sometimes works and sometimes it doesn’t. Reason seems to be that setting the values of I_ART_Flurlampe* does not seem to be effective immediately, esp. not before assigning their new value to the item I_FL_Deckenlampe*.

Example output in logfile when this happens:

2018-04-22 19:45:00.025 [ome.event.ItemCommandEvent] - Item ‘I_ART_Flurlampe_vorne’ received command 15
2018-04-22 19:45:00.043 [ome.event.ItemCommandEvent] - Item ‘I_ART_Flurlampe_hinten’ received command 15
2018-04-22 19:45:00.046 [ome.event.ItemCommandEvent] - Item ‘I_FL_Deckenlampe_vorn_Dimmer’ received command 80
2018-04-22 19:45:00.056 [ome.event.ItemCommandEvent] - Item ‘I_FL_Deckenlampe_hinten_Dimmer’ received command 80
2018-04-22 19:45:00.090 [vent.ItemStateChangedEvent] - I_ART_Flurlampe_vorne changed from 80 to 15
2018-04-22 19:45:00.099 [vent.ItemStateChangedEvent] - I_ART_Flurlampe_hinten changed from 80 to 15
2018-04-22 19:45:00.102 [vent.ItemStateChangedEvent] - I_FL_Deckenlampe_hinten_Dimmer changed from 50 to 80

As you can see, the ART-items get their values assigned correctly, but the FLItems don’t.

Is this a known problem? This would affect many so I assume there is a way around it? Don’t use sendCommand? Wait before calling the next sendCommand?

Thanks a lot,
Torsten


(Vincent Regaud) #2

This is because the sendCommand doesn’t change the state of the item straight away, it needs to be processed through the event bus and persistence first. As a result, when you are retreiving the item state, it hasn’t changed yet. One way to deal with that is to wait a little bit for the event bus to catch up.

Notice the use of the code fences:

rule “Dim lights”
when
    Time cron “0 45 19 ? * *”
then
    I_ART_Flurlampe_vorne.sendCommand(15)
    I_ART_Flurlampe_hinten.sendCommand(15)
    if (I_ART_Anwesenheit.state == ON) {
        Tread::sleep(100) // 100ms
        I_FL_Deckenlampe_vorn_Dimmer.sendCommand(I_ART_Flurlampe_vorne.state)
        I_FL_Deckenlampe_hinten_Dimmer.sendCommand(I_ART_Flurlampe_hinten.state)
    }
end

(Rich Koshak) #3

Even better, since you already know what state I_ART_Flurlampe_vorne and I_ART_Flurlampe_hinten should be since you just commanded them, just use the value:

rule “Dim lights”
when
    Time cron “0 45 19 ? * *”
then
    I_ART_Flurlampe_vorne.sendCommand(15)
    I_ART_Flurlampe_hinten.sendCommand(15)
    if (I_ART_Anwesenheit.state == ON) {
        I_FL_Deckenlampe_vorn_Dimmer.sendCommand(15)
        I_FL_Deckenlampe_hinten_Dimmer.sendCommand(15)
    }
end

You already know what the value is, why wait and go through the Item registry and all that to get a value you already know?


(Torsten) #4

Thank you.

You are right for this example of course. I was wondering how to generally deal with the problem that item updates are delayed but I think adding a sleep should do the trick as well. Are 100ms always sufficient?

Thanks, Torsten


(Rich Koshak) #5

Generally, this problem mainly comes up when a Rule is triggered by received command because the Rule gets triggered before the Item registry gets updated. That is one reason why there is the receivedCommand implicit variable for such Rules. So in that case it is best to use receivedCommand instead of MyItem.state.

In all other cases, I can’t imagine a use case where it would be appropriate to sendCommand or postUpdate to and then within the same Rule want to check the state of that Item. You already know what state the Item will be in.

You would be very hard-pressed to come up with an example that would convince me that a Thread::sleep is the right answer for this.

You should not be writing Rules that depend on timing unless there is no other way. The reason is:

Who knows? On some machines, it might be way overkill. On others, it might not be long enough. You would have to determine the minimum amount of sleep experimentally for your system. However, it also depends on what else your machine is doing at that given time. There may be times, once in a blue moon, where for some reason it just took more than 100 msec that time and your Rule will fail.

It’s much better to write deterministic code (i.e. code that doesn’t depend on the timing of multiple things happening in the background).

There are lots of approaches one can take to achieve this:

  • use values you already know instead of MyItem.state
  • split up rules so when you command or update from one, that command or update triggers a second rule to handle the rest of the work
  • have the rule trigger by all the relevant Items and wait for them all to reach the expected state
  • use Timers or Expire Binding Timers

(Torsten) #6

Thank you, that absolutely makes sense