Simple example for dimming a switch?


(Ryan) #1

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.


(codersaur) #2

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.


(Ryan) #3

@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.

Of course. That list of devices is provided upon authentication of the app.

So, my app knows about “Kitchen Lights”, presumably.

My question, specifically, was “What do I need to do to return the number of switches I have, then set/get a value for each of those switches?”

I assume this is simple, but I keep running into examples that are hundreds or thousands of lines long.

Everything is hooked up, authenticated and running. I’m hoping someone can help me find these answers:


(codersaur) #4

ok, so assuming you have some devices defined in the smartapp preferences, e.g.:

preferences {
    input "switchDevices", "capability.switch", title: "Switches to monitor:", multiple: true, required: true
}

… 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.

This is all covered pretty thoroughly in the documentation and tutorials:
http://docs.smartthings.com/en/latest/smartapp-web-services-developers-guide/index.html

In fact, the first part of the tutorial covers exaclty this scenario and also an example of a setter function to set the state of the switches: http://docs.smartthings.com/en/latest/smartapp-web-services-developers-guide/tutorial-part1.html


(Ryan) #5

Sure - if I want to turn all light to full brightness or turn all lights off, that tutorial is helpful.

I tried your code. It results in a 500: Internal Server Error


(Jim Anderson) #6

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")
    }
}

References:


(Ryan) #7

@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.

Thanks, again, for your help.