Getting started with device types?

I’m working on a simple Arduino/ThingShield device that monitors the lights on my washer/dryer. The goal is to be alerted when the washer/dryer are finished. The hardware is simple enough: A photocell for the “done” LED on the washer, and another on the dryer.

For my device type, I added two custom attributes: washerLightState and dryerLightState. The problem I have now is actually setting up the rest of the device type. While there are at least some docs for writing SmartApps, there seems to be very little for writing device types – it’s all based on examples, really, and it’s not necessarily clear what to use where and why.

This is also my first exposure to Groovy, although I’ve found it easy enough to follow; I’m mostly a C programmer with some dabbling in Objective C, C++, Python, Javascript, HTML.

Some of my questions:

  • What is “Join Fingerprints” entry when creating a new device type? I’m guessing it’s something I don’t need to worry about, but I’m curious.

  • I want to have the tiles for my device change from white when the washer/dryer is not yet done running, and to blue when the washer finishes and red when the dryer finishes. For both I would also like to display “Waiting” or “Done” on the tile. Should I be using standardTile or valueTile or that? It seems that a standardTile is commonly used as a “button” to change state, but it’s not clear to me if valueTiles can change color or not. I’m trying to use “Shield On/Off (Example)” as a reference, but it isn’t clear why one tile is chosen over the other for the “greeting” and “message” tiles, and tapping the “greeting” tile doesn’t seem to actually do anything.

  • It seems you can pick any of the icons for the tile when defining it, and I noticed that washer/dryer icons do exist in the SmartThings iOS app. However, it’s not obvious how to figure out the names for those icons. I’d like an image of a washer on one tile and a dryer on the other, for obvious reasons. Is there some API to get that?

  • I have no idea what this means:

    simulator {
        status "on":  "catchall: 0104 0000 01 01 0040 00 0A21 00 00 0000 0A 00 0A6F6E"
        status "off": "catchall: 0104 0000 01 01 0040 00 0A21 00 00 0000 0A 00 0A6F6666"

        // reply messages
        reply "raw 0x0 { 00 00 0a 0a 6f 6e }": "catchall: 0104 0000 01 01 0040 00 0A21 00 00 0000 0A 00 0A6F6E"
        reply "raw 0x0 { 00 00 0a 0a 6f 66 66 }": "catchall: 0104 0000 01 01 0040 00 0A21 00 00 0000 0A 00 0A6F6666"
    }

I get that this is for setting up the device for use in the simulator. I sort of get the “status” lines. I’m less clear on what “reply” is doing, though, and I don’t know what the catchall: line is at all (I mean, beyond some kind of exception handling, I think? I don’t know what the numbers are meant to represent represent).

The IR Bridge project implies that the simulator block can just be empty if I don’t want to be able to test it in the simulator, I think…

  • It’s not totally clear to me what parse() is doing, although I think i’ve figured out most of it. It seems that it’s only used to process events that come from the device (ThingShield), with “description” being an arbitrary string from said device. The IR Bridge project implies that you can return an array by using createEvent() builders, rather than just a single event. In that event structure, it seems that “name” is the name of the attribute, handlerName is the closure/function/whatever to be executed when to handle the event, and isStateChange is true if the state of the attribute has changed. It’s not entirely clear how descriptionText and linkText are used exactly, or what displayed is actually indicating…

I don’t really understand what the def value = zigbee.parse(description)?.text line is doing – what zigbee.parse() is needed for, and why it is calling .text to presumably return the result as a string. What is it parsing? I guess “description” isn’t the raw string from the device?

  • I think the on(), off(), etc. functions are handling events (as returned by parse() as handlerName), but the zigbee.smartShield() method (such as zigbee.smartShield(text: "on").format()) has no obvious documentation, nor is it clear what the format() method is for.

  • The IR Builder project makes use of sendEvent(). It’s not clear to me what this is doing, exactly; I think it may be so you can send an event outside of parse(), and that the events returned by parse() are executed through sendEvent() internally, or something like that?

I’m really interested in knowing WHY these examples are doing all of this stuff, what all the members of the classes are, what the functions being called do and why they are needed. I could bang away at this and just make guesses until it works, but I really don’t like working that way.

I know documentation is on the list of things to do, but just (very) heavily documenting the example/tutorial code would go a long way helping makers understand how to build their own projects in the meantime.

Thanks!

