Problem with previousState

I think it is very easy but I cannot get what is my error.

I want to get the previousState of an item.

I use jdbc as persistance and in this database all is good.
grafik

But if I want to get it into a rule no success.

Group:Switch:OR(ON, OFF)    gSwitchesAnzahl   "Test-Switches [(%d)]"
Switch swSwitch04  "swSwitch04"                        (gSwitchesAnzahl)
gSwitchesAnzahl.members.forEach[item | 
           logInfo("gSwitches","############### gSwitchesAnzahl:         State: "+item.name + ": " + item.state.toString)
           logInfo("gSwitches","############### gSwitchesAnzahl:    lastUpdate: "+item.name + ": " + item.lastUpdate("jdbc").toString)
           logInfo("gSwitches","############### gSwitchesAnzahl: previousState: "+item.name + ": " + item.previousState(false,"jdbc").state.toString)        ]
2018-01-07 21:22:06.226 [INFO ] [pse.smarthome.model.script.gSwitches] - ############### gSwitchesAnzahl:         State: swSwitch04: ON
2018-01-07 21:22:06.226 [INFO ] [pse.smarthome.model.script.gSwitches] - ############### gSwitchesAnzahl:    lastUpdate: swSwitch04: 2018-01-07T16:23:19.000+01:00
2018-01-07 21:22:06.226 [INFO ] [pse.smarthome.model.script.gSwitches] - ############### gSwitchesAnzahl: previousState: swSwitch04: ON

State is correct and lastUpdate too.
But previousState is wrong.

Whatever I tried, no success.

I also noticed that some time ago so I did not use it. Would be interested to know if it is working at all. I am using mySQL persistence.

It is a bit counter intuitive.

previousState(false) will give you the most recent entry in the database. This will almost certainly always be the current state (unless you have restarted or reloaded a .items file or something like that).

previousState(true) will give you the most most recent entry in the database that is a different state from the current one. Much of the time this is what you are actually after. So if you changed to true your log would show the correct value and time that you expect.

Where this all breaks down is when you are saving updates or periodically in your persistence instead of just changes and you want the previousState even if it is the same as the current state.

Now, if your rule is triggered by a received update, then you have the implicit variable previousState which will have the previous state of the Item independent of persistence.

1 Like

Hi Rich,

thanks for you reply.

I had some z-wave devices which sends updates even if the status does not change.
I want to sort them out and want to trigger a group rule only if the status is changed not updated.

I have to compare the update with the previous value and if it the same, do nothing.

The implicit variable previousState does not fix it, because this will be the group item not the real item which updates the group.

my idea:

val item = gSwitchesAnzahl.members.filter[l | l.lastUpdate != null].sortBy[lastUpdate].last
 if(item.state != item.previousState)
  do something
 else
 do nothing

I searched around the internet and there are some hints, that previousState does not work at all.

But there is an idea to solve it with a workaround.
Look for lastUpdate then check if changedSince(minus some seconds) is true
But I cannot get this to work.

logInfo("gSwitches","############### gSwitchesAnzahl: changedSince: "+swSwitch04.name + ": " + swSwitch04.changedSince(now.minusSeconds(5),"jdbc"))

is working but does not help.
Replacing now() with lastUpdate() should help. But looks like a syntax error

logInfo("gSwitches","############### gSwitchesAnzahl: changedSince: "+swSwitch04.name + ": " + swSwitch04.changedSince(swSwitch04.lastUpdate("jdbc").minusSeconds(5),"jdbc"))

12:10:06.369 [ERROR] [.script.engine.ScriptExecutionThread] - Rule 'swSwitch06 gedrueckt': An error occurred during the script execution: The name '<XMemberFeatureCallImplCustom>.minusSeconds(<XNumberLiteralImpl>)' cannot be resolved to an item or type.  

Other idea:
can it be a time problem

Is this really the same time? O 1h difference due to a wrong persistance database time setting?

12:19:50.867 [INFO ] [pse.smarthome.model.script.gSwitches] - ############### gSwitchesAnzahl:    lastUpdate: swSwitch04: 2018-01-08T10:43:22.000+01:00
12:19:50.870 [INFO ] [pse.smarthome.model.script.gSwitches] - ############### gSwitchesAnzahl: previousState: swSwitch04: Mon Jan 08 10:43:22 CET 2018

