SmartThings API documentation - Frustrating!


(Jim W) #1

While I am new to programming in Groovy, I’m not new to programming in general. Give me some code examples and an API and I’m good to go. I’ve programmed a couple apps now, and the process is so frustrating due to a lack of documentation. I’ve tried using the SmartThings API but there is so much undocumented functionality I’ve found in other apps.

The particular issue I just had that prompted this post is to do with device lists. I wanted to check two device lists to see if there were any devices found in both lists. A google search shows the .intersect() property of lists, easy enough. I try outputting the following lines:

log.debug "Switch list 1: ${mySwitch}"
log.debug "Switch list 2: ${mySwitch2}"
log.debug “Switch intersect: ${mySwitch.intersect(mySwitch2)}”

which gives me the following output:

Switch list 1: [mySwitch[0], Bedroom Flood, Bedroom Jim, Bedroom Michelle]
Switch list 2: [mySwitch2, Bedroom Jim, Bedroom Michelle]
Switch intersect: []

Well that didn’t work! Maybe SmartThings doesn’t support the .intersect function with lists? Lets test that out.

def ListA = [‘Hi’,‘bye’,‘yo’]
def ListB = [‘me’,‘you’,‘yo’]
log.debug “Intersection: ${ListA.intersect(ListB)}”

will give you

Intersection: [yo]

Huh, it worked. So I guess you can intersect lists, so why isn’t the list of devices working? Is it not an actual list? Another Google search teaches me the .getClass() function, so I give that a try on the variable mySwitch.

error java.lang.SecurityException: Invoking class physicalgraph.app.DeviceWrapperList.getClass() is not allowed @ line 75

Oh. So it isn’t a list, it’s a class called DeviceWrapperList. Does it not inherit the List class (and thus the function intersect)? Frustrating. Well, let me read up on that class to find out what I can do.

We have finally come to the SmartThings API. Using Google to search it is more likely to return what you’re looking for than the search built into the API. For this issue, the best I could find was this section. And all it does is tell you that a list of devices will be returned if multiple is set to true. But not a real list apparently.

There’s so much of the API hidden, some of which you can access and some you can’t, but no documentation about it. So if your Google searches don’t turn up someone else’s program that’s doing what you want, you’re kind of SOL.

Anyways, I can of course write my own .intersect function to loop through the lists looking for values in both lists. It’s an expensive operation, but minuscule considering the probably size of both lists. The point of this post is more to vent about the lack of documentation which makes programming for SmartThings difficult. (Though if there is a function to do what I want, please let me know!)


(Tim Slagle) #2

Thanks for the feedback :smile: @Jim and @unixbeast, our amazing documentation gurus, are always looking for good feedback.


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

While we are on the general topic of API Documentation…

Can some confirm that sendEvent(Device, Map) is not applicable in general SmartApps, but only in Service Manager SmartApps… Or whatnot? I did a forum search and could not find any working examples, but the exact constraints are not documentated…

Based on:
http://docs.smartthings.com/en/latest/ref-docs/smartapp-ref.html#sendevent


(John S) #4

intersect is a groovy language feature. For it to work, the elements in each set (or list) must evaluate to equal when compared. My guess is that the device objects don’t do that for some reason.


(Andrew Mager) #5

Hey Jim (@noname4444),

Check out this Getting Started guide: http://docs.smartthings.com/en/latest/getting-started.html

Here is another great example of a SmartApp called Laundry Monitor: https://github.com/SmartThingsCommunity/SmartThingsPublic/blob/master/smartapps/smartthings/laundry-monitor.src/laundry-monitor.groovy


(Jim W) #6

Thanks, sorry about the tone, I was just frustrated at another API wall. I would love to see a full API of all the custom SmartThing classes which includes their sub-classes, public properties, and public functions. And then for the functions include what the parameters are and what class any object(s) they return is. It could even just use the header block above each class/function, it doesn’t need custom documentation for everything.

Yep, I presume if there is a DeviceWrapperList class then there’s also a custom Device class that doesn’t have extended the comparitor to work properly for that class. Which is fine, if I can understand what I’m working with by looking at the API or documentation. My frustration comes from having to figure out what SmartThings classes can and can’t do by trial and error (or even what class I’m working with).

I’ve read through most of the documentation and have written a couple apps (like this one). It’s not that I don’t know how to create an app, it’s where to find information about the custom SmartThings classes. I understand that SmartThings is trying to keep things simple, but their documentation is lacking in many areas.


(Andrew Mager) #7

You should submit that app, it’s pretty cool: https://graph.api.smartthings.com/ide/submissions


(Jim W) #8

Thank you! I was considering it, I wasn’t sure what the criteria is to be accepted in that.

