Can an app access a device no longer in an input?

In an app, is it possible to remember (in app state) the device network ID of a device that the user selected in a device input , clear the input to re-purpose it, and then later retrieve and access that previously selected device for use in the app?

I am trying to create an interface that lets the user dynamically add any number of objects, with the various input fields being reused for adding each object. For example, I want to let the user add any number of "persons", and have for any new person a name input and a device input. When the user clicks the "submit" button, the app would pull the name in the name input and the device in the device input, and add the new person to the app's state. Then, if the user wants to add another person, the name input and the device input would be cleared, then would be filled in by the user for another person, and then when the user clicks the "submit" button this time, the app would pull the new name and the new device and store it in state again.

This works well for non-device inputs so far, but I don't know how to make it work well for device inputs. I can store the device input field in state, but I don't know if that does what I want it to or if it is just a snapshot of the device rather than a dynamic handle to the device. I need something like getDeviceByNetworkId(networkID). I don't suppose such a method exists or is there any workaround to make this work?

With Hubitat's app/device model, apps (or at least custom/user apps) can only access devices that users have specifically selected. Technically, after a device gets selected, it doesn't have to be visible in the UI anymore, but I'd consider not doing so bad practice, as it can lead to the "Rule Machine problem" you may have seen some people complain about where they have phantom "In use by" references they can no longer remove (though in the case of RM, it's not actually a problem for the app per se, as it's not really in use--here it looks like it would be).

It's hard to give specific advice without seeing what you're really doing, but it sounds like the ability to dynamically generate inputs, including their names, would be helpful to you. I wouldn't try to re-use the exact same input for different purposes. This is a bad* way of illustrating what I'm talking about, but if you aren't familiar with the dynamic capabilities of Groovy in Hubitat app UIs, here's an example:

input name: "numberOfPeople", type: "number", defaultValue: 1, required: true, submitOnChange: true
// ...
numberOfPeople.each { num ->
  paragraph "Person ${num}:"
  input name: "personName.${num}", type: "string", title: "Name", required: true
  input name: "personDevice.${num}",  type: "capability.something", title: "Device", required: true
}

(* it would be a bit more user-friendly to just have an "Add" and "Remove" button compared to making them specify a number, but this is easier to write. Also, I'm leaving out the rest of the dynamicPage where this would have to live.)

To directly answer your question, you cannot store a device in state (or at least it's not an allowed data type on ST, and I assume it's the same on Hubitat). You technically can use app.updateSetting() to put something in settings (like an input would) instead, and this will create the setting if it doesn't exist, but you'd still have to get a reference to the device in the first place (from an input) and I'm not 100% sure updateSetting() can take a device as a parameter for the value...and for the same reasons as above, I'd consider this a bad idea even if it does.

Hopefully this is helpful; if not, a minimal example of the code you're working with would likely get better advice.

I thought about the add/remove button as you mentioned there. But how do you handle when a user wants to remove a person in the middle of the list?

[UPDATE] Ok, looks like clearing the input fields when a person is deleted cleans things up nicely. So that will work fine.

Looks like you got something figured out, but this indeed tricky so probably worth answering if you or anyone else ends up caring in the future. I did this in one of my apps, and what I do is track the in-use "indices" in state in a List. So, the "Add" button adds the next available number to the end of that list, and the "Remove" button removes the relevant number from that list (and to be nice, I also remove all the settings associated with it, trying to avoid the "Rule Machine problem"). Then, the inputs really get dynamically generated by iterating over that List rather than a specific range. The easier, less-user-friendly alternative--which may be good enough if the only intended user is yourself--is to make the user delete things in order (backwards). :slight_smile:

Ha, yup that's exactly the way I ended up doing it too. Independently coming up with the same solution must suggest that it's the right way to do it :slight_smile: Thanks for your help.

For security reasons this is not supported (an unscrupulous app could gain access to devices the user has not authorized it to access). You can't put a device in state either. So, the only devices you can access in an app are ones obtained from an input. This leaves the app user in charge of what the app can control, not the app author.

Thanks. Makes sense.