newState doesn't seem to work well

  • Platform information:
    • Hardware: CPUArchitecture/RAM/storage / Raspberry pi 4b
    • OS: _what OS is used and which version_Openhabian
    • Java Runtime Environment: which java platform is used and what version
    • openHAB version: 3.2
  • Issue of the topic: newState gives a wrong value

I changed a lot of my rulesDSL code last from item.state to newState. I noticed that after an item received update, sometimes the item.state isn’t at that state at that moment. So i thought of using newState, that should be right. Now the strangest thing happens this evening.

I use a number item Woonkamer_Preset to set my heating at home (it changes the themostat according to a preset). Woonkamer_Preset can also enable my electric heating when the solar panels generate power and Central Heating when not, sort of, long story… The Woonkamer_Preset trigger reacts on the state change of item Woonkamer_Preset and UseCV item as shown in the code below. It works right after saving the rule file, but after the item UseCV changes to ON or OFF (Switch item) and after that I change Woonkamer_Preset, the newState gives value ON in stead of 1,2,3 etc. I don’t understand why. I thought newState would be the last state of the item that changes. Below is my code how i wrote it:

rule "12 - Thermostaat Preset"
when
    Item Woonkamer_Preset received update or
    Item UseCV changed
then
    var Number numPreset

    logInfo("Verwarming","Woonkamer_Preset: " + Woonkamer_Preset.state + " / trigger = " + triggeringItemName.toString)

    if (triggeringItemName == "Woonkamer_Preset"){
        if (newState == ON){
            sendSmartHomeNotify("Newstate lijkt vreemde waarde te hebben: ON. Woonkamer_Preset: " + Woonkamer_Preset.state + " / trigger = " + triggeringItemName.toString)
        }
        numPreset = (newState as DecimalType).intValue
    }

    if (triggeringItemName == "UseCV"){
        numPreset = (Woonkamer_Preset.state as DecimalType).intValue
    }

This is what my log shows:

