Help with groovy, replace text


(John Lord) #1

i have a smartapp i’m working on that when someone comes home, if they open the front door within 5 minutes, i sonos-greet them with a custom message. However, i would like to be able to automatically plug their name into the text string in place of %person%. When i tried doing it, i got exception errors. How can i modify a text field through code like this?


(Mike Maxwell) #2

def userName = "snoopy"
def prompt = "Hello ${userName} we missed you, welcome home"
There are also replace functions in groovy, but they are a bit more cumbersome than just building the string from scratch.


(John Lord) #3

would this work?
def prompt = ""
prompt = message1 //message1 = a text field
prompt.text.replace (’%person%, presence1)//presence1 is a presence // sensor named the same as the user

thanks for your help. I’m pretty good at programming, but i’m just learning java and groovy.


(Jim Anderson) #4

Funny, the other night I was writing a SmartApp to do this exact thing!

@Mike_Maxwell is correct; the easiest way to do this is by using the ${} Groovy operator to perform text substitution.

For a string defined in double quotes, you can place a statement inside a ${}, and the contents will be evaluated and substituted in the string. Mike’s example shows this:

def userName = "snoopy"
def prompt = "Hello ${userName} we missed you, welcome home!"

In the above example, prompt would become “Hello snoopy we missed you, welcome home!”

(FWIW, you can shortcut the above by omiitting the {}, and just using $userName. This is because it is a simple substitution. The {} are needed when you want to evaluate a statement into the string, like ${person.displayName}. But, it doesn’t hurt to always use the ${} syntax in all cases).

For your case, you could even use the displayName property of the presence device, if you are using it and have configured it for your device. For example, in my app (that I haven’t had a chance to finish and test yet), I define a presence input in my preferences for which I want to greet like this:

preferences {
       section("Choose the person you want to welcome") {
		input "person", "capability.presenceSensor", title: "Which person?", required: true
	}
       ...
}

You can create a custom message for this person by using the displayName of the presence sensor:

def message = "welcome home, ${person.displayName"}

This will result in the message being “welcome home, Rachel” for my wife, since I gave her presence sensor the name of Rachel (coincidentally that’s her name :slight_smile: ). But you could use whatever substitution you want, instead of the displayName.

We’ve identified the need to provide more documentation to help people new to Groovy, but do currently have some documentation about Groovy here. And here is a very brief discussion of this string substitution feature. Also, here is the documentation for the displayName property available to every device instance.

Hope this helps, and would love to see (and compare :slight_smile: ) your SmartApp for this use case!


(John Lord) #5

i’m being hung up by trying to make the greet message configurable. I can’t seem to figure out how to have the user define where the username goes.


(Jim Anderson) #6

Do you want to allow the SmartApp user to specify the name to use in the greeting, or do you want to use the name associated with a presence sensor?


(John Lord) #7

i want to use the presence sensor name, and i want to be able to specify with some kind of “placeholder” such as %person% where exactly in the message it goes. This way i can change the message without having to edit the app.


(Jim Anderson) #8

Ok - that’s pretty straightforward. Did you see my earlier reply about how to do exactly that? Perhaps I wasn’t clear.

Provided you have given your presence sensor a label in the mobile UI (e.g., could be someone’s name), you can then simply use the displayName property on the presence device. The ${} is the placeholder that you speak of, and accomplishes what you want.

Assume that the presence sensor I can configure has the label of “Rachel”:

preferences {
  section("Choose the person you want to welcome") {
    input "person", "capability.presenceSensor", title: "Which person?", required: true
  }
...
def message = "hello ${person.displayName}, welcome home!"

In the above example, message would be “hello Rachel, welcome home!”. If the selected presence detector instead had the name “Jim”, message would be “hello Jim, welcome home!”

Hope that helps.


(John Lord) #9

i understand how the ${} works. what i’m hung up on is how to do that in a field, not a declared string. This is why i was trying to use a marker and use the replace string function. I am having all kinds of problems doing something that should be easy. I tried copying the contents of the text field to a string and then modifying that with a search/replace but it’s erroring out on me.


(Mike Maxwell) #10

what do you mean by a field?


(John Lord) #11

i’m actually not successfully copying the string to a variable. on the properties page, i have this:
input “message1”,“text”,title:"%person% will be replaced with name"

if i simply have “myvariable = message1” i get “null” stored in myvariable. If i try message1.text i get a runtime error (no such property). I can’t find any documentation on the textbox.


(Mike Maxwell) #12

To retrieve the value use def myVar = settings.message1


(Patrick Stuart [@pstuart]) #13

are you trying to set the input box default value?

You can do that using, defaultValue: “${username}” if you need to.

Then you can access it later in the set up as Mike described, using settings.(inputboxname)


(John Lord) #14

that fixed one of my problems.
i’m seriously thinking there may be a bug in the implementation here.

state.greetingText = settings.message1
        log.debug state.greetingText
        log.debug 'that was before replace'
        state.greetingText = state.greetingText.replaceAll('%person%', 'no person')
        log.debug state.greetingtext

the first log.debug shows an expected output: hello %person%
The second one outputs null!
note: i’ve also tried replace instead of replaceAll, and i just recently tried the assigning of it to itself. I found that on a help forum. This is giving me a headache. I’ll be back later.


(Mike Maxwell) #15

state variables aren’t guaranteed to be coalesced between invocations.
I’m not sure what the need to use the state variables here is anyway…
Try debugging this with a local variable first, then add in the read/write to state.
you might want to drop the “%” from your place holder, there’s no need for them to be there unless “person” is going to be part of your greeting…


(John Lord) #16

frankly i didn’t know there was a difference in the variables. There are things i need stored (whether or not they’ve been greeted yet, or how long they’ve been home) but that all seems to be working fine. I’m probably just going to forget the whole thing. The only real purpose of what i’ve been trying to do is have a single smartapp be able to greet all people returning home by name. But i don’t have the support code there for it anyway. Example: i only have a single variable for tracking if the greeting has been said. If i install the app once for each person, it works fine. I don’t understand enough of the platform yet to know if a bunch of small apps is better or worse than one big one.