davglass / doorbot

Ring.com Doorbell API
Other
317 stars 55 forks source link

Alarm Support #26

Open joeyberkovitz opened 6 years ago

joeyberkovitz commented 6 years ago

I just got the alarm and tried to connect to that API.

I discovered some info about the API, but had problems getting the connection to work It looks like the alarm is associated with a location_id, available in the latest API version Sending a POST request to https://app.ring.com/api/v1/rs/connections with accountId: LOCATION_ID and an authorization header using the same oauth token used during the initial login returns an object with a server to connect to along with an auth code.

The alarm communication then occurs over a websocket, seemingly using socket.io. The websocket URL is: wss://SERVERNAME/socket.io/?authcode=AUTHCODE&ack=false&EIO=3&transport=websocket where SERVERNAME and AUTHCODE come from the connections request

I tried connecting to the socket using the socket.io client, but the connection is closed after the initial frame is received. Following is the code I used to initiate the socket: io.connect("wss://" + alarmConnection.server + "/socket.io/?authcode=" + alarmConnection.authCode, { transports: ['websocket'], upgrade: false, nsp: '/' } );

Any help would be appreciated

I did some research and it looks like there is a difference when connecting with socket.io that the official ring client doesn't do. Screenshots below: Official Client: socket_official

Custom Client: socket_custom

davglass commented 6 years ago

I'm not sure what I can do, I don't have the Ring alarm to test with. Hopefully someone else watching this repo can chime in.

joeyberkovitz commented 6 years ago

Thanks anyway. Figured out that the correct websocket URL is actually "wss://" + alarmConnection.server + "/?authcode=" + alarmConnection.authCode, which enabled me to establish a connection.

Will provide updates as I build out a client.

joeyberkovitz commented 6 years ago

PR added: https://github.com/davglass/doorbot/pull/27

broyuken commented 6 years ago

Definitely watching this thread, I just got the alarm and would love to tie it in with my openHAB install. Let me know if I can help test anything

acolytec3 commented 6 years ago

@joeyberkovitz Can you provide some guidance on usage of your new alarm functions? I've got your fork cloned locally and been trying to leveage some of your new alarm-specific functions. I've tried passing a my base station device to a couple of them and always get back undefined results. I'm a complete novice at javascript but I seem to be at least formatting the function calls correctly. Any help would be appreciated.

joeyberkovitz commented 6 years ago

Sure

To get alarm devices: ring.getAlarmDevices(alarm, (alarmDevicesResponse) => {});

To arm/disarm the alarm: ring.setAlarmMode(alarmObject, securityPanelZid, armMode, bypassSensors, (response) => {})

alarmObject is the base_station object returned by the devices function

securityPanelZid is the alarmDevicesResponse.body[i].general.v2.zid where the alarmDevicesResponse.body[i].general.v2.deviceType is "security-panel" This is based on the getAlarmDevices function response

armMode can be one of "all", "some", or "none". All arms away, some arms home and none disarms

bypassSensors is an array of zid's to be bypassed. These zid's can be retrieved by the getAlarmDevices function.

The other functions are used to send messages through socket.io and could be helpful if you're trying to build in new functionality.

The messages are a little odd because of the socket setup. To get the response from an arm/disarm event you'll need to register a callback on 'DataUpdate' Example: ring.registerAlarmCallback(alarm, 'DataUpdate', (message) => { if(message.msg === "DataUpdate" && message.body[0].device !== undefined && message.body[0].device.v1.mode !== undefined){ console.log(message.body[0].device.v1.mode); } });

A result of the setup of their API is that most callbacks like DataUpdate will be called whenever the mode changes or upon the associated trigger, so you can register that callback, but should expect it to be called multiple times unless you unregister it upon a response.

mrose17 commented 6 years ago

@joeyberkovitz - this is very interesting information. the single biggest issue folks struggle with is getting timely notifications of a "ding". i don't have a ring alarm, and the location_id of my ring doorbell is null (no surprise), but i am wondering if the API you are using has an endpoint that culd be used for non-alarm users. any thoughts? thanks!

joeyberkovitz commented 6 years ago

I believe that you can assign a location ID your doorbell. Try opening the latest version of the ring app and editing the location of the doorbell. It should ask for a more granular location which should associate the doorbell with the new location ID.

From what I understand the alarm and doorbell APIs are completely independent from each other, so I don't think that you'll be able to get any doorbell related information.

I think you would be more likely to get better ding alerts by trying to figure out how to subscribe to push notifications. Alternatively just poll the dings endpoint, which has been working for me.

mrose17 commented 6 years ago

thanks! i tried the locationID trick, but no dice, it's still null

it makes sense that the APIs are independent. i am hoping someone can document the API to use for a websocket-based service (since i'm using dave's package for homekit, neither the iOS or android APIs are applicable).

at present, the homekit plugin polls using ding, but that "makes it rain in the cloud" at times, so websockets is preferred if it ever becomes available.