2022-04-04 22:44:27.699 [INFO ] [org.openhab.core.model.script.Verwarming   Woonkamer_Preset: 2 / trigger = Woonkamer_Preset

2022-04-04 22:44:27.701 [ERROR] [ation.module.script.internal.handler.ScriptActionHandler] - Script execution of rule with UID 'mr_verwarming-10' failed: Could not cast ON to org.openhab.core.library.types.DecimalType; line 236, column 22, length 23 in mr_verwarming

So I changed the trigger part to:

    Item Woonkamer_Preset received update or
    Item UseCV received update

And now it looks like it works but i’m not completely convinced.

Does anyone know if this is intended behaviour or is it a bug in the rules system?

Not quite. You’ve used received update as your trigger, which is not the same as changed. As it is, you’re running the rule every single time there’s an update to this item, even if the state remains the same. Still, I would expect that newState would work.

    if (triggeringItemName == "Woonkamer_Preset"){
        if (newState == ON){
            sendSmartHomeNotify("Newstate lijkt vreemde waarde te hebben: ON. Woonkamer_Preset: " + Woonkamer_Preset.state + " / trigger = " + triggeringItemName.toString)
        }
        numPreset = (newState as DecimalType).intValue
    }

This doesn’t make sense. You’re checking that the triggering item is Woonkamer_Preset, and then checking if its new state is ON. But you’ve said that it’s a number item.

I think what you have here is two rules: one that triggers on Item Woonkamer_Preset changed and another that triggers on Item UseCV changed. They do completely different things, so there’s no real value to combining them, or using triggeringItem and newState at all.

  • UseCV is a Switch Item.
  • Woonkamer_Preset is a Number Item.
  • newState is always the state of the Item that caused the rule to trigger

Therefore is Woonkamer_Preset triggered the rule, newState can never be ON.

Your error is probably being generated on the if (newState == ON){ line. ON is not a Number nor is it a DecimalType and it is not compatible with OnOffType. Therefore it dies trying to cast ON to something that is valid to be compared newState.

Add logging to confirm but since that if statement doesn’t make sense in the first place, I’d just delete it.

I don’t see how that could fix this problem. It might just be a fluke.

You guys must have thought I was a bit mad when seeing the code checking the newState == ON whithin the If-statement :rofl:. This was just a “desperate-piece-of-code”. At that moment I just didn’t know what to expect anymore. Should have deleted this part when posting it here. I test a lot with logInfo just to check what the code does and where it fails, I didn’t clean up before posting here, should have done that :slight_smile:

For newState received update and changed should be the exact same output, despite the fact, state changed only triggers on a state change and received update reacts when the items was updated with a value. But newState should be the same output in both cases.

The error was generated when assigning the ON state value to numPreset, which is a number variable and obviously fails. But I thing you meant that.

I just don’t understand why newState could be ON when the triggeringItem is Woonkamer_Preset, which is a number item, so that should be impossible.

The reason I use the trigger received update for Woonkamer_Preset because besides it is used in the automatic heating, it is also beeing used as a button in the UI to manually set the thermostat to anonther preset. On the other hand, UseCV is just beeing used in another rule and it often beeing set to a cetain state, ON or OFF. I just nested the UseCV in an (UseCV == OFF)-statement so it’s beeing called a lot less (with received update trigger) to spare some CPU time. That rule reacts to a change in my household energy usage every 30 seconds. When my solar panels generate enough and the energy usage is reverting back to the grid, the UseCV is changed to OFF, to spare some gas. At the same moment the heaters are turned on to use my own generated energy. For this reason the rule we’re talking about must be triggered by UseCV, because it set’s the thermostat to a certain value. I don’t want to use Woonkamer_Preset to lower the temperature because the temperature must stay at the same value.

To make things more clear, this is the complete rule for changing the thermostat:

rule "12 - Thermostaat Preset"
when
    Item Woonkamer_Preset received update or
    Item UseCV received update
then
    var Number numPreset
    strSetTemp = 0

    if (triggeringItemName == "Woonkamer_Preset"){
        numPreset = (newState as DecimalType).intValue
    }

    if (triggeringItemName == "UseCV"){
        numPreset = (Woonkamer_Preset.state as DecimalType).intValue
    }

    logInfo("verwarming","numPreset = " + numPreset + " / newState: " + newState + " / trigger = " + triggeringItemName.toString)

    if (numPreset == 1){
        if (Woonkamer_Afwezig.state !== NULL){
            VerwarmingBeneden.postUpdate(OFF)
            strSetTemp = String::format("%.1f", (Woonkamer_Afwezig.state as DecimalType).floatValue())
            Woonkamer_temp_wanted.postUpdate(strSetTemp)
            Woonkamer_temp_setpoint.sendCommand(strSetTemp)
            CheckPreset.sendCommand(ON)
        }
    }

    if (numPreset == 15){ // stand voor ochtend
        VerwarmingBeneden.postUpdate(ON)
        strSetTemp = "19.5"
    }

    if (numPreset == 2){
        VerwarmingBeneden.postUpdate(ON)
        if (Woonkamer_Aanwezig_Normaal.state !== NULL){
            strSetTemp = String::format("%.1f", (Woonkamer_Aanwezig_Normaal.state as DecimalType).floatValue())
        }
    }

    if (numPreset == 3){
        VerwarmingBeneden.postUpdate(ON)
        if (Woonkamer_Aanwezig_Comfort.state !== NULL){
            strSetTemp = String::format("%.1f", (Woonkamer_Aanwezig_Comfort.state as DecimalType).floatValue())
        }
    }

    if (numPreset == 4){
        VerwarmingBeneden.postUpdate(OFF)
        if (Woonkamer_Vakantie.state !== NULL){
            strSetTemp = String::format("%.1f", (Woonkamer_Vakantie.state as DecimalType).floatValue())
        }
    }

    if (numPreset != 1){
        if (strSetTemp != 0){
            if (UseCV.state == ON){
                Woonkamer_temp_wanted.postUpdate(strSetTemp)
                Woonkamer_temp_setpoint.sendCommand(strSetTemp)
                Woonkamer_eh_temp.postUpdate(strSetTemp)
            } else {
                Woonkamer_temp_wanted.postUpdate(String::format("%.1f", (Woonkamer_Afwezig.state as DecimalType).floatValue()))
                Woonkamer_temp_setpoint.sendCommand(String::format("%.1f", (Woonkamer_Afwezig.state as DecimalType).floatValue()))
                Woonkamer_eh_temp.postUpdate(strSetTemp)
            }
            CheckPreset.sendCommand(ON)            
        } else {
            sendSmartHomeNotify.sendCommand("(verwarming.rules) - Thermostaat Preset maakt een fout, presets kunnen niet geladen worden. Gevraagde preset was: " + numPreset.toString())
        }
    }
end

But I confirmed it this morning. The rule worked perfect after changing both triggers to Received Update. After changing the trigger for UseCV to ‘changed’, it fails again. So one cannot use the trigger ‘changed’ and ‘received update’ combined in the same rule when using newState. The newState stays “locked” one way or another after the the Switch item state has changed and it stays at that value no matter what the Number Item does, even when the trigger is the number item Woonkamer_Preset the newState = ON or OFF.

So i’m curious if you guys can confirm if this is the wrong behaviour or not?

1 Like

Some of the implicit variables only get called into existence within a rule by the existence of certain rule triggers
example, you only get previousState if there is a changed trigger.

The important part is “existence” not “use”. So if you add say a channel event rule trigger, previousState still exists when the rule is triggered by sunrise or whatever … but what could it’s value be? It’s undefined really. Though as you have found it most likely has some leftover content.

So yes, you need to be careful with multiple rule triggers of different types.

For your newState problem, the docs say -

  • newState - implicitly available in every rule that has at least one status update or status change event trigger.

so you would expect it to be valid for either.

I suspect it’s the docs that are wrong here, and newState id designed to be like its counterpart previousState, only valid for change triggers. EDIT - NO, SEE BELOW

You’ll know that nearly the same thing is available with triggeringItem.state - but it is not identical, the state could have changed since the rule was triggered, so a functional newState certainly has uses.

This looks relevant, I don’t know when fix efeective -

The original introduction - clearly newState is meant to be effective for both changeand update triggers

1 Like

The strange thing is, this is valid for both types of state changes. I use it on rules with only “changed” triggers and rules with only “received update” triggers. Both work perfectly in a lot of my rules. But if I combine “changed” and “received update” in a rule with two triggers for 2 types of items it fails.

Pretty simple to see this strange behaviour

Create some items

Number      NumberItem                  "Test number item"
Switch      SwitchItem                  "Test Switch item"

The rule

rule "Test state changes"
when
    Item NumberItem received update or
    Item SwitchItem changed
then
    var Number numTest

    if (triggeringItemName == "NumberItem"){
        numTest = (newState as DecimalType).intValue
    }

    if (triggeringItemName == "SwitchItem"){
        numTest = 1234
    }

    logInfo("Test","numTest = " + numTest + " / newState: " + newState + " / trigger = " + triggeringItemName.toString)
end

Just change the number item and you will see the log with the values. After that, change the Switch item and the log shows the wrong values or not yet, and change the number value and the log WILL show the wrong newState value.

I thought there was a recent PR that fixed that. Maybe it only changed it for JSR223 type rules. Or maybe it only changed it for the event Object.

IIRC triggeringItem now only exists for Member of triggered rules. In all other cases we only get triggeringItemName. I don’t remember why. There was some technical problem and triggeringItemName was a compromise of sorts.

This is probably something worth filing an issue on. It sounds like an edge case that I’d bet has not been tested.

2 Likes