Collecting data outside of the preferences/settings paradigm


(Kevin Shuk) #1

I’m wondering if it’s possible to collect data from the user in a way more remniscent of HTML forms. I’m finding the tight binding of preferences to settings variables and the inability to directly set them is really limiting.

I’d like to be able to present a form, maybe have some fields pre-filled, collect the data on submit, and process and/or store it into the state variable. Future edits for the same thing would have the form pre-filled with the data last stored in state.

Is this at all doable with ST right now?

Thanks,
Kevin


(Brian Steere) #2

How is this different from the preferences idea?

I believe default options are possible. The only difference I’m aware of is not allowing preferences to be changed by the SmartApp without user intervention.


(Eric R) #3

You could use a state variable and dynamic pages like this example:

preferences {
	page name:"setupInit"
    page name:"setupFirstTime"
    page name:"setupInstalled"
}

def setupInit() {
	if (state.installed) {
    	return setupInstalled()
    } else {
    	return setupFirstTime()
    }
}

def setupFirstTime() {
	
    def inputSomeVariable = [
    	name:			"someVariable",
        type:			"string",
        title:			"Type the variable",
        defaultValue:	"default value",
        required:		true
    ]
       
    def pageProperties = [
    	name:		"setupFirstTime",
        title:		"Preferences",
        install:	true
    ]
    
    return dynamicPage(pageProperties) {
    	section {
        	input inputSomeVariable
        }
    }
    
}

def setupInstalled() {
	def inputSomeVariable = [
    	name:			"someVariable",
        type:			"string",
        title:			"Type the variable",
        defaultValue:	state.someVariable,
        required:		true
    ]
       
    def pageProperties = [
    	name:		"setupFirstTime",
        title:		"Preferences",
        install:	true
    ]
    
    return dynamicPage(pageProperties) {
    	section {
        	input inputSomeVariable
        }
    }
}

def installed() {
	log.debug "Installed with settings: ${settings}"

	initialize()
}

def updated() {
	log.debug "Updated with settings: ${settings}"

	unsubscribe()
	initialize()
}

def initialize() {
	state.someVariable = settings.someVariable
}

That should do what I think you are asking for.


(Kevin Shuk) #4

@Dianoga, yup defaults are a thing, and I see that now since @baldeagle072 called defaultValue out to me. Thanks to both of you for replying

You also describe just what I’m trying to work around - that the settings collection is not mutable from the app, only by the user from the UI. I can’t imagine the rationale behind this partitioning.

My use case is that I want to manage user codes for one or more locks. Each device will be the source of truth for its own data set. In fact, I want the app to not hold any state for the devices, Just taking the simple scenario of a single lock.

I can list the codes already set in the lock device within the app. How I’d like to do this is that, on tapping an existing code or a button toe create a new code, I’d show a page that I reuse with blanks for Name and Code. The variables would always be empty, but I’d use defaultValue if I had to pre-fill a value. If I’m adding a new code, the inputs would be blank. If I’m editing a slot, the inputs would be pre-filled with whatever valued the lock had data for the slot I’m editing (using defaultValue). If deleting a value, I’d use a separate button the on the page. In all cases, once I collect and use the values from the input fields in the updated method, I don’t need or want the settings variable nodes any longer.

The only way I can see to do this is to generate new settings variable names for each invocation of an add, edit or delete since I can’t flush or override whatever values had been in them previously. This seems hugely wasteful at best, and explicitly coding a memory/storage leak at worst.

I’ll be the first to acknowledge that this may be a sign that this isn’t the right way to accomplish this goal - is there a more SmartThings way to go about this? Could using a child app help here? I could only see that working if a child app instance can be brought into existence when I go to add/edit a code, and destroyed after I do what I need to do with the data. Of course, addChild is mentioned only once in the docs (http://docs.smartthings.com/en/latest/smartapp-developers-guide/dashboard-solution-smartapps.html?highlight=addchild) , and there’s no hint of a “removeChild”

To give a thumbnail of why I’m going down this road - I want to manage locks in tandem. Say front and back door locks. I want to set code 8675309 for Jenny, and have it propagate onto both locks. I don’t care what slot number it is in on the locks, or even if it’s in the same slot on each. The device can handle the slot-name-code acrobatics, and the app’s purpose is to provide the UI, and a sensible UX to the end user. Future directions include selecting which lock(s) a code would be inserted on, setting schedules and the like.