Skip to content

Commit 36aaaa4

Browse files
steve-gombosballoob
andcommitted
Drop python 2.7/3.5. Updated readme and test.py examples (python-ring-doorbell#192)
* Removed python 2.7 from tox. Updated readme and test.py examples * Removed another python 2.7 reference * Removed python 2.7 from travis * Added pathlib to requirements_test * Removed python 3.5 * Additional readme updates * Update README.rst Co-Authored-By: Paulus Schoutsen <paulus@home-assistant.io> * Update test.py Co-Authored-By: Paulus Schoutsen <paulus@home-assistant.io> * Updated user agent * Black error * Removed pathlib dep * Updated ringcli script to use new auth implementation * Added examples for getting all specific devices Co-authored-by: Paulus Schoutsen <paulus@home-assistant.io>
1 parent b664169 commit 36aaaa4

6 files changed

Lines changed: 132 additions & 105 deletions

File tree

.travis.yml

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,6 @@ language: python
33
matrix:
44
fast_finish: true
55
include:
6-
- python: "2.7"
7-
env: TOXENV=py27
8-
- python: "3.5"
9-
env: TOXENV=py35
106
- python: "3.6"
117
env: TOXENV=py36
128
- python: "3.7"

README.rst

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ Python Ring Door Bell
1515
:target: https://pypi.python.org/pypi/ring-doorbell
1616

1717

18-
Python Ring Door Bell is a library written in Python 2.7/3x
18+
Python Ring Door Bell is a library written for Python 3.6+
1919
that exposes the Ring.com devices as Python objects.
2020

2121
*Currently Ring.com does not provide an official API. The results of this project are merely from reverse engineering.*
@@ -48,6 +48,7 @@ Initializing your Ring object
4848
auth.fetch_token(username, password)
4949
ring = Ring(auth)
5050
ring.update_data()
51+
devices = ring.devices()
5152
5253
pprint(ring.session['profile'])
5354
@@ -58,17 +59,29 @@ Listing devices linked to your account
5859
.. code-block:: python
5960
6061
# All devices
61-
myring.devices()
62+
devices = ring.devices()
6263
{'chimes': [<RingChime: Downstairs>],
63-
'doorbells': [<RingDoorBell: Front Door>]}
64+
'doorbots': [<RingDoorBell: Front Door>]}
65+
66+
# All doorbells
67+
doorbells = devices['doorbots']
68+
[<RingDoorBell: Front Door>]
69+
70+
# All chimes
71+
chimes = devices['chimes']
72+
[<RingChime: Downstairs>]
73+
74+
# All stickup cams
75+
stickup_cams = devices['stickup_cams']
76+
[<RingStickUpCam: Driveway>]
6477
6578
Playing with the attributes and functions
6679
-----------------------------------------
6780
.. code-block:: python
6881
69-
for dev in list(myring.stickup_cams + myring.chimes + myring.doorbells):
82+
devices = ring.devices()
83+
for dev in list(devices['stickup_cams'] + devices['chimes'] + devices['doorbots']):
7084
dev.update_health_data()
71-
print('Account ID: %s' % dev.account_id)
7285
print('Address: %s' % dev.address)
7386
print('Family: %s' % dev.family)
7487
print('ID: %s' % dev.id)
@@ -96,7 +109,8 @@ Showing door bell events
96109
------------------------
97110
.. code-block:: python
98111
99-
for doorbell in myring.doorbells:
112+
devices = ring.devices()
113+
for doorbell in devices['doorbots']:
100114
101115
# listing the last 15 events of any kind
102116
for event in doorbell.history(limit=15):
@@ -114,10 +128,11 @@ Downloading the last video triggered by ding
114128
--------------------------------------------
115129
.. code-block:: python
116130
117-
doorbell = myring.doorbells[0]
131+
devices = ring.devices()
132+
doorbell = devices['doorbots'][0]
118133
doorbell.recording_download(
119134
doorbell.history(limit=100, kind='ding')[0]['id'],
120-
filename='/home/user/last_ding.mp4',
135+
filename='last_ding.mp4',
121136
override=True)
122137
123138

scripts/ringcli.py

Lines changed: 92 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,12 @@
22
# vim:sw=4:ts=4:et
33
# Many thanks to @troopermax <https://github.com/troopermax>
44

5+
import json
56
import getpass
67
import argparse
7-
from ring_doorbell import Ring
8+
from pathlib import Path
9+
from ring_doorbell import Ring, Auth
10+
from oauthlib.oauth2 import MissingTokenError
811

912

1013
def _header():
@@ -13,95 +16,106 @@ def _header():
1316

1417

1518
def _bar():
16-
print('---------------------------------')
19+
print("---------------------------------")
1720

1821