Found this out, is the same time. cannot be the root of the problem.

Have you tried changing your Group to something like:

Group:Number:SUM gSwitchesAnzahl "Test-Switches [(%d)]"

And trigger your rule using:

Item gSwitchesAnzahl changed

The Group’s state will be the sum of switches that are ON so it will change whenever a Switch changes state but will not trigger for routine updates.

This was my thought in the past too.

The number will counted up and down but this does not create an “Item gSwitchesAnzahl changed” event. Only if all are OFF or ON the event is created.

For me it looks like only previousState can solve this but this does not work and looks liek broken a long time now. Tested with OH2.0 and OH2.1 too.

Do you think I should open a ticket at the developers and if yes where?

Hi Rich,

now it is working like you told me. A reboot of OH helps.

But now this is no longer reliable

val alarm = gSwitchesAnzahl.members.sortBy[lastUpdate(“jdbc”)].last

It does not reflect the changed item. I think I have to play with the sleep before using the rule to give persistance to do his job.

If it is a Group:Number then the Group’s state will change as the Switch’s states change. At least it does for me. The behavior you describe sounds like what happens when you use a Group:Switch like you have now.

Yes, a sleep of no more than a couple hundred milliseconds is should be plenty.

Continuing the discussion from Problem with previousState:

Hi,

I’m facing another situation with ‘.previousState()’.

The issue is with the TRADFRI lights, since they are initialized after persistence kicks in on system reboot.

I’m able to get this value from influxdb, but as @rlkoshak mentioned it is the same state as current once reload is finished. This is, of course, due to fact that state is changed from UNDF to “Current state” which triggers new persistence record to be added to DB.

It is well known problem that TRADFRI lights go to ON state after power loss, and in this situation when system is rebooted, previous state of TRADFRI items is ON as well.

For this reason I would need to return not previous state but one before. Using previousState(true) approach would get good result only in this situation, but let’s say that I deliberately rebooted OH server and I have couple of light ON. In this situation I would get “mirror image”, so all lights that were ON would go OFF and via versa.

The persist rule is set to

“* : strategy = everyChange, restoreOnStartup”

So the question is how to get “previousState(+1)” because it would work in both cases.

Any help would be appreciated.

I wonder if you could somehow discover the last system uptime timestamp, and use that timestamp in a .historicState(timestamp-1)

I get your point… I’ll give it a try…

Also, I’m not sure if I need to hit exact timestamp in order to get the record from DB?

Hi,

I draw the diagram for this and found following problems with this approach:

“lights : strategy = everyChange, restoreOnStartup” should be changed to
“lights : strategy = everyMinute, restoreOnStartup” in order to get state from
SystemStart.previousState + System Uptime.previousState

this would significantly increase DB size in long run.

Is there other way to resolve this?

It would be perfect if it can be something like .previousState(-1) in the future, but for now, I’m trying to find workaround. :frowning:

I believe (but am not sure at all!) that .historicState will attempt to do what it says - return the state at the requested time. Logically, that will be whatever it last changed to or whatever it last updated as, before the target time. Providing a target time of now-less-a-bit should reach back before a reboot?
item.historicState( now.minusMinutes(3) )

Hi @rossko57

Thanks for your efforts. This approach would be problematic if power loss is larger that 3 minutes in this example…

Anyhow, I found a “dirty” workaround. I have created additional item for each of the light switches “_PERS”. I have also created a rule which change _PERS state on light switch change.

From there, I have created part of System started routine with 30 sec delay which set light switches from previous state of _PERS item.

When I said it is “dirty” I meant that for this to work, you would need to create _PERS item, create a rule for changing _PERS item state based on light switch and to make a rule that will change light switch state based on _PERS state on startup for every light you introduce to the system.

All of this until simple previousState(-1) is introduced at certain point in time hopefully. :smiley:

No, I believe historicState(xx) will rummage back in the database to find the previous update. i.e to determine the asked for state at time xx, it finds the most recent clue from before time xx.

This is correct. historicState will return the database entry before the time passed to it. So as long as you pick a time that is after the time you want but before it changed state because of the power failure. rossko57’s suggestion is sound.