Skip to content

Commit

Permalink
Added logging, and documented rate limiting in test.py
Browse files Browse the repository at this point in the history
  • Loading branch information
avryhof committed Oct 26, 2018
1 parent 3b2cb70 commit ac4ad87
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 15 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -196,3 +196,4 @@ gen### VisualStudioCode template
!.vscode/extensions.json

/*.env
/ambient_api.log
88 changes: 77 additions & 11 deletions ambient_api/ambientapi.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import datetime
import logging

import requests

Expand All @@ -23,23 +24,32 @@ def __init__(self, api_instance, device_dict):
self.info = device_dict.get('info', {})

def __str__(self):
retn = '%s@%s' % (self.info.get('name'), self.mac_address)
self.api_instance.log(retn)

return '%s@%s' % (self.info.get('name'), self.mac_address)
return retn

@staticmethod
def convert_datetime(datetime_object):
def convert_datetime(self, datetime_object):
try:
posix_timestamp = datetime_object.timestamp()

except AttributeError:
epoch = datetime.datetime(year=1969, month=12, day=31, hour=19, minute=0, second=0)
self.api_instance.log('EPOCH:')
self.api_instance.log(epoch)

posix_timestamp = (datetime_object - epoch).total_seconds()

self.api_instance.log('POSIX TIMESTAMP:')
self.api_instance.log(posix_timestamp)

return int(posix_timestamp * 1000.0)

def current_time(self):
retn = self.convert_datetime(datetime.datetime.now())
self.api_instance.log(retn)

return self.convert_datetime(datetime.datetime.now())
return retn

def get_data(self, **kwargs):
"""
Expand All @@ -52,18 +62,23 @@ def get_data(self, **kwargs):
:return:
"""
limit = int(kwargs.get('limit', 288))
end_date = kwargs.get('end_date', self.current_time())
end_date = kwargs.get('end_date', False)

if isinstance(end_date, datetime.datetime):
if end_date and isinstance(end_date, datetime.datetime):
end_date = self.convert_datetime(end_date)

if self.mac_address is not None:
service_address = 'devices/%s' % self.mac_address
self.api_instance.log('SERVICE ADDRESS: %s' % service_address)

data = dict(
limit=limit,
endDate=end_date
)
data = dict(limit=limit)

# If endDate is left blank (not passed in), the most recent results will be returned.
if end_date:
data.update({'endDate': end_date})

self.api_instance.log('DATA:')
self.api_instance.log(data)

return self.api_instance.api_call(service_address, **data)

Expand All @@ -74,6 +89,8 @@ class AmbientAPI:
application_key = None
client = requests

log_level = None

def __init__(self, **kwargs):
http_client = kwargs.get('http_client', requests)

Expand All @@ -82,10 +99,36 @@ def __init__(self, **kwargs):
self.api_key = getattr(settings, 'AMBIENT_API_KEY', None)
self.application_key = getattr(settings, 'AMBIENT_APPLICATION_KEY', None)

default_log_level = getattr(settings, 'AMBIENT_LOG_LEVEL', None)
self.log_level = kwargs.get('log_level', default_log_level)
default_log_file = getattr(settings, 'AMBIENT_LOG_FILE', None)
self.log_file = kwargs.get('log_file', default_log_file)

def log(self, message):
if self.log_level:
log_level = self.log_level.lower()

if self.log_file and log_level != 'console':
logging.basicConfig(filename=self.log_file, level=getattr(logging, log_level.upper(), 'ERROR'))

if log_level == 'debug':
logging.debug(message)
if log_level == 'info':
logging.info(message)
if log_level == 'warning':
logging.warning(message)
if log_level == 'error':
logging.error(message)
if log_level == 'critical':
logging.critical(message)
if log_level == 'console':
print(message)

def api_call(self, service, **kwargs):
retn = {}

target_url = '%s/%s' % (self.endpoint, service)
self.log('TARGET URL: %s' % target_url)

params = {
'applicationKey': self.application_key,
Expand All @@ -95,10 +138,25 @@ def api_call(self, service, **kwargs):
for kwarg_k, kwarg_v in kwargs.items():
params.update({kwarg_k: kwarg_v})

# Remove sensitive parameters from log
if self.log_level:
log_params = params.copy()
log_params['applicationKey'] = '[secure]'
log_params['apiKey'] = '[secure]'
self.log('PARAMS:')
self.log(log_params)

res = self.client.get(target_url, params, verify=True)
self.log('RESPONSE:')
self.log(res)

if res.status_code == 200:
retn = res.json()
self.log('RETURN DATA:')
self.log(retn)

if res.status_code == 429:
self.log('RATE LIMIT EXCEEDED')

return retn

Expand All @@ -110,7 +168,15 @@ def get_devices(self):
A list of AmbientWeatherStation instances.
"""
retn = []
for device in self.api_call('devices'):
api_devices = self.api_call('devices')

self.log('DEVICES:')
self.log(api_devices)

for device in api_devices:
retn.append(AmbientWeatherStation(self, device))

self.log('DEVICE INSTANCE LIST:')
self.log(retn)

return retn
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

setup(
name='ambient_api',
version='1.0.3',
version='1.5.0',
packages=['ambient_api'],
url='https://github.com/avryhof/ambient_api',
license='MIT',
Expand Down
10 changes: 7 additions & 3 deletions test.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,22 @@
import datetime
import pprint
import time

from ambient_api.ambientapi import AmbientAPI

weather = AmbientAPI()
weather = AmbientAPI(log_level='CONSOLE')

devices = weather.get_devices()

for device in devices:
# Wait two seconds between requests so we don't get a 429 response.
# https://ambientweather.docs.apiary.io/#introduction/rate-limiting
# This probably won't happen much in real world situations.
time.sleep(2)
print('Device')
print(str(device))

print('Last Data')
pprint.pprint(device.last_data)

print('Get Data')
pprint.pprint(device.get_data(end_date=datetime.datetime(year=2018, month=10, day=1)))
pprint.pprint(device.get_data())

0 comments on commit ac4ad87

Please sign in to comment.