SYNTAX Question: Tile Action call a function with a parameter


(Steve Ledridge) #1

How do you format the action on a tile so that it calls a function and passes a parameter?

I currently have to create a separate on and off function for each of the eight ports instead of calling the one function that accepts two parameters…

I know the function works because I can add a command and trigger it from the IDE like:

command “OutletAction”, [“string”], [“string”]

I just can not figure out the right syntax to get it to fire from the action.

//CURRENT TILE
standardTile(“Outlet1”, “device.Outlet1”, width: 1, height: 1) {
state “off”, action:“on1” , label: “Off”, backgroundColor: “#ffffff”, nextState: "on"
state “on” , action:“off1”, label: “On” , backgroundColor: “#79b821”, nextState: “off”
}

//CURRENT FUNCTION
def on1() {
log.debug "Send Outlet 1 ON"
def uri = "/outlet?1=ON"
postAction(uri)
}

//WANTED TILE
standardTile(“Outlet1”, “device.Outlet1”, width: 1, height: 1) {
state “off”, action:‘OutletAction(“1”,“ON”)’ , label: “Off”, backgroundColor: “#ffffff”, nextState: "on"
state “on” , action:‘OutletAction(“1”,“OFF”)’, label: “On” , backgroundColor: “#79b821”, nextState: “off”
}

//WANTED FUNCTION
def OutletAction(outlet,action) {
log.debug "Send Outlet ${outlet} ${action}"
def uri = "/outlet?${outlet}=${action}"
postAction(uri)
}


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

Great question, and I can’t give you a conclusive answer … perhaps @Jim (the ST Documentation czar) will be able to research sometime and clue us in.

But here’s my observations:
First reference the Documentation: http://docs.smartthings.com/en/latest/device-type-developers-guide/tiles-metadata.html

Notice that the argument action must be the name of a <command> (i.e., it is NOT the name of an arbitrary method in the Device Handler, it must be a Command). Still, that may not be of much consequence because I’m not sure it is enforced that all Commands to be declared in the metadata {}

Now take a look at any common slider ControlTile; such as this one from “Hue Bulb”.

controlTile("levelSliderControl", "device.level", "slider", height: 1, width: 2, inactiveLabel: false, range:"(0..100)") { state "level", action:"switch level.setLevel" }

This is correct syntax according to the Documentation.

But what does the Command method signature look like for setLevel()?

def setLevel(percent) {
	log.debug "Executing 'setLevel'"
	parent.setLevel(this, percent)
	sendEvent(name: "level", value: percent)
}

Aha!?: It takes one argument ("percent") and yet, this is not explicitly specified in the action:"switch level.setLevel". That action clause has no parameters at all!

So where does the value of the argument percent come from? It must be implicitly supplied by the controlTile, no?


So if you are using a “standardTile”, I believe that similar conclusion can be made.

  1. Perhaps the value of “state” is passed as the parameter to the Command if necessary,
    OR
  2. (More likely…): Actions (commands) called by standardTiles are not permitted to have any arguments.

(Steve Ledridge) #3

I had seen that example as well and have tried using spaces between parameters like this:
action: “OutletAction 5 ON”

but this did not work either. in fact, every way I have tried fails without any error or debug entry to identify what it didn’t like about it so I am limited to trial and error until it just finally works.


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

The spaces are only valid in the Capability name (from the Capabilities Taxonomy).

E.g. “switch level.level

The first part (qualifier) is required (?), because theoretically, you could have a `level()’ Command from two or more different Capabilities claimed by the one Device Handler.

Browse through lots of code examples (that’s what the experts here do, until Docs improve).

But the official docs don’t permit parameters.

So just write cover methods for each Tile?


(Steve Ledridge) #5

Cover Methods was my fallback, but I was just hoping there was a better option.


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

There’s always hope. :sunrise_over_mountains:


(John S) #7

Why not just read the current state, and set it to the opposite one in the command (like a toggle)


(Steve Ledridge) #8

John, I don’t understand how that helps me,

I can read the state but I still have to make a specific url call “/outlet?${outlet}=${action}” where outlet is 1 to 8 and action is either on,off, or ccl which (8x3) comes to 24 different versions of the url. if I can’t pass a parameter then I would have to create 24 covering methods.


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

Instead of having 8 Buttons under one Device (one “Thing”), could you create 8 Child Devices?

Each Child device would know its own outlet number in a global.

I can’t be more detailed because I haven’t written a Parent / Child Device Type yet, but I keep thinking that it really is the proper (?) way to handle multi-instance devices (whether they be multi-button or multi-outlet, etc.).


(Steve Ledridge) #10

that would probably also resolve the issue of where to apply “switch” context. I have a device written for the Aeon smart switch which does that, I will have to go look at that for an example, I hadn’t started from there because this was a web api rather than zwave and it was much more complex.


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

A key advantage will be that all your SmartApps that accept any “capability.switch” Things will be able to select any of the individual outlets with no additional coding.

i.e., To the SmartApp, it should look like just a bunch of distinct Appliance Modules.

This is the reason I call it the “proper” approach, as interchangeability of Things of the same Capability is fundamental to ST.


(John S) #12

I was assuming “outlets” were distinct devices with their own state (like port #, and current setting on/off) - so I agree the clean way to do this is to make a device type that is a single switched outlet, which also knows what port it.


(Michael) #13

Sorry to revive a very old thread but I would like to know the answer to this question too on how a parameter can be passed in an action of a standardTime. My use case is simple, instead of duplicating a function 15 times, I would like to create one function and pass in a number as a parameter that corresponds to the tile number.
action: “functionName(1)” as an example

@Jim @slagle @jody.albritton @Tyler any thoughts?


(Michael) #14

Bump…
@Jim, @slagle, @csuk, @jody.albritton, @Tyler any ideas?


(Tim Slagle) #15

I don’t believe there is a way to pass a parameter, like you want, as it stands now.


(Michael) #16

@slagle thanks for confirming. One last question, is there a way to know which tile called an action function? That would work for my use case if that’s possible to get the tile device attribute somehow in the execution of the action.


(George) #17

Maybe I’m missing something here, would this not work?

action: "tileOne"

def tileOne() {
     realMethod(1)
}

def realMethod(whichTile) {
//do whatever
}

(Michael) #18

I will have 16 buttons and this will require 16 action functions. Each of these functions will call the same code but with a different tile number. I am trying to avoid this code duplication thus having 1 action function where I can pass in a tile number.


(George) #19

Makes sense. Yeah, there’s no way to pass a param or be able to tell which tile was tapped. The issue with not being able to pass a param is similar to the problem with runIn.


(Eric) #20

Same issue with runIn(…) & schedule(…). It can make your code look sloppy.