It seems that a driver sendEvent command for an attribute is not instaneous, even when issued without a delay. Expecting attribute armMode to be 'disarmed' which it eventually becomes, but immediately after the sendEvent it remains 'armedAway'.
Is there another way to do this or am I doing something that is wrong?
The issue is that the device's values and states are not updated in the same thread. Its a confusing issue.
The new value won't be reflected until the device executes that method again.
I have a method I'm working on to turn on a bunch of lights and verify they are on and try again if not. To do that I can only do it by executing the method in a loop using the runin command. Below is a very ruff pseudo code of what I do (minus all the logic behind checking and stopping the loop etc).
The runin command will reload the states before the next execution of the method.
def turnOnDevices() {
if devices are not on then
turn on devices
runin 3s turnOnDevices
else
All are on and we are done
More details in thread below. Somebody else was having a similar issue.
That's a good question: is this a difference from ST?
I was assuming this was done on purpose to ensure ST compatibility. If this is different from ST then I see absolutely no justifiable reason for this behavior. It makes doing some really basic things exponentially more difficult than they should be.
Well, I know that ST didn't update the state values in the DATABASE until the end of execution (not real-time as states changed). I ran into that nuance multiple times.
If 'device' functioned like 'state' in ST, this DTH would be failing 100% of the time. It appears in ST device.currentValue attribute is a realtime fetch, or it works like "instant update" atomicState .
From the ST docs (for the record, I don't look everything up, I just happened to already have the ST docs open ) :
The current or latest state for an attribute value is the most recent value the device has reported to SmartThings. It is not calculated by polling or otherwise directly communicating with the device.
For example, someDevice.currentValue('someAttribute') will get the most recently reported value for the specified attribute. If the device has malfunctioned, or the SmartThings Hub has gone offline, it is possible that the value returned is not consistent with the physical status of the device.
So in this instance, if I am thinking correctly, the question is when does HE update the state after the lock() command is issued to the device.
Might be a question for the HE guys I guess, but I would have thought AFTER the instance execution of the driver. But I would have thought that on ST as well since it is supposed to read all states from the DB at the beginning, and write them all at the end... So external changes during execution shouldn't be seen. But based on your comments on how it worked in ST, I am obviously wrong.
I haven't run into a scenario where the timing mattered this closely for me. I need to noodle on this some more.
I think this line might speak for itself. It doesn't say "most recent value after the thread/instance that caused the attribute to change." This would be a very important nuance to note here. Instead it very clearly says "most recent value reported" period.
@JasonJoelOld I agree with what you're saying when dealing with state variables... But I suspect it's not the same thing. When you refer to state I think you're referring to a state variable, IE:
state.variableName = 'Some Value'
But that's not exactly the same thing as a device "attribute" like locked/unlocked or on/off, etc. They may be internally stored the same way perhaps, but they are exposed differently. For example, here's a basic dimmer switch device in HE:
On the right you have the "Current States" section which makes up the attribute values that are accessible using device.currentValue("attribute name")
At the bottom you have the "State Variables" section which lists the state variables that are only accessible within the device driver code using: state.stateVariableName
Again: maybe all of these are stored the same way in the same database. But they are definitely exposed and handled differently in the UI and from within Groovy.
I am definitely thinking in a state variable context. Maybe that doesn't apply here. If not, then I've just confused the situation more, instead of helping.
I guess I'll think some more before typing all my thoughts.
Yes, we cache these values for performance sake. typically you never need to access the value that you just sent.. ie in your example you are asking for the armMode but you just set the armMode 2 lines above.
If you really want to do this, or you need the non-cached current value, pass true as the second parameter:
Have you tried the sendevent with isStateChange: true, and no delay? I saw the commented out sendevent has statechange, but not the test with no delay.
Just curious as In ST that was needed if you wanted tile status to immediately update... Not sure if it has a similar effect in HE - might not.
So I guess we kinda just went along with what you were asking instead of asking what you are trying to accomplish. Yes, sendEvent is not instantaneous. It creates a request that is put in a queue and a separate thread picks up and runs. For human consumption this happens pretty much instantly, in the computer however it can very easily run the next line of code before any of that happens.
So I'll start over. What are you trying to accomplish by setting the armMode to a value and then looking up that same value again? can you post the full code and let us know what that method is trying to do?
It an existing ST DTH sometimes armMode attribute is updated in a routine
other routines subsequently test armMode and expect the most recent value.
So is the sendEvent is queued, and there is no enq / deque funtion that I am aware of to serialize a subsequent fetch of the data, it's hit or miss on getting the most recent value.