garagebot

Ok, I'm not as lazy as the description suggests. In fact, I originally built the bot for a good reason. The garage door opener I used to use was old, clunky, and most importantly very unreliable. On several occasions I've been temporarily locked out of my own home. Eventually, it broke entirely, rendering it impossible to enter through the garage from outside.

Months have passed and my family and I switched from an old, clunky garage door opener to a slow, clunky garage door opener app called MyQ. It's not that MyQ itself is slow, just the app was glitchy and required you to sign in every time. A lightbulb dinged in my head. If it's just the app that's slow, why not create a bot to open it for me? And so I embarked on my journey to figure out how to make a garage bot.

testing options

At first, I did some research on whether MyQ was compatible with HomeKit.

MyQ, by design, is not compatible with Apple HomeKit. However, it can be connected using a HomeBridge hub (on Amazon)[here]

Excuse-moi?! There's no way I'm paying an additional $98 just for HomeKit to work with it.

The next thought I had was surely there's a MyQ API, right? Well, kinda. There is no documented official API, but some projects have achieved just that. A quick google led me to the project hjdhjd/myq (on GitHub). The best way to automate the API-calling is the Shortcuts app. The app does come with its own shortcomings, however, namely the fact that it doesn't support JavaScript execution to invoke the API. There is a way to get around it, though. If you were to offload the whole garage-opening-API-calling thing to a server, we could then ping the server from a shortcut. And the perfect server, in this case, is Vercel.

building the bot

First, just to ensure the API was actually functioning, I whipped up a quick test script:

import { myQApi } from "@hjdhjd/myq"

const api = new myQApi("secret@gmail.com", "$3cret#123")
await api.refreshDevices()
await api.execute(api.devices[0], "open")

Sure enough, I heard the sound of the garage opening. I sat there for a few seconds with my mouth agape. I felt like I had become a hacker! Now, the next step was to write a thin wrapper on this baby and publish it with Vercel.

// [setup]

export default async (req, res) => {
    try {
        const params = new URL(req.url, "http:.").searchParams
        const command = params.get("command")
        if (params.get("password") !== process.env.password)
            return
        await api.refreshDevices()
        res.write(
            (await api.execute(api.devices[0], command))
            ? "success" : "command failed"
        )
    } finally { res.end() }
}
Now, navigating to foobar.vercel.app/api?password=secret&command=open once again opened the garage as expected. All that was left was to actually create the shortcut. This can be summed up in a few screenshots. a Shortcuts action that reads: get contents of URL a Shortcuts automation that reads: when I arrive at address run shortcut