Mixing atomicState and state


#1

I know not to mix these in the same app but can I have an app using state and a child app using atomicState ?

As a bit of background I have a device driver that discovers devices over the network, this discovery takes a while (maybe a minute) and devices are returned individually. I'm trying to build an array that I can present to the user to select devices to add. But from experience it seems I will have to use atomicState otherwise my array is incomplete, but device drivers don't support atomicState so I am passing each device back using events to my app.

I then tried using atomic state in my app but it appears then I cant add an atomicState array variable for options to the 'enum' in an input.

input "MQTTSwitches", "enum", multiple: true, title: "Discovered MQTT switches", options: atomicState.MQTTSwitchDevices

Cannot get property 'MQTTSwitchDevices' on null object on line 23

It errors during compile/save. So my only workaround seems to be build the array in a child app using atomicState and then pass the complete array back to the main app using state to then use as the options in an enum input ?

Or am I just approaching this all wrong ?
Is there another example device driver that does this anywhere I can look at ?
I'm new to Groovy/HE coding and the lack of scoped vars is weird.


#2

I'm not sure that you can use any variable for the options in an enum - unless that's changed in one of the most recent updates.

My LIFX driver uses an app with child devices, but I'm not sure how much it would help you, see GitHub - robheyes/lifxcode and the thread about it LIFX Local Control


#3

Looks like the problem is because your variable is null.

What you can do is use an if statement to display the input only if the variable is not null. If it is null display a message. I’ve done this in my apps.


#4

Gavin ,let me think on that but it's not a runtime error, it's a compile time error.


#5

state variables seem to work OK in options - but atomicState variables don't.

Let me look over the LIFX app as you must have to do the same I think, if you allow the user to select which bulbs to add.


#6

Thinking laterally is there a programmatic way to create but hide devices , and also a way to disable devices ?

Hoping that one just hides them in UI but allows selection in inputs , Rule Machine etc - and the other would hide them from everything except getChildDevice()


#7

In this case, I add all devices, not sure why I you wouldn't - the user can always delete them


#8

My issue is on my large network using MQTT I am discovering 250+ devices !!
Everything with onoff or dim capability - lights, switches, sensors like PIR's etc, Sonos amps

Maybe I need to look at building dynamic html pages


#9

Strange. But I see that it doesn’t happen with state variables. I wonder if it’s because of the differences between the two.

I remember looking at them before but other than having it save the values right away with atomic state the actual variable is handled differently too.

I’ve done what you are trying to do but with only state variables. And it doesn’t update real time. I had to added a refresh button to refresh the page. I think it was in one of my apps where I was discovering the Wemo switches.

You can also set the page up to automatically refresh every x seconds. Though I always hated that.


#10

@chuck.schwer or @bravenel just before I got too far down the wrong rabbit hole have you any tips for this ? Both the very first question in OT and the aspect of building a runtime list for input enum options using an atomicState variable.

Oh and this Q.

Or maybe you can point me at code for a similar app/driver where many devices appear randomly / asynchronously , sometimes in rapid bursts, where I want to give the user a choice of which devices to add , prior to creation.


#11

I don't know the answer. But, why don't you pull the atomicState list into a local variable first, examine it for grins with a log.debug, and then stick that local variable in the input "enum" as its options. See what's going on and causing your compile error.


#12

Probably a really stupid Q but by local variable do you mean a state variable ?
I can't create a local variable that is scoped across all the device handler routines can I ?


#13

I took that line and added it to an app I was working on just to check (in its own section).

It works fine. The app compiled fine and the drop down is blank (as expected as that variable does not exist).

Not sure if its something else causing the error or the variable has some data already that its not agreeing with.


#14

Ahh... i took it out of the section statement and got that error when trying to install the app...

Could that be it?


#15

OOOhh that is promising .. let me investigate further.
There's not the possibility that atomicState.MQTTSwitchDevices was previously actually created but empty is there ?

Mine is in

 preferences {
   section {
             // here
        }
}

#16

You could change it to atomicState.MQTTSwitchDevices ?: [] (assuming that it's a list - if it's a Map then use [:] instead.


#17
	input "HASwitches", "enum", multiple: true, title: "Discovered HA switches", options: atomicState.HASwitchDevices ?: []

Cannot get property 'HASwitchDevices' on null object on line 23
when trying to install


#18

Shot in the dark..but try changing

section {

to

section ("") {


#19

Ok.. able to reproduce it at compile time. This causes an error when trying to save

preferences {
	section {
		input "MQTTSwitches", "enum", multiple: true, title: "Discovered MQTT switches", options: state.MQTTSwitchDevices
	}
}

However on my apps I use pages so I have it setup like this and it works.

preferences {
	page(name: "config")
}
def config() {
    dynamicPage(name: "config", title: "", install: true, uninstall: true) {        
	section {
		input "MQTTSwitches", "enum", multiple: true, title: "Discovered MQTT switches", options: state.MQTTSwitchDevices
	}
}

It must be how it handles the state/atomicstate at compile time.


#20

Doesn't matter. First form is fine.

I don't know what you're trying to do or where. I meant just locally in that method, as in

def myList = atomicState.xyx

No, you can't have a variable that is scoped across all the device handler methods, except for state. I thought you were talking about an app though.

And, all input statements must be within a section { ... }