ThingSpeak Communication Library Enables an Arduino, ESP8266, or Particle to write or read data to or from ThingSpeak™ |

- Main Page
- Data Structures

ThingSpeak.h
1 /*
2 ThingSpeak(TM) Communication Library For Arduino, ESP8266, and Particle
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 2016, The MathWorks, Inc.
11
12 See the accompaning licence file for licensing information.
13 */
14
50 #ifndef ThingSpeak_h
51 #define ThingSpeak_h
52
53 //#define PRINT_DEBUG_MESSAGES
54 //#define PRINT_HTTP
55
56 #ifdef SPARK
57 // Create platform defines for Particle devices
58 #if PLATFORM_ID == 6
59 #define PARTICLE_PHOTON
60 #define PARTICLE_PHOTONELECTRON
61 #elif PLATFORM_ID == 10
62 #define PARTICLE_ELECTRON
63 #define PARTICLE_PHOTONELECTRON
64 #elif PLATFORM_ID == 0
65 #define PARTICLE_CORE
66 #endif
67
68 #include "math.h"
69 #include "application.h"
70 #ifdef PARTICLE_PHOTONELECTRON
71 extern char* dtoa(double val, unsigned char prec, char *sout);
72 // On spark photon, There is no itoa, so map to ltoa.
73 #include "string_convert.h"
74 #define itoa ltoa
75 #else
76 // On spark core, a long and an int are equivalent, and so there's no "ltoa" function defined. Map it to itoa.
77 extern char * itoa(int a, char* buffer, unsigned char radix);
78 #define ltoa itoa
79 extern char *dtostrf (double val, signed char width, unsigned char prec, char *sout);
80 #endif
81 #else
82 #if defined(ARDUINO_ARCH_AVR) || defined(ARDUINO_ARCH_ESP8266)
83 #include "Arduino.h"
84 #include <Client.h>
85 #else
86 #error Only Arduino Yun, Uno/Mega/Due with either Wired or wi-fi Ethernet shield, ESP8266, and Spark Core/Photon/Electron are supported.
87 #endif
88 #endif
89
90 #define THINGSPEAK_URL "api.thingspeak.com"
91 #define THINGSPEAK_IPADDRESS IPAddress(184,106,153,149)
92 #define THINGSPEAK_PORT_NUMBER 80
93
94 #ifdef ARDUINO_ARCH_AVR
95 #ifdef ARDUINO_AVR_YUN
96 #define TS_USER_AGENT "tslib-arduino/1.0 (arduino yun)"
97 #else
98 #define TS_USER_AGENT "tslib-arduino/1.0 (arduino uno or mega)"
99 #endif
100 #elif defined(ARDUINO_ARCH_ESP8266)
101 #define TS_USER_AGENT "tslib-arduino/1.0 (ESP8266)"
102 #elif defined(SPARK)
103 #ifdef PARTICLE_CORE
104 #define TS_USER_AGENT "tslib-arduino/1.0 (particle core)"
105 #elif defined(PARTICLE_PHOTON)
106 #define TS_USER_AGENT "tslib-arduino/1.0 (particle photon)"
107 #elif defined(PARTICLE_ELECTRON)
108 #define TS_USER_AGENT "tslib-arduino/1.0 (particle electron)"
109 #endif
110 #define SPARK_PUBLISH_TTL 60 // Spark "time to live" for published messages
111 #define SPARK_PUBLISH_TOPIC "thingspeak-debug"
112 #endif
113
114 #define FIELDNUM_MIN 1
115 #define FIELDNUM_MAX 8
116 #define FIELDLENGTH_MAX 255 // Max length for a field in ThingSpeak is 255 bytes (UTF-8)
117
118 #define TIMEOUT_MS_SERVERRESPONSE 5000 // Wait up to five seconds for server to respond
119
120 #define OK_SUCCESS 200 // OK / Success
121 #define ERR_BADAPIKEY 400 // Incorrect API key (or invalid ThingSpeak server address)
122 #define ERR_BADURL 404 // Incorrect API key (or invalid ThingSpeak server address)
123 #define ERR_OUT_OF_RANGE -101 // Value is out of range or string is too long (> 255 bytes)
124 #define ERR_INVALID_FIELD_NUM -201 // Invalid field number specified
125 #define ERR_SETFIELD_NOT_CALLED -210 // setField() was not called before writeFields()
126 #define ERR_CONNECT_FAILED -301 // Failed to connect to ThingSpeak
127 #define ERR_UNEXPECTED_FAIL -302 // Unexpected failure during write to ThingSpeak
128 #define ERR_BAD_RESPONSE -303 // Unable to parse response
129 #define ERR_TIMEOUT -304 // Timeout waiting for server to respond
130 #define ERR_NOT_INSERTED -401 // Point was not inserted (most probable cause is the rate limit of once every 15 seconds)
131
135 class ThingSpeakClass
136 {
137 public:
138 ThingSpeakClass()
139 {
140 resetWriteFields();
141 this->lastReadStatus = OK_SUCCESS;
142 };
143
165 bool begin(Client & client, const char * customHostName, unsigned int port)
166 {
167 #ifdef PRINT_DEBUG_MESSAGES
168 Serial.print("ts::tsBegin (client: Client URL: "); Serial.print(customHostName); Serial.println(")");
169 #endif
170 this->setClient(&client);
171 this->setServer(customHostName, port);
172 resetWriteFields();
173 this->lastReadStatus = OK_SUCCESS;
174 return true;
175 };
176
198 bool begin(Client & client, IPAddress customIP, unsigned int port)
199 {
200 #ifdef PRINT_DEBUG_MESSAGES
201 Serial.print("ts::tsBegin (client: Client IP: "); Serial.print(customIP); Serial.println(")");
202 #endif
203 this->setClient(&client);
204 this->setServer(customIP, port);
205 resetWriteFields();
206 this->lastReadStatus = OK_SUCCESS;
207 return true;
208 };
209
229 bool begin(Client & client)
230 {
231 #ifdef PRINT_DEBUG_MESSAGES
232 Serial.print("ts::tsBegin");
233 #endif
234 this->setClient(&client);
235 this->setServer();
236 resetWriteFields();
237 this->lastReadStatus = OK_SUCCESS;
238 return true;
239 };
240
257 int writeField(unsigned long channelNumber, unsigned int field, int value, const char * writeAPIKey)
258 {
259 #ifdef SPARK
260 // On Spark, int and long are the same, so map to the long version
261 return writeField(channelNumber, field, (long)value, writeAPIKey);
262 #else
263 char valueString[10]; // int range is -32768 to 32768, so 7 bytes including terminator, plus a little extra
264 itoa(value, valueString, 10);
265 return writeField(channelNumber, field, valueString, writeAPIKey);
266 #endif
267 };
268
285 int writeField(unsigned long channelNumber, unsigned int field, long value, const char * writeAPIKey)
286 {
287 char valueString[15]; // long range is -2147483648 to 2147483647, so 12 bytes including terminator
288 ltoa(value, valueString, 10);
289 return writeField(channelNumber, field, valueString, writeAPIKey);
290 };
291
309 int writeField(unsigned long channelNumber, unsigned int field, float value, const char * writeAPIKey)
310 {
311 #ifdef PRINT_DEBUG_MESSAGES
312 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(")");
313 #endif
314 char valueString[20]; // range is -999999000000.00000 to 999999000000.00000, so 19 + 1 for the terminator
315 int status = convertFloatToChar(value, valueString);
316 if(status != OK_SUCCESS) return status;
317
318 return writeField(channelNumber, field, valueString, writeAPIKey);
319 };
320
342 int writeField(unsigned long channelNumber, unsigned int field, const char * value, const char * writeAPIKey)
343 {
344 return writeField(channelNumber, field, String(value), writeAPIKey);
345 };
346
371 int writeField(unsigned long channelNumber, unsigned int field, String value, const char * writeAPIKey)
372 {
373 // Invalid field number specified
374 if(field < FIELDNUM_MIN || field > FIELDNUM_MAX) return ERR_INVALID_FIELD_NUM;
375 // Max # bytes for ThingSpeak field is 255
376 if(value.length() > FIELDLENGTH_MAX) return ERR_OUT_OF_RANGE;
377
378 #ifdef PRINT_DEBUG_MESSAGES
379 #ifdef SPARK
380 Particle.publish(SPARK_PUBLISH_TOPIC, "writeField (" + String(channelNumber) + ", " + String(writeAPIKey) + ", " + String(field) + ", " + String(value) + ")", SPARK_PUBLISH_TTL, PRIVATE);
381 #else
382 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("\")");
383 #endif
384 #endif
385 String postMessage = String("field") + String(field) + "=" + value;
386 return writeRaw(channelNumber, postMessage, writeAPIKey);
387 };
388
389
421 int setField(unsigned int field, int value)
422 {
423 #ifdef SPARK
424 // On Spark, int and long are the same, so map to the long version
425 return setField(field, (long)value);
426 #else
427 char valueString[10]; // int range is -32768 to 32768, so 7 bytes including terminator
428 itoa(value, valueString, 10);
429
430 return setField(field, valueString);
431 #endif
432 };
433
465 int setField(unsigned int field, long value)
466 {
467 char valueString[15]; // long range is -2147483648 to 2147483647, so 12 bytes including terminator
468 ltoa(value, valueString, 10);
469 return setField(field, valueString);
470 };
471
472
504 int setField(unsigned int field, float value)
505 {
506 char valueString[20]; // range is -999999000000.00000 to 999999000000.00000, so 19 + 1 for the terminator
507 int status = convertFloatToChar(value, valueString);
508 if(status != OK_SUCCESS) return status;
509
510 return setField(field, valueString);
511 };
512
544 int setField(unsigned int field, const char * value)
545 {
546 return setField(field, String(value));
547 };
548
580 int setField(unsigned int field, String value)
581 {
582 #ifdef PRINT_DEBUG_MESSAGES
583 #ifdef SPARK
584 Particle.publish(SPARK_PUBLISH_TOPIC, "setField " + String(field) + " to " + String(value), SPARK_PUBLISH_TTL, PRIVATE);
585 #else
586 Serial.print("ts::setField (field: "); Serial.print(field); Serial.print(" value: \""); Serial.print(value); Serial.println("\")");
587 #endif
588 #endif
589 if(field < FIELDNUM_MIN || field > FIELDNUM_MAX) return ERR_INVALID_FIELD_NUM;
590 // Max # bytes for ThingSpeak field is 255 (UTF-8)
591 if(value.length() > FIELDLENGTH_MAX) return ERR_OUT_OF_RANGE;
592 this->nextWriteField[field - 1] = value;
593 return OK_SUCCESS;
594 };
595
596
630 int setLatitude(float latitude)
631 {
632 #ifdef PRINT_DEBUG_MESSAGES
633 Serial.print("ts::setLatitude(latitude: "); Serial.print(latitude,3); Serial.println("\")");
634 #endif
635 this->nextWriteLatitude = latitude;
636 return OK_SUCCESS;
637 };
638
639
673 int setLongitude(float longitude)
674 {
675 #ifdef PRINT_DEBUG_MESSAGES
676 Serial.print("ts::setLongitude(longitude: "); Serial.print(longitude,3); Serial.println("\")");
677 #endif
678 this->nextWriteLongitude = longitude;
679 return OK_SUCCESS;
680 };
681
682
716 int setElevation(float elevation)
717 {
718 #ifdef PRINT_DEBUG_MESSAGES
719 Serial.print("ts::setElevation(elevation: "); Serial.print(elevation,3); Serial.println("\")");
720 #endif
721 this->nextWriteElevation = elevation;
722 return OK_SUCCESS;
723 };
724
725
760 int writeFields(unsigned long channelNumber, const char * writeAPIKey)
761 {
762 String postMessage = String("");
763 bool fFirstItem = true;
764 for(size_t iField = 0; iField < 8; iField++)
765 {
766 if(this->nextWriteField[iField].length() > 0)
767 {
768 if(!fFirstItem)
769 {
770 postMessage = postMessage + String("&");
771 }
772 postMessage = postMessage + String("field") + String(iField + 1) + String("=") + this->nextWriteField[iField];
773 fFirstItem = false;
774 this->nextWriteField[iField] = "";
775 }
776 }
777
778 if(!isnan(nextWriteLatitude))
779 {
780 if(!fFirstItem)
781 {
782 postMessage = postMessage + String("&");
783 }
784 postMessage = postMessage + String("lat=") + String(this->nextWriteLatitude);
785 fFirstItem = false;
786 this->nextWriteLatitude = NAN;
787 }
788
789 if(!isnan(this->nextWriteLongitude))
790 {
791 if(!fFirstItem)
792 {
793 postMessage = postMessage + String("&");
794 }
795 postMessage = postMessage + String("long=") + String(this->nextWriteLongitude);
796 fFirstItem = false;
797 this->nextWriteLongitude = NAN;
798 }
799
800
801 if(!isnan(this->nextWriteElevation))
802 {
803 if(!fFirstItem)
804 {
805 postMessage = postMessage + String("&");
806 }
807 postMessage = postMessage + String("elevation=") + String(this->nextWriteElevation);
808 fFirstItem = false;
809 this->nextWriteElevation = NAN;
810 }
811
812 if(fFirstItem)
813 {
814 // setField was not called before writeFields
815 return ERR_SETFIELD_NOT_CALLED;
816 }
817
818 return writeRaw(channelNumber, postMessage, writeAPIKey);
819 };
820
821
842 int writeRaw(unsigned long channelNumber, const char * postMessage, const char * writeAPIKey)
843 {
844 return writeRaw(channelNumber, String(postMessage), writeAPIKey);
845 };
846
847
863 int writeRaw(unsigned long channelNumber, String postMessage, const char * writeAPIKey)
864 {
865 #ifdef PRINT_DEBUG_MESSAGES
866 Serial.print("ts::writeRaw (channelNumber: "); Serial.print(channelNumber); Serial.print(" writeAPIKey: "); Serial.print(writeAPIKey); Serial.print(" postMessage: \""); Serial.print(postMessage); Serial.println("\")");
867 #endif
868
869 if(!connectThingSpeak())
870 {
871 // Failed to connect to ThingSpeak
872 return ERR_CONNECT_FAILED;
873 }
874
875 postMessage = postMessage + String("&headers=false");
876
877 #ifdef PRINT_DEBUG_MESSAGES
878 #ifdef SPARK
879 Particle.publish(SPARK_PUBLISH_TOPIC, "Post " + postMessage, SPARK_PUBLISH_TTL, PRIVATE);
880 #else
881 Serial.print(" POST \"");Serial.print(postMessage);Serial.println("\"");
882 #endif
883 #endif
884
885 postMessage = postMessage + String("\n");
886
887 // Post data to thingspeak
888 if(!this->client->print("POST /update HTTP/1.1\n")) return abortWriteRaw();
889 if(!writeHTTPHeader(writeAPIKey)) return abortWriteRaw();
890 if(!this->client->print("Content-Type: application/x-www-form-urlencoded\n")) return abortWriteRaw();
891 if(!this->client->print("Content-Length: ")) return abortWriteRaw();
892 if(!this->client->print(postMessage.length())) return abortWriteRaw();
893 if(!this->client->print("\n\n")) return abortWriteRaw();
894 if(!this->client->print(postMessage)) return abortWriteRaw();
895
896 String entryIDText = String();
897 int status = getHTTPResponse(entryIDText);
898 if(status != OK_SUCCESS)
899 {
900 client->stop();
901 return status;
902 }
903 long entryID = entryIDText.toInt();
904
905 #ifdef PRINT_DEBUG_MESSAGES
906 Serial.print(" Entry ID \"");Serial.print(entryIDText);Serial.print("\" (");Serial.print(entryID);Serial.println(")");
907 #endif
908
909 client->stop();
910
911 #ifdef PRINT_DEBUG_MESSAGES
912 Serial.println("disconnected.");
913 #endif
914 if(entryID == 0)
915 {
916 // ThingSpeak did not accept the write
917 status = ERR_NOT_INSERTED;
918 }
919 return status;
920 };
921
937 String readStringField(unsigned long channelNumber, unsigned int field, const char * readAPIKey)
938 {
939 if(field < FIELDNUM_MIN || field > FIELDNUM_MAX)
940 {
941 this->lastReadStatus = ERR_INVALID_FIELD_NUM;
942 return("");
943 }
944 #ifdef PRINT_DEBUG_MESSAGES
945 Serial.print("ts::readStringField(channelNumber: "); Serial.print(channelNumber);
946 if(NULL != readAPIKey)
947 {
948 Serial.print(" readAPIKey: "); Serial.print(readAPIKey);
949 }
950 Serial.print(" field: "); Serial.print(field); Serial.println(")");
951 #endif
952 return readRaw(channelNumber, String(String("/fields/") + String(field) + String("/last")), readAPIKey);
953 }
954
955
970 String readStringField(unsigned long channelNumber, unsigned int field)
971 {
972 return readStringField(channelNumber, field, NULL);
973 };
974
975
992 float readFloatField(unsigned long channelNumber, unsigned int field, const char * readAPIKey)
993 {
994 return convertStringToFloat(readStringField(channelNumber, field, readAPIKey));
995 };
996
997
1013 float readFloatField(unsigned long channelNumber, unsigned int field)
1014 {
1015 return readFloatField(channelNumber, field, NULL);
1016 };
1017
1018
1034 long readLongField(unsigned long channelNumber, unsigned int field, const char * readAPIKey)
1035 {
1036 // Note that although the function is called "toInt" it really returns a long.
1037 return readStringField(channelNumber, field, readAPIKey).toInt();
1038 }
1039
1040
1055 long readLongField(unsigned long channelNumber, unsigned int field)
1056 {
1057 return readLongField(channelNumber, field, NULL);
1058 };
1059
1060
1077 int readIntField(unsigned long channelNumber, unsigned int field, const char * readAPIKey)
1078 {
1079 return readLongField(channelNumber, field, readAPIKey);
1080 }
1081
1082
1098 int readIntField(unsigned long channelNumber, unsigned int field)
1099 {
1100 return readLongField(channelNumber, field, NULL);
1101 };
1102
1118 String readRaw(unsigned long channelNumber, String URLSuffix)
1119 {
1120 return readRaw(channelNumber, URLSuffix, NULL);
1121 }
1122
1139 String readRaw(unsigned long channelNumber, String URLSuffix, const char * readAPIKey)
1140 {
1141 #ifdef PRINT_DEBUG_MESSAGES
1142 Serial.print("ts::readRaw (channelNumber: "); Serial.print(channelNumber);
1143 if(NULL != readAPIKey)
1144 {
1145 Serial.print(" readAPIKey: "); Serial.print(readAPIKey);
1146 }
1147 Serial.print(" URLSuffix: \""); Serial.print(URLSuffix); Serial.println("\")");
1148 #endif
1149
1150 if(!connectThingSpeak())
1151 {
1152 this->lastReadStatus = ERR_CONNECT_FAILED;
1153 return String("");
1154 }
1155
1156 String URL = String("/channels/") + String(channelNumber) + URLSuffix;
1157
1158 #ifdef PRINT_DEBUG_MESSAGES
1159 Serial.print(" GET \"");Serial.print(URL);Serial.println("\"");
1160 #endif
1161
1162 // Post data to thingspeak
1163 if(!this->client->print("GET ")) return abortReadRaw();
1164 if(!this->client->print(URL)) return abortReadRaw();
1165 if(!this->client->print(" HTTP/1.1\n")) return abortReadRaw();
1166 if(!writeHTTPHeader(readAPIKey)) return abortReadRaw();
1167 if(!this->client->print("\n")) return abortReadRaw();
1168
1169 String content = String();
1170 int status = getHTTPResponse(content);
1171 this->lastReadStatus = status;
1172
1173
1174 #ifdef PRINT_DEBUG_MESSAGES
1175 if(status == OK_SUCCESS)
1176 {
1177 Serial.print("Read: \""); Serial.print(content); Serial.println("\"");
1178 }
1179 #endif
1180
1181 client->stop();
1182 #ifdef PRINT_DEBUG_MESSAGES
1183 Serial.println("disconnected.");
1184 #endif
1185
1186 if(status != OK_SUCCESS)
1187 {
1188 // return status;
1189 return String("");
1190 }
1191
1192 // This is a workaround to a bug in the Spark implementation of String
1193 return String("") + content;
1194 };
1195
1229 int getLastReadStatus()
1230 {
1231 return this->lastReadStatus;
1232 };
1233 private:
1234
1235 int abortWriteRaw()
1236 {
1237 this->client->stop();
1238 return ERR_UNEXPECTED_FAIL;
1239 }
1240
1241 String abortReadRaw()
1242 {
1243 this->client->stop();
1244 #ifdef PRINT_DEBUG_MESSAGES
1245 Serial.println("ReadRaw abort - disconnected.");
1246 #endif
1247 this->lastReadStatus = ERR_UNEXPECTED_FAIL;
1248 return String("");
1249 }
1250
1251 void setServer(const char * customHostName, unsigned int port)
1252 {
1253 #ifdef PRINT_DEBUG_MESSAGES
1254 Serial.print("ts::setServer (URL: \""); Serial.print(customHostName); Serial.println("\")");
1255 #endif
1256 this->customIP = INADDR_NONE;
1257 this->customHostName = customHostName;
1258 this->port = port;
1259 };
1260
1261 void setServer(IPAddress customIP, unsigned int port)
1262 {
1263 #ifdef PRINT_DEBUG_MESSAGES
1264 Serial.print("ts::setServer (IP: \""); Serial.print(customIP); Serial.println("\")");
1265 #endif
1266 this->customIP = customIP;
1267 this->customHostName = NULL;
1268 this->port = port;
1269 };
1270
1271 void setServer()
1272 {
1273 #ifdef PRINT_DEBUG_MESSAGES
1274 Serial.print("ts::setServer (default)");
1275 #endif
1276 this->customIP = INADDR_NONE;
1277 this->customHostName = NULL;
1278 this->port = THINGSPEAK_PORT_NUMBER;
1279 };
1280
1281 void setClient(Client * client) {this->client = client;};
1282
1283 Client * client = NULL;
1284 const char * customHostName = NULL;
1285 IPAddress customIP = INADDR_NONE;
1286 unsigned int port = THINGSPEAK_PORT_NUMBER;
1287 String nextWriteField[8];
1288 float nextWriteLatitude;
1289 float nextWriteLongitude;
1290 float nextWriteElevation;
1291 int lastReadStatus;
1292
1293 bool connectThingSpeak()
1294 {
1295 bool connectSuccess = false;
1296 if(this->customIP == INADDR_NONE && NULL == this->customHostName)
1297 {
1298 #ifdef PRINT_DEBUG_MESSAGES
1299 Serial.print(" Connect to default ThingSpeak URL...");
1300 #endif
1301 connectSuccess = client->connect(THINGSPEAK_URL,THINGSPEAK_PORT_NUMBER);
1302 if(!connectSuccess)
1303 {
1304 #ifdef PRINT_DEBUG_MESSAGES
1305 Serial.print("Failed. Try default IP...");
1306 #endif
1307 connectSuccess = client->connect(THINGSPEAK_IPADDRESS,THINGSPEAK_PORT_NUMBER);
1308 }
1309 }
1310 else
1311 {
1312 if(!(this->customIP == INADDR_NONE))
1313 {
1314 // Connect to the server on port 80 (HTTP) at the customIP address
1315 #ifdef PRINT_DEBUG_MESSAGES
1316 Serial.print(" Connect to ");Serial.print(this->customIP);Serial.print("...");
1317 #endif
1318 connectSuccess = client->connect(this->customIP,this->port);
1319 }
1320 if(NULL != this->customHostName)
1321 {
1322 // Connect to the server on port 80 (HTTP) at the URL address
1323 #ifdef PRINT_DEBUG_MESSAGES
1324 #ifdef SPARK
1325 Particle.publish(SPARK_PUBLISH_TOPIC, "Attempt Connect to URL " + String(this->customHostName), SPARK_PUBLISH_TTL, PRIVATE);
1326 #else
1327 Serial.print(" Connect to ");Serial.print(this->customHostName);Serial.print(" ...");
1328 #endif
1329 #endif
1330 connectSuccess = client->connect(customHostName,this->port);
1331 }
1332 }
1333
1334 #ifdef PRINT_DEBUG_MESSAGES
1335 if (connectSuccess)
1336 {
1337 #ifdef SPARK
1338 Particle.publish(SPARK_PUBLISH_TOPIC, "Connection Success", SPARK_PUBLISH_TTL, PRIVATE);
1339 #else
1340 Serial.println("Success.");
1341 #endif
1342 }
1343 else
1344 {
1345 #ifdef SPARK
1346 Particle.publish(SPARK_PUBLISH_TOPIC, "Connection Failure", SPARK_PUBLISH_TTL, PRIVATE);
1347 #else
1348 Serial.println("Failed.");
1349 #endif
1350 }
1351 #endif
1352 return connectSuccess;
1353 };
1354
1355 bool writeHTTPHeader(const char * APIKey)
1356 {
1357 if(NULL != this->customHostName)
1358 {
1359 if (!this->client->print("Host: ")) return false;
1360 if (!this->client->print(this->customHostName)) return false;
1361 if (!this->client->print("\n")) return false;
1362 }
1363 else
1364 {
1365 if (!this->client->print("Host: api.thingspeak.com\n")) return false;
1366 }
1367 if (!this->client->print("Connection: close\n")) return false;
1368 if (!this->client->print("User-Agent: ")) return false;
1369 if (!this->client->print(TS_USER_AGENT)) return false;
1370 if (!this->client->print("\n")) return false;
1371 if(NULL != APIKey)
1372 {
1373 if (!this->client->print("X-THINGSPEAKAPIKEY: ")) return false;
1374 if (!this->client->print(APIKey)) return false;
1375 if (!this->client->print("\n")) return false;
1376 }
1377 return true;
1378 };
1379
1380 int getHTTPResponse(String & response)
1381 {
1382 long startWaitForResponseAt = millis();
1383 while(client->available() == 0 && millis() - startWaitForResponseAt < TIMEOUT_MS_SERVERRESPONSE)
1384 {
1385 delay(100);
1386 }
1387 if(client->available() == 0)
1388 {
1389 return ERR_TIMEOUT; // Didn't get server response in time
1390 }
1391
1392 if(!client->find(const_cast<char *>("HTTP/1.1")))
1393 {
1394 #ifdef PRINT_HTTP
1395 #ifdef SPARK
1396 Particle.publish(SPARK_PUBLISH_TOPIC, "ERROR: Didn't find HTTP/1.1", SPARK_PUBLISH_TTL, PRIVATE);
1397 #else
1398 Serial.println("ERROR: Didn't find HTTP/1.1");
1399 #endif
1400 #endif
1401 return ERR_BAD_RESPONSE; // Couldn't parse response (didn't find HTTP/1.1)
1402 }
1403 int status = client->parseInt();
1404 #ifdef PRINT_HTTP
1405 #ifdef SPARK
1406 Particle.publish(SPARK_PUBLISH_TOPIC, "Got Status of " + String(status), SPARK_PUBLISH_TTL, PRIVATE);
1407 #else
1408 Serial.print("Got Status of ");Serial.println(status);
1409 #endif
1410 #endif
1411 if(status != OK_SUCCESS)
1412 {
1413 return status;
1414 }
1415
1416 if(!client->find(const_cast<char *>("\r\n")))
1417 {
1418 #ifdef PRINT_HTTP
1419 #ifdef SPARK
1420 Particle.publish(SPARK_PUBLISH_TOPIC, "ERROR: Didn't find end of status line", SPARK_PUBLISH_TTL, PRIVATE);
1421 #else
1422 Serial.println("ERROR: Didn't find end of status line");
1423 #endif
1424 #endif
1425 return ERR_BAD_RESPONSE;
1426 }
1427 #ifdef PRINT_HTTP
1428 #ifdef SPARK
1429 Particle.publish(SPARK_PUBLISH_TOPIC, "Found end of status line", SPARK_PUBLISH_TTL, PRIVATE);
1430 #else
1431 Serial.println("Found end of status line");
1432 #endif
1433 #endif
1434
1435 if(!client->find(const_cast<char *>("\n\r\n")))
1436 {
1437 #ifdef PRINT_HTTP
1438 #ifdef SPARK
1439 Particle.publish(SPARK_PUBLISH_TOPIC, "ERROR: Didn't find end of header", SPARK_PUBLISH_TTL, PRIVATE);
1440 #else
1441 Serial.println("ERROR: Didn't find end of header");
1442 #endif
1443 #endif
1444 return ERR_BAD_RESPONSE;
1445 }
1446 #ifdef PRINT_HTTP
1447 #ifdef SPARK
1448 Particle.publish(SPARK_PUBLISH_TOPIC, "Found end of header", SPARK_PUBLISH_TTL, PRIVATE);
1449 #else
1450 Serial.println("Found end of header");
1451 #endif
1452 #endif
1453 // This is a workaround to a bug in the Spark implementation of String
1454 String tempString = client->readStringUntil('\r');
1455 response = tempString;
1456 #ifdef PRINT_HTTP
1457 #ifdef SPARK
1458 Particle.publish(SPARK_PUBLISH_TOPIC, "Response: \"" + tempString + "\"", SPARK_PUBLISH_TTL, PRIVATE);
1459 #else
1460 Serial.print("Response: \"");Serial.print(response);Serial.println("\"");
1461 #endif
1462 #endif
1463 return status;
1464 };
1465
1466 int convertFloatToChar(float value, char *valueString)
1467 {
1468 // Supported range is -999999000000 to 999999000000
1469 if(0 == isinf(value) && (value > 999999000000 || value < -999999000000))
1470 {
1471 // Out of range
1472 return ERR_OUT_OF_RANGE;
1473 }
1474 // 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
1475 #ifdef PARTICLE_PHOTONELECTRON
1476 //Photon doesn't have a dtostrf, but does have dtoa
1477 dtoa((double)value,5, valueString);
1478 #else
1479 dtostrf(value,1,5, valueString);
1480 #endif
1481 return OK_SUCCESS;
1482 };
1483
1484 float convertStringToFloat(String value)
1485 {
1486 // There's a bug in the AVR function strtod that it doesn't decode -INF correctly (it maps it to INF)
1487 float result = value.toFloat();
1488 if(1 == isinf(result) && *value.c_str() == '-')
1489 {
1490 result = (float)-INFINITY;
1491 }
1492 return result;
1493 };
1494
1495 void resetWriteFields()
1496 {
1497 for(size_t iField = 0; iField < 8; iField++)
1498 {
1499 this->nextWriteField[iField] = "";
1500 }
1501 this->nextWriteLatitude = NAN;
1502 this->nextWriteLongitude = NAN;
1503 this->nextWriteElevation = NAN;
1504 };
1505 };
1506
1507 extern ThingSpeakClass ThingSpeak;
1508
1509 #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:842
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:937
ThingSpeakClass::readStringField
String readStringField(unsigned long channelNumber, unsigned int field)
Read the latest string from a public ThingSpeak channel.
Definition: ThingSpeak.h:970
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:465
ThingSpeakClass::writeRaw
int writeRaw(unsigned long channelNumber, String postMessage, const char *writeAPIKey)
Write a raw POST to a ThingSpeak channel.
Definition: ThingSpeak.h:863
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:198
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:760
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:421
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:630
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:165
ThingSpeakClass::getLastReadStatus
int getLastReadStatus()
Get the status of the previous read.
Definition: ThingSpeak.h:1229
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:257
ThingSpeakClass
Enables an Arduino, ESP8266, Particle or other compatible hardware to write or read data to or from T...
Definition: ThingSpeak.h:135
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:1034
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:371
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:544
ThingSpeakClass::readRaw
String readRaw(unsigned long channelNumber, String URLSuffix)
Read a raw response from a public ThingSpeak channel.
Definition: ThingSpeak.h:1118
ThingSpeakClass::readLongField
long readLongField(unsigned long channelNumber, unsigned int field)
Read the latest long from a public ThingSpeak channel.
Definition: ThingSpeak.h:1055
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:309
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:1077
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:580
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:673
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:992
ThingSpeakClass::begin
bool begin(Client &client)
Initializes the ThingSpeak library and network settings using the ThingSpeak.com service.
Definition: ThingSpeak.h:229
ThingSpeakClass::readFloatField
float readFloatField(unsigned long channelNumber, unsigned int field)
Read the latest float from a public ThingSpeak channel.
Definition: ThingSpeak.h:1013
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:342
ThingSpeakClass::readIntField
int readIntField(unsigned long channelNumber, unsigned int field)
Read the latest int from a public ThingSpeak channel.
Definition: ThingSpeak.h:1098
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:504
ThingSpeakClass::readRaw
String readRaw(unsigned long channelNumber, String URLSuffix, const char *readAPIKey)
Read a raw response from a private ThingSpeak channel.
Definition: ThingSpeak.h:1139
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:716
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:285