ItemStateUpdateTrigger: No implicit state variables, item returns old state

openHAB 3.1.0.

I am using ItemStateUpdateTrigger, because I want to be also informed about updates with the same value.
Unlike ItemStateChangeTrigger, I do not have implicit variables event, previousState or newState available in my script.

When I use itemRegistry.getItem(“MyItem”).state, I sometimes get the old state from before the update.

How do I get the new state reliably?

Example where it did not work:
events.log:

2022-01-09 07:05:01.999 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'TextToSpeech' changed from Alarmanlage ist aktiviert. to Alarmanlage wurde deaktiviert.

openhab.log:

2022-01-09 07:05:01.998 [WARN ] [org.openhab.rule.Text_to_Speech     ] - Alarmanlage ist aktiviert.

One can already see the reason for the issue when looking at the timestamps.

Code:

var log = Java.type('org.slf4j.LoggerFactory').getLogger('org.openhab.rule.' + ctx.ruleUID);
var Voice = Java.type("org.openhab.core.model.script.actions.Voice");
var volume = new PercentType(70);

var text = itemRegistry.getItem("TextToSpeech").state;
log.warn(text);
Voice.say(text, volume);

Any hints would be greatly appreciated.

Thanks!

That seems a bit unlikely, but we are dealing with a multi-threading system.

As the rule triggering is pretty crucial here, may we see the complete rule? (Use code tab in UI)

I note the rule WARN message comes before the ItemStateChangedEvent message. That’s okay, its the update that generates the change.
The log does not show show us the preceding update, but the rule will run, and I would expect live Item state to reflect new state before change event.

As a general comment, there has been work on rules and javascript libraries - you might not get much interest in delving deep into OH3.1 now OH3.2 is released.

The complete rule:

triggers:
  - id: "1"
    configuration:
      itemName: TextToSpeech
    type: core.ItemStateUpdateTrigger
conditions: []
actions:
  - inputs: {}
    id: "2"
    configuration:
      type: application/javascript
      script: >
        var log =
        Java.type('org.slf4j.LoggerFactory').getLogger('org.openhab.rule.' +
        ctx.ruleUID);

        var Voice = Java.type("org.openhab.core.model.script.actions.Voice");

        var volume = new PercentType(70);

        java.lang.Thread.sleep(1000);

        var text = itemRegistry.getItem("TextToSpeech").state;
        log.warn(text);
        Voice.say(text, volume);
    type: script.ScriptAction

This now includes my workaround for this issue (sleep).

The previous update:

2022-01-08 22:03:03.476 [INFO ] [openhab.event.ItemStateChangedEvent ] - Item 'TextToSpeech' changed from Alarmanlage wird aktiviert in 30 Sekunden. to Alarmanlage ist aktiviert.

I do remember that I had similar effects (getting the old state) with change triggers in the DSL rule files in the past, mostly when items had persistance enabled. The solution was to use triggeringItem instead of fetching the item by name. But for update triggers, I do not have those implicit variables.

This behavior should not be possible. The every occurs after the Item precesses the update. Therefore the rule triggers after the Item has changed (if a change occurred which is the only case where you’d be able to tell that you got the “old” value.

It’s only on a. command where the rule triggers at the same time as the Item may be updating. Are you sure that wasn’t what you’ve seen in the past and are protecting to now? maybe the Item is changing again before the rule runs? Maybe you were trying to pull the previous state out of persistence?

Regardless, event.itemState always exists when the rule was triggered by an update or a change and it holds the state that caused the rule to run regardless of what state the Item is in now. Use that.

This item does not have persistence. The code of the rule is like shown above. The item only changed once. I can not explain why getting the state from the item itself returned the old value.

But you are right about my past (OH 2.x, I guess) problems with DSL. That was with persistence enabled for an item. And the issue there was that getting the current state of the item itself pulled the old value because persistence did not have time yet to write the update.

Thanks for the pointer about event.itemState (I thought that I had checked if there is an event object, but apparently I did not). I will try that. I will also add more logging to see if the issue happens again. It only happened once.

But that’s not how persistence works either. When you call MyItem.state (or what ever is the equivalent in the various languages) persistence isn’t involved at all. So it can’t cause you to get the old state in that case.

When you are in a rule, if you get the state from the Item that triggered the rule with an update or a changed trigger, the only way you should get a different state from what triggered the rule is if the Item changed state after the rule was triggered but before the line that gets the Item’s state. As I understand it, the update and change events are published to the event bus after the Item updates or changes. In fact, looking at the code briefly it appears like it’s the Item that actually generates that event in the first place.

Commands are different and it is very possible to get the old Item’s state on a received command triggered Item.

Calling MyItem.lastState or other persistence actions could execute before persistence has had a chance to save the most recent update/change.

But again, based on my understanding and experience, what you’ve described is not possible for change and update triggered rules. So either something changed, my understanding is incorrect, or something else is going on.

Yes, it may be that my past problem was with a rule triggered by a command. I don’t remember.

For this current issue, I will try and see if I can reproduce it.

Please do.
Just for clarity, an Item state change will produce both an update event - not visible in log, but will trigger your rule - and a change event later, that we see in the log but is irrelevant to your rule.