Faulty, old value of Item within rule

Dear all,

I have some rules for controlling my roller shutter.
There is a file for roller shutter scenes (rollo_szenen.rules). These scene rules trigger the control of the rollershutter (rollo_basikansteuerung.rules). Finally the real command is send to rollo_shelly.rules.

Why so complicated:
The rollo_shelly.rules deal with the low level hardware control (incl. converting numbers properly from 0 to 100 instead of 100 to 0 etc.)

As once a while the command is ignored by the shelly, the rollo_basikansteuerung.rules takes care if the command has been sent and repeats the command if needed.

The rollo_szenen.rules itself takes care of the defined roller shutter positions I want to have, e.g. for sleeping, waking up etc. These scenes are used within other rules then as well.

The rollo_shelly.rules file seems to work properly. While implementing, I figured out some very weird behavior and therefore reduced the rollo_basikansteuerung.rules a lot to identify the reason. But I am struggling.

Attached the code I am currently using

rollo_basikansteuerung.rules

rule "Control Rollo Kueche Neu"
when
    Item ControlRolloKueche received command
then
    logInfo("Control Rollo","Kueche, Zielwert: "+ ControlRolloKueche.state.toString +", Istwert: "+ Shelly_Kuecherollo_Steuerung.state.toString)
    Shelly_Kuecherollo_Positionsansteuerung.sendCommand(ControlRolloKueche.state as Number)
end

rollo_szenen.rules

rule "Rollos Szene"
when
    Item Rollo_Szene received command
then 
    logInfo("Rollo Szene", "Rollo Szene start ...")
    switch (Rollo_Szene.state.toString) {
        case "Sonnenaufgang" : {
            //
            // Normaler Modus - nur Schlafzimmer runterfahren
            //
            if (Klimamodus.state == 1) {
                logInfo("Rollo Szene", "Sonnenaufgang, Klimamodus "+Klimamodus.state.toString)
                ControlRolloSchlafzimmer.sendCommand(95)
                ControlRolloKinderzimmer.sendCommand(0)
                ControlRolloKueche.sendCommand(0)
                ControlRolloWohnzimmer_links.sendCommand(0)
                ControlRolloWohnzimmer_rechts.sendCommand(0)
            }
            //
            // Hitzemodus
            //
            if (Klimamodus.state == 2) {
                logInfo("Rollo Szene", "Sonnenaufgang, Klimamodus "+Klimamodus.state.toString)
                ControlRolloSchlafzimmer.sendCommand(95)
                ControlRolloKinderzimmer.sendCommand(95)
                ControlRolloKueche.sendCommand(0)
                ControlRolloWohnzimmer_links.sendCommand(0)
                ControlRolloWohnzimmer_rechts.sendCommand(0)
            }
            //
            // Kältemodus
            //
            if (Klimamodus.state == 3) {
                logInfo("Rollo Szene", "Sonnenaufgang, Klimamodus "+Klimamodus.state.toString)
                //ControlRolloSchlafzimmer.sendCommand(0)
                ControlRolloKinderzimmer.sendCommand(0)
                ControlRolloKueche.sendCommand(0)
                ControlRolloWohnzimmer_links.sendCommand(0)
                ControlRolloWohnzimmer_rechts.sendCommand(0)
            }
        }
        
        case "Aufstehen" : {
            //
            // Kälte Modus
            //
            if (Klimamodus.state == 3) {
                logInfo("Rollo Szene", "Aufstehen, Klimamodus "+Klimamodus.state.toString)
                //ControlRolloSchlafzimmer.sendCommand(0)
                //ControlRolloKinderzimmer.sendCommand(0)
                ControlRolloKueche.sendCommand(0)
                //ControlRolloWohnzimmer_links.sendCommand(0)
                //ControlRolloWohnzimmer_rechts.sendCommand(0)
            }
        }
        case "Ab ins Bett" : {
            //
            // Kälte Modus
            //
            if (Klimamodus.state == 3) {
                logInfo("Rollo Szene", "Ab ins Bett, Klimamodus "+Klimamodus.state.toString)
                ControlRolloSchlafzimmer.sendCommand(0)
                ControlRolloKinderzimmer.sendCommand(0)
                ControlRolloKueche.sendCommand(100)
                ControlRolloWohnzimmer_links.sendCommand(100)
                ControlRolloWohnzimmer_rechts.sendCommand(0)
            }
        }
        case "Schlafen" :{
            //
            // Kälte Modus
            //
            if (Klimamodus.state == 3) {
                logInfo("Rollo Szene", "Schlafen, Klimamodus "+Klimamodus.state.toString)
                ControlRolloSchlafzimmer.sendCommand(95)
                ControlRolloKinderzimmer.sendCommand(100)
                ControlRolloKueche.sendCommand(100)
                ControlRolloWohnzimmer_links.sendCommand(100)
                ControlRolloWohnzimmer_rechts.sendCommand(100)
            }
        }
        case "Mittag" : {
            //
            // Normaler Modus
            //
            if (Klimamodus.state == 1) {
                logInfo("Rollo Szene", "Mittag, Klimamodus "+Klimamodus.state.toString)
                ControlRolloSchlafzimmer.sendCommand(0)
                ControlRolloKinderzimmer.sendCommand(0)
                ControlRolloKueche.sendCommand(0)
                ControlRolloWohnzimmer_links.sendCommand(0)
                ControlRolloWohnzimmer_rechts.sendCommand(0)
            }
            //
            // Kälte  Modus
            //
            if (Klimamodus.state == 3) {
                logInfo("Rollo Szene", "12 Uhr, Klimamodus "+Klimamodus.state.toString)
                ControlRolloSchlafzimmer.sendCommand(0)
                ControlRolloKinderzimmer.sendCommand(0)
                ControlRolloKueche.sendCommand(0)
                ControlRolloWohnzimmer_links.sendCommand(0)
                ControlRolloWohnzimmer_rechts.sendCommand(0)
            }
        }
        case "Sonnenuntergang": {
            //
            // Kälte Modus
            //
            if (Klimamodus.state == 3) {
                logInfo("Rollo Szene", "Sonnenuntergang, Klimamodus "+Klimamodus.state.toString)
                ControlRolloSchlafzimmer.sendCommand(95)
                ControlRolloKinderzimmer.sendCommand(100)
            }
        }
        case "Nacht" : {
            //
            // Kälte Modus
            //
            if (Klimamodus.state == 3) {
                logInfo("Rollo Szene", "Nacht, Klimamodus "+Klimamodus.state.toString)
                //ControlRolloKinderzimmer.sendCommand(100)
                ControlRolloKueche.sendCommand(100)
                //ControlRolloWohnzimmer_links.sendCommand(100)
                //ControlRolloWohnzimmer_rechts.sendCommand(100)
            }
        }

        case "Unterwegs" :{
            //
            // Kälte Modus
            //
            if (Klimamodus.state == 3) {
                logInfo("Rollo Szene", "Unterwegs, Klimamodus "+Klimamodus.state.toString)
                ControlRolloSchlafzimmer.sendCommand(0)
                ControlRolloKinderzimmer.sendCommand(0)
                ControlRolloKueche.sendCommand(0)
                ControlRolloWohnzimmer_links.sendCommand(0)
                ControlRolloWohnzimmer_rechts.sendCommand(0)
            }
        }
        case "Zuhause" :{
            //
            // Kälte Modus
            //
            if (Klimamodus.state == 3) {
                logInfo("Rollo Szene", "Zuhause, Klimamodus "+Klimamodus.state.toString)
                ControlRolloSchlafzimmer.sendCommand(95)
                ControlRolloKinderzimmer.sendCommand(100)
                ControlRolloKueche.sendCommand(0)
                ControlRolloWohnzimmer_links.sendCommand(0)
                ControlRolloWohnzimmer_rechts.sendCommand(0)
            }
        }
        
        case "Kino" :{
            logInfo("Rollo Szene", "Kino")
            ControlRolloKueche.sendCommand(50)
            ControlRolloWohnzimmer_links.sendCommand(100)
            ControlRolloWohnzimmer_rechts.sendCommand(50)
        }
    }
    logInfo("Rollo Szene", "Rollo Szene beendet ...")
