-
Notifications
You must be signed in to change notification settings - Fork 27
/
IoTgo.cpp
340 lines (314 loc) · 9.28 KB
/
IoTgo.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
/**
* @file IoTgo.cpp
*
* API of IoTgo (iotgo.iteadstudio.com)
*
* @author Wu Pengfei (email:<[email protected]>)
* @date 2014/11/11
* @copyright
* Copyright (C) 2013-2014 ITEAD Intelligent Systems Co., Ltd. \n
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*/
#include "IoTgo.h"
/**
* Constructor.
*
* @param net - the pointer to object of subclass of NetInterface.
*
* @see NetInterface
*/
IoTgo::IoTgo(NetInterface *net)
:net(net)
{
memset(buffer, '\0', sizeof(buffer));
memset(apikey, '\0', sizeof(apikey));
memset(device_id, '\0', sizeof(device_id));
memset(ip, '\0', sizeof(ip));
memset(domain_name, '\0', sizeof(domain_name));
}
/**
* Set IoT Server.
*
* @param ip - IP address of server
* @param domain_name - Domain name of server
*
* @return void
*/
void IoTgo::setHost(const char *ip, const char *domain_name)
{
strncpy(this->ip, ip, sizeof(this->ip) - 1);
strncpy(this->domain_name, domain_name, sizeof(this->domain_name) - 1);
}
/**
* Send http request to host and get the response.
*
* @param http_body - the body of http request
* @param buffer - the buffer to store the response of this request
* @param len - the length of buffer
*
* @return the pointer of response buffer terminated with '\0', if success. NULL, if falied!
*/
const char * IoTgo::request(const char *http_body, char *const buffer,
int32_t len)
{
static int32_t counter = 0;
static bool connect_TCP = false;
int32_t time_delay = 1000;
int32_t reconnectTCP = 0;
if (buffer == NULL)
{
DebugSerial.println("buffer cannot be NULL!");
return NULL;
}
buffer[0] = '\0';
request_reconnect:
if (connect_TCP == false && !net->createTCPConnection(ip, 80))
{
connect_TCP = true;
}
if (connect_TCP == false)
{
DebugSerial.println("Cannot connect to host");
return NULL;
}
String http_req;
/* Request line */
http_req = "POST /api/http HTTP/1.1\r\n";
/* Http header */
#if 0
http_req += "Host: iotgo.iteadstudio.com\r\n";
#else
http_req += "Host: ";
http_req += domain_name;
http_req += "\r\n";
#endif
http_req += "Content-Type: application/json\r\n";
http_req += "Content-Length: " + String(strlen(http_body));
http_req += "\r\n\r\n";
/* Http body */
http_req += http_body;
#ifdef DEBUG
DebugSerial.print("http_req=[");
DebugSerial.print(http_req);
DebugSerial.println("]");
#endif
if (!net->send(http_req))
{
//DebugSerial.println("Request Sent Successfully!");
}
else
{
if ((reconnectTCP++) < 5)
{
connect_TCP = false;
net->releaseTCPConnection();
goto request_reconnect;
}
else
{
DebugSerial.println("Request Sending Failed!");
return NULL;
}
}
/* Waiting for response for 10 seconds */
while (time_delay--)
{
if (net->recv(buffer, len) > 0)
{
//DebugSerial.print("Received:\n");
//DebugSerial.print(buffer);
break;
}
delay(10);
}
if (time_delay <= 0)
{
DebugSerial.println("Request timeout!");
return NULL;
}
buffer[len - 1] = '\0';
//DebugSerial.print("request counter=");
//DebugSerial.println(++counter);
//DebugSerial.print("time_delay=");
//DebugSerial.println(time_delay);
//DebugSerial.print("strlen(buffer)=");
//DebugSerial.println(strlen(buffer));
#ifdef DEBUG
DebugSerial.println(buffer);
#endif
return buffer;
}
/**
* Get the apikey of user who own the device specified by device_id.
*
* If the device_type = DEVICE_DIY, apikey_like should be the apikey of
* the user who owns the device.
* If the device_type = DEVICE_PRODUCT, apikey_like should be found around
* your finished device purchased from ITEAD.
*
* @warning You must call this before update and query.
*
* @param device_id - device identifier
* @param apikey_like - just like a password for accessing the respective device
* @param device_type - indicate the type of your device from DEVICE_DIY or DEVICE_PRODUCT.
* For developers, device_type=DEVICE_DIY(default). For users, device_type=DEVICE_PRODUCT.
*
* @retval apikey - a pointer of char array terminated with '\0'.
* @retval NULL - if falied!
*/
const char *IoTgo::init(const char *device_id, const char *apikey_like,
IoTgoDeviceType device_type)
{
char http_body[100];
char *temp;
const char *response;
strcpy(this->device_id, device_id);
if (device_type == DEVICE_PRODUCT)
{
/* Construct init http_body */
strcpy(http_body, "{");
strcat(http_body, "\"apikey\":");
strcat(http_body, "\"");
strcat(http_body, apikey_like);
strcat(http_body, "\"");
strcat(http_body, ",");
strcat(http_body, "\"deviceid\":");
strcat(http_body, "\"");
strcat(http_body, this->device_id);
strcat(http_body, "\"");
strcat(http_body, ",");
strcat(http_body, "\"action\":\"register\"");
strcat(http_body, "}");
/* {"error":0,"apikey":"d0555f12-a67c-4c54-9ee0-8f5b7f4268fa"} */
response = request(http_body, buffer, sizeof(buffer));
if (response == NULL)
{
DebugSerial.println("request failed!");
return NULL;
}
temp = strstr(response, "apikey");
if (temp == NULL)
{
DebugSerial.println("Cannot find \"apikey\" from response!");
return NULL;
}
else
{
temp += 7;
char *apikey_index = strstr(temp, "\"");
if (apikey_index != NULL)
{
apikey_index += 1;
strncpy(this->apikey, apikey_index, APIKEY_LEN);
//DebugSerial.print("apikey=");
//DebugSerial.println(this->apikey);
}
}
return this->apikey;
}
else if (device_type == DEVICE_DIY)
{
strncpy(this->apikey, apikey_like, APIKEY_LEN);
return this->apikey;
}
else
{
DebugSerial.println("Unknown device flag!");
return NULL;
}
}
/**
* Get the values specified by params from server.
*
* You must call this after init.
*
* @param params - the list(terminated with NULL) of attributes need to query.
*
* @return the pointer of response buffer terminated with '\0', if success. NULL, if falied!
*/
const char *IoTgo::query(const char *params[])
{
char http_body[100+IOT_BUFFER_SIZE];
int32_t i;
/* Construct query http_body */
strcpy(http_body, "{");
strcat(http_body, "\"apikey\":");
strcat(http_body, "\"");
strcat(http_body, this->apikey);
strcat(http_body, "\"");
strcat(http_body, ",");
strcat(http_body, "\"deviceid\":");
strcat(http_body, "\"");
strcat(http_body, this->device_id);
strcat(http_body, "\"");
strcat(http_body, ",");
strcat(http_body, "\"action\":\"query\"");
strcat(http_body, ",");
strcat(http_body, "\"params\":[");
for (i=0; params[i] != NULL; i++)
{
strcat(http_body, "\"");
strcat(http_body, params[i]);
strcat(http_body, "\"");
if (params[i+1] != NULL)
{
strcat(http_body, ",");
}
}
strcat(http_body, "]");
strcat(http_body, "}");
return request(http_body, buffer, sizeof(buffer));;
}
/**
* Update the values specified by params to server.
*
* You must call this after init.
*
* @param params - the list(terminated with NULL) of attributes need to update.
* @param values - the list(terminated with NULL) of values corresponding to
* items of attributes.
*
* @return the pointer of response buffer terminated with '\0', if success. NULL, if falied!
*
* @warning the number of items in params must be equal to that in values.
*/
const char *IoTgo::update(const char *params[], const char *values[])
{
char http_body[100+IOT_BUFFER_SIZE];
int32_t i;
/* Construct update http_body */
strcpy(http_body, "{");
strcat(http_body, "\"apikey\":");
strcat(http_body, "\"");
strcat(http_body, this->apikey);
strcat(http_body, "\"");
strcat(http_body, ",");
strcat(http_body, "\"deviceid\":");
strcat(http_body, "\"");
strcat(http_body, this->device_id);
strcat(http_body, "\"");
strcat(http_body, ",");
strcat(http_body, "\"action\":\"update\"");
strcat(http_body, ",");
strcat(http_body, "\"params\":{");
for (i=0; (params[i] != NULL && values[i] != NULL); i++)
{
strcat(http_body, "\"");
strcat(http_body, params[i]);
strcat(http_body, "\"");
strcat(http_body, ":");
strcat(http_body, "\"");
strcat(http_body, values[i]);
strcat(http_body, "\"");
if (params[i+1] != NULL && values[i+1] != NULL)
{
strcat(http_body, ",");
}
}
strcat(http_body, "}");
strcat(http_body, "}");
return request(http_body, buffer, sizeof(buffer));
}