1
- # Copyright (c) 2014 Adafruit Industries
1
+ # Copyright (c) 2018 Adafruit Industries
2
2
# Authors: Justin Cooper & Tony DiCola
3
3
4
4
# Permission is hereby granted, free of charge, to any person obtaining a copy
21
21
import json
22
22
import pkg_resources
23
23
import platform
24
+ # import logging
24
25
25
26
import requests
26
27
@@ -41,23 +42,30 @@ class Client(object):
41
42
REST API. Use this client class to send, receive, and enumerate feed data.
42
43
"""
43
44
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 ' ):
45
46
"""Create an instance of the Adafruit IO REST API client. Key must be
46
47
provided and set to your Adafruit IO access key value. Optionaly
47
48
provide a proxies dict in the format used by the requests library, a
48
49
base_url to point at a different Adafruit IO service (the default is
49
50
the production Adafruit IO service over SSL), and a api_version to
50
51
add support for future API versions.
51
52
"""
53
+ self .username = username
52
54
self .key = key
53
55
self .proxies = proxies
54
56
self .api_version = api_version
57
+ # self.logger = logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s')
58
+
55
59
# Save URL without trailing slash as it will be added later when
56
60
# constructing the path.
57
61
self .base_url = base_url .rstrip ('/' )
58
62
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
+
61
69
62
70
def _handle_error (self , response ):
63
71
# Handle explicit errors.
@@ -73,12 +81,15 @@ def _headers(self, given):
73
81
headers .update (given )
74
82
return headers
75
83
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 ),
78
86
headers = self ._headers ({'X-AIO-Key' : self .key }),
79
87
proxies = self .proxies )
80
88
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
82
93
83
94
def _post (self , path , data ):
84
95
response = requests .post (self ._compose_url (path ),
@@ -97,14 +108,25 @@ def _delete(self, path):
97
108
self ._handle_error (response )
98
109
99
110
# 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 .
105
116
"""
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 })
108
130
109
131
def append (self , feed , value ):
110
132
"""Helper function to simplify adding a value to a feed. Will append the
@@ -114,6 +136,26 @@ def append(self, feed, value):
114
136
"""
115
137
return self .create_data (feed , Data (value = value ))
116
138
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
+
117
159
def receive (self , feed ):
118
160
"""Retrieve the most recent value for the specified feed. Feed can be a
119
161
feed ID, feed key, or feed name. Returns a Data instance whose value
@@ -185,7 +227,7 @@ def create_feed(self, feed):
185
227
type with at least the name property set.
186
228
"""
187
229
path = "feeds/"
188
- return Feed .from_dict (self ._post (path , feed ._asdict ()))
230
+ return Feed .from_dict (self ._post (path , { " feed" : feed ._asdict ()} ))
189
231
190
232
def delete_feed (self , feed ):
191
233
"""Delete the specified feed. Feed can be a feed ID, feed key, or feed
@@ -194,25 +236,6 @@ def delete_feed(self, feed):
194
236
path = "feeds/{0}" .format (feed )
195
237
self ._delete (path )
196
238
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
-
216
239
def receive_group (self , group ):
217
240
"""Retrieve the most recent value for the specified group. Group can be
218
241
a group ID, group key, or group name. Returns a Group instance whose
0 commit comments