19-
def get_username():
20-
try:
21-
username = raw_input("Username: ")
22-
except NameError:
23-
username = input("Username: ")
24-
return username
22+
cache_file = Path("test_token.cache")
23+
24+
25+
def token_updated(token):
26+
cache_file.write_text(json.dumps(token))
2527

2628

2729
def _format_filename(event):
2830
if not isinstance(event, dict):
2931
return
3032

31-
if event['answered']:
32-
answered_status = 'answered'
33+
if event["answered"]:
34+
answered_status = "answered"
3335
else:
34-
answered_status = 'not_answered'
36+
answered_status = "not_answered"
3537

36-
filename = "{}_{}_{}_{}".format(event['created_at'],
37-
event['kind'],
38-
answered_status,
39-
event['id'])
38+
filename = "{}_{}_{}_{}".format(
39+
event["created_at"], event["kind"], answered_status, event["id"]
40+
)
4041

41-
filename = filename.replace(' ', '_').replace(':', '.')+'.mp4'
42+
filename = filename.replace(" ", "_").replace(":", ".") + ".mp4"
4243
return filename
4344

4445

4546
def main():
4647

4748
parser = argparse.ArgumentParser(
48-
description='Ring Doorbell',
49-
epilog='https://github.com/tchellomello/python-ring-doorbell',
50-
formatter_class=argparse.RawDescriptionHelpFormatter)
51-
52-
parser.add_argument('-u',
53-
'--username',
54-
dest='username',
55-
type=str,
56-
help='username for Ring account')
57-
58-
parser.add_argument('-p',
59-
'--password',
60-
type=str,
61-
dest='password',
62-
help='username for Ring account')
63-
64-
parser.add_argument('--count',
65-
action='store_true',
66-
default=False,
67-
help='count the number of videos on your Ring account')
68-
69-
parser.add_argument('--download-all',
70-
action='store_true',
71-
default=False,
72-
help='download all videos on your Ring account')
49+
description="Ring Doorbell",
50+
epilog="https://github.com/tchellomello/python-ring-doorbell",
51+
formatter_class=argparse.RawDescriptionHelpFormatter,
52+
)
53+
54+
parser.add_argument(
55+
"-u", "--username", dest="username", type=str, help="username for Ring account"
56+
)
57+
58+
parser.add_argument(
59+
"-p", "--password", type=str, dest="password", help="username for Ring account"
60+
)
61+
62+
parser.add_argument(
63+
"--count",
64+
action="store_true",
65+
default=False,
66+
help="count the number of videos on your Ring account",
67+
)
68+
69+
parser.add_argument(
70+
"--download-all",
71+
action="store_true",
72+
default=False,
73+
help="download all videos on your Ring account",
74+
)
7375

7476
args = parser.parse_args()
7577
_header()
7678

77-
if not args.username:
78-
args.username = get_username()
79+
# connect to Ring account
80+
if cache_file.is_file():
81+
auth = Auth("RingCLI/0.6", json.loads(cache_file.read_text()), token_updated)
82+
else:
83+
if not args.username:
84+
args.username = input("Username: ")
85+
86+
if not args.password:
87+
args.password = getpass.getpass("Password: ")
7988

80-
if not args.password:
81-
args.password = getpass.getpass("Password: ")
89+
auth = Auth("RingCLI/0.6", None, token_updated)
90+
try:
91+
auth.fetch_token(args.username, args.password)
92+
except MissingTokenError:
93+
auth.fetch_token(args.username, args.password, input("2FA Code: "))
8294

83-
# connect to Ring account
84-
myring = Ring(args.username, args.password)
85-
doorbell = myring.doorbells[0]
95+
ring = Ring(auth)
96+
ring.update_data()
97+
devices = ring.devices()
98+
doorbell = devices["doorbots"][0]
8699

87100
_bar()
88101

89102
if args.count:
90-
print("\tCounting videos linked on your Ring account.\n" +
91-
"\tThis may take some time....\n")
103+
print(
104+
"\tCounting videos linked on your Ring account.\n"
105+
+ "\tThis may take some time....\n"
106+
)
92107

93108
events = []
94109
counter = 0
95110
history = doorbell.history(limit=100)
96-
while (len(history) > 0):
111+
while len(history) > 0:
97112
events += history
98113
counter += len(history)
99-
history = doorbell.history(older_than=history[-1]['id'])
114+
history = doorbell.history(older_than=history[-1]["id"])
100115

101-
motion = len([m['kind'] for m in events if m['kind'] == 'motion'])
102-
ding = len([m['kind'] for m in events if m['kind'] == 'ding'])
103-
on_demand = \
104-
len([m['kind'] for m in events if m['kind'] == 'on_demand'])
116+
motion = len([m["kind"] for m in events if m["kind"] == "motion"])
117+
ding = len([m["kind"] for m in events if m["kind"] == "ding"])
118+
on_demand = len([m["kind"] for m in events if m["kind"] == "on_demand"])
105119

