python-ring-doorbell
python-ring-doorbell copied to clipboard
Contact Sensor implementation
Is there a way to get data from the contact sensors? I have one installed but it does not show up when I list devices.
Hi @neviskevin did you ever make any progress? Im just starting to play around and started #254 to address this issue for my own interest as well. If you're interested I would very much appreciate any help or collaboration.
Yeah, I added code to example.ts, added my logic inside of the same async function that connects to ring.
alarmEvents = await location.getHistory({limit: 1, category: 'alarm',}) //gets the latest alarm event sync = (JSON.stringify(alarmEvents[0].context)).slice(12, 48)// cuts out event id from string of data, unique to each event
For me I just have one contact sensor so I am constantly checking to see if another event has passed to tell if it has been opened or closed. You cannot see the state of the contact sensor from the data sent by ring (I think this is due to security reasons), so I assumed the starting position was closed and added some logic to keep track of the state of the sensor. If you have multiple sensors there is a device ID in the alarmEvent you can use to sort things out. I used this to automatically turn off my air-conditioning when I leave my door open. Hope this helps!
Also, I am not sure what you are working on, but alexa has the ability to react to an open or closed contact sensor directly so maybe you could leverage a skill as a solution
After looking through some code: https://github.com/dgreif/ring/blob/master/api/ https://github.com/dgreif/ring/blob/master/api/location.ts
and going through some threads: https://github.com/dgreif/ring/issues/19 https://github.com/davglass/doorbot/issues/26 https://github.com/asishrs/smartthings-ringalarm/issues/6
Then looking at data on ring.com's dashboard on Chrome DevTools (ctrl+shift+j then go to Network tab)...
I was able to get access to several sensors attached to the Ring Alarm Base Station (including contact sensor). Here's a basic implementation:
import getpass
from pathlib import Path
from ring_doorbell import Ring, Auth
from oauthlib.oauth2 import MissingTokenError
import websocket # pip install websocket-client (there's another one called websockets, which is different)
import threading
import json
from time import sleep
#############################################################
# From https://github.com/tchellomello/python-ring-doorbell #
#############################################################
cache_file = Path("test_token.cache")
def token_updated(token):
cache_file.write_text(json.dumps(token))
def otp_callback():
auth_code = input("2FA code: ")
return auth_code
if cache_file.is_file():
auth = Auth("System Test", json.loads(cache_file.read_text()), token_updated)
else:
username = input("Username: ")
password = getpass.getpass("Password: ")
auth = Auth("System Test", None, token_updated)
try:
auth.fetch_token(username, password)
except MissingTokenError:
auth.fetch_token(username, password, otp_callback())
ring = Ring(auth)
ring.update_data()
#######################################
# Ring Alarm Base Station Device Data #
#######################################
# Get Location ID(s) for Ring Alarm Base Station(s)
list_locationID = []
for base_station_id in ring.devices_data['base_stations']:
list_locationID.append(ring.devices_data['base_stations'][base_station_id]['location_id'])
# Set up socket functions
def on_open(wsapp):
print("open")
data_buffer = [] # Set up a variable to store all messages received through the socket
def on_message(wsapp, message):
print(message)
try:
data_buffer.append(json.loads(message))
except:
print('Failed to load message into buffer')
pass
def on_close(wsapp, close_status_code, close_msg):
# Because on_close was triggered, we know the opcode = 8
print("on_close args:")
if close_status_code or close_msg:
print("close status code: " + str(close_status_code))
print("close message: " + str(close_msg))
# May need to implement some code in this function to reconnect the socket if it disconnects for any reason.
# Generate socket link
socket_ticket = ring.auth.query("https://app.ring.com/api/v1/clap/tickets?locationID=%s"%(list_locationID[0]),method="GET").json()
socket = 'wss://%s/ws?authcode=%s&ack=false'%(socket_ticket['host'],socket_ticket['ticket'])
# Set up socket
websocket.enableTrace(True) # For debugging
ws = websocket.WebSocketApp(socket,
on_open=on_open,
on_message=on_message,
on_close=on_close,
)
# Run socket in a thread
wst = threading.Thread(target=lambda: ws.run_forever())
wst.daemon = True
wst.start()
# Add a little delay to wait for socket to be connected
sleep(2)
# Send these messages through the socket to retrieve room data and list of all devices
if ws.sock.connected:
ws.send('{"channel":"message","msg":{"msg":"RoomGetList","dst":"%s","seq":1}}'%(socket_ticket['assets'][0]['uuid']))
ws.send('{"channel":"message","msg":{"msg":"DeviceInfoDocGetList","dst":"%s","seq":2}}'%(socket_ticket['assets'][0]['uuid']))
# At this point you should be able to see messages coming through the socket and also access data through data_buffer
# You can also get a history of events from the Ring Alarm Base Station
event_history = ring.auth.query("https://app.ring.com/api/v1/rs/history?category=alarm&offset=0&limit=100&maxLevel=50&accountId=%s"%(list_locationID[0]),method="GET").json()