La Vita è Bella

2017-03-19

SmartThings, MyQ and Scala

SmartThings

Ever since I became a homeowner last year, I started to explore the IoT/home automation world.

The first IoT product I decided to purchase was Schlage Connect deadbolt. The only problem with it is that to use something more than passcode, I need to pair it with some third-party home automation hub.

After some research, I chose SmartThings in the end. It worked great with the Schlage deadbolt.

After the lock and the hub, the next step was garage door. The only garage door controller SmartThings "supports" out of the box is GD00Z-4, so I just bought that.

Besides basic functions (e.g. check status and open/close from your phone), SmartThings also provided routines and "SmartApps". SmartApps are the real gem here: besides the ones published on SmartThings' "Marketplace", you can also just use the developer site to write your own SmartApps (the developer platform is based on Groovy) and publish to yourself. Since it's just so easy to get code running, a lot of developers just don't bother to get their apps reviewed and published in the "Marketplace". Instead, they just share the source code, and anyone can just copy the code to their own developer console.

At first I found an app that can close the garage door after N minutes, and did some modifications so that it can send me a notification at 3 minutes, close the garage door at 5 minutes, and did a check again at 6 minutes to see if it's still open (because regulations, the remote closing of garage door could fail because of obstacles and things).

That's useful, but not really "smart". What I want is auto open the garage door when I'm driving home, and auto close it when I'm leaving.

So I purchased an Arrival Sensor to put in my car, and starting to write my own SmartApp.

This should quite simple, right? Just open the garage door when the arrival sensor's status changed from leave to present, and close the garage door when the arrival sensor's status changed from present to leave. That's what I did initially, and that worked great. At least for a while.

Until one day, the arrival sensor just went haywire, starting to flipping status randomly, while it's physically in my garage, unmoved. That caused my garage door to open unexpected.

So I changed the code, added a condition that the auto open will only happen if it's more than N minutes after we last tried to auto close it. And that worked great. You know the catch, for a while, again.

One night it went haywire again, and this time it flips status on a longer interval -- longer than the 5 minutes I set on my version 2. My garage door opened several times that night.

So it's time for version 3. This time I changed the condition. Instead of only open it if it's N minutes after last close, I only auto open it after a true auto close -- defined as it really closed the garage door, or the garage door was already closed, but that's no longer than N minutes before the app tries to close it (for the case when I manually closed the garage door when leaving).

Version 3 worked great for several months now, I think this is the mature version. You can find the code on this gist.

MyQ

After I happily used my Presence and Garage Door SmartApp for a couple of months, one day the smart garage door controller just stopped working.

Looking at Amazon reviews, that seems to be a very common problem: A lot of users also had it suddenly stopped working after couple of months. The manufacturer didn't provide any warranty, instead they kicked the ball to the sellers. We contacted Amazon, and got full refund (as it's still within the first year).

Because of this being a widespread issue, I decided to buy something else. One of my friend once has his garage door motor broken, so he was forced to upgrade his garage door motor, and the new one he purchased has MyQ. He was happy with that, so I decided to buy MyQ this time (also it comes from the same manufacturer of my garage door motor, just my garage door motor doesn't have MyQ built-in).

I purchased the MyQ package, installed it, and installed their app. Wow that's really disappointing. Yes the app can check the status of the garage door and open/close it, but there's literally nothing more. They don't have any integration (they do have a Nest integration, but that means I can control Nest in MyQ app, not vice-versa. Like, what's the point of that?), and they don't even have any open API.

Digging around the internet, someone actually reverse engineered the closed API they use on their mobile apps, so they do "have" an API, just there's no guarantee when will it be broken.

At first I decided to write an Android app to do the automation. The idea was simple, I define an interface to detect that I'm on the car (it could be from bluetooth connection, or detected that Android Auto app is running, etc.), and an interface to detect my presence (it could be geofence, or from WiFi connection). Combining the two interfaces and the MyQ API, I could implement the automation I wanted.

On first step I implemented the MyQ API on Android, nothing special here. Then I implemented the bluetooth car detection.

The WiFi presence detection didn't work as I expected, and geofence will require some extra UI work, so as a temporary workaround, I implemented an Android Auto notification instead: the app send an Android Auto notification when it detected it's in the car, and when I replied the notification with keyword "open" or "close", it uses MyQ API to open or close the garage door. That way, although it's not automation I wanted, at least I can control my garage door by voice, which is supposed to be much safer than fiddling with the MyQ app.

But that didn't work as I expected either. I'm not sure if it's because of Nexus 5X's infamous low memory, but the Android Auto reply will have a very long latency before it actually works. Often I tried to reply the notification with "open" when I'm near home, and I still need to manually open my garage door when I'm actually home, and after I already parked the car and in the living room, the reply actually worked and the garage door is (finally) open. That's not useful at all.

So I gave up on the Android app, and looked back at SmartThings.

SmartApps are not the only thing you can write on SmartThings' developer platform. You can also implement custom Device Handlers, to bring other device into SmartThings platform. Someone actually tried to do the same thing a few years ago, but their device handler no longer works, probably because the MyQ API they used no longer works. As a result, I took a night to implement the new, working MyQ API in the old device handler, and it actually worked. I can finally use my garage automation SmartApp with MyQ garage controller again, at least before MyQ kills the API I use (I hope they'll provide real open APIs if they ever decided to do that).

Scala

As I'm using closed MyQ API, there's an insecure fear that my SmartThings device handler could break any day. The SmartApp will actually send a notification when it auto open or close the garage door, but as I'm using Android Auto now, Android Auto will only show its compatible notifications, and hide everything else (which makes sense, because you don't want to distract drivers). And SmartThings notifications belong to "everything else".

With my experience with that failed Android app attempt, I thought maybe I can write another Android app, this time just translate normal notifications into Android Auto compatible notifications, so I can know that it worked.

There's a catch, I don't want to use Java this time. Having a day job writing Go, writing Java code at night is quite a contextual switch makes my head aches. So I decided to use this project as an opportunity to learn Kotlin or Scala.

There's another catch, I don't want to use Gradle or Android Studio. I wrote my codes in vim, and I want to use some better building tools, preferably Bazel.

They both have Bazel support (Scala through Bazel offically and Kotlin through third-party Skylark rules), but neither supports Android.

There are some comparisons on the internet prefer Kotlin over Scala, also Scala has some bad reputation about its learning curve, so I slightly leaned towards Kotlin.

But Kotlin has no documentation about how to use their kotlinc compiler CLI to build Android apps. I have absolutely no clue how to make it work outside of Gradle. Scala, on the other hand, has sbt. It's not Bazel, but at least I like it much more than Gradle.

So I took one week to wrote the app in Scala. The result is on GitHub. This is quite a simple app so there's nothing fancy there. I didn't have a chance to use a lot of advanced Scala features. But I do like the features I used, like foreach over an Option to do null handling.

When I tried to publish it on Google Play last night, I got a problem: Android Auto only allow one type of notifications, and that's peer-to-peer messages. Because my app send notifications that's not peer-to-peer messages, it's rejected. I guess that's why SmartThings didn't make their notifications compatible with Android Auto in the first place.

If you find it useful and don't mind sideloading apps on your Android phone, you can find the apk on the GitHub release page. But you probably mind it, as do I (I don't sideload any app on my phone). So going forward I need to find another way, at least before Android Auto loosen their notification restrictions.

One idea is to make it a chat-bot with an chat app with existing Android Auto support, and the chat app I'm thinking about is Telegram. The reason is that it has both quite good Android Auto support, and bot API support.

So that is probably what I will do in the next few weeks. Please stay tuned. Thinking about it, maybe I'll actually make a poor man's PushBullet accidentally :)

18:52:00 by fishy - Permanent Link

May the Force be with you. RAmen