ThingSpeak Communication Library
Enables an Arduino, ESP8266, or Particle to write or read data to or from ThingSpeak™
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 an analytic IoT platform service that allows you to aggregate, visualize and
8  analyze live data streams in the cloud.
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 
57 #if defined(ARDUINO_ARCH_AVR) || defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_SAMD) || defined(ARDUINO_ARCH_SAM)
58  #include "Arduino.h"
59  #include <Client.h>
60 #else
61  #error Only Arduino MKR1000, Yun, Uno/Mega/Due with either WiFi101 or Ethernet shield. ESP8266 also supported.
62 #endif
63 
64 
65 #define THINGSPEAK_URL "api.thingspeak.com"
66 #define THINGSPEAK_IPADDRESS IPAddress(184,106,153,149)
67 #define THINGSPEAK_PORT_NUMBER 80
68 
69 #ifdef ARDUINO_ARCH_AVR
70  #ifdef ARDUINO_AVR_YUN
71  #define TS_USER_AGENT "tslib-arduino/1.0 (arduino yun)"
72  #else
73  #define TS_USER_AGENT "tslib-arduino/1.0 (arduino uno or mega)"
74  #endif
75 #elif defined(ARDUINO_ARCH_ESP8266)
76  #define TS_USER_AGENT "tslib-arduino/1.0 (ESP8266)"
77 #elif defined(ARDUINO_SAMD_MKR1000)
78  #define TS_USER_AGENT "tslib-arduino/1.0 (arduino mkr1000)"
79 #elif defined(ARDUINO_SAM_DUE)
80  #define TS_USER_AGENT "tslib-arduino/1.0 (arduino due)"
81 #elif defined(ARDUINO_ARCH_SAMD) || defined(ARDUINO_ARCH_SAM)
82  #define TS_USER_AGENT "tslib-arduino/1.0 (arduino unknown sam or samd)"
83 #else
84  #error "Platform not supported"
85 #endif
86 
87 #define FIELDNUM_MIN 1
88 #define FIELDNUM_MAX 8
89 #define FIELDLENGTH_MAX 255 // Max length for a field in ThingSpeak is 255 bytes (UTF-8)
90 
91 #define TIMEOUT_MS_SERVERRESPONSE 5000 // Wait up to five seconds for server to respond
92 
93 #define OK_SUCCESS 200 // OK / Success
94 #define ERR_BADAPIKEY 400 // Incorrect API key (or invalid ThingSpeak server address)
95 #define ERR_BADURL 404 // Incorrect API key (or invalid ThingSpeak server address)
96 #define ERR_OUT_OF_RANGE -101 // Value is out of range or string is too long (> 255 bytes)
97 #define ERR_INVALID_FIELD_NUM -201 // Invalid field number specified
98 #define ERR_SETFIELD_NOT_CALLED -210 // setField() was not called before writeFields()
99 #define ERR_CONNECT_FAILED -301 // Failed to connect to ThingSpeak
100 #define ERR_UNEXPECTED_FAIL -302 // Unexpected failure during write to ThingSpeak
101 #define ERR_BAD_RESPONSE -303 // Unable to parse response
102 #define ERR_TIMEOUT -304 // Timeout waiting for server to respond
103 #define ERR_NOT_INSERTED -401 // Point was not inserted (most probable cause is the rate limit of once every 15 seconds)
104 
109 {
110  public:
112  {
113  resetWriteFields();
114  this->lastReadStatus = OK_SUCCESS;
115  };
116 
138  bool begin(Client & client, const char * customHostName, unsigned int port)
139  {
140 #ifdef PRINT_DEBUG_MESSAGES
141  Serial.print("ts::tsBegin (client: Client URL: "); Serial.print(customHostName); Serial.println(")");
142 #endif
143  this->setClient(&client);
144  this->setServer(customHostName, port);
145  resetWriteFields();
146  this->lastReadStatus = OK_SUCCESS;
147  return true;
148  };
149 
171  bool begin(Client & client, IPAddress customIP, unsigned int port)
172  {
173 #ifdef PRINT_DEBUG_MESSAGES
174  Serial.print("ts::tsBegin (client: Client IP: "); Serial.print(customIP); Serial.println(")");
175 #endif
176  this->setClient(&client);
177  this->setServer(customIP, port);
178  resetWriteFields();
179  this->lastReadStatus = OK_SUCCESS;
180  return true;
181  };
182 
202  bool begin(Client & client)
203  {
204 #ifdef PRINT_DEBUG_MESSAGES
205  Serial.print("ts::tsBegin");
206 #endif
207  this->setClient(&client);
208  this->setServer();
209  resetWriteFields();
210  this->lastReadStatus = OK_SUCCESS;
211  return true;
212  };
213 
230  int writeField(unsigned long channelNumber, unsigned int field, int value, const char * writeAPIKey)
231  {
232  char valueString[10]; // int range is -32768 to 32768, so 7 bytes including terminator, plus a little extra
233  itoa(value, valueString, 10);
234  return writeField(channelNumber, field, valueString, writeAPIKey);
235  };
236 
253  int writeField(unsigned long channelNumber, unsigned int field, long value, const char * writeAPIKey)
254  {
255  char valueString[15]; // long range is -2147483648 to 2147483647, so 12 bytes including terminator
256  ltoa(value, valueString, 10);
257  return writeField(channelNumber, field, valueString, writeAPIKey);
258  };
259 
277  int writeField(unsigned long channelNumber, unsigned int field, float value, const char * writeAPIKey)
278  {
279  #ifdef PRINT_DEBUG_MESSAGES
280  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(")");
281  #endif
282  char valueString[20]; // range is -999999000000.00000 to 999999000000.00000, so 19 + 1 for the terminator
283  int status = convertFloatToChar(value, valueString);
284  if(status != OK_SUCCESS) return status;
285 
286  return writeField(channelNumber, field, valueString, writeAPIKey);
287  };
288 
310  int writeField(unsigned long channelNumber, unsigned int field, const char * value, const char * writeAPIKey)
311  {
312  return writeField(channelNumber, field, String(value), writeAPIKey);
313  };
314 
339  int writeField(unsigned long channelNumber, unsigned int field, String value, const char * writeAPIKey)
340  {
341  // Invalid field number specified
342  if(field < FIELDNUM_MIN || field > FIELDNUM_MAX) return ERR_INVALID_FIELD_NUM;
343  // Max # bytes for ThingSpeak field is 255
344  if(value.length() > FIELDLENGTH_MAX) return ERR_OUT_OF_RANGE;
345 
346  #ifdef PRINT_DEBUG_MESSAGES
347  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("\")");
348  #endif
349  String postMessage = String("field") + String(field) + "=" + value;
350  return writeRaw(channelNumber, postMessage, writeAPIKey);
351  };
352 
353 
385  int setField(unsigned int field, int value)
386  {
387 
388  char valueString[10]; // int range is -32768 to 32768, so 7 bytes including terminator
389  itoa(value, valueString, 10);
390 
391  return setField(field, valueString);
392 
393  };
394 
426  int setField(unsigned int field, long value)
427  {
428  char valueString[15]; // long range is -2147483648 to 2147483647, so 12 bytes including terminator
429  ltoa(value, valueString, 10);
430  return setField(field, valueString);
431  };
432 
433 
465  int setField(unsigned int field, float value)
466  {
467  char valueString[20]; // range is -999999000000.00000 to 999999000000.00000, so 19 + 1 for the terminator
468  int status = convertFloatToChar(value, valueString);
469  if(status != OK_SUCCESS) return status;
470 
471  return setField(field, valueString);
472  };
473 
505  int setField(unsigned int field, const char * value)
506  {
507  return setField(field, String(value));
508  };
509 
541  int setField(unsigned int field, String value)
542  {
543  #ifdef PRINT_DEBUG_MESSAGES
544  Serial.print("ts::setField (field: "); Serial.print(field); Serial.print(" value: \""); Serial.print(value); Serial.println("\")");
545  #endif
546  if(field < FIELDNUM_MIN || field > FIELDNUM_MAX) return ERR_INVALID_FIELD_NUM;
547  // Max # bytes for ThingSpeak field is 255 (UTF-8)
548  if(value.length() > FIELDLENGTH_MAX) return ERR_OUT_OF_RANGE;
549  this->nextWriteField[field - 1] = value;
550  return OK_SUCCESS;
551  };
552 
553 
587  int setLatitude(float latitude)
588  {
589  #ifdef PRINT_DEBUG_MESSAGES
590  Serial.print("ts::setLatitude(latitude: "); Serial.print(latitude,3); Serial.println("\")");
591  #endif
592  this->nextWriteLatitude = latitude;
593  return OK_SUCCESS;
594  };
595 
596 
630  int setLongitude(float longitude)
631  {
632  #ifdef PRINT_DEBUG_MESSAGES
633  Serial.print("ts::setLongitude(longitude: "); Serial.print(longitude,3); Serial.println("\")");
634  #endif
635  this->nextWriteLongitude = longitude;
636  return OK_SUCCESS;
637  };
638 
639 
673  int setElevation(float elevation)
674  {
675  #ifdef PRINT_DEBUG_MESSAGES
676  Serial.print("ts::setElevation(elevation: "); Serial.print(elevation,3); Serial.println("\")");
677  #endif
678  this->nextWriteElevation = elevation;
679  return OK_SUCCESS;
680  };
681 
682 
717  int writeFields(unsigned long channelNumber, const char * writeAPIKey)
718  {
719  String postMessage = String("");
720  bool fFirstItem = true;
721  for(size_t iField = 0; iField < 8; iField++)
722  {
723  if(this->nextWriteField[iField].length() > 0)
724  {
725  if(!fFirstItem)
726  {
727  postMessage = postMessage + String("&");
728  }
729  postMessage = postMessage + String("field") + String(iField + 1) + String("=") + this->nextWriteField[iField];
730  fFirstItem = false;
731  this->nextWriteField[iField] = "";
732  }
733  }
734 
735  if(!isnan(nextWriteLatitude))
736  {
737  if(!fFirstItem)
738  {
739  postMessage = postMessage + String("&");
740  }
741  postMessage = postMessage + String("lat=") + String(this->nextWriteLatitude);
742  fFirstItem = false;
743  this->nextWriteLatitude = NAN;
744  }
745 
746  if(!isnan(this->nextWriteLongitude))
747  {
748  if(!fFirstItem)
749  {
750  postMessage = postMessage + String("&");
751  }
752  postMessage = postMessage + String("long=") + String(this->nextWriteLongitude);
753  fFirstItem = false;
754  this->nextWriteLongitude = NAN;
755  }
756 
757 
758  if(!isnan(this->nextWriteElevation))
759  {
760  if(!fFirstItem)
761  {
762  postMessage = postMessage + String("&");
763  }
764  postMessage = postMessage + String("elevation=") + String(this->nextWriteElevation);
765  fFirstItem = false;
766  this->nextWriteElevation = NAN;
767  }
768 
769  if(fFirstItem)
770  {
771  // setField was not called before writeFields
772  return ERR_SETFIELD_NOT_CALLED;
773  }
774 
775  return writeRaw(channelNumber, postMessage, writeAPIKey);
776  };
777 
778 
799  int writeRaw(unsigned long channelNumber, const char * postMessage, const char * writeAPIKey)
800  {
801  return writeRaw(channelNumber, String(postMessage), writeAPIKey);
802  };
803 
804 
820  int writeRaw(unsigned long channelNumber, String postMessage, const char * writeAPIKey)
821  {
822  #ifdef PRINT_DEBUG_MESSAGES
823  Serial.print("ts::writeRaw (channelNumber: "); Serial.print(channelNumber); Serial.print(" writeAPIKey: "); Serial.print(writeAPIKey); Serial.print(" postMessage: \""); Serial.print(postMessage); Serial.println("\")");
824  #endif
825 
826  if(!connectThingSpeak())
827  {
828  // Failed to connect to ThingSpeak
829  return ERR_CONNECT_FAILED;
830  }
831 
832  postMessage = postMessage + String("&headers=false");
833 
834  #ifdef PRINT_DEBUG_MESSAGES
835  Serial.print(" POST \"");Serial.print(postMessage);Serial.println("\"");
836  #endif
837 
838  postMessage = postMessage + String("\n");
839 
840  // Post data to thingspeak
841  if(!this->client->print("POST /update HTTP/1.1\n")) return abortWriteRaw();
842  if(!writeHTTPHeader(writeAPIKey)) return abortWriteRaw();
843  if(!this->client->print("Content-Type: application/x-www-form-urlencoded\n")) return abortWriteRaw();
844  if(!this->client->print("Content-Length: ")) return abortWriteRaw();
845  if(!this->client->print(postMessage.length())) return abortWriteRaw();
846  if(!this->client->print("\n\n")) return abortWriteRaw();
847  if(!this->client->print(postMessage)) return abortWriteRaw();
848 
849  String entryIDText = String();
850  int status = getHTTPResponse(entryIDText);
851  if(status != OK_SUCCESS)
852  {
853  client->stop();
854  return status;
855  }
856  long entryID = entryIDText.toInt();
857 
858  #ifdef PRINT_DEBUG_MESSAGES
859  Serial.print(" Entry ID \"");Serial.print(entryIDText);Serial.print("\" (");Serial.print(entryID);Serial.println(")");
860  #endif
861 
862  client->stop();
863 
864  #ifdef PRINT_DEBUG_MESSAGES
865  Serial.println("disconnected.");
866  #endif
867  if(entryID == 0)
868  {
869  // ThingSpeak did not accept the write
870  status = ERR_NOT_INSERTED;
871  }
872  return status;
873  };
874 
890  String readStringField(unsigned long channelNumber, unsigned int field, const char * readAPIKey)
891  {
892  if(field < FIELDNUM_MIN || field > FIELDNUM_MAX)
893  {
894  this->lastReadStatus = ERR_INVALID_FIELD_NUM;
895  return("");
896  }
897  #ifdef PRINT_DEBUG_MESSAGES
898  Serial.print("ts::readStringField(channelNumber: "); Serial.print(channelNumber);
899  if(NULL != readAPIKey)
900  {
901  Serial.print(" readAPIKey: "); Serial.print(readAPIKey);
902  }
903  Serial.print(" field: "); Serial.print(field); Serial.println(")");
904  #endif
905  return readRaw(channelNumber, String(String("/fields/") + String(field) + String("/last")), readAPIKey);
906  }
907 
908 
923  String readStringField(unsigned long channelNumber, unsigned int field)
924  {
925  return readStringField(channelNumber, field, NULL);
926  };
927 
928 
945  float readFloatField(unsigned long channelNumber, unsigned int field, const char * readAPIKey)
946  {
947  return convertStringToFloat(readStringField(channelNumber, field, readAPIKey));
948  };
949 
950 
966  float readFloatField(unsigned long channelNumber, unsigned int field)
967  {
968  return readFloatField(channelNumber, field, NULL);
969  };
970 
971 
987  long readLongField(unsigned long channelNumber, unsigned int field, const char * readAPIKey)
988  {
989  // Note that although the function is called "toInt" it really returns a long.
990  return readStringField(channelNumber, field, readAPIKey).toInt();
991  }
992 
993 
1008  long readLongField(unsigned long channelNumber, unsigned int field)
1009  {
1010  return readLongField(channelNumber, field, NULL);
1011  };
1012 
1013 
1030  int readIntField(unsigned long channelNumber, unsigned int field, const char * readAPIKey)
1031  {
1032  return readLongField(channelNumber, field, readAPIKey);
1033  }
1034 
1035 
1051  int readIntField(unsigned long channelNumber, unsigned int field)
1052  {
1053  return readLongField(channelNumber, field, NULL);
1054  };
1055 
1071  String readRaw(unsigned long channelNumber, String URLSuffix)
1072  {
1073  return readRaw(channelNumber, URLSuffix, NULL);
1074  }
1075 
1092  String readRaw(unsigned long channelNumber, String URLSuffix, const char * readAPIKey)
1093  {
1094  #ifdef PRINT_DEBUG_MESSAGES
1095  Serial.print("ts::readRaw (channelNumber: "); Serial.print(channelNumber);
1096  if(NULL != readAPIKey)
1097  {
1098  Serial.print(" readAPIKey: "); Serial.print(readAPIKey);
1099  }
1100  Serial.print(" URLSuffix: \""); Serial.print(URLSuffix); Serial.println("\")");
1101  #endif
1102 
1103  if(!connectThingSpeak())
1104  {
1105  this->lastReadStatus = ERR_CONNECT_FAILED;
1106  return String("");
1107  }
1108 
1109  String URL = String("/channels/") + String(channelNumber) + URLSuffix;
1110 
1111  #ifdef PRINT_DEBUG_MESSAGES
1112  Serial.print(" GET \"");Serial.print(URL);Serial.println("\"");
1113  #endif
1114 
1115  // Post data to thingspeak
1116  if(!this->client->print("GET ")) return abortReadRaw();
1117  if(!this->client->print(URL)) return abortReadRaw();
1118  if(!this->client->print(" HTTP/1.1\n")) return abortReadRaw();
1119  if(!writeHTTPHeader(readAPIKey)) return abortReadRaw();
1120  if(!this->client->print("\n")) return abortReadRaw();
1121 
1122  String content = String();
1123  int status = getHTTPResponse(content);
1124 
1125  this->lastReadStatus = status;
1126 
1127 
1128  #ifdef PRINT_DEBUG_MESSAGES
1129  if(status == OK_SUCCESS)
1130  {
1131  Serial.print("Read: \""); Serial.print(content); Serial.println("\"");
1132  }
1133  #endif
1134 
1135  client->stop();
1136  #ifdef PRINT_DEBUG_MESSAGES
1137  Serial.println("disconnected.");
1138  #endif
1139 
1140  if(status != OK_SUCCESS)
1141  {
1142  // return status;
1143  return String("");
1144  }
1145 
1146  // This is a workaround to a bug in the Spark implementation of String
1147  return String("") + content;
1148  };
1149 
1184  {
1185  return this->lastReadStatus;
1186  };
1187 private:
1188 
1189  int abortWriteRaw()
1190  {
1191  this->client->stop();
1192  return ERR_UNEXPECTED_FAIL;
1193  }
1194 
1195  String abortReadRaw()
1196  {
1197  this->client->stop();
1198  #ifdef PRINT_DEBUG_MESSAGES
1199  Serial.println("ReadRaw abort - disconnected.");
1200  #endif
1201  this->lastReadStatus = ERR_UNEXPECTED_FAIL;
1202  return String("");
1203  }
1204 
1205  void setServer(const char * customHostName, unsigned int port)
1206  {
1207  #ifdef PRINT_DEBUG_MESSAGES
1208  Serial.print("ts::setServer (URL: \""); Serial.print(customHostName); Serial.println("\")");
1209  #endif
1210  this->customIP = INADDR_NONE;
1211  this->customHostName = customHostName;
1212  this->port = port;
1213  };
1214 
1215  void setServer(IPAddress customIP, unsigned int port)
1216  {
1217  #ifdef PRINT_DEBUG_MESSAGES
1218  Serial.print("ts::setServer (IP: \""); Serial.print(customIP); Serial.println("\")");
1219  #endif
1220  this->customIP = customIP;
1221  this->customHostName = NULL;
1222  this->port = port;
1223  };
1224 
1225  void setServer()
1226  {
1227  #ifdef PRINT_DEBUG_MESSAGES
1228  Serial.print("ts::setServer (default)");
1229  #endif
1230  this->customIP = INADDR_NONE;
1231  this->customHostName = NULL;
1232  this->port = THINGSPEAK_PORT_NUMBER;
1233  };
1234 
1235  void setClient(Client * client) {this->client = client;};
1236 
1237  Client * client = NULL;
1238  const char * customHostName = NULL;
1239  IPAddress customIP = INADDR_NONE;
1240  unsigned int port = THINGSPEAK_PORT_NUMBER;
1241  String nextWriteField[8];
1242  float nextWriteLatitude;
1243  float nextWriteLongitude;
1244  float nextWriteElevation;
1245  int lastReadStatus;
1246 
1247  bool connectThingSpeak()
1248  {
1249  bool connectSuccess = false;
1250  if(this->customIP == INADDR_NONE && NULL == this->customHostName)
1251  {
1252  #ifdef PRINT_DEBUG_MESSAGES
1253  Serial.print(" Connect to default ThingSpeak URL...");
1254  #endif
1255  connectSuccess = client->connect(THINGSPEAK_URL,THINGSPEAK_PORT_NUMBER);
1256  if(!connectSuccess)
1257  {
1258  #ifdef PRINT_DEBUG_MESSAGES
1259  Serial.print("Failed. Try default IP...");
1260  #endif
1261  connectSuccess = client->connect(THINGSPEAK_IPADDRESS,THINGSPEAK_PORT_NUMBER);
1262  }
1263  }
1264  else
1265  {
1266  if(!(this->customIP == INADDR_NONE))
1267  {
1268  // Connect to the server on port 80 (HTTP) at the customIP address
1269  #ifdef PRINT_DEBUG_MESSAGES
1270  Serial.print(" Connect to ");Serial.print(this->customIP);Serial.print("...");
1271  #endif
1272  connectSuccess = client->connect(this->customIP,this->port);
1273  }
1274  if(NULL != this->customHostName)
1275  {
1276  // Connect to the server on port 80 (HTTP) at the URL address
1277  #ifdef PRINT_DEBUG_MESSAGES
1278  Serial.print(" Connect to ");Serial.print(this->customHostName);Serial.print(" ...");
1279  #endif
1280  connectSuccess = client->connect(customHostName,this->port);
1281  }
1282  }
1283 
1284  #ifdef PRINT_DEBUG_MESSAGES
1285  if (connectSuccess)
1286  {
1287  Serial.println("Success.");
1288  }
1289  else
1290  {
1291  Serial.println("Failed.");
1292  }
1293  #endif
1294  return connectSuccess;
1295  };
1296 
1297  bool writeHTTPHeader(const char * APIKey)
1298  {
1299  if(NULL != this->customHostName)
1300  {
1301  if (!this->client->print("Host: ")) return false;
1302  if (!this->client->print(this->customHostName)) return false;
1303  if (!this->client->print("\n")) return false;
1304  }
1305  else
1306  {
1307  if (!this->client->print("Host: api.thingspeak.com\n")) return false;
1308  }
1309  if (!this->client->print("Connection: close\n")) return false;
1310  if (!this->client->print("User-Agent: ")) return false;
1311  if (!this->client->print(TS_USER_AGENT)) return false;
1312  if (!this->client->print("\n")) return false;
1313  if(NULL != APIKey)
1314  {
1315  if (!this->client->print("X-THINGSPEAKAPIKEY: ")) return false;
1316  if (!this->client->print(APIKey)) return false;
1317  if (!this->client->print("\n")) return false;
1318  }
1319  return true;
1320  };
1321 
1322  int getHTTPResponse(String & response)
1323  {
1324  long startWaitForResponseAt = millis();
1325  while(client->available() == 0 && millis() - startWaitForResponseAt < TIMEOUT_MS_SERVERRESPONSE)
1326  {
1327  delay(100);
1328  }
1329  if(client->available() == 0)
1330  {
1331  return ERR_TIMEOUT; // Didn't get server response in time
1332  }
1333 
1334  if(!client->find(const_cast<char *>("HTTP/1.1")))
1335  {
1336  #ifdef PRINT_HTTP
1337  Serial.println("ERROR: Didn't find HTTP/1.1");
1338  #endif
1339  return ERR_BAD_RESPONSE; // Couldn't parse response (didn't find HTTP/1.1)
1340  }
1341  int status = client->parseInt();
1342  #ifdef PRINT_HTTP
1343  Serial.print("Got Status of ");Serial.println(status);
1344  #endif
1345  if(status != OK_SUCCESS)
1346  {
1347  return status;
1348  }
1349 
1350  if(!client->find(const_cast<char *>("\r\n")))
1351  {
1352  #ifdef PRINT_HTTP
1353  Serial.println("ERROR: Didn't find end of status line");
1354  #endif
1355  return ERR_BAD_RESPONSE;
1356  }
1357  #ifdef PRINT_HTTP
1358  Serial.println("Found end of status line");
1359  #endif
1360 
1361  if(!client->find(const_cast<char *>("\n\r\n")))
1362  {
1363  #ifdef PRINT_HTTP
1364  Serial.println("ERROR: Didn't find end of header");
1365  #endif
1366  return ERR_BAD_RESPONSE;
1367  }
1368  #ifdef PRINT_HTTP
1369  Serial.println("Found end of header");
1370  #endif
1371  // This is a workaround to a bug in the Spark implementation of String
1372  String tempString = client->readStringUntil('\r');
1373  response = tempString;
1374  #ifdef PRINT_HTTP
1375  Serial.print("Response: \"");Serial.print(response);Serial.println("\"");
1376  #endif
1377  return status;
1378  };
1379 
1380  int convertFloatToChar(float value, char *valueString)
1381  {
1382  // Supported range is -999999000000 to 999999000000
1383  if(0 == isinf(value) && (value > 999999000000 || value < -999999000000))
1384  {
1385  // Out of range
1386  return ERR_OUT_OF_RANGE;
1387  }
1388  // assume that 5 places right of decimal should be sufficient for most applications
1389 
1390  #if defined(ARDUINO_ARCH_SAMD) || defined(ARDUINO_ARCH_SAM)
1391  sprintf(valueString, "%.5f", value);
1392  #else
1393  dtostrf(value,1,5, valueString);
1394  #endif
1395  return OK_SUCCESS;
1396  };
1397 
1398  float convertStringToFloat(String value)
1399  {
1400  // There's a bug in the AVR function strtod that it doesn't decode -INF correctly (it maps it to INF)
1401  float result = value.toFloat();
1402  if(1 == isinf(result) && *value.c_str() == '-')
1403  {
1404  result = (float)-INFINITY;
1405  }
1406  return result;
1407  };
1408 
1409  void resetWriteFields()
1410  {
1411  for(size_t iField = 0; iField < 8; iField++)
1412  {
1413  this->nextWriteField[iField] = "";
1414  }
1415  this->nextWriteLatitude = NAN;
1416  this->nextWriteLongitude = NAN;
1417  this->nextWriteElevation = NAN;
1418  };
1419 };
1420 
1421 extern ThingSpeakClass ThingSpeak;
1422 
1423 #endif //ThingSpeak_h
int writeRaw(unsigned long channelNumber, const char *postMessage, const char *writeAPIKey)
Write a raw POST to a ThingSpeak channel.
Definition: ThingSpeak.h:799
String readStringField(unsigned long channelNumber, unsigned int field, const char *readAPIKey)
Read the latest string from a private ThingSpeak channel.
Definition: ThingSpeak.h:890
String readStringField(unsigned long channelNumber, unsigned int field)
Read the latest string from a public ThingSpeak channel.
Definition: ThingSpeak.h:923
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:426
int writeRaw(unsigned long channelNumber, String postMessage, const char *writeAPIKey)
Write a raw POST to a ThingSpeak channel.
Definition: ThingSpeak.h:820
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:171
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:717
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:385
int setLatitude(float latitude)
Set the latitude of a multi-field update. To record latitude, longitude and elevation of a write...
Definition: ThingSpeak.h:587
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:138
int getLastReadStatus()
Get the status of the previous read.
Definition: ThingSpeak.h:1183
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:230
Enables an Arduino, ESP8266, Particle or other compatible hardware to write or read data to or from T...
Definition: ThingSpeak.h:108
long readLongField(unsigned long channelNumber, unsigned int field, const char *readAPIKey)
Read the latest long from a private ThingSpeak channel.
Definition: ThingSpeak.h:987
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:339
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:505
String readRaw(unsigned long channelNumber, String URLSuffix)
Read a raw response from a public ThingSpeak channel.
Definition: ThingSpeak.h:1071
long readLongField(unsigned long channelNumber, unsigned int field)
Read the latest long from a public ThingSpeak channel.
Definition: ThingSpeak.h:1008
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:277
int readIntField(unsigned long channelNumber, unsigned int field, const char *readAPIKey)
Read the latest int from a private ThingSpeak channel.
Definition: ThingSpeak.h:1030
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:541
int setLongitude(float longitude)
Set the longitude of a multi-field update. To record latitude, longitude and elevation of a write...
Definition: ThingSpeak.h:630
float readFloatField(unsigned long channelNumber, unsigned int field, const char *readAPIKey)
Read the latest float from a private ThingSpeak channel.
Definition: ThingSpeak.h:945
bool begin(Client &client)
Initializes the ThingSpeak library and network settings using the ThingSpeak.com service.
Definition: ThingSpeak.h:202
float readFloatField(unsigned long channelNumber, unsigned int field)
Read the latest float from a public ThingSpeak channel.
Definition: ThingSpeak.h:966
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:310
int readIntField(unsigned long channelNumber, unsigned int field)
Read the latest int from a public ThingSpeak channel.
Definition: ThingSpeak.h:1051
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:465
String readRaw(unsigned long channelNumber, String URLSuffix, const char *readAPIKey)
Read a raw response from a private ThingSpeak channel.
Definition: ThingSpeak.h:1092
int setElevation(float elevation)
Set the elevation of a multi-field update. To record latitude, longitude and elevation of a write...
Definition: ThingSpeak.h:673
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:253