– Joe

I took the bang away approach and it has been pretty frustrating, but not without results. You can see my thread here: http://build.smartthings.com/forums/topic/device-type-for-web-service/ with some back and forth with @dlieberman

  • Join Fingerprints: I’m pretty sure that is related to z-wave/zigbee things that have unique fingerprints. Not really sure as I haven’t played with it.

  • Tiles: This is a particularly painful topic, but here is what I know. Value tiles can change color

valueTile("temperature", "device.temperature", width: 2, height: 2) {
    state("temperature", label:'${currentValue}°', unit:"F",
        backgroundColors:[    
            [value: 31, color: "#153591"],
            [value: 44, color: "#1e9cbb"],
            [value: 59, color: "#90d2a7"],
            [value: 74, color: "#44b621"],
            [value: 84, color: "#f1d801"],
            [value: 95, color: "#d04e00"],
            [value: 96, color: "#bc2323"]
        ]
    )
}

I’m not sure if there is a programmatic way to set the color (this is something I would like to do for my thermostat). This example changes color based on the temperature value.

As for when to use standard vs value vs any other tile types, I have no idea. I don’t even know what all kinds of tiles are available.

  • Available icons is another things for which there is no information yet.

  • Simulator: I think this is primarily to make testing easier. The status messages populate a dropdown list of messages you can send to your virtual device type. I’m not sure what the replies are though. I leave the simulator block empty as it isn’t applicable with my device.

  • Parse receives the messages from your device and creates events using them.

  • I assume zigbee.parse is doing some intelligent text parsing for zigbee devices. Some kind of convenience methods. Haven’t played with it though.

  • sendEvent() is how you create and process events outside of the parse function. I use it heavily since my events are all web based and never trigger parse.

I really hope the documentation for device types is coming soon as trying to create things without it is nearly impossible to do well.

@jangell, @dianoga – A generally available resource that lists out icons and their paths is on our product backlog but isn’t at the top of the priority list at the moment.

In the meantime, if there are specific icons that you’d like the path to, let me know and I’ll look them up.

Thanks for the info @dianoga. I had seen your thread about a web service device type and noticed you were having a lot of the same problems I was. Looks like I’m going to just have to bash against it until the docs are ready.

  • Tiles: That’s very helpful – I wasn’t sure if valueTiles had the same kind of color support as standardTiles. I had assumed the difference between the two kinds of tiles was that standardTiles can issue commands, while valueTiles can only display values, but I haven’t tried to prove that yet. It never even occurred to me that there might be more than two kinds of tiles, although that seems obvious now, even if it is just for future expansion.

  • Colors: Choosing from a few different colors by value works for my purposes, but I can see how arbitrary color selection could be useful. I imagine this might be more of an issue when something like the Philips Hue color-changing LED bulbs are supported.

  • sendEvent(): Thanks, that reinforces my inference that parse()'s job is to convert a string into one or more events that will be implicitly passed to sendEvent() by whatever system function called parse() in the first place.

  • zigbee.parse(): I guess I’ll have to play with it, and use the log to see what the difference is between the raw string and the parsed string. It’s easy enough to use it like in the examples; I just like to know why.

@dlieberman, I’d like the path for the washer/dryer-like icons for the moment, which are the first (top left) and fourteenth icons (right-most second row) in the Appliances part of the icon chooser in the iOS tile’s “Icon” list. I can understand that providing the full list is a low priority, but it would be handy just to have a list of the symbols dumped out as text from the source file (assuming it’s a simple list and not procedurally generated), even if there’s no nice description – we can experiment with that just like we are with everything else. Although I do hope we’ll get some docs or heavily commented example code for device types and other bits sooner than later. Thanks!

– Joe

@jangell – Use:

  • st.appliances.appliances1
  • st.appliances.appliances8

For example:

standardTile("dryerIcon", "device.dryerIcon", decoration: "flat") {
	state "default", icon:"st.appliances.appliances1", label: ""
}

and

standardTile("washerIcon", "device.washerIcon", decoration: "flat") {
	state "default", icon:"st.appliances.appliances8", label: ""
}

Excellent – looks like it’ll be pretty easy to guess any other icons I might be interested in. Thanks, @dlieberman!

– Joe

@dlieberman Should those icons work in the simulator? The image returns 403 forbidden from s3