end

For debug reasons I manually select either “Nacht” or “Aufstehen” to check whats happening. Kitchen (Kueche) should be either 0 (Aufstehen) or 100 (Nacht). Quite simple for testing.

When changing scenes manually forth and back from Nacht to Aufstehen and vice versa after a while the log shows that the wrong “Zielwert” (target value) is used. As said: Night should have “Zielwert” 100, “Aufstehen” 0. The last log shows that after a while it takes the wrong value and I have no idea why. Log file is attached.

I am using openhabian 2.4 on my raspberry 3B+.

log.log (12.3 KB)

Thank you a lot!
Best
Matthias

Because commands are asynchronous. Any state update happens later.

Thank you for the hint.

I was not aware of the event bus causing latency that could cause the rule to get the firing trigger but not the updated value itself. As postUpdate seems also not to be a solution regarding the link, I am wondering what the proper way of sending a value to a rule (not calling it a command :wink:) might be. I assume this is something that is used regularly but is obviously also not that trivial. I could think about global variables but I assume this is neither required nor efficient.

I am up for good solutions.

Thanks
Matthias

You just have to think carefully about what you use as rule triggers, and what you use as data.
Are you truly interested in the state of an Item? Then trigger your rule from state changes or updates.
Are you interested in the command that was sent? Then use receivedCommand in your rule.

Sounds trivial when reading it but to be honest: what is the difference of the state or the received command? And how do they address or even solve the asynchron issue?

Sorry if the question is too easy, for me it’s not :wink:.

Thank and best
Matthias

The underlying model of openHAB -
An Item is our model of some external device - let’s say, a roller blind.
You might send it a command from a rule or UI. Let’s say you command “UP”.
The command passes through bindings and communication methods to the device.
The device actions the command and passes it’s new status back through comms and binding etc.
Eventually that results in the Item state being updated, say to “80%”.
Maybe after a while longer it will send again, “90%”.

In order to work with real world devices, two key issues arise there -
We never expect an immediate response to a command.
Item state value has no direct connection to last command value.

The model also has to deal with devices that never send any status at all - so there is a mechanism to emulate the usual path, called “autoupdate” (it guesses a likely outcome).
Just like a real binding and device, it makes status updates in response to commands. So there’s still a turnaround delay.
That’s a useful feature for “dummy” Items that aren’t associated with any real device, but Items are Items and play by the same rules.

Looking at your rule, it’s a perfect example of why it works this way. You send a command to a rollershutter. Of course, at the moment you send it the roller is exactly where it was before you sent the command. It takes time to move to a new position.

You have choices to make about what you are interested in for your rules.

If you want to know the command, you can trigger rules from command and use the explicit variable in the rule to find out what the command was.

If you’re interested in the state after the command is actioned, you can trigger your rule from changed or updated to get the new state (and totally ignore commands if you like).

1 Like

Thank you for the detailed reply!!!

So if I understand correct received command will contain the sent command ignoring the real state and having no delay? This would be probably the solution for my virtual items.

Best regards
Matthias

The implicit variables in rules are a powerful feature

Thank you for the hint. The implicit variables solved my problem.

Best
Matthias