Sendevent command not instantaneous?

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 :smile:) :


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.

1 Like

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.

-Jeremy

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. :frowning:

I guess I'll think some more before typing all my thoughts. :slight_smile:

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:

def devarmMode = device.currentValue("armMode", true)
def devarmState = device.currentState("armMode", true)

The second parameter is "skip cache"

3 Likes

Cool. I certainly didn't know that! Was that the same in ST, too (I don't ever remember seeing that there)? Or something HE specific?

So I was close to right on the "why", I just didn't know "how" to fix it. :wink:

I assume you are asking about the second parameter? I do not think ST has that, I've not looked.

Yes, thanks. I don't think it was in ST, either - didn't turn up in some quick looking.

So thanks for the tip!!! Not sure I will ever need it (haven't yet), but it is good to know these little tricks.

Posted this in the apps and driver porting to Hubitat thread

1 Like

Just tried this. It did not work as advertised. Please verify.

sendEvent(name: "armMode", value: armMode) where armMode=disarm current value is armedAway

def armModex = device.currentValue("armMode", true)
logdebug 'Arm mode: '+armModex

result
dev:1942019-02-26 16:08:06.686 debugArm mode: armedAway

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?

Try adding a pause between sending the event and checking it's status. it may not update immediately.

-Jeremy

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.

What I did as a work around

private setModeHelper(String armMode, delay) {
logdebug "In setmodehelper armMode: $armMode delay: $delay"
sendEvent(name: "armMode", value: armMode)
// sendStatusToDevice()
sendStatusToDevice(armMode)
}

// private sendStatusToDevice() {
// armMode = device.currentValue("armMode")
private sendStatusToDevice(armModex='') {
logdebug 'Entering sendStatusToDevice armModex: '+armModex+', Device.armMode: '+device.currentValue('armMode')
def armMode=null
if (armModex=='')
{
log.debug "using device armMode"
armMode = device.currentValue("armMode")
}
else
{
log.debug "using passed armModex"
armMode = armModex
}

Could do it with states (or even a local variable?)...

Internal states get updated immediately in memory for the instance, so if you set state.armModeX (or whatever) on the line before/after the sendEvent, you can reference that all you want and it would be up to date...

I'm attempting to convert a working ST DTH to a HE Driver. Meaning as few logic and code changes as possible. I posted my functional workaround above that avoids this entire issue without using state.

For the record, the ST driver should not really be doing it that way either, but that is neither here nor there.

Glad you got it working in any case.

1 Like

For the record I am not the author of the original ST DTH.

Understood.

And I certainly understand modifying the minimum necessary to 'get it working'. No judgement being cast by me for that!!! :smile:

1 Like

YESS!!! Thank you @chuck.schwer

it.currentValue(attribute,true) works for me.

I have a loop that will turn off a bunch of switches and then loop to check if they are off and try again.

Until today I had to code something complicated to use the runIn to get the updated values, but now I can just use a regular loop to retry a few times. My method is just to verify things did report back that they were turned off successfully.

It does work but you need to pause in between setting and reading. I had a 1s pause and it would sometimes catch it. I set the pause to 5s and then check again and it catches the new values much more reliably. It just takes time to save it.

1 Like