@dianoga, @jangell – Sorry, I thought it was case insensitive and I didn’t test before I posted. It’s:

  • st.Appliances.appliances1
  • st.Appliances.appliances8

Hey Joe,
Let me jump in and shed some light on the way I did the IR Bridge project.

  • “Join fingerprints” can really be ignored during development.

  • A standard tile is just about always what you’re looking for - we can control it’s color and set the message it will display. Take a look at the following minimalist example:

//Minimalist example with one one custom attribute: washerLightState 
metadata {
    tiles {
        standardTile("Washer", "device.washerLightState", width: 1, height: 1, canChangeIcon: true, canChangeBackground: true)
        {
            state "red", label: 'Washer Off', backgroundColor: "#ff0000", icon:"st.Appliances.appliances1"
            state "green", label: 'Washer On', backgroundColor: "#00ff00", icon:"st.Appliances.appliances1"
        }
        main("Washer")
        details("Washer")
    }
}
def parse(String description) //incoming messages coming from Arduino are automatically routed to this function
{
	def arduinoMsg = zigbee.parse(description)?.text //helper function returns original message from Arduino
	log.debug arduinoMsg  //show message in debug 
    
	if(arduinoMsg == "red" || arduinoMsg == "green")
	{
		//set the attribute, ultimately changing the color
		//return createEvent(name:"WasherLightState", value:arduinoMsg) 
                //or 

                sendEvent(name:"washerLightState", value:arduinoMsg)
	}
}

With this custom device type, we can change the Washer tile color by calling the following somewhere in our Arduino code.

  smartthings.send('green')
  • The simulator{} block is a way to generate articifical responses - really for the circumstance that you don’t have the hardware available. Really I say avoid this where possible.

To clarify, you can test in the IDE without the need to ‘simulate’ interactions. You can actually send and receive real data with an actual device.

To do that - Always “publish” before you run this process To the right side of the code editor, after saving and publishing your updates, click “Set Location.” Next pick your device to test with from the list provided and then click “Install”.

Note, you can interact with the details of the tile in the IDE by clicking the very bottom right corner, just below the gear (looks like a bug in Chrome).

  • You are really close on the parse function. Effecitvely, this functiong gets called each time the Arduino calls smartthings.send(“example”). Then we use a helper function to convert the zigbee response to only contain the text of our message.
def parse(String description) 
{
	def value = zigbee.parse(description)?.text
	log.debug value
}

//the message from the arduino will be written to the log output
  • The result of createEvent() should be returned at the end of the parse function. The “name” in the parameters list is the attribute name we defined in the settings and the “value” will be assigned to that attribute (variable). I used “isStateChange = true” to force the event to take place even if the new value already matched the current value.

  • You are correct in your thinking on createEvent(…) vs sendEvent(…). The response from createEvent(…) needs to be returned at the end of parse. sendEvent(…) can be used to set attribute values by itself. The result of multiple createEvents can be returned in an array at the end of the parse function.

-Danny

@jangell @dlieberman A list of all available icons (that I can get through the api) is here: http://scripts.3dgo.net/smartthings/icons.php

Hover over the icon to get the name you would use in your tile.

Hi everyone. It’s been a few weeks, but I’ve finally gotten a chance to play with this again. But first:

@dianoga - The icon page you set up is awesome – thanks!
@megapixel - Thank you very much for the information; it has been very helpful! I’m ignoring the simulator blocks as suggested. The trouble clicking on the gear icon in the Simulator is also present in Safari on OS X, BTW.

Now for my current problem. I set up my device type like so:

/**
 *  Washer/Dryer Finished Monitor
 *
 *  Author: jangell@tmproductions.com
 *  Date: 2013-06-30
 */
 // for the UI
metadata {
    tiles {
        standardTile("Washer", "device.washerLightState", width: 1, height: 1, canChangeIcon: true, canChangeBackground: true)
        {
            state "pending", label: 'Washer',       backgroundColor: "#ffffff", icon: "st.Appliances.appliances1"
            state "done",    label: 'Washer Done',  backgroundColor: "#00ff00", icon: "st.Appliances.appliances1"
        }

        standardTile("Dryer", "device.dryerLightState", width: 1, height: 1, canChangeIcon: true, canChangeBackground: true)
        {
            state "pending", label: 'Dryer',       backgroundColor: "#ffffff", icon: "st.Appliances.appliances8"
            state "done",    label: 'Dryer Done',  backgroundColor: "#00ff00", icon: "st.Appliances.appliances8"
        }

	main(   "Washer")
        details("Washer")
    }
}

