What can I store in state?

I’m working on my first SmartApp and I’m new to Groovy, so this is a neophyte question.

My app associates pairs of virtual switches with physical doors, and rather than create a separate event handler for each individual device, I have, generic handlers that figure out which door or switch is being handled and changes something in the associated door/switch. Here’s an example:

def onHandler(evt)
{
	log.debug "Handler caught ON request from virtual Switch: $evt.device"
    def map = [
    	(switch1 ? switch1.id : "") : door1, 
    	(switch2 ? switch2.id : "") : door2, 
    	(switch3 ? switch3.id : "") : door3, 
    	(switch4 ? switch4.id : "") : door4, 
    ]
    
    def d = map.get(evt.device.id, null)
    if (d)
	{
    	log.debug "Opening door $d in response to switch ${evt.device}"
        d.open()
	}
}

I’d like to not need to create the map on each callback, but persist it in the app. Based on a recommendation on another thread, I tried putting it in state. That, unfortunately, quickly caused a crash. I can’t paste the exact error because Live Logging is broken for me right now. It was a rather vague and terse exception, and my guess is that I can’t put device references into state.

The docs say:

You can use state to store strings, numbers, lists, booleans, maps, etc

It’s the etc that I’m wondering about. It also mentions:

State is stored in JSON format; for most data types this works fine, but for more complex object types this may cause issues.

My guess is that may cause issues means might crash.

So, I can’t store devices into state. The obvious question is, what can I store? Presumably, any POD is fine, such as device IDs. But if I store device IDs, how do I retrieve a device from its ID? It seems like somewhere there should be a map of all devices by ID.

Am I missing something, or am I going about this wrong?

you can’t save a device object in a state variable, but you can put the device.id in there, and that’s the attribute to use since it’s value won’t change after it’s been created.

def device = devices.find{ it.id == evt.deviceId}

1 Like

devices – that’s exactly what I was looking for. Is that documented anywhere?

“devices” is whatever the preferences name is, the same list used for the subscriptons
IE

	input(
            	name	: "devices"
                ,multiple	: true
                ,required	: true
                ,type		: "capability.switch"
            )
then:
subscribe(devices, "switch.on", onHandler)
1 Like

I don’t have any multi-preferences nor would it be appropriate for my use case so that’s not going to work. Isn’t there some kind of registry of all devices?

You can only access devices that the user who has installed your SmartApp has selected (through the preferences).

1 Like

Okay - I guess that might be a security-based decision. What about the devices that the app does know about; is there a way to search them other than the objects that get created with the preferences section?

The reason I’m not using a multi-preference declaration is that I need to associate N pairs of switches and doors. The ordering and association is important, so having switches[] and doors[] both declared in preferences isn’t going to work.

What I really want to do is something like this:

struct SwitchDoorPair
{
	DeviceId slaveSwitch;
	DeviceId doorControl;
};
vector<SwitchDoorPair> switchDoorPairs;

and then be able to have the user enter those pairs in the UI. I’m new to Groovy, so it’s easier for me to describe what I want to do in C++. For now, I’m just declaring the preferences like this:

section("Synced Switch/Door 1")
{
	paragraph "some text"
	input name: "switch1", type: "device.simulatedSwitch", title: "Virtual Switch", required: true
	input name: "door1", type: "capability.doorControl", title: "Door Control", required: true
}
section("Synced Switch/Door 2")
{
	input name: "switch2", type: "device.simulatedSwitch", title: "Virtual Switch", required: false
	input name: "door2", type: "capability.doorControl", title: "Door Control", required: false
}
...

but I’m sure there’s a better way.

You are correct.

Is it always one switch to one door? And are there really N such possible combinations?

I don’t want to send you off on a wild goose chase without being able to understand and think about your specific requirements, but I do wonder if having one parent SmartApp that contains multiple (N) child SmartApps that control each door/switch pair might make sense (similar to how Smart Lights works - each new lighting automation is an instance of a child SmartApp).

You can learn more about parent/child SmartApps here. Again, I don’t want to send you off on a tangent, but it just occurs to me that this might fit this use case.

2 Likes