State vs previousState, strange behaviour?

Hello folks,

I’m trying to learn openhab design and it’s taking me a lot. A week ago, you helped me to create a Virtual Switch (item) because I didn’t know you can create one. So, I’m trying to build some basic rules with a virtual switch to understand how they work together. Although I am not a programmer, I have a computer science degree so it’s something I can understand and follow the logic.

So I create the following rule. It is as simple as that. It only monitors a Switch and when something “changes” it prints some information in the log. I’m using the variable previousState and it works as expected but with item.state and item.previousState, it’s becoming much more difficult.

Here is the code,

rule "Virtual Switch Change"
when
    Item VirtualSwitch changed
then
    logInfo("DCG", "Something has changed")

    if (previousState == ON) {
        logInfo("DCG", "Before ON")
        logInfo("DCG", "VS PreviousState " + VirtualSwitch.previousState(false, "mysql").state.toString)
        logInfo("DCG", "VS State         " + VirtualSwitch.state.toString)
    } else {
        logInfo("DCG", "Before OFF")
        logInfo("DCG", "VS PreviousState " + VirtualSwitch.previousState(false, "mysql").state.toString)
        logInfo("DCG", "VS State         " + VirtualSwitch.state.toString)
    }
end

But the output I’m seeing is this:

2017-12-27 19:49:52.238 [INFO ] [g.eclipse.smarthome.model.script.DCG] - Something has changed
2017-12-27 19:49:52.244 [INFO ] [g.eclipse.smarthome.model.script.DCG] - Before ON
2017-12-27 19:49:52.253 [INFO ] [g.eclipse.smarthome.model.script.DCG] - VS PreviousState OFF
2017-12-27 19:49:52.260 [INFO ] [g.eclipse.smarthome.model.script.DCG] - VS State OFF

2017-12-27 19:50:14.682 [INFO ] [g.eclipse.smarthome.model.script.DCG] - Something has changed
2017-12-27 19:50:14.689 [INFO ] [g.eclipse.smarthome.model.script.DCG] - Before OFF
2017-12-27 19:50:14.699 [INFO ] [g.eclipse.smarthome.model.script.DCG] - VS PreviousState ON
2017-12-27 19:50:14.704 [INFO ] [g.eclipse.smarthome.model.script.DCG] - VS State ON

That doesn’t make sense to me as VirtualSwitch.previousState == VirtualSwitch.state. Before sending this message, I took a look at my persistence service (mysql) and the table looks fine as it has a sequence ON-OFF-ON-OFF what it’s clearly what I’m doing with the switch.

Can someone shed some light about this behaviour? Is it normal?

Thank you very much for your support.

PS: By the way, I’m using the latest openHABian release

The things to realize are:

  • the previousState variable gets populated based on values in memory and is completely independent from Persistence
  • passing false to VirtualSwitch.previousState causes it to return the most recent saved state even if it is the same as the current state. If your .persist file is configured to save periodically or on every update it can easily be the case where the VirtualSwitch.previousState == VirtualSwitch.state
  • Persistence takes place in parallel with Rule execution, it is possible that the current state hasn’t been saved in the DB yet, or it has already been saved; since you are using false, if the current state gets saved before you get to that log statement that gets the previousState then it will return the current state

it seems to me that this check is failing.
shouldn’t it be:

if (VirtualSwitch.previousState == ON) {

No, dcalvo is using the previousState implicit variable in that test:

https://docs.openhab.org/configuration/rules-dsl.html#implicit-variables

previousState - will be implicitly available in every rule that has at least one status change event trigger.

If you have a rule triggered by a changed, previousState will be populated in what the state changed from. So, for example

rule "Switch Chaged"
when
    Item MySwich changed
then
    if(MySwitch.state == ON) // previousState == OFF or NULL
   else if(MySwitch.state == OFF) // previousState == ON or NULL
end

The previousState variable is indenpendent from Persistence.

1 Like

I came to this old post.

Do I understand it right, that mapdb does not have the possibility to give me previousState?

What I try to do is:
group items and detect which one triggers my rule as a change of the single item

item definition:
Group:Switch:OR(ON, OFF) gSwitchesStatus “Test-Switches [(%d)]”

If I use in rule:
Item gSwitchesStatus received update
the items which just get an update to the same state triggers the rule too, but I want to sort them out.

checking .previousState(false,“mapdb”).state.toString does not work because the status is the same as the current state, because of what was written above.

If I change to mysql as persistance does this fix this?

correct since it only saves the most recent state which is the current state of the item.

most of the rest will work because they save more than just the most recent state.

Rich,

First, sorry for my delay in coming back to this thread but it has been a busy week and second, what a pleasure having you here!!

I’ve been reading some answers from you and they have given me a lot of insights and useful information about the openhab internals!! So Thank you.

I read your answer very carefully, but honestly I don’t get it (the full picture), It’s quite clear that previousState gets populated from memory and not from mysql but why do I want to have a previousState method when it is not giving me the previous state? I know that I can change the “false” to a “true” and in that case I will receive the latest value that it’s different but let’s imagine that my sequence is:

OFF-ON-ON

I would like to know that I’m coming from an ON to another ON but if I use the method with false, I guess I will see an OFF. Am I right? (what a mess!)

And finally, I would like to go deeper with openHAB and its internals, where do I can get more information about its structure, classes, types and on? I’ve been browsing Eclipse web site but I don’t find the exact page.

Thank you very much.

Hi Angelos,

As Rich wrote, inside a rule based on “changed status” you can use the previousState implicit variable.

Thank you.

I can answer the “what”, as in what OH and the Rules engine does which I’ve learned through experience. I’m not a maintainer and do not follow the development threads that closely so I can’t answer the “why” it works the way it does. All I can say is the way I described above is how previousState has worked for as long as I’ve used OH.

I think perhaps it is mainly poorly named as it doesn’t return the previous state at all, just the most recent entry in the DB or the most recent state in the DB that is different without taking into account whether that entry is the result of the current State, saved because of a periodic save (e.g. everyMinute strategy) or is actually the previous update.

Correct. But let me ask another question from the other side. How would the persistence be able to differentiate between that middle ON being saved because of an update verses just because the value is saved every minute? In that case that ON would not be the valid previousState, it is just an entry because the Switch has been ON for more than a minute.

It is indeed a mess, but a mess with no clear way to clean it up.

Most of the stuff you will want to look at will be in the Eclipse SmartHome repo.

That is where the actual code that makes up most of these core concepts is implemented. You can find the JavaDocs for the classes here:

https://www.eclipse.org/smarthome/documentation/javadoc/index.html

There really isn’t any documentation at this level so you will have to look through the source code itself.

1 Like

Once again, thank you very much.

I can see that I’m not very far from your point of view as it seems that my thinking was accurate.

Regardind your big question:

Correct. But let me ask another question from the other side. How would the persistence be able to differentiate between that middle ON being saved because of an update verses just because the value is saved every minute? In that case that ON would not be the valid previousState, it is just an entry because the Switch has been ON for more than a minute.

Absolutely right, that is why I have the following persistence directive:

VirtualSwitch : strategy = everyChange

Because I only want to keep track of when that item has changed.

As you said, maybe its name is not correct and it shoud be called differently because the way it is now (previousState) it is not very appropiate. For me, previousState means that, “the previous state” and it seems it’s showing something different.

I will take a look at the documentation and try to learn as much as possible.

Thank you!!