// parse events into attributes
def parse(String description) {
	log.debug "Parsing '${description}'"

	def arduinoMsg = zigbee.parse(description)?.text
	log.debug arduinoMsg

	def parts = arduinoMsg.split( /:/ );

	if(parts[1] == "pending" || parts[1] == "done")
	{
		return createEvent(name:parts[0], value:parts[1]) 
	}
}

For some reason, though, I only see a single title in the SmartThings app. I can’t see any syntax errors in the code, and it seems to match up with what I’ve seen in other apps, but maybe I’m missing something here. When I Publish the device type, then Install it form the IDE onto my shield, I get this in the console output:

9:07:24 PM EDT: error 1
9:07:24 PM EDT: debug ping
9:07:24 PM EDT: debug Parsing 'catchall: 0104 0000 01 01 0140 00 4ECF 00 00 0000 0A 00 0A70696E67'

I’m not sure what “error 1” is in regards to, but I imagine it may be my problem.

At the moment the Arduino isn’t sending messages (I have the hardware ready, but I was writing the device type before implementing the sketch) , but the format I was planning on was “target:state”, where “target” is “dryerLightState” or “washerLightState”, and “state” is “pending” or “on”. I think split(/:/) to get an array a valid way of going about that, but I haven’t tested that part yet.

Lastly, does anyone know if it’s possible to create a kind of tile that only shows up in the list of devices and not in the device details? The idea is that I could have separate Washer and Dryer icons in the device details, but in the device list I’d have a single icon that showed the state of both the Washer and Dryer. Alternatively, a way to indicate that the Washer and Dryer icons should be displayed as separate devices in the device list would also solve this problem (and do so more elegantly, in the case of my example).

Thanks!

– Joe

For the single tile problem, add your dryer tile to the details call.

I’m not sure about the rest of it.

Aha! That did the trick – thanks! I was going to ask what “details” was for. “main” seemed fairly obvious (determines which tile shows up in the device list, right?).

Thanks!

BTW, your Nest device type looks pretty neat. I just installed it, and it’s working great. I just have to decide what SmartApps I want to make work with it. :slight_smile:

– Joe

I’m working on a SmartApp to automatically turn the thermostat on/off based on open/close sensors, but I’m running into weird issues with how the sensors are reporting. I’m hoping to talk to @dlieberman about it tomorrow.

Don’t mean to hijack the thread or anything but my wife started wondering why I was spending half my weekend in the shop playing with “that little frisbee looking thing” and when I explained what it was she said “great, can you put one of those sensors that detects vibration on my washer so in know when it’s done?”. Just sayin…

@dianoga - What I’d love to be able to do is convince the Nest that I’m home when I’m not in the same room as it. Right now it tends to go “away” on my when I’m in my home office; after I bit I notice that it’s gotten kinda warm, launch the app on my phone and realize what’s happened. I was thinking a motion sensor coupled with some way to tickle the Nest “away” feature, but I’m not sure if that functionality is exposed through their API (also, I don’t know enough web dev to implement it myself – I was just waiting for someone like you to do it. :slight_smile: ).

@solardave1 - I thought about using the a multisensor’s accelerometer to detect when the machines have stopped, but we a high-efficiency washer and dryer that tend to spin down and spin up periodically to save energy and all that, so I don’t think it would be reliable. Monitoring the LEDs seemed to be the most reliable way to do it. I had considered opening the control panel and wiring in directly, but I didn’t feel like want to void the warranty. I’ll be sure to post my code and schematics once I have it all finished.

– Joe

@jangell I’ve given up on Nest’s auto away feature. My thermostat is in a spot I don’t regularly pass in front of and I’m not aware of a way to let it know I’m still around via the ‘api’.

That said, I could see using presence tags or a collection of motion detectors to toggle away. That probably wouldn’t be too terribly difficult to program a simple version of. It could get complicated pretty quickly depending on how fancy you wanted to go.

I updated the Nest device type to include support for setting away/present. Update code is here: https://gist.github.com/Dianoga/6055918

Nice – thanks! Now I just need to get a motion sensor.

You may want to sanitize the source; your username, password and serial are there.

– Joe

Thanks for the heads up. Now to change everything…