thanks!

ps: i'll buy a ring alarm and see if i can integrate it into the plugin. that would be cool!

mrose17 commented 6 years ago

@joeyberkovitz - my ring alarm arrived. do you have anything else to add to this PR?

mrose17 commented 6 years ago

@joeyberkovitz - also what's the battery in the range extender? the screws on the access panel are frozen on mine... thanks!

joeyberkovitz commented 6 years ago

I'm a little busy now, but I never built unit tests for it. Also because of the socket system, if you try to set the mode to the current mode, your callback will never get called. There's also some basic functionality like defining sensor attributes, which I didn't investigate much. These changes could be future improvements, but the PR is functional.

The battery is just a standard LiPo

mrose17 commented 6 years ago

can you send me a picture of the battery? i need the form factor. thanks!

joeyberkovitz commented 6 years ago

img_20181010_212801

mrose17 commented 6 years ago

thank you! it's rechargeable, so it probably shipped empty!

acolytec3 commented 6 years ago

I'm circling back to this after some time away (given that my ignorance of javascript was keeping me from making much progress.

Does the PR work right now? I passed my base_station object to the getAlarmDevices function and the API is returning a 403 error (per the doorbot debug messages) and then hangs at "connecting to websocket." Any guesses on whether I'm doing something boneheaded or if Ring changed their API?

joeyberkovitz commented 6 years ago

I last used it last night and it worked. Can send detailed instructions later

joeyberkovitz commented 6 years ago

Just an example of some code I use that I can verify is functional for getting the alarm devices (like motion sensors, ...):

ring.devices((e, devices) => {
    let alarm = devices.base_stations[0];
    ring.getAlarmDevices(alarm, (alarmDevicesResponse) => {
       console.log(alarmDevicesResponse);
    });
});
acolytec3 commented 6 years ago

Thanks for the follow-up.

It must be something in my account settings or something. I tried your code and it ends up with the exact same result as I was getting before. The ring.devices call returns my base station object but I get a 403 response from the API in the debug logs when I pass that object to getAlarmDevices and then it hangs at the "connecting to websocket" line.

On Tue, Oct 16, 2018, 9:38 PM joeyberkovitz notifications@github.com wrote:

Just an example of some code I use that I can verify is functional for getting the alarm devices (like motion sensors, ...):

ring.devices((e, devices) => { let alarm = devices.base_stations[0]; ring.getAlarmDevices(alarm, (alarmDevicesResponse) => { console.log(alarmDevicesResponse); }); });

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/davglass/doorbot/issues/26#issuecomment-430458727, or mute the thread https://github.com/notifications/unsubscribe-auth/AQjS3NqtxzxL_x6ZXtvSbEkKCUDlkVKaks5ulooOgaJpZM4VXTzz .

joeyberkovitz commented 6 years ago

Are you by any chance logging in using a pre-existing token?

acolytec3 commented 6 years ago

No, I figured it out. When I was defining the ringAPI call, you need to set the API version to 11 if you want the alarm functions you added to work. I guess it lets you call the main devices function using an older version but subsequent calls to the alarm API want a newer version of the API (evidently at least v11). When I add that api_version to the ringAPI definition, it works as expected and returned the list of alarmobjects you described.

Thanks again for this code set. Time to see if I can adapt it for my specific needs.

On Wed, Oct 17, 2018, 7:47 AM joeyberkovitz notifications@github.com wrote:

Are you by any chance logging in using a pre-existing token?

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/davglass/doorbot/issues/26#issuecomment-430596689, or mute the thread https://github.com/notifications/unsubscribe-auth/AQjS3DwCpY2h88ZePgq4HnEkdnqGT_ahks5ulxi0gaJpZM4VXTzz .

mrose17 commented 6 years ago

@joeyberkovitz - i finally have had an opportunity to take a look at this!

what i am interested in is getting updates via websockets when sensors change status. is there a way to register for that?

joeyberkovitz commented 6 years ago

You should be able to do that. I haven't investigated the messages sent back too much, but I think DataUpdate is the one you need: ring.registerAlarmCallback(alarm, 'DataUpdate', (message) => { if(message.msg === "DataUpdate" && message.body[0].device !== undefined && message.body[0].device.v1.mode !== undefined){ console.log(message.body[0].device.v1.mode); } }); That callback will be called every time Ring sends an update, which I think it periodically does.

mrose17 commented 6 years ago

thanks! i'll try it out...

mrose17 commented 6 years ago

outside of re-using a couple of internal calls, there really isn't much overlap in the functionality. i'm going to create a new repository that focuses on this new functionality... please stay tuned!

mrose17 commented 6 years ago

https://github.com/homespun/ring-alarm

joeyberkovitz commented 4 years ago

Are you using a socket.io compatible client in C#?

Socket.io isn't a standard socket or websocket, it's a custom protocol built on top of web sockets.