Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Alarm Support #26

Open
joeyberkovitz opened this issue Jul 20, 2018 · 27 comments
Open

Alarm Support #26

joeyberkovitz opened this issue Jul 20, 2018 · 27 comments

Comments

@joeyberkovitz
Copy link

joeyberkovitz commented Jul 20, 2018

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
Copy link
Owner

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
Copy link
Author

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
Copy link
Author

PR added: #27

@broyuken
Copy link

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
Copy link

@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
Copy link
Author

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
Copy link
Collaborator

mrose17 commented Aug 22, 2018

@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
Copy link
Author

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
Copy link
Collaborator

mrose17 commented Aug 22, 2018

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
Copy link
Collaborator

mrose17 commented Oct 10, 2018

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

@mrose17
Copy link
Collaborator

mrose17 commented Oct 10, 2018

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

@joeyberkovitz
Copy link
Author

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
Copy link
Collaborator

mrose17 commented Oct 10, 2018

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

@joeyberkovitz
Copy link
Author

img_20181010_212801

@mrose17
Copy link
Collaborator

mrose17 commented Oct 11, 2018

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

@acolytec3
Copy link

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
Copy link
Author

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

@joeyberkovitz
Copy link
Author

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
Copy link

acolytec3 commented Oct 17, 2018 via email

@joeyberkovitz
Copy link
Author

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

@acolytec3
Copy link

acolytec3 commented Oct 17, 2018 via email

@mrose17
Copy link
Collaborator

mrose17 commented Oct 17, 2018

@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
Copy link
Author

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
Copy link
Collaborator

mrose17 commented Oct 18, 2018

thanks! i'll try it out...

@mrose17
Copy link
Collaborator

mrose17 commented Oct 22, 2018

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
Copy link
Collaborator

mrose17 commented Oct 22, 2018

@joeyberkovitz
Copy link
Author

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants