Skip to content

Commit 017e6de

Browse files
committed
Add logging
1 parent a45cda8 commit 017e6de

File tree

5 files changed

+55
-3
lines changed

5 files changed

+55
-3
lines changed

.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,4 +40,7 @@ nosetests.xml
4040
MANIFEST
4141

4242
# PyCharm
43-
.idea/*
43+
.idea
44+
45+
# VS Code
46+
.vscode

README.rst

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -223,14 +223,14 @@ Command line
223223
224224
usage: nest [-h] [--conf FILE] [--token-cache TOKEN_CACHE_FILE] [-t TOKEN]
225225
[--client-id ID] [--client-secret SECRET] [-k] [-c] [-s SERIAL]
226-
[-S STRUCTURE] [-i INDEX]
226+
[-S STRUCTURE] [-i INDEX] [-v]
227227
{temp,fan,mode,away,target,humid,target_hum,show,camera-show,camera-streaming,protect-show}
228228
...
229229
230230
Command line interface to Nest™ Thermostats
231231
232232
positional arguments:
233-
{temp,fan,mode,away,target,humid,target_hum,show,camera-show,camera-streaming,protect-show}
233+
{temp,fan,mode,away,target,humid,target_hum,show,camera-show,camera-streaming,protect-show}
234234
command help
235235
temp show/set temperature
236236
fan set fan "on" or "auto"
@@ -265,6 +265,7 @@ Command line
265265
actions
266266
-i INDEX, --index INDEX
267267
optional, specify index number of nest to talk to
268+
-v, --verbose showing verbose logging
268269
269270
examples:
270271
# If your nest is not in range mode

nest/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
# -*- coding:utf-8 -*-
2+
import logging
23

34
from .nest import Nest
45

56
from .utils import CELSIUS
67
from .utils import FAHRENHEIT
78

9+
logging.getLogger(__name__).addHandler(logging.NullHandler())
10+
811
__all__ = ['CELSIUS', 'FAHRENHEIT', 'Nest']

nest/command_line.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
import argparse
1111
import datetime
12+
import logging
1213
import os
1314
import sys
1415
import errno
@@ -76,6 +77,10 @@ def get_parser():
7677
help='optional, specify index number of nest to '
7778
'talk to')
7879

80+
parser.add_argument('-v', '--verbose', dest='verbose',
81+
action='store_true',
82+
help='showing verbose logging')
83+
7984
subparsers = parser.add_subparsers(dest='command',
8085
help='command help')
8186
temp = subparsers.add_parser('temp', help='show/set temperature')
@@ -298,6 +303,17 @@ def main():
298303
parser = get_parser()
299304
args = parser.parse_args()
300305

306+
if args.verbose:
307+
logger = logging.getLogger('nest')
308+
logger.setLevel(logging.DEBUG)
309+
console_handler = logging.StreamHandler()
310+
formatter = logging.Formatter(
311+
"%(asctime)s %(levelname)s (%(threadName)s) "
312+
"[%(name)s] %(message)s", datefmt="%Y-%m-%d %H:%M:%S")
313+
console_handler.setFormatter(formatter)
314+
console_handler.setLevel(logging.DEBUG)
315+
logger.addHandler(console_handler)
316+
301317
# This is the command(s) passed to the command line utility
302318
cmd = args.command
303319
if cmd is None:

nest/nest.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import copy
55
import datetime
66
import hashlib
7+
import logging
78
import threading
89
import time
910
import os
@@ -62,6 +63,8 @@
6263
MINIMUM_TEMPERATURE_C = 9
6364
MAXIMUM_TEMPERATURE_C = 32
6465

66+
_LOGGER = logging.getLogger(__name__)
67+
6568

6669
class APIError(Exception):
6770
def __init__(self, response, msg=None):
@@ -131,6 +134,8 @@ def __init__(self, auth_callback=None, session=None,
131134
access_token is None and
132135
os.path.exists(access_token_cache_file)):
133136
with open(access_token_cache_file, 'r') as f:
137+
_LOGGER.debug("Load access token from %s",
138+
access_token_cache_file)
134139
self._res = json.load(f)
135140
self._callback(self._res)
136141

@@ -145,6 +150,8 @@ def _cache(self):
145150
with os.fdopen(os.open(self._access_token_cache_file,
146151
os.O_WRONLY | os.O_CREAT, 0o600),
147152
'w') as f:
153+
_LOGGER.debug("Save access token to %s",
154+
self._access_token_cache_file)
148155
json.dump(self._res, f)
149156

150157
def _callback(self, res):
@@ -164,7 +171,9 @@ def login(self, headers=None):
164171
session = self._session()
165172
post = session.post
166173

174+
_LOGGER.debug(">> POST %s", ACCESS_TOKEN_URL)
167175
response = post(ACCESS_TOKEN_URL, data=data, headers=headers)
176+
_LOGGER.debug("<< %s", response.status_code)
168177
if response.status_code != 200:
169178
raise AuthorizationError(response)
170179
self._res = response.json()
@@ -1681,6 +1690,8 @@ def _handle_ratelimit(self, res, verb, url, data,
16811690
while response.status_code == 429 and retries <= max_retries:
16821691
retries += 1
16831692
retry_after = response.headers['Retry-After']
1693+
_LOGGER.info("Reach rate limit, retry (%d), after %s",
1694+
retries, retry_after)
16841695
# Default Retry Time
16851696
wait = default_wait
16861697

@@ -1697,22 +1708,27 @@ def _handle_ratelimit(self, res, verb, url, data,
16971708
# Does nothing and uses default (shouldn't happen)
16981709
pass
16991710

1711+
_LOGGER.debug("Wait %d seconds.", wait)
17001712
time.sleep(wait)
1713+
_LOGGER.debug(">> %s %s", 'STREAM' if stream else verb, url)
17011714
response = self._session.request(verb, url,
17021715
allow_redirects=False,
17031716
stream=stream,
17041717
headers=headers,
17051718
data=data)
1719+
_LOGGER.debug("<< %s", response.status_code)
17061720
return response
17071721

17081722
def _open_data_stream(self, path="/"):
17091723
url = "%s%s" % (API_URL, path)
1724+
_LOGGER.debug(">> STREAM %s", url)
17101725

17111726
# Opens the data stream
17121727
headers = {'Accept': 'text/event-stream'}
17131728
response = self._session.get(url, stream=True, headers=headers,
17141729
allow_redirects=False)
17151730

1731+
_LOGGER.debug("<< %s", response.status_code)
17161732
if response.status_code == 401:
17171733
raise AuthorizationError(response)
17181734

@@ -1725,10 +1741,12 @@ def _open_data_stream(self, path="/"):
17251741

17261742
if response.status_code == 307:
17271743
redirect_url = response.headers['Location']
1744+
_LOGGER.debug(">> STREAM %s", redirect_url)
17281745
response = self._session.get(redirect_url,
17291746
allow_redirects=False,
17301747
headers=headers,
17311748
stream=True)
1749+
_LOGGER.debug("<< %s", response.status_code)
17321750
if response.status_code == 429:
17331751
response = self._handle_ratelimit(response, 'GET', url, None,
17341752
max_retries=10,
@@ -1745,12 +1763,15 @@ def _open_data_stream(self, path="/"):
17451763
self._event_thread.setDaemon(True)
17461764
self._event_thread.start()
17471765
ready_event.wait(timeout=10)
1766+
_LOGGER.info("Event loop started.")
17481767

17491768
def _start_event_loop(self, response, queue, ready_event, update_event):
1769+
_LOGGER.debug("Starting event loop.")
17501770
try:
17511771
client = sseclient.SSEClient(response.iter_content())
17521772
for event in client.events():
17531773
event_type = event.event
1774+
_LOGGER.debug("<<< %s event", event_type)
17541775
if event_type == 'open' or event_type == 'keep-alive':
17551776
pass
17561777
elif event_type == 'put':
@@ -1765,22 +1786,26 @@ def _start_event_loop(self, response, queue, ready_event, update_event):
17651786
if not ready_event.is_set():
17661787
ready_event.set()
17671788
finally:
1789+
_LOGGER.debug("Stopping event loop.")
17681790
queue.clear()
17691791
update_event.set()
17701792
try:
17711793
response.close()
17721794
except Exception:
17731795
pass
1796+
_LOGGER.info("Event loop stopped.")
17741797

17751798
def _request(self, verb, path="/", data=None):
17761799
url = "%s%s" % (API_URL, path)
1800+
_LOGGER.debug(">> %s %s", verb, url)
17771801

17781802
if data is not None:
17791803
data = json.dumps(data)
17801804

17811805
response = self._session.request(verb, url,
17821806
allow_redirects=False,
17831807
data=data)
1808+
_LOGGER.debug("<< %s", response.status_code)
17841809
if response.status_code == 200:
17851810
return response.json()
17861811

@@ -1802,10 +1827,12 @@ def _request(self, verb, path="/", data=None):
18021827
raise APIError(response)
18031828

18041829
redirect_url = response.headers['Location']
1830+
_LOGGER.debug(">> %s %s", verb, redirect_url)
18051831
response = self._session.request(verb, redirect_url,
18061832
allow_redirects=False,
18071833
data=data)
18081834

1835+
_LOGGER.debug("<< %s", response.status_code)
18091836
# Rate Limit Exceeded Catch
18101837
if response.status_code == 429:
18111838
response = self._handle_ratelimit(response, verb, redirect_url,
@@ -1835,6 +1862,7 @@ def _status(self):
18351862
self._queue_lock.acquire()
18361863
if len(self._queue) == 0 or not self._queue[0]:
18371864
try:
1865+
_LOGGER.info("Open data stream")
18381866
self._open_data_stream("/")
18391867
except AuthorizationError as authorization_error:
18401868
self._queue_lock.release()
@@ -1847,6 +1875,7 @@ def _status(self):
18471875
value = self._queue[0]['data'] if len(self._queue) > 0 else None
18481876
if value is None:
18491877
# fall back to pull mode
1878+
_LOGGER.info("Fall back to pull mode")
18501879
value = self._get("/")
18511880

18521881
return value

0 commit comments

Comments
 (0)