106120
print("\tTotal videos: {}".format(counter))
107121
print("\tDing triggered: {}".format(ding))
@@ -111,43 +125,44 @@ def main():
111125
# already have all events in memory
112126
if args.download_all:
113127
counter = 0
114-
print("\tDownloading all videos linked on your Ring account.\n" +
115-
"\tThis may take some time....\n")
128+
print(
129+
"\tDownloading all videos linked on your Ring account.\n"
130+
+ "\tThis may take some time....\n"
131+
)
116132

117133
for event in events:
118134
counter += 1
119135
filename = _format_filename(event)
120-
print("\t{}/{} Downloading {}".format(counter,
121-
len(events),
122-
filename))
136+
print("\t{}/{} Downloading {}".format(counter, len(events), filename))
123137

124-
doorbell.recording_download(event['id'],
125-
filename=filename,
126-
override=False)
138+
doorbell.recording_download(
139+
event["id"], filename=filename, override=False
140+
)
127141

128142
if args.download_all and not args.count:
129-
print("\tDownloading all videos linked on your Ring account.\n" +
130-
"\tThis may take some time....\n")
143+
print(
144+
"\tDownloading all videos linked on your Ring account.\n"
145+
+ "\tThis may take some time....\n"
146+
)
131147
history = doorbell.history(limit=100)
132148

133-
while (len(history) > 0):
134-
print("\tProcessing and downloading the next" +
135-
" videos".format(len(history)))
149+
while len(history) > 0:
150+
print(
151+
"\tProcessing and downloading the next" + " videos".format(len(history))
152+
)
136153

137154
counter = 0
138155
for event in history:
139156
counter += 1
140157
filename = _format_filename(event)
141-
print("\t{}/{} Downloading {}".format(counter,
142-
len(history),
143-
filename))
158+
print("\t{}/{} Downloading {}".format(counter, len(history), filename))
144159

145-
doorbell.recording_download(event['id'],
146-
filename=filename,
147-
override=False)
160+
doorbell.recording_download(
161+
event["id"], filename=filename, override=False
162+
)
148163

149-
history = doorbell.history(limit=100, older_than=history[-1]['id'])
164+
history = doorbell.history(limit=100, older_than=history[-1]["id"])
150165

151166

152-
if __name__ == '__main__':
167+
if __name__ == "__main__":
153168
main()

setup.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,6 @@ def readme():
4141
'GNU Lesser General Public License v3 or later (LGPLv3+)',
4242
'Operating System :: OS Independent',
4343
'Programming Language :: Python',
44-
'Programming Language :: Python :: 2.7',
45-
'Programming Language :: Python :: 3.5',
4644
'Programming Language :: Python :: 3.6',
4745
'Programming Language :: Python :: 3.7',
4846
'Topic :: Home Automation',

test.py

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import json
2+
import getpass
23
from pathlib import Path
3-
from pprint import pprint
44

55
from ring_doorbell import Ring, Auth
66
from oauthlib.oauth2 import MissingTokenError
@@ -20,15 +20,11 @@ def otp_callback():
2020

2121
def main():
2222
if cache_file.is_file():
23-
auth = Auth(
24-
"HomeAssistant/0.105.0dev0",
25-
json.loads(cache_file.read_text()),
26-
token_updated,
27-
)
23+
auth = Auth("MyProject/1.0", json.loads(cache_file.read_text()), token_updated)
2824
else:
2925
username = input("Username: ")
30-
password = input("Password: ")
31-
auth = Auth(None, token_updated)
26+
password = getpass.getpass("Password: ")
27+
auth = Auth("MyProject/1.0", None, token_updated)
3228
try:
3329
auth.fetch_token(username, password)
3430
except MissingTokenError:
@@ -37,9 +33,16 @@ def main():
3733
ring = Ring(auth)
3834
ring.update_data()
3935

40-
print(f"Hello {ring.session['profile']['first_name']}")
41-
print()
42-
pprint(ring.devices_data)
36+
devices = ring.devices()
37+
print(devices)
38+
39+
doorbells = devices["doorbots"]
40+
chimes = devices["chimes"]
41+
stickup_cams = devices["stickup_cams"]
42+
43+
print(doorbells)
44+
print(chimes)
45+
print(stickup_cams)
4346

4447

4548
if __name__ == "__main__":

tox.ini

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[tox]
2-
envlist = py27, py35, py36, py37, lint
2+
envlist = py36, py37, lint
33
skip_missing_interpreters = True
44

55
[testenv]
@@ -17,6 +17,6 @@ deps =
1717
ignore_errors = True
1818
commands =
1919
pip3 install black
20-
flake8 ring_doorbell tests test.py
20+
flake8 ring_doorbell tests test.py scripts
2121
pylint ring_doorbell
22-
black --check ring_doorbell tests test.py
22+
black --check ring_doorbell tests test.py scripts

0 commit comments

Comments
 (0)