I suppose I am a bit confused at the seemingly needless over-complication of SmartThings. I’m a longtime developer and consummate home automator.
I purchased a SmartHub, in conjunction with some GE Z-Wave dimmer switches to control the lighting in my home. My home automation setup is custom and includes a dedicated external server through which I run everything. Python drives it all - and it will run this as well.
This should be simple - but it seems overly complicated.
I’ve created a SmartApp
I’ve registered my Hub
I’ve created a custom endpoint on my server to authorize my app
In Python, I’m successfully getting a code, requesting a token, getting my endpoints
Great. I’m fully authenticated to my custom SmartThings app via the REST api. Whew.
How the hell do I simply return a list of authenticated switches, then set the value of the light intensity on said switches?
It seems I need to add permissions in my Groovy code, they create a function to return the switches, then add functions to interact with those switches - just so I can communicate with them through Python.
So now I need to write and maintain two separate codebases, one in Python, and one in… Groovy?
Why am I spending time learning Groovy again?
Whatever, I’m doing it.
I created a function in Groovy, using the strange SmartThings web based text editor.
I’ve ‘mapped’ the function to an endpoint
I can call that function in Python using my authenticated code/token/endpoint
What do I need to do to return the number of switches I have, then set/get a value for each of those switches?
Bonus: Why is this so complicated?
I’m ready to return it all and try something else.
Why are you using SmartThings then? Wouldn’t it be simpler to just add a Z-wave dongle to your existing HA server and do everything in Python? Then you wouldn’t have to touch Groovy.
Your SmartApp will need to be given a list of devices that it’s able to access. There’s plenty of examples on the forum. The HomeBridge SmartApp is likely to do what you want (i.e. two-way getting and setting via a SmartThings endpoint): SmartThings + Raspberry Pi & Homebridge = Siri HomeKit Controlled Smart Home
I think I’ve also seen a standard REST API SmartApp somewhere, but I can’t seem to find it atm.
@zcapr17 Why are you using SmartThings then? Wouldn’t it be simpler to just add a Z-wave dongle to your existing HA server and do everything in Python? Then you wouldn’t have to touch Groovy.
Two primary reasons -
SmartThings should allow for greater extendability over time with support from multiple manufacturers
My server is external as mentioned in my post - I need to be able to control it from anywhere
Your SmartApp will need to be given a list of devices that it’s able to access.
… and you’ve added some switches in the smartphone GUI, then in your getSwitches() command you would want to iterate through them and return the attributes you want, e.g.:
def getSwitches() {
def data = []
switchDevices.each {
data << [ switchName: it.displayName, switchId: it.deviceId, switchState: it.latestValue("switch") ]
}
return data
}
I think SmartThings should convert the returned list into a JSON object automatically.
Here’s some code that might be what you’re looking for, or at least a good start. I haven’t tested this, so there might be a typo or something, but you can get the gist.
preferences {
section() {
input "switches", "capability.switchLevel", multiple: true
}
}
mappings {
// e.g., GET <path>/switches
path("/switches") {
action: [
GET: "getSwitches"
]
}
// e.g., GET <path>/switches/1234
path("/switches/:id") {
action: [
GET: "getSwitch"
]
}
// e.g., POST <path>/switches/1234/80
path("/switches/:id/:level") {
action: [
POST: "setSwitchLevel"
]
}
}
// return a list of maps that has info about the configured switches
// will be serialized to JSON when sent to the client
def getSwitches() {
def theSwitches = []
theSwitches.each {
theSwitches << [id: it.id, name: it.displayName, status: it.currentSwitch, level: it.currentLevel]
}
return theSwitches
}
// return a map that has info about the switch with the specified id.
// will be serialized to JSON when sent to the client
// 404 if no switch with specified id configured
def getSwitch() {
def s = switches.find { it.id == params.id }
if (s) {
return [id: it.id, name: it.displayName, status: it.currentSwitch, level: it.currentLevel]
} else {
httpError(400, "No switch with id $params.id configured")
}
}
// sets the switch with the specified id to the specified level
// 404 if no switch with specified id configured
def setSwitchLevel() {
def d = switches.find { it.id == params.id }
if (d) {
d.setLevel(params.level)
} else {
httpError(400, "No switch with $id authorized")
}
}
@Jim Thank you! I really appreciate your post. After some code shuffling, I am finally up and running.
I was about to make a screencap to explain my situation as I could not get things to work correctly, even after massaging your code into my app several times.
Suddenly, I came across something in the docs that was surprising to me…
I have a suspicion that many of my problems were related to the way I was naming my functions. After renaming my functions to names that made no mention of getting or setting, I was free of errors and everything started working as expected.
I’d love to compile more information and confirm my suspicion, but I’ve frankly sank so much time into this that I need to move on - I’m thrilled this tiny integration is working.