ThingSpeak Communication Library for Arduino Enables an Arduino or other compatible hardware to write or read data to or from ThingSpeak™ |

- Main Page
- Data Structures

ThingSpeak.h
1 /*
2 ThingSpeak(TM) Communication Library For Arduino
3
4 Enables an Arduino or other compatible hardware to write or read data to or from ThingSpeak,
5 an open data platform for the Internet of Things with MATLAB analytics and visualization.
6
7 ThingSpeak ( https://www.thingspeak.com ) is a free IoT service for building
8 systems that collect, analyze, and react to their environments.
9
10 Copyright 2015, The MathWorks, Inc.
11
12 See the accompaning licence file for licensing information.
13 */
14
49 #ifndef ThingSpeak_h
50 #define ThingSpeak_h
51
52 //#define PRINT_DEBUG_MESSAGES
53 //#define PRINT_HTTP
54
55 #ifdef SPARK
56 // Create platform defines for Particle devices
57 #if PLATFORM_ID == 6
58 #define PARTICLE_PHOTON
59 #elif PLATFORM_ID == 0
60 #define PARTICLE_CORE
61 #endif
62
63 #include "math.h"
64 #include "application.h"
65 #ifdef PARTICLE_PHOTON
66 extern char* dtoa(double val, unsigned char prec, char *sout);
67 // On spark photon, There is no itoa, so map to ltoa.
68 #include "string_convert.h"
69 #define itoa ltoa
70 #else
71 // On spark core, a long and an int are equivalent, and so there's no "ltoa" function defined. Map it to itoa.
72 extern char * itoa(int a, char* buffer, unsigned char radix);
73 #define ltoa itoa
74 extern char *dtostrf (double val, signed char width, unsigned char prec, char *sout);
75 #endif
76 #else
77 #ifdef ARDUINO_ARCH_AVR
78 #include "Arduino.h"
79 #include <Client.h>
80 #else
81 #error Only Arduino Yun, Uno/Mega/Due with either Wired or wi-fi Ethernet shield, and Spark Core/Photon are supported.
82 #endif
83 #endif
84
85 #define THINGSPEAK_URL "api.thingspeak.com"
86 #define THINGSPEAK_IPADDRESS IPAddress(184,106,153,149)
87 #define THINGSPEAK_PORT_NUMBER 80
88
89 #ifdef ARDUINO_ARCH_AVR
90 #ifdef ARDUINO_AVR_YUN
91 #define TS_USER_AGENT "tslib-arduino/1.0 (arduino uno or mega)"
92 #else
93 #define TS_USER_AGENT "tslib-arduino/1.0 (arduino yun)"
94 #endif
95 #endif
96 #ifdef SPARK
97 #define TS_USER_AGENT "tslib-arduino/1.0 (particle core or photon)"
98 #define SPARK_PUBLISH_TTL 60 // Spark "time to live" for published messages
99 #define SPARK_PUBLISH_TOPIC "thingspeak-debug"
100 #endif
101
102 #define FIELDNUM_MIN 1
103 #define FIELDNUM_MAX 8
104 #define FIELDLENGTH_MAX 255 // Max length for a field in ThingSpeak is 255 bytes (UTF-8)
105
106 #define TIMEOUT_MS_SERVERRESPONSE 5000 // Wait up to five seconds for server to respond
107
108 #define OK_SUCCESS 200 // OK / Success
109 #define ERR_BADAPIKEY 400 // Incorrect API key (or invalid ThingSpeak server address)
110 #define ERR_BADURL 404 // Incorrect API key (or invalid ThingSpeak server address)
111 #define ERR_OUT_OF_RANGE -101 // Value is out of range or string is too long (> 255 bytes)
112 #define ERR_INVALID_FIELD_NUM -201 // Invalid field number specified
113 #define ERR_SETFIELD_NOT_CALLED -210 // setField() was not called before writeFields()
114 #define ERR_CONNECT_FAILED -301 // Failed to connect to ThingSpeak
115 #define ERR_UNEXPECTED_FAIL -302 // Unexpected failure during write to ThingSpeak
116 #define ERR_BAD_RESPONSE -303 // Unable to parse response
117 #define ERR_TIMEOUT -304 // Timeout waiting for server to respond
118 #define ERR_NOT_INSERTED -401 // Point was not inserted (most probable cause is the rate limit of once every 15 seconds)
119
123 class ThingSpeakClass
124 {
125 public:
126 ThingSpeakClass()
127 {
128 resetWriteFields();
129 this->lastReadStatus = OK_SUCCESS;
130 };
131
153 bool begin(Client & client, const char * customHostName, unsigned int port)
154 {
155 #ifdef PRINT_DEBUG_MESSAGES
156 Serial.print("ts::tsBegin (client: Client URL: "); Serial.print(customHostName); Serial.println(")");
157 #endif
158 this->setClient(&client);
159 this->setServer(customHostName, port);
160 resetWriteFields();
161 this->lastReadStatus = OK_SUCCESS;
162 return true;
163 };
164
186 bool begin(Client & client, IPAddress customIP, unsigned int port)
187 {
188 #ifdef PRINT_DEBUG_MESSAGES
189 Serial.print("ts::tsBegin (client: Client IP: "); Serial.print(customIP); Serial.println(")");
190 #endif
191 this->setClient(&client);
192 this->setServer(customIP, port);
193 resetWriteFields();
194 this->lastReadStatus = OK_SUCCESS;
195 return true;
196 };
197
217 bool begin(Client & client)
218 {
219 #ifdef PRINT_DEBUG_MESSAGES
220 Serial.print("ts::tsBegin");
221 #endif
222 this->setClient(&client);
223 this->setServer();
224 resetWriteFields();
225 this->lastReadStatus = OK_SUCCESS;
226 return true;
227 };
228
245 int writeField(unsigned long channelNumber, unsigned int field, int value, const char * writeAPIKey)
246 {
247 #ifdef SPARK
248 // On Spark, int and long are the same, so map to the long version
249 return writeField(channelNumber, field, (long)value, writeAPIKey);
250 #else
251 char valueString[10]; // int range is -32768 to 32768, so 7 bytes including terminator, plus a little extra
252 itoa(value, valueString, 10);
253 return writeField(channelNumber, field, valueString, writeAPIKey);
254 #endif
255 };
256
273 int writeField(unsigned long channelNumber, unsigned int field, long value, const char * writeAPIKey)
274 {
275 char valueString[15]; // long range is -2147483648 to 2147483647, so 12 bytes including terminator
276 ltoa(value, valueString, 10);
277 return writeField(channelNumber, field, valueString, writeAPIKey);
278 };
279
297 int writeField(unsigned long channelNumber, unsigned int field, float value, const char * writeAPIKey)
298 {
299 #ifdef PRINT_DEBUG_MESSAGES
300 Serial.print("ts::writeField (channelNumber: "); Serial.print(channelNumber); Serial.print(" writeAPIKey: "); Serial.print(writeAPIKey); Serial.print(" field: "); Serial.print(field); Serial.print(" value: "); Serial.print(value,5); Serial.println(")");
301 #endif
302 char valueString[20]; // range is -999999000000.00000 to 999999000000.00000, so 19 + 1 for the terminator
303 int status = convertFloatToChar(value, valueString);
304 if(status != OK_SUCCESS) return status;
305
306 return writeField(channelNumber, field, valueString, writeAPIKey);
307 };
308
330 int writeField(unsigned long channelNumber, unsigned int field, const char * value, const char * writeAPIKey)
331 {
332 return writeField(channelNumber, field, String(value), writeAPIKey);
333 };
334
359 int writeField(unsigned long channelNumber, unsigned int field, String value, const char * writeAPIKey)
360 {
361 // Invalid field number specified
362 if(field < FIELDNUM_MIN || field > FIELDNUM_MAX) return ERR_INVALID_FIELD_NUM;
363 // Max # bytes for ThingSpeak field is 255
364 if(value.length() > FIELDLENGTH_MAX) return ERR_OUT_OF_RANGE;
365
366 #ifdef PRINT_DEBUG_MESSAGES
367 #ifdef SPARK
368 Spark.publish(SPARK_PUBLISH_TOPIC, "writeField (" + String(channelNumber) + ", " + String(writeAPIKey) + ", " + String(field) + ", " + String(value) + ")", SPARK_PUBLISH_TTL, PRIVATE);
369 #else
370 Serial.print("ts::writeField (channelNumber: "); Serial.print(channelNumber); Serial.print(" writeAPIKey: "); Serial.print(writeAPIKey); Serial.print(" field: "); Serial.print(field); Serial.print(" value: \""); Serial.print(value); Serial.println("\")");
371 #endif
372 #endif
373 String postMessage = String("field") + String(field) + "=" + value;
374 return writeRaw(channelNumber, postMessage, writeAPIKey);
375 };
376
377
409 int setField(unsigned int field, int value)
410 {
411 #ifdef SPARK
412 // On Spark, int and long are the same, so map to the long version
413 return setField(field, (long)value);
414 #else
415 char valueString[10]; // int range is -32768 to 32768, so 7 bytes including terminator
416 itoa(value, valueString, 10);
417
418 return setField(field, valueString);
419 #endif
420 };
421
453 int setField(unsigned int field, long value)
454 {
455 char valueString[15]; // long range is -2147483648 to 2147483647, so 12 bytes including terminator
456 ltoa(value, valueString, 10);
457 return setField(field, valueString);
458 };
459
460
492 int setField(unsigned int field, float value)
493 {
494 char valueString[20]; // range is -999999000000.00000 to 999999000000.00000, so 19 + 1 for the terminator
495 int status = convertFloatToChar(value, valueString);
496 if(status != OK_SUCCESS) return status;
497
498 return setField(field, valueString);
499 };
500
532 int setField(unsigned int field, const char * value)
533 {
534 return setField(field, String(value));
535 };
536
568 int setField(unsigned int field, String value)
569 {
570 #ifdef PRINT_DEBUG_MESSAGES
571 #ifdef SPARK
572 Spark.publish(SPARK_PUBLISH_TOPIC, "setField " + String(field) + " to " + String(value), SPARK_PUBLISH_TTL, PRIVATE);
573 #else
574 Serial.print("ts::setField (field: "); Serial.print(field); Serial.print(" value: \""); Serial.print(value); Serial.println("\")");
575 #endif
576 #endif
577 if(field < FIELDNUM_MIN || field > FIELDNUM_MAX) return ERR_INVALID_FIELD_NUM;
578 // Max # bytes for ThingSpeak field is 255 (UTF-8)
579 if(value.length() > FIELDLENGTH_MAX) return ERR_OUT_OF_RANGE;
580 this->nextWriteField[field - 1] = value;
581 return OK_SUCCESS;
582 };
583
584
618 int setLatitude(float latitude)
619 {
620 #ifdef PRINT_DEBUG_MESSAGES
621 Serial.print("ts::setLatitude(latitude: "); Serial.print(latitude,3); Serial.println("\")");
622 #endif
623 this->nextWriteLatitude = latitude;
624 return OK_SUCCESS;
625 };
626
627
661 int setLongitude(float longitude)
662 {
663 #ifdef PRINT_DEBUG_MESSAGES
664 Serial.print("ts::setLongitude(longitude: "); Serial.print(longitude,3); Serial.println("\")");
665 #endif
666 this->nextWriteLongitude = longitude;
667 return OK_SUCCESS;
668 };
669
670
704 int setElevation(float elevation)
705 {
706 #ifdef PRINT_DEBUG_MESSAGES
707 Serial.print("ts::setElevation(elevation: "); Serial.print(elevation,3); Serial.println("\")");
708 #endif
709 this->nextWriteElevation = elevation;
710 return OK_SUCCESS;
711 };
712
713
748 int writeFields(unsigned long channelNumber, const char * writeAPIKey)
749 {
750 String postMessage = String("");
751 bool fFirstItem = true;
752 for(size_t iField = 0; iField < 8; iField++)
753 {
754 if(this->nextWriteField[iField].length() > 0)
755 {
756 if(!fFirstItem)
757 {
758 postMessage = postMessage + String("&");
759 }
760 postMessage = postMessage + String("field") + String(iField + 1) + String("=") + this->nextWriteField[iField];
761 fFirstItem = false;
762 this->nextWriteField[iField] = "";
763 }
764 }
765
766 if(!isnan(nextWriteLatitude))
767 {
768 if(!fFirstItem)
769 {
770 postMessage = postMessage + String("&");
771 }
772 postMessage = postMessage + String("lat=") + String(this->nextWriteLatitude);
773 fFirstItem = false;
774 this->nextWriteLatitude = NAN;
775 }
776
777 if(!isnan(this->nextWriteLongitude))
778 {
779 if(!fFirstItem)
780 {
781 postMessage = postMessage + String("&");
782 }
783 postMessage = postMessage + String("long=") + String(this->nextWriteLongitude);
784 fFirstItem = false;
785 this->nextWriteLongitude = NAN;
786 }
787
788
789 if(!isnan(this->nextWriteElevation))
790 {
791 if(!fFirstItem)
792 {
793 postMessage = postMessage + String("&");
794 }
795 postMessage = postMessage + String("elevation=") + String(this->nextWriteElevation);
796 fFirstItem = false;
797 this->nextWriteElevation = NAN;
798 }
799
800 if(fFirstItem)
801 {
802 // setField was not called before writeFields
803 return ERR_SETFIELD_NOT_CALLED;
804 }
805
806 return writeRaw(channelNumber, postMessage, writeAPIKey);
807 };
808
809
830 int writeRaw(unsigned long channelNumber, const char * postMessage, const char * writeAPIKey)
831 {
832 return writeRaw(channelNumber, String(postMessage), writeAPIKey);
833 };
834
835
851 int writeRaw(unsigned long channelNumber, String postMessage, const char * writeAPIKey)
852 {
853 #ifdef PRINT_DEBUG_MESSAGES
854 Serial.print("ts::writeRaw (channelNumber: "); Serial.print(channelNumber); Serial.print(" writeAPIKey: "); Serial.print(writeAPIKey); Serial.print(" postMessage: \""); Serial.print(postMessage); Serial.println("\")");
855 #endif
856
857 if(!connectThingSpeak())
858 {
859 // Failed to connect to ThingSpeak
860 return ERR_CONNECT_FAILED;
861 }
862
863 postMessage = postMessage + String("&headers=false");
864
865 #ifdef PRINT_DEBUG_MESSAGES
866 #ifdef SPARK
867 Spark.publish(SPARK_PUBLISH_TOPIC, "Post " + postMessage, SPARK_PUBLISH_TTL, PRIVATE);
868 #else
869 Serial.print(" POST \"");Serial.print(postMessage);Serial.println("\"");
870 #endif
871 #endif
872
873 postMessage = postMessage + String("\n");
874
875 // Post data to thingspeak
876 if(!this->client->print("POST /update HTTP/1.1\n")) return abortWriteRaw();
877 if(!writeHTTPHeader(writeAPIKey)) return abortWriteRaw();
878 if(!this->client->print("Content-Type: application/x-www-form-urlencoded\n")) return abortWriteRaw();
879 if(!this->client->print("Content-Length: ")) return abortWriteRaw();
880 if(!this->client->print(postMessage.length())) return abortWriteRaw();
881 if(!this->client->print("\n\n")) return abortWriteRaw();
882 if(!this->client->print(postMessage)) return abortWriteRaw();
883
884 String entryIDText = String();
885 int status = getHTTPResponse(entryIDText);
886 if(status != OK_SUCCESS)
887 {
888 client->stop();
889 return status;
890 }
891 long entryID = entryIDText.toInt();
892
893 #ifdef PRINT_DEBUG_MESSAGES
894 Serial.print(" Entry ID \"");Serial.print(entryIDText);Serial.print("\" (");Serial.print(entryID);Serial.println(")");
895 #endif
896
897 client->stop();
898
899 #ifdef PRINT_DEBUG_MESSAGES
900 Serial.println("disconnected.");
901 #endif
902 if(entryID == 0)
903 {
904 // ThingSpeak did not accept the write
905 status = ERR_NOT_INSERTED;
906 }
907 return status;
908 };
909
925 String readStringField(unsigned long channelNumber, unsigned int field, const char * readAPIKey)
926 {
927 if(field < FIELDNUM_MIN || field > FIELDNUM_MAX)
928 {
929 this->lastReadStatus = ERR_INVALID_FIELD_NUM;
930 return("");
931 }
932 #ifdef PRINT_DEBUG_MESSAGES
933 Serial.print("ts::readStringField(channelNumber: "); Serial.print(channelNumber);
934 if(NULL != readAPIKey)
935 {
936 Serial.print(" readAPIKey: "); Serial.print(readAPIKey);
937 }
938 Serial.print(" field: "); Serial.print(field); Serial.println(")");
939 #endif
940 return readRaw(channelNumber, String(String("/fields/") + String(field) + String("/last")), readAPIKey);
941 }
942
943
958 String readStringField(unsigned long channelNumber, unsigned int field)
959 {
960 return readStringField(channelNumber, field, NULL);
961 };
962
963
980 float readFloatField(unsigned long channelNumber, unsigned int field, const char * readAPIKey)
981 {
982 return convertStringToFloat(readStringField(channelNumber, field, readAPIKey));
983 };
984
985
1001 float readFloatField(unsigned long channelNumber, unsigned int field)
1002 {
1003 return readFloatField(channelNumber, field, NULL);
1004 };
1005
1006
1022 long readLongField(unsigned long channelNumber, unsigned int field, const char * readAPIKey)
1023 {
1024 // Note that although the function is called "toInt" it really returns a long.
1025 return readStringField(channelNumber, field, readAPIKey).toInt();
1026 }
1027
1028
1043 long readLongField(unsigned long channelNumber, unsigned int field)
1044 {
1045 return readLongField(channelNumber, field, NULL);
1046 };
1047
1048
1065 int readIntField(unsigned long channelNumber, unsigned int field, const char * readAPIKey)
1066 {
1067 return readLongField(channelNumber, field, readAPIKey);
1068 }
1069
1070
1086 int readIntField(unsigned long channelNumber, unsigned int field)
1087 {
1088 return readLongField(channelNumber, field, NULL);
1089 };
1090
1106 String readRaw(unsigned long channelNumber, String URLSuffix)
1107 {
1108 return readRaw(channelNumber, URLSuffix, NULL);
1109 }
1110
1127 String readRaw(unsigned long channelNumber, String URLSuffix, const char * readAPIKey)
1128 {
1129 #ifdef PRINT_DEBUG_MESSAGES
1130 Serial.print("ts::readRaw (channelNumber: "); Serial.print(channelNumber);
1131 if(NULL != readAPIKey)
1132 {
1133 Serial.print(" readAPIKey: "); Serial.print(readAPIKey);
1134 }
1135 Serial.print(" URLSuffix: \""); Serial.print(URLSuffix); Serial.println("\")");
1136 #endif
1137
1138 if(!connectThingSpeak())
1139 {
1140 this->lastReadStatus = ERR_CONNECT_FAILED;
1141 return String("");
1142 }
1143
1144 String URL = String("/channels/") + String(channelNumber) + URLSuffix;
1145
1146 #ifdef PRINT_DEBUG_MESSAGES
1147 Serial.print(" GET \"");Serial.print(URL);Serial.println("\"");
1148 #endif
1149
1150 // Post data to thingspeak
1151 if(!this->client->print("GET ")) return abortReadRaw();
1152 if(!this->client->print(URL)) return abortReadRaw();
1153 if(!this->client->print(" HTTP/1.1\n")) return abortReadRaw();
1154 if(!writeHTTPHeader(readAPIKey)) return abortReadRaw();
1155 if(!this->client->print("\n")) return abortReadRaw();
1156
1157 String content = String();
1158 int status = getHTTPResponse(content);
1159 this->lastReadStatus = status;
1160
1161
1162 #ifdef PRINT_DEBUG_MESSAGES
1163 if(status == OK_SUCCESS)
1164 {
1165 Serial.print("Read: \""); Serial.print(content); Serial.println("\"");
1166 }
1167 #endif
1168
1169 client->stop();
1170 #ifdef PRINT_DEBUG_MESSAGES
1171 Serial.println("disconnected.");
1172 #endif
1173
1174 if(status != OK_SUCCESS)
1175 {
1176 // return status;
1177 return String("");
1178 }
1179
1180 // This is a workaround to a bug in the Spark implementation of String
1181 return String("") + content;
1182 };
1183
1217 int getLastReadStatus()
1218 {
1219 return this->lastReadStatus;
1220 };
1221 private:
1222
1223 int abortWriteRaw()
1224 {
1225 this->client->stop();
1226 return ERR_UNEXPECTED_FAIL;
1227 }
1228
1229 String abortReadRaw()
1230 {
1231 this->client->stop();
1232 #ifdef PRINT_DEBUG_MESSAGES
1233 Serial.println("ReadRaw abort - disconnected.");
1234 #endif
1235 this->lastReadStatus = ERR_UNEXPECTED_FAIL;
1236 return String("");
1237 }
1238
1239 void setServer(const char * customHostName, unsigned int port)
1240 {
1241 #ifdef PRINT_DEBUG_MESSAGES
1242 Serial.print("ts::setServer (URL: \""); Serial.print(customHostName); Serial.println("\")");
1243 #endif
1244 this->customIP = INADDR_NONE;
1245 this->customHostName = customHostName;
1246 this->port = port;
1247 };
1248
1249 void setServer(IPAddress customIP, unsigned int port)
1250 {
1251 #ifdef PRINT_DEBUG_MESSAGES
1252 Serial.print("ts::setServer (IP: \""); Serial.print(customIP); Serial.println("\")");
1253 #endif
1254 this->customIP = customIP;
1255 this->customHostName = NULL;
1256 this->port = port;
1257 };
1258
1259 void setServer()
1260 {
1261 #ifdef PRINT_DEBUG_MESSAGES
1262 Serial.print("ts::setServer (default)");
1263 #endif
1264 this->customIP = INADDR_NONE;
1265 this->customHostName = NULL;
1266 this->port = THINGSPEAK_PORT_NUMBER;
1267 };
1268
1269 void setClient(Client * client) {this->client = client;};
1270
1271 Client * client = NULL;
1272 const char * customHostName = NULL;
1273 IPAddress customIP = INADDR_NONE;
1274 unsigned int port = THINGSPEAK_PORT_NUMBER;
1275 String nextWriteField[8];
1276 float nextWriteLatitude;
1277 float nextWriteLongitude;
1278 float nextWriteElevation;
1279 int lastReadStatus;
1280
1281 bool connectThingSpeak()
1282 {
1283 bool connectSuccess = false;
1284 if(this->customIP == INADDR_NONE && NULL == this->customHostName)
1285 {
1286 #ifdef PRINT_DEBUG_MESSAGES
1287 Serial.print(" Connect to default ThingSpeak URL...");
1288 #endif
1289 connectSuccess = client->connect(THINGSPEAK_URL,THINGSPEAK_PORT_NUMBER);
1290 if(!connectSuccess)
1291 {
1292 #ifdef PRINT_DEBUG_MESSAGES
1293 Serial.print("Failed. Try default IP...");
1294 #endif
1295 connectSuccess = client->connect(THINGSPEAK_IPADDRESS,THINGSPEAK_PORT_NUMBER);
1296 }
1297 }
1298 else
1299 {
1300 if(!(this->customIP == INADDR_NONE))
1301 {
1302 // Connect to the server on port 80 (HTTP) at the customIP address
1303 #ifdef PRINT_DEBUG_MESSAGES
1304 Serial.print(" Connect to ");Serial.print(this->customIP);Serial.print("...");
1305 #endif
1306 connectSuccess = client->connect(this->customIP,this->port);
1307 }
1308 if(NULL != this->customHostName)
1309 {
1310 // Connect to the server on port 80 (HTTP) at the URL address
1311 #ifdef PRINT_DEBUG_MESSAGES
1312 #ifdef SPARK
1313 Spark.publish(SPARK_PUBLISH_TOPIC, "Attempt Connect to URL " + String(this->customHostName), SPARK_PUBLISH_TTL, PRIVATE);
1314 #else
1315 Serial.print(" Connect to ");Serial.print(this->customHostName);Serial.print(" ...");
1316 #endif
1317 #endif
1318 connectSuccess = client->connect(customHostName,this->port);
1319 }
1320 }
1321
1322 #ifdef PRINT_DEBUG_MESSAGES
1323 if (connectSuccess)
1324 {
1325 #ifdef SPARK
1326 Spark.publish(SPARK_PUBLISH_TOPIC, "Connection Success", SPARK_PUBLISH_TTL, PRIVATE);
1327 #else
1328 Serial.println("Success.");
1329 #endif
1330 }
1331 else
1332 {
1333 #ifdef SPARK
1334 Spark.publish(SPARK_PUBLISH_TOPIC, "Connection Failure", SPARK_PUBLISH_TTL, PRIVATE);
1335 #else
1336 Serial.println("Failed.");
1337 #endif
1338 }
1339 #endif
1340 return connectSuccess;
1341 };
1342
1343 bool writeHTTPHeader(const char * APIKey)
1344 {
1345 if(NULL != this->customHostName)
1346 {
1347 if (!this->client->print("Host: ")) return false;
1348 if (!this->client->print(this->customHostName)) return false;
1349 if (!this->client->print("\n")) return false;
1350 }
1351 else
1352 {
1353 if (!this->client->print("Host: api.thingspeak.com\n")) return false;
1354 }
1355 if (!this->client->print("Connection: close\n")) return false;
1356 if (!this->client->print("User-Agent: ")) return false;
1357 if (!this->client->print(TS_USER_AGENT)) return false;
1358 if (!this->client->print("\n")) return false;
1359 if(NULL != APIKey)
1360 {
1361 if (!this->client->print("X-THINGSPEAKAPIKEY: ")) return false;
1362 if (!this->client->print(APIKey)) return false;
1363 if (!this->client->print("\n")) return false;
1364 }
1365 return true;
1366 };
1367
1368 int getHTTPResponse(String & response)
1369 {
1370 long startWaitForResponseAt = millis();
1371 while(client->available() == 0 && millis() - startWaitForResponseAt < TIMEOUT_MS_SERVERRESPONSE)
1372 {
1373 delay(100);
1374 }
1375 if(client->available() == 0)
1376 {
1377 return ERR_TIMEOUT; // Didn't get server response in time
1378 }
1379
1380 if(!client->find(const_cast<char *>("HTTP/1.1")))
1381 {
1382 #ifdef PRINT_HTTP
1383 Serial.println("ERROR: Didn't find HTTP/1.1");
1384 #endif
1385 return ERR_BAD_RESPONSE; // Couldn't parse response (didn't find HTTP/1.1)
1386 }
1387 int status = client->parseInt();
1388 #ifdef PRINT_HTTP
1389 Serial.print("Got Status of ");Serial.println(status);
1390 #endif
1391 if(status != OK_SUCCESS)
1392 {
1393 return status;
1394 }
1395
1396 if(!client->find(const_cast<char *>("\n\r\n")))
1397 {
1398 #ifdef PRINT_HTTP
1399 Serial.println("ERROR: Didn't find end of header");
1400 #endif
1401 return ERR_BAD_RESPONSE;
1402 }
1403 #ifdef PRINT_HTTP
1404 Serial.println("Found end of header");
1405 #endif
1406 #ifndef PRINT_HTTP
1407 client->parseInt();
1408 #else
1409 long length = client->parseInt();
1410 Serial.print("Got length of ");Serial.println(length);
1411 #endif
1412 if(!client->find(const_cast<char *>("\r\n")))
1413 {
1414 #ifdef PRINT_HTTP
1415 Serial.println("ERROR: Didn't find end of length");
1416 #endif
1417 return ERR_BAD_RESPONSE;
1418 }
1419 #ifdef PRINT_HTTP
1420 Serial.println("Found end of length");
1421 #endif
1422 // This is a workaround to a bug in the Spark implementation of String
1423 String tempString = client->readStringUntil('\r');
1424 response = tempString;
1425 #ifdef PRINT_HTTP
1426 Serial.print("Response: \"");Serial.print(response);Serial.println("\"");
1427 #endif
1428 return status;
1429 };
1430
1431 int convertFloatToChar(float value, char *valueString)
1432 {
1433 // Supported range is -999999000000 to 999999000000
1434 if(0 == isinf(value) && (value > 999999000000 || value < -999999000000))
1435 {
1436 // Out of range
1437 return ERR_OUT_OF_RANGE;
1438 }
1439 // Given that the resolution of Spark is 1 / 2^12, or ~0.00024 volts, assume that 5 places right of decimal should be sufficient for most applications
1440 #ifdef PARTICLE_PHOTON
1441 //Photon doesn't have a dtostrf, but does have dtoa
1442 dtoa((double)value,5, valueString);
1443 #else
1444 dtostrf(value,1,5, valueString);
1445 #endif
1446 return OK_SUCCESS;
1447 };
1448
1449 float convertStringToFloat(String value)
1450 {
1451 // There's a bug in the AVR function strtod that it doesn't decode -INF correctly (it maps it to INF)
1452 float result = value.toFloat();
1453 if(1 == isinf(result) && *value.c_str() == '-')
1454 {
1455 result = (float)-INFINITY;
1456 }
1457 return result;
1458 };
1459
1460 void resetWriteFields()
1461 {
1462 for(size_t iField = 0; iField < 8; iField++)
1463 {
1464 this->nextWriteField[iField] = "";
1465 }
1466 this->nextWriteLatitude = NAN;
1467 this->nextWriteLongitude = NAN;
1468 this->nextWriteElevation = NAN;
1469 };
1470 };
1471
1472 extern ThingSpeakClass ThingSpeak;
1473
1474 #endif //ThingSpeak_h
ThingSpeakClass::writeRaw
int writeRaw(unsigned long channelNumber, const char *postMessage, const char *writeAPIKey)
Write a raw POST to a ThingSpeak channel.
Definition: ThingSpeak.h:830
ThingSpeakClass::readStringField
String readStringField(unsigned long channelNumber, unsigned int field, const char *readAPIKey)
Read the latest string from a private ThingSpeak channel.
Definition: ThingSpeak.h:925
ThingSpeakClass::readStringField
String readStringField(unsigned long channelNumber, unsigned int field)
Read the latest string from a public ThingSpeak channel.
Definition: ThingSpeak.h:958
ThingSpeakClass::setField
int setField(unsigned int field, long value)
Set the value of a single field that will be part of a multi-field update. To write multiple fields a...
Definition: ThingSpeak.h:453
ThingSpeakClass::writeRaw
int writeRaw(unsigned long channelNumber, String postMessage, const char *writeAPIKey)
Write a raw POST to a ThingSpeak channel.
Definition: ThingSpeak.h:851
ThingSpeakClass::begin
bool begin(Client &client, IPAddress customIP, unsigned int port)
Initializes the ThingSpeak library and network settings using a custom installation of ThingSpeak...
Definition: ThingSpeak.h:186
ThingSpeakClass::writeFields
int writeFields(unsigned long channelNumber, const char *writeAPIKey)
Write a multi-field update. Call setField() for each of the fields you want to write, setLatitude() / setLongitude() / setElevation(), and then call writeFields()
Definition: ThingSpeak.h:748
ThingSpeakClass::setField
int setField(unsigned int field, int value)
Set the value of a single field that will be part of a multi-field update. To write multiple fields a...
Definition: ThingSpeak.h:409
ThingSpeakClass::setLatitude
int setLatitude(float latitude)
Set the latitude of a multi-field update. To record latitude, longitude and elevation of a write...
Definition: ThingSpeak.h:618
ThingSpeakClass::begin
bool begin(Client &client, const char *customHostName, unsigned int port)
Initializes the ThingSpeak library and network settings using a custom installation of ThingSpeak...
Definition: ThingSpeak.h:153
ThingSpeakClass::getLastReadStatus
int getLastReadStatus()
Get the status of the previous read.
Definition: ThingSpeak.h:1217
ThingSpeakClass::writeField
int writeField(unsigned long channelNumber, unsigned int field, int value, const char *writeAPIKey)
Write an integer value to a single field in a ThingSpeak channel.
Definition: ThingSpeak.h:245
ThingSpeakClass
This library enables an Arduino or other compatible hardware to write or read data to or from ThingSp...
Definition: ThingSpeak.h:123
ThingSpeakClass::readLongField
long readLongField(unsigned long channelNumber, unsigned int field, const char *readAPIKey)
Read the latest long from a private ThingSpeak channel.
Definition: ThingSpeak.h:1022
ThingSpeakClass::writeField
int writeField(unsigned long channelNumber, unsigned int field, String value, const char *writeAPIKey)
Write a String to a single field in a ThingSpeak channel.
Definition: ThingSpeak.h:359
ThingSpeakClass::setField
int setField(unsigned int field, const char *value)
Set the value of a single field that will be part of a multi-field update. To write multiple fields a...
Definition: ThingSpeak.h:532
ThingSpeakClass::readRaw
String readRaw(unsigned long channelNumber, String URLSuffix)
Read a raw response from a public ThingSpeak channel.
Definition: ThingSpeak.h:1106
ThingSpeakClass::readLongField
long readLongField(unsigned long channelNumber, unsigned int field)
Read the latest long from a public ThingSpeak channel.
Definition: ThingSpeak.h:1043
ThingSpeakClass::writeField
int writeField(unsigned long channelNumber, unsigned int field, float value, const char *writeAPIKey)
Write a floating point value to a single field in a ThingSpeak channel.
Definition: ThingSpeak.h:297
ThingSpeakClass::readIntField
int readIntField(unsigned long channelNumber, unsigned int field, const char *readAPIKey)
Read the latest int from a private ThingSpeak channel.
Definition: ThingSpeak.h:1065
ThingSpeakClass::setField
int setField(unsigned int field, String value)
Set the value of a single field that will be part of a multi-field update. To write multiple fields a...
Definition: ThingSpeak.h:568
ThingSpeakClass::setLongitude
int setLongitude(float longitude)
Set the longitude of a multi-field update. To record latitude, longitude and elevation of a write...
Definition: ThingSpeak.h:661
ThingSpeakClass::readFloatField
float readFloatField(unsigned long channelNumber, unsigned int field, const char *readAPIKey)
Read the latest float from a private ThingSpeak channel.
Definition: ThingSpeak.h:980
ThingSpeakClass::begin
bool begin(Client &client)
Initializes the ThingSpeak library and network settings using the ThingSpeak.com service.
Definition: ThingSpeak.h:217
ThingSpeakClass::readFloatField
float readFloatField(unsigned long channelNumber, unsigned int field)
Read the latest float from a public ThingSpeak channel.
Definition: ThingSpeak.h:1001
ThingSpeakClass::writeField
int writeField(unsigned long channelNumber, unsigned int field, const char *value, const char *writeAPIKey)
Write a string to a single field in a ThingSpeak channel.
Definition: ThingSpeak.h:330
ThingSpeakClass::readIntField
int readIntField(unsigned long channelNumber, unsigned int field)
Read the latest int from a public ThingSpeak channel.
Definition: ThingSpeak.h:1086
ThingSpeakClass::setField
int setField(unsigned int field, float value)
Set the value of a single field that will be part of a multi-field update. To write multiple fields a...
Definition: ThingSpeak.h:492
ThingSpeakClass::readRaw
String readRaw(unsigned long channelNumber, String URLSuffix, const char *readAPIKey)
Read a raw response from a private ThingSpeak channel.
Definition: ThingSpeak.h:1127
ThingSpeakClass::setElevation
int setElevation(float elevation)
Set the elevation of a multi-field update. To record latitude, longitude and elevation of a write...
Definition: ThingSpeak.h:704
ThingSpeakClass::writeField
int writeField(unsigned long channelNumber, unsigned int field, long value, const char *writeAPIKey)
Write a long value to a single field in a ThingSpeak channel.
Definition: ThingSpeak.h:273