Skip to content

Instantly share code, notes, and snippets.

@matthewpwatkins
Last active February 2, 2019 16:52
Show Gist options
  • Save matthewpwatkins/17d70e6a3ddcddb4c6b26f47a00c0914 to your computer and use it in GitHub Desktop.
Save matthewpwatkins/17d70e6a3ddcddb4c6b26f47a00c0914 to your computer and use it in GitHub Desktop.
Working around MyQ's partner integration limitations

Working around MyQ's partner integration limitations

I got a new home recently. And for the first time in my life, I have a garage! And a smart garage door to boot! However, if I want to integrate the rest of my stuff into it (like IFTTT or the Google Assistant), I have to pay $10. Per year. Per integration. You can sort of get around that by setting up a Google Assistant applet in IFTTT (two integrations for the price of one), but when I tried their free one month trial, it turns out you can't even use their partner integrations to open your garage door-- only to close it. Lame sauce.

Fortunately, @thomasmanduchira was kind enough to sniff the traffic on the MyQ app, document the pretty basic MyQ API, and throw together a simple NPM package for us. Now where to host it? I do have a Raspberry Pi mounted behind my TV, but I'd prefer something with better reliability and easier deploy. And for a quick little node app like this, you can't get much better than Glitch.com. One hour later and I have ultimate control over my garage door. Nothing fancy, but it works great. Now I'm throwing IFTTT button widgets on my phone's home screen, adding Google Assistant commands, and placing physical Dash it All! buttons around the house to my heart's content.

If you want to try it out, here's how to get started:

Setting up your API

  1. Create a new project on Glitch using the Express JS project template. Delete the html, css, and client js files since we won't have to serve any pages.
  2. Add "myq-api": "^0.0.2" to the list of dependencies in the packages.json file.
  3. Replace the contents of server.js with this. This holds all the logic that powers your server.
  4. Replace the contents of the .env file with this. This will hold all the user-specific information needed to tell MyQ what to do. Remember, Glitch never lets anyone see that env file, even if your project is public, so it's a "pretty good" place to store that. But make sure not to include spaces around the equals sign. This is a shell file, after all.
  5. Come up with an access token you will use when calling this app (keep it long and unique since it will control your home's garage door, after all) and store it as the TOKEN environment variable in your .env file.
  6. Set your MyQ account email as MYQ_EMAIL and password as MYQ_PASSWORD in the .env file. as well.
  7. You should now have a working API! But you're not a Jedi, yet. Fire up your browser (or cURL or PostMan or ...) and hit out to the get-garage-door-id endpoint of your Glitch app with your access token as a query parameter (ex. https://my-garage-door-api.glitch.me/get-garage-door-id?token=193c347181764542acdd19174799e43e). If your MyQ username and password are correct, you will see a message like "Your garage door ID is 7391672." Copy that ID as the final MYQ_GARAGE_DOOR_ID variable in the environment file.

That's it! Always use your access token in the query string (so always use HTTPS). To open the door, issue a POST to the /open-garage-door endpoint. To close, hit out to /close-garage-door.

Notes

  1. I know it's not the best JavaScript in the world. I'm not a JS guy in my day job, and it was one hour. I'm sure there is someone out there who has had more than the ~5 hours of NodeJS experience I've had who could do the whole thing with a proper auth handler and get the whole thing down to a nice, readable 20 lines. If you are that person, shoot me a PR :)
  2. I'm storing my authentication information in the .env file of my Glitch project. Sure I could have chosen to use the Glitch project template that uses SQLite, but then I'd want to add an actual UI to persist data and make it pretty and distributable, and, well:

Database and UI? Ain't nobody got time for that!

Although maybe I will... someday :)

const GARAGE_DOOR_TYPE_ID = 17;
const express = require('express');
const MyQ = require('myq-api');
const app = express();
// Returns the garage door device associated with your MyQ account
// so you can put it in your secret
app.get('/get-garage-door-id', function(request, response) {
if (app.auth(request, response)) {
app.getMyqAccount(function (account) {
account.getDevices([GARAGE_DOOR_TYPE_ID]).then(function (result) {
console.log(result);
response.send(`Your garage door ID is ${result.devices[0].id}`);
}).catch(function (err) {
console.error(err);
response.send(err);
});
}, function (err) {
console.error(err);
response.send(err);
});
}
});
// Opens your garage door
app.post('/open-garage-door', function(request, response) {
if (app.auth(request, response)) {
app.setDoorState(request, response, true);
}
});
// Closes your garage door
app.post('/close-garage-door', function(request, response) {
if (app.auth(request, response)) {
app.setDoorState(request, response, false);
}
});
// listen for requests
const listener = app.listen(process.env.PORT, function() {
console.log('Your app is listening on port ' + listener.address().port);
});
// Helpers
app.auth = function(request, response) {
let token = request.query.token || '';
let match = token.toLowerCase() === process.env.TOKEN;
if (!match) {
response.send('Wrong token parameter. Make sure your TOKEN secret is set');
}
return match;
};
app.setDoorState = function(request, response, open) {
app.getMyqAccount(function (account) {
account.setDoorState(process.env.MYQ_GARAGE_DOOR_ID, open ? 1 : 0)
.then(function (result) {
console.log(result);
response.send(result);
}).catch(function (err) {
console.error(err);
response.send(err);
});
}, function (err) {
console.error(err);
response.send(err);
});
};
app.getMyqAccount = function(success, error) {
let account = new MyQ(process.env.MYQ_EMAIL, process.env.MYQ_PASSWORD);
account.login()
.then(function (result) {
console.log(result);
success(account);
}).catch(function (err) {
console.error(err);
error(err);
});
};
TOKEN=
MYQ_EMAIL=
MYQ_PASSWORD=
MYQ_GARAGE_DOOR_ID=
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment