How to pass parameters in href?


#1

I try to pass parameters in href to the function using the following:

href (name: "test", title: "Testing href", page: "testId?id=1");

and try to retrieve this parameter in the function:

def testId() {
   log.debug "Params: ${params}"
   log.debug "Id: ${params.id}"
...
}

I see that params is empty in the log. What am I doing wrong?


dynamicPage(s) and href question
(ActionTiles.com co-founder Terry @ActionTiles; GitHub: @cosmicpuppy) #2

Just confirming… Are you referring to “preferences { section() { href ( ... ) } }”?

http://docs.smartthings.com/en/latest/smartapp-developers-guide/preferences-and-settings.html?highlight=href

I don’t think you can pass any parameters (though I’m not sure); but all your settings up to that point are global to the SmartApp, so you can just refer to these global variables.

More context / detail and we can figure this out together.

…CP / Terry.


#3

Yes, it’s for href in preferences (as in your second example with a reference to another preference page.

I found that it’s possible to pass parameters here: I can’t seem to find enough API information
I also found that I can use preference page id with parameters (“testId?id=1”) and app accepts it. testId is the id of another preference page.
The only issue is that I cannot get this parameter in the testId page.

Unfortunately, global variables doesn’t work, because each href in my app should have it’s own set of parameters:

for (int i=0; i<maxNumber; i++) {
   href (name: "test", title: "Testing href", page: "testId?id=${i}");
}

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

Hi Oleg,

This is really tough to figure out without having detailed documentation on “preferences{ href() }”, of course. SmartThings has a relatively new “documentation guy” and he’s doing a great job at fleshing things out (@Jim). In the meantime, you can email Support@SmartThings.com and they will pass it around if necessary to find the definitive answer.

But here’s my best guess:
Unfortunately the posting that you linked doesn’t give a very detailed example. Send a Private Message to @cooperglee for more information, perhaps?

But I still think you could use a “state” variable ("state" is the map of variables that are global to the SmartApp) as a workaround.

for (int i=0; i&lt;maxNumber; i++) {
   state.currentId = i
   href (name: "test", title: "Testing href", page: "testId");
}

Then use: state.currentId inside your “testId” page.
I don’t think it is a messy as it sounds … due to Groovy scoping.

http://docs.smartthings.com/en/latest/smartapp-developers-guide/state.html

…CP / Terry.


#5

Hi Terry,

Thank you for your answer!

But I still think you could use a “state” variable (“state” is the map of variables that are global to the SmartApp) as a workaround.

It was my first thought to try state variable, but unfortunately it doesn’t work. The issue is that the preference page is generated after all internal sections are generated. This means that state.currentId from the sample above will always be equal to maxNumber-1 regardless of which button is pressed.

The more generic question is: How can I dynamically create some buttons and create a new preference page based on what button is pressed? It should look the same way as phrases / actions on the Home screen. I’ve noticed that many developers use the following approach: ask user to enter the number of something (it could be zones, pages, modes, etc.) and after that generate a page (or several pages) with all these entities. This approach allows to work with a limited number of entities, because developer has to pre-create static pages for each combination. It looks pretty ugly (just imagine, there are 10 pages with exactly the same parameters and names like testId1, testId2, … just because there is no way to pass id value as a parameter to the function). This approach doesn’t allow to delete or add any entity and user has to re-configure the whole app (ooops).

It looks like the approach I described above should work, but for some reason parameters are not passed to the params map. May be I just missed smth.

Let me send an email to support and check what they think about it.

Thank you,
Oleg


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

I think I am still misunderstanding your requirement.

Check out Lines 161 to 170 in my code… This is a dynamic page with the number of choice entries and range of each entry dependant on earlier defined input local variables…


#7

Thank you, it’s a really good example and almost what I need. Let me try to explain my requirements using an example.

Thermostat modes
I would like to have an option to configure thermostat modes in the application. Each mode includes thermostatMode, heatingSetpoint, coolingSetpoint and other parameters. I would like to add, change or remove a mode at any time. Currently I have the following modes:
Off: thermostatMode="off"
Regular: thermostatMode=“auto”, heatingSetpoint=70, coolingSetpoint=80
Energy Saving: thermostatMode=“auto”, heatingSetpoint=65, coolingSetpoint=85

I may need other modes later on. My application should switch thermostat to one of these modes based on some configurable conditions (time of the day, presence sensors, movement sensors, windows/doors opened, etc.)


NOTE: I already tried to use Phrases, but the solution look overcomplicated and still cannot correctly process all events.


I tried to create a simple app with a UI similar to phrases with the following pages:

preferences {
    page (name: "modes");
    page (name: "modeConfiguration");
}

def modes() {
	dynamicPage(name: "modes", title: "Configure Thermostat Modes", nextPage: "appPreferences") {
		section ("List of Modes") {
			for(int i = 0; i < state.modeNumber; i++) {
				def mode_name=settings."mode_name_${i}"
				href (name: "mode_${i}_id", title: "${mode_name}", page: "modeConfiguration?mode=${i}");
			}
		}
		section ("") {
			href (name: "modeAddInput", title: "Add a mode", page: "modeConfiguration?mode=${state.modeNumber}", required: false);
		}
	}
}

def modeConfiguration() {
    currentMode=params.mode
    dynamicPage (name: "modeConfiguration", title: "Add a thermostat mode", uninstall: false) {
    	section ("Mode Preferences") {
			input (name: "mode_name_${currentMode}", type: "text", title: "Enter mode name");
			input (name: "mode_therm_$currentMode}", type: "enum", title: "Enter thermostat mode", options: ["off", "auto", "heat", "cool"], refreshAfterSelection: true);
			if (settings."mode_therm_${currentMode}"=="auto" || settings."mode_therm_${currentMode}"=="heat") {
				input (name: "mode_heat_${currentMode}", type: "number", title: "Enter heat point");
			}
			if (settings."mode_therm_${currentMode}"=="auto" || settings."mode_therm_${currentMode}"=="cool") {
				input (name: "mode_cool_${currentMode}", type: "number", title: "Enter cool point");
			}
			if (!settings."mode_name_${currentMode}") { 
				state.modeNumber = state.modeNumber+1;
			}
		}
	}
}

The only issue is that parameters are not passed to the second page. I have several similar requirements (like configuring time of the day when thermostat should be switched to a different mode) for this app and for other apps.


(Cooper Lee) #8

This looks good - you don’t need the {} in the href: and you can pass as many variables as you want with &varname=value

href name: “mode_$i_id”, title: “${mode_name}”, page: “modeConfiguration?mode=$i&varname=value”)

