-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathring.py
161 lines (123 loc) · 5.11 KB
/
ring.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
#!/usr/bin/env python3
"""
Polyglot v3 node server - Ring
Copyright (C) 2023 Universal Devices
MIT License
"""
# https://github.com/UniversalDevicesInc/udi_python_interface/blob/master/API.md
import sys
import json
import traceback
from udi_interface import LOGGER, Custom, Interface
from lib.ringInterface import RingInterface
from nodes.controller import Controller
validEvents = [ 'new-ding', 'new-motion', 'webhook-test' ]
# Event 'new-on_demand' is sent when someone uses Live view
polyglot = None
ringInterface = None
controller = None
def configDoneHandler():
polyglot.Notices.clear()
try:
ringInterface.getAccessToken()
except ValueError as err:
LOGGER.warning('Access token is not yet available. Please authenticate.')
polyglot.Notices['auth'] = 'Please initiate authentication'
return
try:
controller.discoverDevices()
ringInterface.subscribe()
except ValueError as err:
LOGGER.debug(f"Error in configDoneHandler: {err}")
def oauthHandler(token):
LOGGER.info('Authentication successful {}'.format(json.dumps(token)))
# When user just authorized, the ringInterface needs to store the tokens
ringInterface.oauthHandler(token)
# Then proceed with device discovery
configDoneHandler()
def pollHandler(pollType):
try:
ringInterface.getAccessToken()
except ValueError as err:
LOGGER.info('Poll skipped as we are not authenticated to Ring.')
polyglot.Notices['auth'] = 'Please initiate authentication'
return
if pollType == 'longPoll':
ringInterface.subscribe()
else:
controller.queryAll()
def addNodeDoneHandler(node):
# We will automatically query the device after discovery
controller.addNodeDoneHandler(node)
def stopHandler():
# Set nodes offline
for node in polyglot.nodes():
if hasattr(node, 'setOffline'):
node.setOffline()
polyglot.stop()
def webhookHandler(data):
# TEST FOR NEST:
#polyglot.webhookResponse()
#LOGGER.info(f"-------------Returning RESPONSE---------")
# Available information: headers, query, body
LOGGER.info(f"Webhook received: { data }")
receivedPragma = data['headers']['pragma']
currentPragma = ringInterface.getCurrentPragma()
# Ignore webhooks if they don't have the right pragma
if receivedPragma != currentPragma:
LOGGER.info(f"Expected pragma { currentPragma }, receivedPragma { receivedPragma }: Webhook is ignored.")
return
LOGGER.info(f"Webhook body received: { data['body'] }")
eventInfo = json.loads(data['body'])
event = eventInfo['event'] # 'new-ding' or 'new-motion'
id = eventInfo['data']['doorbell']['id']
deviceName = eventInfo['data']['doorbell']['description']
if event not in validEvents:
LOGGER.info(f"Invalid event received: { event }")
return
if event == 'new-ding':
address = str(id) + '_db'
elif event == 'new-motion':
address = str(id) + '_m'
elif event == 'webhook-test':
address = id
LOGGER.info(f"Event { event } for address { address } ({ deviceName })")
node = polyglot.getNode(address)
if node is not None:
node.activate()
else:
LOGGER.info(f"Node { address } not found")
if __name__ == "__main__":
try:
polyglot = Interface([], { "enableWebhook": True })
polyglot.start({ 'version': '1.2.2', 'requestId': True })
# Show the help in PG3 UI under the node's Configuration option
polyglot.setCustomParamsDoc()
# Update the profile files
polyglot.updateProfile() # Use checkProfile() instead?
# Implements the API calls & Handles the oAuth authentication & token renewals
ringInterface = RingInterface(polyglot)
# Create the controller node
controller = Controller(polyglot, 'controller', 'controller', 'Ring', ringInterface)
#polyglot.webhookStart({ "name": "Ring" })
# Tests for Tesla
polyglot.webhookStart({ "assets": [{ "id": "5YJ3E1EA5RF721953" }], "name": "Ring"})
# subscribe to the events we want
polyglot.subscribe(polyglot.POLL, pollHandler)
polyglot.subscribe(polyglot.STOP, stopHandler)
polyglot.subscribe(polyglot.CUSTOMDATA, ringInterface.customDataHandler) # Used for migration from older OAuth class
polyglot.subscribe(polyglot.CUSTOMNS, ringInterface.customNsHandler) # oAuth config & tokens saved
polyglot.subscribe(polyglot.CUSTOMPARAMS, ringInterface.customParamsHandler) # UI params
polyglot.subscribe(polyglot.OAUTH, oauthHandler) # oAuth tokens received after authentication
polyglot.subscribe(polyglot.WEBHOOK, webhookHandler)
polyglot.subscribe(polyglot.CONFIGDONE, configDoneHandler)
polyglot.subscribe(polyglot.ADDNODEDONE, addNodeDoneHandler)
# We can start receive events
polyglot.ready()
# Just sit and wait for events
polyglot.runForever()
except (KeyboardInterrupt, SystemExit):
sys.exit(0)
except Exception:
LOGGER.error(f"Error starting Ring: {traceback.format_exc()}")
polyglot.stop()