I still have a little more to do with it. I’ve added a sendNotificationEvent that contains the full days forecast, now I’m adding error checking to the input screens.

Which is why I was wanting to find the intersection of two lists, if someone uses a bulb in the temp group and the forecast group, that will be wonky. Well, it will have the forecast color as that’s assigned second, but I don’t want people to have a bulb in both groups.


(Andrew Mager) #9

You can read more about the process here: http://docs.smartthings.com/en/latest/smartapp-developers-guide/submitting-smartapps-for-publication.html


(Jody) #10

I second this. We can never have too much documentation.


(John S) #11

Something like this then:

[mySwitch,mySwitch2]*.groupBy{it}.with { a, b -> assert a.id == b.id }

Maybe?


(Tim Slagle) #12

No no, this isn’t what I was suggesting. We are currently running a whole program around giving more complete docs. That’s why i thanked you for your suggestion and tagged our documentation guys here.


(Jim W) #13

Hmmm… that gives me a null value, but I see where you’re going with it. I’ll have to play with it tomorrow when I’m not half asleep and see if I can’t get that working. Thanks for the suggestion!


(Jason Mok) #14

Intersecting device.id works:

log.debug "Switch list 1: ${mySwitch*.id}"
log.debug "Switch list 2: ${mySwitch2*.id}"
log.debug "Switch intersect: ${(mySwitch*.id).intersect(mySwitch2*.id)}"

an alternative to intersect:

log.debug "Switch intersect: ${mySwitch.findAll { e -> mySwitch2*.id.contains( e.id ) }}"

(Jim W) #15

Wonderful, thank you Jason! That’s much more elegant than the solution I eventually went with. So for someone new to the SmartThing classes, is there a way to learn about the properties for devices (in this case device.id) in any documentation that I’ve missed? Or is it just from reading other apps?


(Patrick Stuart [@pstuart]) #16

getProperties() is your friend.


(Dave Hastings) #17

Yes. We understand your pain and frustration. Good API documentation has been on our radar for a long time. Our plan is to come up with a mechanism to generate the API documentation right from the src code. However, the way things stand now, it’s not as simple as generating Groovy Doc. This is one of the higher priority items for us and hopefully you will start seeing improvements soon.

Dave


(Jim W) #18

Thanks to everyone for the replies and the help. I’m quickly picking up on what can and can’t be done.

For any of the many knowledgeable and helpful individuals who have replied thus far, I have a question about the number input type.

Lets say I want to allow a user to select the brightness (aka switch level) for a bulb. I have a numeric input field, and based on the code I’ve read through I set a property “range: 1…99”. Recently I discovered that this range isn’t enforced and that users can enter any positive number.

Well, checking the documentation, range is not listed as a property of the input field, so it seems that’s not actually supported. I then setup some error checking to prevent users from installing the app if they have a number that’s out of range, but it turns out submitOnChange does not work for the numeric input.

So right now I’ll probably test what happens when you set the level, hue, and saturation of a bulb to something like 500 for each, which I presume will be they get set to their max possible value, and just not check those values. Or if out of range numbers don’t work, my program will have to check for that at runtime and set the numeric value to the max allowed. I could change the type to an enum and give the user a pick list, but I rather the user have the full range to pick from.

Anyways, if anyone managed to read through this full post, my question is whether I’m missing something and there’s a better way to limit numeric input. Should the range property actually be working? Should submitOnChange work for numeric?

Also, changing topics slightly, I’ve yet to find any documentation on the “state” property for href! From what I can tell, state: “complete” will cause the row to be green, and state: anything else will leave it grey like default. Is this correct? I wanted to have the href tag turn red (like a required field that hasn’t yet been filled out), but setting state: “incomplete” did not do that. Does anyone know if there’s a way to do this?

Why is the property state for href not in the docs? Why is the property defaultValue for input not in the docs?


(Jody) #19

Something like that?

input "tempOffset", "number", title: "Temperature Offset", description: "Adjust temperature by this many degrees", range: "*..*"

You are saying there is no validation on the range when the user hits submit?


(Jim W) #20

Correct, when I have the input

input(
	name		: "${deviceID}Level"
	,type		: "number"
	,title		: "Brightness level, between 1 and 99.  Defaults to keeping the current level."
	,range: "1..99"
	,required	: false
	,defaultValue: settings["${deviceID}Level"] ?: null
	,submitOnChange: true
)

The range field does nothing, you can put in any valid numeric value. Which is fine, as it turns out there’s nothing in the user docs about a “range” property for inputs, but I’ve seen it in multiple apps so I figured it was a valid setting. It would be nice if the range field did exist for numeric inputs.