Here is what you are missing on the other side: the variable “params” is specific to http mapping data coming back just like “data” is specific to a GET, POST, PUT, etc…

def modeConfiguration(variables) {
currentMode=variables.mode
or
currentMode=variables?.mode
incase the variable “mode” is omitted or null… This is also the same for any other variables you choose to pass…

 *variables?.someVariableName* 

That should get you squared away…


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

Thanks Cooper!

Is the List “paramsstandard in Groovy, or is that just what SmartThings’s href method names it?
If the latter … how did you find out? Guess? Support? A mystery documentation page?

…CP / Terry.


(Cooper Lee) #10

A bit more… params seems to have all the data that is sent via a GET or a POST if it is not JSON… If it is JSON then you have to do a def jsonHook = request.JSON inside of the corresponding “mapping” process… whereas on the prior of the two you can just use params.varName…

pulled apart about every piece of sample code I could find, trial and error with servers locally, created a bald spot on my head, then had success… (lots of guessing) If the mystery documentation were around I would love it :slight_smile: At this point I think I could get hired to write it :smile:


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

Could you provide an example of that with a bit of context, please? No rush … I don’t have a SmartApp in the works that needs this, but you’d be saving us Groovy n00b “readers” out a great deal!

Don’t hesitate to consider applying for a job at SmartThings (if you happen to be “looking”)! They have a lot more hiring planned than implied in just the open roles list. I think @Jim would welcome a team-mate.

…CP / Terry.


#12

Thank you, Cooper! It works well.
I hope I can resolve other issue and finish my app :slight_smile:


(Mike M.) #13

This isn’t working for me. The basic href calls are fine, but if I add arguments to the url, the related function is never called. Has something changed in the last month with regard to how href parameters are parsed?

So,
href name: "name_$i", page:"targetPage", title: "Title $i"
will successfully call
targetPage()

But,
href name: "name_$i", page:"targetPage?id=$i", title: "Title $i"
will not call
targetPage()
or
targetPage(variables)

No errors in the log output, and the first line of the target methods are simple log.debug calls with the method name (which is how I just whether or not a call is being made) the preferences UI just spins and never gets to the target page. In the Android app, the frame for an empty page is presented, but nothing is ever loaded.


#14

Please try

href name: "name_${i}", page:"targetPage?id=${i}", title: "Title ${i}"

I would also suggest to try the following if the line above doesn’t work. I believe the issue is in figure brackets, but having just number will help to understand if it works or not.

 href name: "name_1", page:"targetPage?id=1", title: "Title 1"

(Mike Maxwell) #15

There’s another thread going on about this, and your latter example (which we tried in the other thread), no workie… The gstring evaluations work just fine in the name and title keys, adding ?xx=xx to the page call (with our without gstring usage) results in the page method never being called…


#16

My application works well with these parameters and the method is called. I use the syntax mentioned in my response - no errors and it does whatever is expected.
I will try to create a small test app tomorrow to check this approach on a new app.


(Mike Maxwell) #17

Appreciated as @llamas and I aren’t having much luck with this bad boy.


(Mike Maxwell) #18

Well just call me hack-o-matic…
I think something’s changed, anyway this works:

//href link in another page
href(
    name	: "yada"
    ,title	: "putz" 
    ,page	: "seriously"
    ,install	: "[key:value]"  //any string value, maps, gstrings whatever
)
//page method
def seriously(vars) {
    log.debug "vars:${vars}" //mostly worthless info and what you passed in...
    log.debug "install:${vars.install}" //whatever you passed in in the href call
    dynamicPage(name: "seriously", title: "yea") {
    	section("blabla"){}
    }
}

UPDATE, the above doesn’t work in the APP, so this is still unresolved.


dynamicPage(s) and href question
(Todd Wackford) #19

This works for me:

href "nextPage", 
      title: "Delete", 
      params: [mydata: "a string of data"], 
      description: ""


def nextPage(params) {
        dynamicPage(name: "notherPage", 
            title: "passed in data ${params.mydata}") {
 
  "blah-blah more code"
  }
}

(Mike Maxwell) #20

Wow, just wow…
This works in the app, but not in the IDE, however I can live with that.
Thanks @wackware