Sharing lessons from a weekend of learning ST SmartApps and Device Handlers

Took the weekend to write up a modified device handler and smart app to accommodate my desired goals with the Aeon Minimote this weekend.

I wanted to go ahead and post a few lessons I found via trial & error versus what’s available in the documentation. Hopefully this will server to shorten the time spent figuring out the quirks for other new developers diving down the rabbit hole.

Device Handlers

  • When creating tiles using the action argument, you can’t pass an argument, even though you can define commands in the device metadata with argument signatures. As a workaround, create wrapper commands (and the methods) to target the final command you want to pass the argument to.

  • Be liberal with exposing attributes and commands that make sense. You’ll make other developer’s (using your device handler) lives a whole lot easier not having to make custom versions of your handler.

  • The current architecture of ST seems to be 1 device handler per device. This seems anti-pattern and anti-dry to me. Really annoying when trying to deal with things like multi-button remote controllers. I haven’t looked at the multi-sensor device handlers yet (perhaps I should before writing this) but I’d imagine they use some hacks I did to get around some of the issues I faced with the multi-button remote.

  • Sadly, it seems as though the concept of repeating and action with a button hold isn’t supported because of the architecture of z-wave. I’ve seen funny business in the logs when I hit the button once and the hub receives the same signal multiple times. I’m guessing this is due to the way the hub receives the signals (bounced signals?). So if you’re set on rewriting some handlers to add timed events via held button presses, don’t waste your time unless you can confirm the device itself is capable of sending a “release” event in addition to the “pushed” event. I’ve seen discussions regarding trying to get the capability out of the time stamps, but in the end, I don’t see how it’s possible to achieve the desired result (think button held working a dimmer).

SmartApps

  • Using dynamicPage for preferences is powerful and beautiful.
  • Once they incorporate a wrapper into preserving href input params it will be even better.
    • In the mean time, you can use this workaround.
      • In your href input, wrap your arguments in a map object and inject that into the main params map object (this makes life easy when preserving in state).
      • Save the map object (params.yourMappedObj) to the state (state.yourMappedObj).
      • You can create helper methods to do this for you and just call it at the top of the dynamicPage wrapper method before you call the dynamicPage method.
      • Additionally, make life simple and create a helper method to retrieve your settings from the state for generating your page.
      • Don’t forget to remove the mapped object from your state in your installed method so you don’t end up wasting the limited state space.
    • I feel like this functionality could be easily automated into the dynamicPage source code by ST to make things simpler for developers.
  • Input names generated from parameters can cause issues. Make sure you are passing the input name a true string and avoid “${var}” formats when building the string, or try using toString() if you notice issues. If you forget the .toString() extension method, you’ll probably end up with missing/null settings.
  • I feel like phantom settings is an issue that isn’t being addressed by any of the app examples I’ve scanned through.
    • Example: Your user adds a device via an input. You then generate another input for an action based on that device, this action setting name is generated based on the device name or id. Your user then goes back to the SmartApp settings to change the device, and sets up the action for the new device. While the device input setting will change properly, the device action setting will be sitting there still.
    • Short of creating an entire dynamicPage settings engine to manage such a case, just create a method to compare dependent (on params to generate the setting name) settings with the parent setting to ensure it’s still valid. If not, remove it of course. And just call this setting cleanup method from your installed (yes, installed, because the setting will get created and they could change their mind on initial install, if using the submitOnChange input argument) and updated built in methods.
  • If you’ve subscribed to a device event, and notice your live logging is spitting out a warning message about not finding the event handler (method) for the device event, check your device handler’s event being fired. I noticed when calling an event for the button capability, that has no defined attributes, but passing values “pushed” and “held”, the subscription would spit out the warning and not execute my event handler. Once I defined the pushed and held (with no arguments) commands in the device handler metadata, the event handler in the SmartApp was matched. Very odd considering I was subscribing to “button” (this is suppose to capture everything), and not “button.pushed”, but the issue was solved once the commands were defined.

Thoughts and comments welcome.

Cheers,

Kyse

6 Likes

Thanks for sharing these excellent observations.

I think @Jim and @unixbeast (SmartThings documentarians extraordinere…) will take note.

The docs need to be strong and accurate references, but there also needs to be more tutorials for both dummies and experienced alike.

Consider contributing to the not well known Wiki: http://ThingsThatAreSmart.wiki ?

1 Like

Couldn’t agree more that the docs are somewhat lacking and trial and error (and reading other people’s code) is the only way to really get anything done.

My example, from my weekend of getting a LAN connected device working, is that it took me ages to figure out you can call multiple hubActions by returning an array of them from a command rather than a single hubAction. It might be somewhere, but it was when I saw an example that the penny dropped.

1 Like

I’d like to see some of the hub source code for getting a better understanding underneath the API.

I’m wondering if there’s any real benefit to resource usage if I call a device action on an array of multiple devices, rather than parsing through the devices, and calling the action independently. It’s easier logic wise to give more control to the end user doing it the latter way, but I was wondering if I beefed up the parse logic to combine the actual actions to a single array if it would make a difference. Like, would the underlying code, loop through all the devices anyways, would I be saving some method calls in the underlying code if I group them together, etc.