Something Rotten in the State (that can't save its value)


#1

I have an app that sets different state attribute value depend on which function was last called.
i.e state.changedBy=1

The code goes something like

def funct1() {
log.debug "So what is the value at start of funct1 - ${state.changedBy}"
if (state.changedBy== 2) {
do nothing except
state.changedBy=0
}
else
{
doSomething like turn on a switch AND…
state.changedBy=1

}
log.debug “So what is the value at exit of funct1 - ${state.changedBy}”

}

def funct2() {
log.debug "So what is the value at start of funct2 - ${state.changedBy}"
if (state.changedBy== 1) {
do nothing except
state.changedBy=0
}
else
{
doSomething like httpGet() and…
state.changedBy=2

}
log.debug “So what is the result at exit of funct2 - ${state.changedBy}”
}

Funct1 is called via Endpoint api
Funct2 is called via on/off event of a button.

So the problem is that the value will randomnly be set back to zero. Here is a typical log output in such case

So what is the value at start of funct1 - 0
So what is the value at start of funct1 - 1
(funct1 turned on/off a switch that caused the on/off event to fire and call funct2. BUT WHAT HAPPENED TO > state.changedBy=1??? )
So what is the value at start of funct2 - 0

Somehow state.changedBy lost its value of 1 . This is a problem because now funct2 will execute the “Else block” which is a no no


(ActionTiles.com co-founder Terry @ActionTiles; GitHub: @cosmicpuppy) #2

I’ve experienced something like this a while back, but didn’t dig into it. I just changed my code not to use state for the functionality I needed.

I know that doesn’t help… Just posting to agree this is not just your app, and curious to follow.


(Barry) #3

try atomicState.changedBy for both value change and if comparisons.

YMMV/


(Jeff Beck) #4

So I can tell you how state works at this time and point to what might be happening.

At the start of execution state is retrieved.
Your code executes on a copy of the state.
At the end of execution if there are any modifications to the copy retrieved the state is saved.

So what can cause issues is triggering other executions of the app such as via a subscription or schedule those will can pull state before other executions have finished and they can save state values that were retrieved earlier possibly.

Trying to do coordination with state will be odd based on how it is stored and retrieved. Using event and their data would be a better option IMHO.


(ActionTiles.com co-founder Terry @ActionTiles; GitHub: @cosmicpuppy) #5

That definitely explains what I encountered.

Thing is that there are no “global variables” available except state (but limited per your description) and Device Attributes (requires Events to consistently update… And requires a Device to hold the Attribute(s)).

I guess we are allowed to create named Events that are not pre-declared as an Attribute, but is this proper?


(Kristopher Kubicki) #6

Personally, I just make a new attribute and check device.current value() – its probably not how it was intended to be used, but its much easier to track everything


(ActionTiles.com co-founder Terry @ActionTiles; GitHub: @cosmicpuppy) #7

That’s the complication though… Only Device Handlers can have ad hoc added Attributes (i.e., variables with scope outside their methods).

Except for state, there are no similar full file scope variables or attributes in SmartApps.

On the other hand, I think it would be perfectly fine to use Virtual Device instances as data stores for SmartApps. It should work fine. Virtual Switches are a simple and common example.

I’d like to see Capability “Data Store” to explicitly tag such Devices, perhaps with a single Map Attribute.


#8

This all sounds very interesting . Can you elaborate how this could be done? Modify the device type by adding attribute?


#9

Well it seems my state attribute issue is the least of my problem :rage: The real issue is network lag between this ST app and an app running on a Windows Server to control my Wemo Devices. Under normal conditions the flow is as follows:

ST App sends ON command to WemoServer via httpGet()
WemoServer responds back to same ST app with “ON” command
ST app ignores this as the virtual switch is already on.

But what happens if you press the same switch 2 times or more in a rapid succession?

ST App sends ON command to WemoServer via httpGet()
Before the WemoServer can respond, ST App sends OFF command to WemoServer via httpGet()
WemoServer responds back to the first command from the ST app with “ON” command
ST app processes the ON command received as the ST virtual switch is OFF (by step 2 above).
WemoServer responds back to the second command from the ST app with “OFF” command

The only solution I have found to this problem is: Dont push the button too fast :rage:


(ActionTiles.com co-founder Terry @ActionTiles; GitHub: @cosmicpuppy) #10

Correct. SmartThings currently lets you add “ad-hoc” (arbitrary) Attributes in the “metadata{}” section and then update these with “sendEvent” so that their values will be retained and shared among any SmartApps granted access to the particular Device Instances.


(ActionTiles.com co-founder Terry @ActionTiles; GitHub: @cosmicpuppy) #11

That is the correct solution.

SmartThings runs very asynchronously by design. The local network is a mesh and delivery of messages isn’t guaranteed … not even the sequence of events is guaranteed.

ST’s documentation states this upfront and talks about the internal state reflecting the real world as “eventual consistency” or something like that …