1- # Copyright (c) 2014 Adafruit Industries
1+ # Copyright (c) 2018 Adafruit Industries
22# Authors: Justin Cooper & Tony DiCola
33
44# Permission is hereby granted, free of charge, to any person obtaining a copy
2121import json
2222import pkg_resources
2323import platform
24+ # import logging
2425
2526import requests
2627
@@ -41,23 +42,30 @@ class Client(object):
4142 REST API. Use this client class to send, receive, and enumerate feed data.
4243 """
4344
44- def __init__ (self , key , proxies = None , base_url = 'https://io.adafruit.com' , api_version = 'v1 ' ):
45+ def __init__ (self , username , key , proxies = None , base_url = 'https://io.adafruit.com' , api_version = 'v2 ' ):
4546 """Create an instance of the Adafruit IO REST API client. Key must be
4647 provided and set to your Adafruit IO access key value. Optionaly
4748 provide a proxies dict in the format used by the requests library, a
4849 base_url to point at a different Adafruit IO service (the default is
4950 the production Adafruit IO service over SSL), and a api_version to
5051 add support for future API versions.
5152 """
53+ self .username = username
5254 self .key = key
5355 self .proxies = proxies
5456 self .api_version = api_version
57+ # self.logger = logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s')
58+
5559 # Save URL without trailing slash as it will be added later when
5660 # constructing the path.
5761 self .base_url = base_url .rstrip ('/' )
5862
59- def _compose_url (self , path ):
60- return '{0}/api/{1}/{2}' .format (self .base_url , self .api_version , path )
63+ def _compose_url (self , path , is_time = None ):
64+ if not is_time :
65+ return '{0}/api/{1}/{2}/{3}' .format (self .base_url , self .api_version , self .username , path )
66+ else : # return a call to https://io.adafruit.com/api/v2/time/{unit}
67+ return '{0}/api/{1}/{2}' .format (self .base_url , self .api_version , path )
68+
6169
6270 def _handle_error (self , response ):
6371 # Handle explicit errors.
@@ -73,12 +81,15 @@ def _headers(self, given):
7381 headers .update (given )
7482 return headers
7583
76- def _get (self , path ):
77- response = requests .get (self ._compose_url (path ),
84+ def _get (self , path , is_time = None ):
85+ response = requests .get (self ._compose_url (path , is_time ),
7886 headers = self ._headers ({'X-AIO-Key' : self .key }),
7987 proxies = self .proxies )
8088 self ._handle_error (response )
81- return response .json ()
89+ if not is_time :
90+ return response .json ()
91+ else : # time doesn't need to serialize into json, just return text
92+ return response .text
8293
8394 def _post (self , path , data ):
8495 response = requests .post (self ._compose_url (path ),
@@ -97,14 +108,25 @@ def _delete(self, path):
97108 self ._handle_error (response )
98109
99110 # Data functionality.
100- def send (self , feed_name , value ):
101- """Helper function to simplify adding a value to a feed. Will find the
102- specified feed by name or create a new feed if it doesn't exist, then
103- will append the provided value to the feed. Returns a Data instance
104- with details about the newly appended row of data .
111+ def send_data (self , feed , value ):
112+ """Helper function to simplify adding a value to a feed. Will append the
113+ specified value to the feed identified by either name, key, or ID.
114+ Returns a Data instance with details about the newly appended row of data.
115+ Note that send_data now operates the same as append .
105116 """
106- path = "feeds/{0}/data/send" .format (feed_name )
107- return Data .from_dict (self ._post (path , {'value' : value }))
117+ return self .create_data (feed , Data (value = value ))
118+
119+ send = send_data
120+
121+ def send_batch_data (self , feed , data_list ):
122+ """Create a new row of data in the specified feed. Feed can be a feed
123+ ID, feed key, or feed name. Data must be an instance of the Data class
124+ with at least a value property set on it. Returns a Data instance with
125+ details about the newly appended row of data.
126+ """
127+ path = "feeds/{0}/data/batch" .format (feed )
128+ data_dict = type (data_list )((data ._asdict () for data in data_list ))
129+ self ._post (path , {"data" : data_dict })
108130
109131 def append (self , feed , value ):
110132 """Helper function to simplify adding a value to a feed. Will append the
@@ -114,6 +136,26 @@ def append(self, feed, value):
114136 """
115137 return self .create_data (feed , Data (value = value ))
116138
139+ def send_location_data (self , feed , value , lat , lon , ele ):
140+ """Sends locational data to a feed
141+
142+ args:
143+ - lat: latitude
144+ - lon: logitude
145+ - ele: elevation
146+ - (optional) value: value to send to the feed
147+ """
148+ return self .create_data (feed , Data (value = value ,lat = lat , lon = lon , ele = ele ))
149+
150+ def receive_time (self , time ):
151+ """Returns the time from the Adafruit IO server.
152+
153+ args:
154+ - time (string): millis, seconds, ISO-8601
155+ """
156+ timepath = "time/{0}" .format (time )
157+ return self ._get (timepath , is_time = True )
158+
117159 def receive (self , feed ):
118160 """Retrieve the most recent value for the specified feed. Feed can be a
119161 feed ID, feed key, or feed name. Returns a Data instance whose value
@@ -185,7 +227,7 @@ def create_feed(self, feed):
185227 type with at least the name property set.
186228 """
187229 path = "feeds/"
188- return Feed .from_dict (self ._post (path , feed ._asdict ()))
230+ return Feed .from_dict (self ._post (path , { " feed" : feed ._asdict ()} ))
189231
190232 def delete_feed (self , feed ):
191233 """Delete the specified feed. Feed can be a feed ID, feed key, or feed
@@ -194,25 +236,6 @@ def delete_feed(self, feed):
194236 path = "feeds/{0}" .format (feed )
195237 self ._delete (path )
196238
197- # Group functionality.
198- def send_group (self , group_name , data ):
199- """Update all feeds in a group with one call. Group_name should be the
200- name of a group to update. Data should be a dict with an item for each
201- feed in the group, where the key is the feed name and value is the new
202- data row value. For example a group 'TestGroup' with feeds 'FeedOne'
203- and 'FeedTwo' could be updated by calling:
204-
205- send_group('TestGroup', {'FeedOne': 'value1', 'FeedTwo': 10})
206-
207- This would add the value 'value1' to the feed 'FeedOne' and add the
208- value 10 to the feed 'FeedTwo'.
209-
210- After a successful update an instance of Group will be returned with
211- metadata about the updated group.
212- """
213- path = "groups/{0}/send" .format (group_name )
214- return Group .from_dict (self ._post (path , {'value' : data }))
215-
216239 def receive_group (self , group ):
217240 """Retrieve the most recent value for the specified group. Group can be
218241 a group ID, group key, or group name. Returns a Group instance whose
0 commit comments