myq-api icon indicating copy to clipboard operation
myq-api copied to clipboard

V6 Support

Open nsnyder opened this issue 3 years ago • 33 comments

Noticed errors being thrown from my implementation of this package. After a bit of looking, it appears that Chamberlain has deprecated V5 of their API, and has moved to V6. (Discussion here.)

It looks like someone on that side has been able to reverse engineer it, but I'm not sure how to grab the logs myself to get an implementation going. Might be possible to get into the Discord server and ask them for the info.

Not sure how big a change this is. Ideally, the public facing API for this package remains as-is.

Happy to help if I have time.

nsnyder avatar Jan 09 '21 23:01 nsnyder

Acknowledged, thanks for reporting! This does align with the cron tests that started failing as of yesterday.

I might try to see if I can MITM to see what the new requests look like. I will join the Discord as well to keep up with progress on the Homebridge end.

thomasmunduchira avatar Jan 09 '21 23:01 thomasmunduchira

Thanks a lot. Stupid that they just can change the api without compatibility to the last one...

RedondoBoony avatar Jan 11 '21 20:01 RedondoBoony

I'll add my thanks - yes, would love to see this work again! Missing the functionality here. Shout if I can help in any way.

cjustinhall avatar Jan 11 '21 21:01 cjustinhall

A short-term fix with the V5 API has landed (see #35). I did some MITM/research with the V6 API that I didn't get a chance to publish yet, but hopefully I can get around to it relatively soon.

thomasmunduchira avatar Jan 19 '21 09:01 thomasmunduchira

Does the app work for you using mitmproxy? I was trying to capture some traces (and yes, noticed the app is now using V6 per the hombridge implementation) but when using mitmproxy the app says it can't find the server. I can see the initial OAuth traffic but that's it.

BTW, thanks for doing this!

avie avatar Mar 21 '21 23:03 avie

I'm getting consistent 400 errors today, chatter on other projects seems to indicate something changed with the API to break it. The Homebridge plugin ported to v6 Oauth and seems to be still working. Any current plans to update to v6 or otherwise fix?

heisler3030 avatar Aug 25 '21 19:08 heisler3030

Receiving the same 400 issue today as well. Coincidently when I got a new garage motor, thought it was because of that 😅

syntag avatar Aug 25 '21 22:08 syntag

Yes, I'm getting the same error:

Error received:
{ MyQError: Unidentified error returned from service.
    at Function.handleServiceError (/srv/dev/cfg/openhab2/scripts/node_modules/myq-api/src/ErrorHandler.js:49:13)
    at MyQ._executeServiceRequest (/srv/dev/cfg/openhab2/scripts/node_modules/myq-api/src/MyQ.js:732:27)
    at process._tickCallback (internal/process/next_tick.js:68:7)
  name: 'MyQError',
  code: 'ERR_MYQ_INVALID_SERVICE_RESPONSE',
  _serviceError:
   { Error: Request failed with status code 400
       at createError (/srv/dev/cfg/openhab2/scripts/node_modules/axios/lib/core/createError.js:16:15)
       at settle (/srv/dev/cfg/openhab2/scripts/node_modules/axios/lib/core/settle.js:17:12)
       at IncomingMessage.handleStreamEnd (/srv/dev/cfg/openhab2/scripts/node_modules/axios/lib/adapters/http.js:244:11)
       at IncomingMessage.emit (events.js:203:15)
       at endReadableNT (_stream_readable.js:1145:12)
       at process._tickCallback (internal/process/next_tick.js:63:19)

simmonyau avatar Aug 26 '21 00:08 simmonyau

We need to prioritize this now that the v5 API is turned down. I'll actively start working on this, but it won't be an overnight fix by any means.

thomasmunduchira avatar Aug 29 '21 19:08 thomasmunduchira

Let me know if I can be of assistance :)

nsnyder avatar Aug 30 '21 21:08 nsnyder

I haven't looked at what @koush did but have been updating some home automation code I have that was based on what I learned from this project. I now have it mostly working. I figured most things out by looking at the HomeBridge code along with some detective work watching network traffic. The MyQ server is very finicky and wants headers and such a certain way. Anyway, if it's helpful, the general gist of V6 is the switch to the Oauth2/PKCE flow and minor changes to the regular api. Here's some more details:

For auth:

Instead of the old security token you use an Access Code generated by the OAuth flow. It's passed along in the api with an Authorization header. [Yes, it gives you an "access_token" in a JSON reply but you put it in an Authorization header].

To do this, start at https://partner-identity.myq-cloud.com/connect/authorize with a bunch of query params (see Homebridge code) and the PKCE challenge. This will return with several redirects. Keep following them until the server returns with a 200 returns code. With this return you need to parse the html and find a __RequestVerificationToken. With that token, redo the last query as a POST and in the body of the POST put url encoded email, password and token.

This will return a page with one more redirect... don't follow the redirect! Instead, pull out the "code" and "scope" it returns and turn around and use them in a POST to https://partner-identity.myq-cloud.com/connect/token (you will also send along the PKCE verifier now), which will return an actual access code.

The reply will have an "access_token" and "token_type" which are then used in all the api commands. Basically, create a header as "Authorization: <token_type> <access_token>" which replaces prior use of the Security Token. You can also save away the refresh_token to get new access tokens when you need them without logging back in. [I have not tried that].

Now that you've got your access token everything is very similar to what it was before. First, you need to get the account ID. This is a little different. Query https://accounts.myq-cloud.com/api/v6.0/accounts and a list of accounts will be returned. Not sure why there can be more than one. Anyway, this will give you and Account ID which you use in the api as before.

To get the device list, use https://devices.myq-cloud.com/api/v5.2/Accounts/<accountID>/Devices. This list will be the same as before.

To then control a device use https://account-devices-gdo.myq-cloud.com/api/v5.2/Accounts/<accountID>/door_openers//

where command is "Open" or "Close" (used to be open or close). This is a PUT command as before with an empty body (be sure to set Content-Length: 0).

Oh, make sure to have cookie processing on as it is required.

You can find details of some of the search parameters in the HomeBridge code.

Hope it helps!

avie avatar Aug 31 '21 01:08 avie

Here's what koush did... https://github.com/koush/myq/blob/main/src/myq-api.ts

Some useful bits from his commenting:

  • Starting with v6 of the myQ API, myQ now uses OAuth 2.0 + PKCE to authenticate users and
  • provide access tokens for future API calls. In order to successfully use the API, we need
  • to first authenticate to the myQ API using OAuth, get the access token, and use that for
  • future API calls.
  • On the plus side, the myQ application identifier and HTTP user agent - previously pain
  • points for the community when they get seemingly randomly changed or blacklisted - are
  • no longer required.
  • For those familiar with prior versions of the API, v6 does not represent a substantial
  • change outside of the shift in authentication type and slightly different endpoint
  • semantics. The largest non-authentication-related change relate to how commands are
  • sent to the myQ API to execute actions such as opening and closing a garage door, and
  • even those changes are relatively minor.

cjustinhall avatar Aug 31 '21 01:08 cjustinhall

Here's what koush did... https://github.com/koush/myq/blob/main/src/myq-api.ts

The above is not my code, it's from the myq homebridge plugin. I stripped out the homebridge stuff for just the MyQ API bindings, which were updated to work with the v6 API. Hopefully it helps the authors of this project. Or anyone else that has a pressing need to control their MyQ devices, and want a relatively quick way to access them, albeit by targeting a different node library.

koush avatar Aug 31 '21 02:08 koush

What's the best way to test this? Node won't run it, nor npm.

skykep avatar Sep 03 '21 16:09 skykep

What's the best way to test this? Node won't run it, nor npm.

This is a library, not an application, so you would need to build an application to use this library's API. Examples are listed in the readme.

parnic avatar Sep 03 '21 16:09 parnic

In case it helps anyone, I ended up switching my home automation to use the following API that works very well:

https://github.com/arraylabs/pymyq

simmonyau avatar Sep 03 '21 18:09 simmonyau

What's the best way to test this? Node won't run it, nor npm.

This is a library, not an application, so you would need to build an application to use this library's API. Examples are listed in the readme.

Perfect. Just what I needed. Thanks!

skykep avatar Sep 03 '21 19:09 skykep

What's the best way to test this? Node won't run it, nor npm.

This is a library, not an application, so you would need to build an application to use this library's API. Examples are listed in the readme.

It appears I need a little more handholding. How do you reference the v6 library since it's written in TypeScript?
The older myq-api is JS. I tried running tsc on it to convert it, but get errors about it being an ES module...

skykep avatar Sep 03 '21 20:09 skykep

What's the best way to test this? Node won't run it, nor npm.

This is a library, not an application, so you would need to build an application to use this library's API. Examples are listed in the readme.

It appears I need a little more handholding. How do you reference the v6 library since it's written in TypeScript? The older myq-api is JS. I tried running tsc on it to convert it, but get errors about it being an ES module...

Sorry, it's been fixed. I had the incorrect package entry point. Should work from a normal js project.

koush avatar Sep 03 '21 21:09 koush

Sorry, it's been fixed. I had the incorrect package entry point. Should work from a normal js project.

Thanks, so what is the proper way to call this?
Using const MyQ = require('myq-api'); still calls the v5 api and pointing the require directly to your myq-api.js doesn't work either.

skykep avatar Sep 03 '21 21:09 skykep

Sorry, it's been fixed. I had the incorrect package entry point. Should work from a normal js project.

Thanks, so what is the proper way to call this? Using const MyQ = require('myq-api'); still calls the v5 api and pointing the require directly to your myq-api.js doesn't work either.

Make sure you're on at least v1.0.9

npm install @koush/myq@latest

require('@koush/myq')

koush avatar Sep 03 '21 21:09 koush

Make sure you're on at least v1.0.9

npm install @koush/myq@latest

require('@koush/myq')

No joy.

const MyQ = require('@koush/myq');
const account = new MyQ();
phuz@wazebot:~/MyQ$ node myq.js
/home/phuz/MyQ/myq.js:6
const account = new MyQ();
                ^
TypeError: MyQ is not a constructor

(that was me that DM'd you on discord earlier)

skykep avatar Sep 03 '21 22:09 skykep

> require('@koush/myq')
{ myQApi: [Getter] }

that example is out of date I think.

koush avatar Sep 04 '21 02:09 koush

that example is out of date I think.

yeah that old example won't work with this new API, but I can't even figure out my starting point on this. It also looks like multiple things need to happen during the authentication process. I wonder if we look at the homebridge code to see how they're using it specifically.

skykep avatar Sep 04 '21 11:09 skykep

yeah, that's how I did it. it's not complicated.

    this.account = new myQApi(console.log.bind(console), console, email, password);
    await this.account.refreshDevices();
    
    const devices: Device[] = [];
    for (const device of this.account.devices) {
      // do stuff
    }

koush avatar Sep 04 '21 16:09 koush

yeah, that's how I did it. it's not complicated.

I've tried very similar but I still get the myQApi is not a constructor

skykep avatar Sep 04 '21 17:09 skykep

const {myQApi} = require('@koush/myq')

you're probably importing it wrong

koush avatar Sep 04 '21 17:09 koush

you're probably importing it wrong

hah, yup. completely missed the deconstruction. but that opened up more errors. I hope this isn't all related to being on node v12 (which I need on this test box)

skykep avatar Sep 04 '21 17:09 skykep

For the heck of it, I just wiped my code and pasted what you have above (with credentials) and it still blows up. Did that actually work for you? TypeError: this.devices is not iterable

skykep avatar Sep 04 '21 18:09 skykep

For the heck of it, I just wiped my code and pasted what you have above (with credentials) and it still blows up. Did that actually work for you? TypeError: this.devices is not iterable

yes.

const { myQApi } = require('@koush/myq')


async function start() {
    const account = new myQApi(console.log.bind(console), console, 'username', 'password');
    await account.refreshDevices();
    
    for (const device of account.devices) {
        console.log(device);
    }
}

start();

koush avatar Sep 04 '21 19:09 koush