How to call a method using a variable

i am writing an app, and i just can't get what should be a simple substitution to work. i always struggle with this stuff.
i just want to turn on each device in turn with a one second delay between each. the on() method is supported for the device.
e.g. device1 is the name of the device (in the input section of the app).
the log shows that the device variable is correct (i.e. "device1").
the error is:
groovy.lang.MissingMethodException: No signature of method: java.lang.String.on() is applicable for argument types: () values: []
Possible solutions: drop(int), count(java.lang.CharSequence), join(java.lang.CharSequence, [Ljava.lang.CharSequence;), join(java.lang.CharSequence, java.lang.Iterable), toURL(), toURL() on line 608 (eventHandler)

def doThemAllwithDelays() {
    doEachOne("device1")
    runIn(1, doEachOne, [overwrite: false, data: "device2"])
    runIn(2, doEachOne, [overwrite: false, data: "device3"])
}

def doEachOne(device) {
    log.trace "device: ${device}"
    "$device".on()
}

You can't pass a device in the data of a schedule as you are trying to do. The method you are calling would need to have some other means of referencing the device by its name in your app, perhaps with a switch().

i'm passing in (manually typed) string names of device objects to the runIn command, not the device objects themselves, if thats what you mean?

so i want the interpreter to action these commands (with delay of course):
device1.on()
device2.on()
device3.on()

so its getting the interpolation/substitution of the method/property name from the provided string.

Keep in mind that in Hubitat, all the inputs in your app get saved to the settings map--besides just becoming field variables like device2. So if you have the name of that input/field and are passing that to another method, you can do something like:

void doSomething(String inputName) {
  // turn on device where inputName matches the 'name' parameter of the input() in app preferences
  settings[inputName].on()
}
// ...
doSomething("device2")

I generally find this clearer than trying to deal with the "plain" field variable name, plus in this case it's easier to get what you want. :slight_smile: (Assuming that is the string you have...)

PS - I'm pretty sure data must be a Map, not a String (and I don't think a DeviceWrapper is something you can pass as part of that regardless, but the name from the input(), again, is; or you could use something like the device ID or other value you can look the device in question up from later if needed). So my example wouldn't work for runIn() but could if the String parameter were a Map (which could contain one key/value pair with this information if that is what you want), again assuming that Hubitat requires a Map for the data parameter (SmartThings does and I assumed it was the same; the Hubitat docs show only this as an example, though technically not specifically typed).

4 Likes

yar har that worked!!!

thank you Bert. all i had to do was change:
"$device".on()

to

settings[device].on()

god I spent hours trying to figure that one out before going cap in hand to the community. took you 1 minute. :clap: :grinning:

2 Likes

Download the Hubitat app