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.
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.
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.
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.
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.
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.
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) )
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.
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.