First SmartThings SmartApp, part II

This is a direct follow on from part I, where I give my tips for getting started with SmartApps for SmartThings.

Without further ado, let’s get into the code.

First of all we’re going to get rid of the hardcoding of the server IP, port and URL. It’s fine for testing, but for the final code it’s going to be much more flexible if we can change it from the SmartApp configuration screen.

So, in the preferences section, let’s add:

section("Set destination server") {
  input("serverIp", "text", title: "IP", 
         description: "IP Address")
  input("serverPort", "number", title: "Port", 
         description: "Port", defaultValue: 80)
  input("serverUrl", "text", title: "URL", 
         description: "URL")
} 

While we’re at it, let’s select the temperature sensors:

 
section("Select temperature sensors") {
  input("temperature", "capability.temperatureMeasurement", 
         required: true, multiple: true)
}

This is how it’ll look in the phone app when we add the SmartApp:

Now we hook the events up to our event handler:

def initialize() {
    subscribe(sensors, "motion", evtHandlerMotion)
    subscribe(temperature, "temperature", evtHandlerMotion)

} 

Note that we’re using the same event handler for both event types. We just want to send the results to our server and let the code at that end figure out what to do.

Here’s our event handler:

def evtHandlerMotion(evt) {

  log.debug("Event Handler called")

  try {

    def map = [ eventid: "${evt.id}",
              date: "${evt.isoDate}",
              eventname: "${evt.name}",
              devicename: "${evt.displayName}",
              value: "${evt.stringValue}"
              ]

    def json = new groovy.json.JsonBuilder(map).toString()

    def action = new physicalgraph.device.HubAction([
                    method: "POST",
                    path: serverUrl,
                    body: json,
                    headers: [
                       HOST: "${serverIp}:${serverPort}",
                       "Content-Type": "application/json"
                    ]]) 
    sendHubCommand(action)

  } catch(e) {
    log.debug("Exception $e")
  }

}

We’re using the serverIp, serverPort and serverUrl configuration parameters we set up in the configuration screens to set the path and HOST header.

The content we’re posting is a JSON string generated from a Groovy map. A map is an associative array, equivalent to Python’s dictionary object or Perl’s hashes. We’ve pulled just a few attributes from the event:

1. The date from the isoDate attribute that will give the date and time that the event occurs. This will be in UTC, i.e. not accounting for time zone. We could convert this into a different format in Groovy, but the idea is to do as little as possible to get our message into our server and let that handle the rest where it’s a bit easier to debug.

2. The eventname from the name attribute is the short text name of the event – for the events we’re currently subscribing to it will be either “motion” or “temperature”

3. The displayname from the displayName attribute is the name of the sending device as it appears in the SmartThings app.
The value from the stringValue attribute is the value of the event. In the case of a motion event this will be “active” or “inactive”, while for a temperature event it will just be a number.

We could also send the deviceId so that we have a unique identifier and it doesn’t matter if we rename the device. It’s a design choice for our code, but my preference is to use the friendly display name. The mostly likely reason to rename a device is because we’re using it for a different purpose, in which case it makes sense to treat it as a different device.

We’re taking string values for simplicity and readability in our server application code. It’s easier to understand what’s going on when we’re checking that the motion value is “active” or “inactive” instead of being 1 or 0.

Now we’ve got that running we just need to set up something on our server that will respond to a JSON post to the URL we’ve put in the SmartApp.

There are any number of ways to do that – a PHP script running under Apache is probably the simplest method, but I’m sort of assuming that anyone reading this already knows how to do the server side of it and is mainly interested in how to get the data out of SmartThings.

For my purposes, I’m using the Zato ESB so I just need to create some code. Again, I’ll start simple and just log the input to see what’s being sent by putting the following in smartthings.py

from zato.server.service import Service

class DumpInput(Service):
    def handle(self):
    self.logger.info(self.request.raw_request)

And creating the channel:

So now if I configure my SmartApp to use my server IP address, port 11223 for the ESB and the URL of /testing/smartthings I should get events being logged by the ESB. Sure enough, in the server logs:

2016-06-12 16:25:59,749 - INFO - 12779:Dummy-1244852 - smartthings.dump-input:22 - {"eventid":"f69d56f0-30b1-11e6-83b7-d052a8263153","date":"2016-06-12T15:25:58.504Z","eventname":"temperature","devicename":"Front Door","value":"20"}

I can now start to extend my server side code to do something else with the event data.

in Home Automation

Add a Comment

Your email address will not be published. All comments will be reviewed.

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Related Posts