From 3ea4990c918231f41c61cfab9e556a80047e9f27 Mon Sep 17 00:00:00 2001 From: jasontwinters Date: Fri, 20 Jan 2017 11:17:18 -0500 Subject: [PATCH] Add files via upload --- .../documentation/_thing_speak_8h_source.html | 64 +-- extras/documentation/annotated.html | 24 +- .../class_thing_speak_class.html | 442 +++++++++++++++++- extras/documentation/classes.html | 22 +- .../dir_339e8c1d13ed9d171a31356d80f51341.html | 22 +- .../dir_9eb8a1162b9e86c4bf1f8e762bfe83d1.html | 22 +- extras/documentation/functions.html | 72 ++- extras/documentation/functions_func.html | 72 ++- extras/documentation/index.html | 22 +- extras/test/testBegin/testBegin.ino | 11 +- extras/test/testReadField/testReadField.ino | 104 ++++- extras/test/testSetField/testSetField.ino | 175 ++++++- extras/test/testWriteField/testWriteField.ino | 6 +- 13 files changed, 898 insertions(+), 160 deletions(-) diff --git a/extras/documentation/_thing_speak_8h_source.html b/extras/documentation/_thing_speak_8h_source.html index 7a61c21..cfbe3cb 100644 --- a/extras/documentation/_thing_speak_8h_source.html +++ b/extras/documentation/_thing_speak_8h_source.html @@ -1,7 +1,7 @@ - @@ -9,7 +9,7 @@ -ThingSpeak Communication Library For Arduino, ESP8266, and Particle +ThingSpeak Communication Library For Arduino and ESP8266 @@ -23,7 +23,7 @@
ThingSpeak Communication Library
-
Enables an Arduino, ESP8266, or Particle to write or read data to or from ThingSpeak™
+
Enables an Arduino or ESP8266 to write or read data to or from ThingSpeak™
Logo @@ -48,43 +48,55 @@
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
+
1 /*
2  ThingSpeak(TM) Communication Library For Arduino and ESP8266
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 2017, 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.3 (arduino yun)"
72  #else
73  #define TS_USER_AGENT "tslib-arduino/1.3 (arduino uno or mega)"
74  #endif
75 #elif defined(ARDUINO_ARCH_ESP8266)
76  #define TS_USER_AGENT "tslib-arduino/1.3 (ESP8266)"
77 #elif defined(ARDUINO_SAMD_MKR1000)
78  #define TS_USER_AGENT "tslib-arduino/1.3 (arduino mkr1000)"
79 #elif defined(ARDUINO_SAM_DUE)
80  #define TS_USER_AGENT "tslib-arduino/1.3 (arduino due)"
81 #elif defined(ARDUINO_ARCH_SAMD) || defined(ARDUINO_ARCH_SAM)
82  #define TS_USER_AGENT "tslib-arduino/1.3 (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 
715  int setStatus(const char * status)
716  {
717  return setStatus(String(status));
718  };
719 
752  int setStatus(String status)
753  {
754  #ifdef PRINT_DEBUG_MESSAGES
755  Serial.print("ts::setStatus(status: "); Serial.print(status); Serial.println("\")");
756  #endif
757  // Max # bytes for ThingSpeak field is 255 (UTF-8)
758  if(status.length() > FIELDLENGTH_MAX) return ERR_OUT_OF_RANGE;
759  this->nextWriteStatus = status;
760  return OK_SUCCESS;
761  };
762 
795  int setTwitterTweet(const char * twitter, const char * tweet)
796  {
797  return setTwitterTweet(String(twitter), String(tweet));
798  };
799 
832  int setTwitterTweet(String twitter, const char * tweet)
833  {
834  return setTwitterTweet(twitter, String(tweet));
835  };
836 
869  int setTwitterTweet(const char * twitter, String tweet)
870  {
871  return setTwitterTweet(String(twitter), tweet);
872  };
873 
906  int setTwitterTweet(String twitter, String tweet){
907  #ifdef PRINT_DEBUG_MESSAGES
908  Serial.print("ts::setTwitterTweet(twitter: "); Serial.print(twitter); Serial.print(", tweet: "); Serial.print(tweet); Serial.println("\")");
909  #endif
910  // Max # bytes for ThingSpeak field is 255 (UTF-8)
911  if((twitter.length() > FIELDLENGTH_MAX) || (tweet.length() > FIELDLENGTH_MAX)) return ERR_OUT_OF_RANGE;
912 
913  this->nextWriteTwitter = twitter;
914  this->nextWriteTweet = tweet;
915 
916  return OK_SUCCESS;
917  };
918 
951  int setCreatedAt(const char * createdAt)
952  {
953  return setCreatedAt(String(createdAt));
954  }
955 
988  int setCreatedAt(String createdAt)
989  {
990  #ifdef PRINT_DEBUG_MESSAGES
991  Serial.print("ts::setCreatedAt(createdAt: "); Serial.print(createdAt); Serial.println("\")");
992  #endif
993 
994  // the ISO 8601 format is too complicated to check for valid timestamps here
995  // we'll need to reply on the api to tell us if there is a problem
996  // Max # bytes for ThingSpeak field is 255 (UTF-8)
997  if(createdAt.length() > FIELDLENGTH_MAX) return ERR_OUT_OF_RANGE;
998  this->nextWriteCreatedAt = createdAt;
999 
1000  return OK_SUCCESS;
1001  }
1002 
1003 
1038  int writeFields(unsigned long channelNumber, const char * writeAPIKey)
1039  {
1040  String postMessage = String("");
1041  bool fFirstItem = true;
1042  for(size_t iField = 0; iField < 8; iField++)
1043  {
1044  if(this->nextWriteField[iField].length() > 0)
1045  {
1046  if(!fFirstItem)
1047  {
1048  postMessage = postMessage + String("&");
1049  }
1050  postMessage = postMessage + String("field") + String(iField + 1) + String("=") + this->nextWriteField[iField];
1051  fFirstItem = false;
1052  this->nextWriteField[iField] = "";
1053  }
1054  }
1055 
1056  if(!isnan(nextWriteLatitude))
1057  {
1058  if(!fFirstItem)
1059  {
1060  postMessage = postMessage + String("&");
1061  }
1062  postMessage = postMessage + String("lat=") + String(this->nextWriteLatitude);
1063  fFirstItem = false;
1064  this->nextWriteLatitude = NAN;
1065  }
1066 
1067  if(!isnan(this->nextWriteLongitude))
1068  {
1069  if(!fFirstItem)
1070  {
1071  postMessage = postMessage + String("&");
1072  }
1073  postMessage = postMessage + String("long=") + String(this->nextWriteLongitude);
1074  fFirstItem = false;
1075  this->nextWriteLongitude = NAN;
1076  }
1077 
1078 
1079  if(!isnan(this->nextWriteElevation))
1080  {
1081  if(!fFirstItem)
1082  {
1083  postMessage = postMessage + String("&");
1084  }
1085  postMessage = postMessage + String("elevation=") + String(this->nextWriteElevation);
1086  fFirstItem = false;
1087  this->nextWriteElevation = NAN;
1088  }
1089 
1090  if(this->nextWriteStatus.length() > 0)
1091  {
1092  if(!fFirstItem)
1093  {
1094  postMessage = postMessage + String("&");
1095  }
1096  postMessage = postMessage + String("status=") + String(this->nextWriteStatus);
1097  fFirstItem = false;
1098  this->nextWriteStatus = "";
1099  }
1100 
1101  if(this->nextWriteTwitter.length() > 0)
1102  {
1103  if(!fFirstItem)
1104  {
1105  postMessage = postMessage + String("&");
1106  }
1107  postMessage = postMessage + String("twitter=") + String(this->nextWriteTwitter);
1108  fFirstItem = false;
1109  this->nextWriteTwitter = "";
1110  }
1111 
1112  if(this->nextWriteTweet.length() > 0)
1113  {
1114  if(!fFirstItem)
1115  {
1116  postMessage = postMessage + String("&");
1117  }
1118  postMessage = postMessage + String("tweet=") + String(this->nextWriteTweet);
1119  fFirstItem = false;
1120  this->nextWriteTweet = "";
1121  }
1122 
1123  if(this->nextWriteCreatedAt.length() > 0)
1124  {
1125  if(!fFirstItem)
1126  {
1127  postMessage = postMessage + String("&");
1128  }
1129  postMessage = postMessage + String("created_at=") + String(this->nextWriteCreatedAt);
1130  fFirstItem = false;
1131  this->nextWriteCreatedAt = "";
1132  }
1133 
1134 
1135  if(fFirstItem)
1136  {
1137  // setField was not called before writeFields
1138  return ERR_SETFIELD_NOT_CALLED;
1139  }
1140 
1141  return writeRaw(channelNumber, postMessage, writeAPIKey);
1142  };
1143 
1144 
1165  int writeRaw(unsigned long channelNumber, const char * postMessage, const char * writeAPIKey)
1166  {
1167  return writeRaw(channelNumber, String(postMessage), writeAPIKey);
1168  };
1169 
1170 
1186  int writeRaw(unsigned long channelNumber, String postMessage, const char * writeAPIKey)
1187  {
1188  #ifdef PRINT_DEBUG_MESSAGES
1189  Serial.print("ts::writeRaw (channelNumber: "); Serial.print(channelNumber); Serial.print(" writeAPIKey: "); Serial.print(writeAPIKey); Serial.print(" postMessage: \""); Serial.print(postMessage); Serial.println("\")");
1190  #endif
1191 
1192  if(!connectThingSpeak())
1193  {
1194  // Failed to connect to ThingSpeak
1195  return ERR_CONNECT_FAILED;
1196  }
1197 
1198  postMessage = postMessage + String("&headers=false");
1199 
1200  #ifdef PRINT_DEBUG_MESSAGES
1201  Serial.print(" POST \"");Serial.print(postMessage);Serial.println("\"");
1202  #endif
1203 
1204  postMessage = postMessage + String("\n");
1205 
1206  // Post data to thingspeak
1207  if(!this->client->print("POST /update HTTP/1.1\r\n")) return abortWriteRaw();
1208  if(!writeHTTPHeader(writeAPIKey)) return abortWriteRaw();
1209  if(!this->client->print("Content-Type: application/x-www-form-urlencoded\r\n")) return abortWriteRaw();
1210  if(!this->client->print("Content-Length: ")) return abortWriteRaw();
1211  if(!this->client->print(postMessage.length())) return abortWriteRaw();
1212  if(!this->client->print("\r\n\r\n")) return abortWriteRaw();
1213  if(!this->client->print(postMessage)) return abortWriteRaw();
1214 
1215  String entryIDText = String();
1216  int status = getHTTPResponse(entryIDText);
1217  if(status != OK_SUCCESS)
1218  {
1219  client->stop();
1220  return status;
1221  }
1222  long entryID = entryIDText.toInt();
1223 
1224  #ifdef PRINT_DEBUG_MESSAGES
1225  Serial.print(" Entry ID \"");Serial.print(entryIDText);Serial.print("\" (");Serial.print(entryID);Serial.println(")");
1226  #endif
1227 
1228  client->stop();
1229 
1230  #ifdef PRINT_DEBUG_MESSAGES
1231  Serial.println("disconnected.");
1232  #endif
1233  if(entryID == 0)
1234  {
1235  // ThingSpeak did not accept the write
1236  status = ERR_NOT_INSERTED;
1237  }
1238  return status;
1239  };
1240 
1256  String readStringField(unsigned long channelNumber, unsigned int field, const char * readAPIKey)
1257  {
1258  if(field < FIELDNUM_MIN || field > FIELDNUM_MAX)
1259  {
1260  this->lastReadStatus = ERR_INVALID_FIELD_NUM;
1261  return("");
1262  }
1263  #ifdef PRINT_DEBUG_MESSAGES
1264  Serial.print("ts::readStringField(channelNumber: "); Serial.print(channelNumber);
1265  if(NULL != readAPIKey)
1266  {
1267  Serial.print(" readAPIKey: "); Serial.print(readAPIKey);
1268  }
1269  Serial.print(" field: "); Serial.print(field); Serial.println(")");
1270  #endif
1271  return readRaw(channelNumber, String(String("/fields/") + String(field) + String("/last")), readAPIKey);
1272  }
1273 
1274 
1289  String readStringField(unsigned long channelNumber, unsigned int field)
1290  {
1291  return readStringField(channelNumber, field, NULL);
1292  };
1293 
1294 
1311  float readFloatField(unsigned long channelNumber, unsigned int field, const char * readAPIKey)
1312  {
1313  return convertStringToFloat(readStringField(channelNumber, field, readAPIKey));
1314  };
1315 
1316 
1332  float readFloatField(unsigned long channelNumber, unsigned int field)
1333  {
1334  return readFloatField(channelNumber, field, NULL);
1335  };
1336 
1337 
1353  long readLongField(unsigned long channelNumber, unsigned int field, const char * readAPIKey)
1354  {
1355  // Note that although the function is called "toInt" it really returns a long.
1356  return readStringField(channelNumber, field, readAPIKey).toInt();
1357  }
1358 
1359 
1374  long readLongField(unsigned long channelNumber, unsigned int field)
1375  {
1376  return readLongField(channelNumber, field, NULL);
1377  };
1378 
1379 
1396  int readIntField(unsigned long channelNumber, unsigned int field, const char * readAPIKey)
1397  {
1398  return readLongField(channelNumber, field, readAPIKey);
1399  }
1400 
1401 
1417  int readIntField(unsigned long channelNumber, unsigned int field)
1418  {
1419  return readLongField(channelNumber, field, NULL);
1420  };
1421 
1436  String readStatus(unsigned long channelNumber, const char * readAPIKey)
1437  {
1438  String content = readRaw(channelNumber, "/feeds/last.txt?status=true", readAPIKey);
1439 
1440  if(getLastReadStatus() != OK_SUCCESS){
1441  return String("");
1442  }
1443 
1444  return getJSONValueByKey(content, "status");
1445  };
1446 
1460  String readStatus(unsigned long channelNumber)
1461  {
1462  return readStatus(channelNumber, NULL);
1463  };
1464 
1479  String readCreatedAt(unsigned long channelNumber, const char * readAPIKey)
1480  {
1481  String content = readRaw(channelNumber, "/feeds/last.txt", readAPIKey);
1482 
1483  if(getLastReadStatus() != OK_SUCCESS){
1484  return String("");
1485  }
1486 
1487  return getJSONValueByKey(content, "created_at");
1488  };
1489 
1503  String readCreatedAt(unsigned long channelNumber)
1504  {
1505  return readCreatedAt(channelNumber, NULL);
1506  };
1507 
1523  String readRaw(unsigned long channelNumber, String URLSuffix)
1524  {
1525  return readRaw(channelNumber, URLSuffix, NULL);
1526  }
1527 
1544  String readRaw(unsigned long channelNumber, String URLSuffix, const char * readAPIKey)
1545  {
1546  #ifdef PRINT_DEBUG_MESSAGES
1547  Serial.print("ts::readRaw (channelNumber: "); Serial.print(channelNumber);
1548  if(NULL != readAPIKey)
1549  {
1550  Serial.print(" readAPIKey: "); Serial.print(readAPIKey);
1551  }
1552  Serial.print(" URLSuffix: \""); Serial.print(URLSuffix); Serial.println("\")");
1553  #endif
1554 
1555  if(!connectThingSpeak())
1556  {
1557  this->lastReadStatus = ERR_CONNECT_FAILED;
1558  return String("");
1559  }
1560 
1561  String URL = String("/channels/") + String(channelNumber) + URLSuffix;
1562 
1563  #ifdef PRINT_DEBUG_MESSAGES
1564  Serial.print(" GET \"");Serial.print(URL);Serial.println("\"");
1565  #endif
1566 
1567  // Post data to thingspeak
1568  if(!this->client->print("GET ")) return abortReadRaw();
1569  if(!this->client->print(URL)) return abortReadRaw();
1570  if(!this->client->print(" HTTP/1.1\r\n")) return abortReadRaw();
1571  if(!writeHTTPHeader(readAPIKey)) return abortReadRaw();
1572  if(!this->client->print("\r\n")) return abortReadRaw();
1573 
1574  String content = String();
1575  int status = getHTTPResponse(content);
1576 
1577  this->lastReadStatus = status;
1578 
1579 
1580  #ifdef PRINT_DEBUG_MESSAGES
1581  if(status == OK_SUCCESS)
1582  {
1583  Serial.print("Read: \""); Serial.print(content); Serial.println("\"");
1584  }
1585  #endif
1586 
1587  client->stop();
1588  #ifdef PRINT_DEBUG_MESSAGES
1589  Serial.println("disconnected.");
1590  #endif
1591 
1592  if(status != OK_SUCCESS)
1593  {
1594  // return status;
1595  return String("");
1596  }
1597 
1598  // This is a workaround to a bug in the Spark implementation of String
1599  return String("") + content;
1600  };
1601 
1636  {
1637  return this->lastReadStatus;
1638  };
1639 private:
1640 
1641  String getJSONValueByKey(String textToSearch, String key)
1642  {
1643  if(textToSearch.length() == 0){
1644  return String("");
1645  }
1646 
1647  String searchPhrase = String("\"") + key + String("\":\"");
1648 
1649  int fromPosition = textToSearch.indexOf(searchPhrase,0);
1650 
1651  if(fromPosition == -1){
1652  // return because there is no status or it's null
1653  return String("");
1654  }
1655 
1656  fromPosition = fromPosition + searchPhrase.length();
1657 
1658  int toPosition = textToSearch.indexOf("\"", fromPosition);
1659 
1660 
1661  if(toPosition == -1){
1662  // return because there is no end quote
1663  return String("");
1664  }
1665 
1666  textToSearch.remove(toPosition);
1667 
1668  return textToSearch.substring(fromPosition);
1669  }
1670 
1671  int abortWriteRaw()
1672  {
1673  this->client->stop();
1674  return ERR_UNEXPECTED_FAIL;
1675  }
1676 
1677  String abortReadRaw()
1678  {
1679  this->client->stop();
1680  #ifdef PRINT_DEBUG_MESSAGES
1681  Serial.println("ReadRaw abort - disconnected.");
1682  #endif
1683  this->lastReadStatus = ERR_UNEXPECTED_FAIL;
1684  return String("");
1685  }
1686 
1687  void setServer(const char * customHostName, unsigned int port)
1688  {
1689  #ifdef PRINT_DEBUG_MESSAGES
1690  Serial.print("ts::setServer (URL: \""); Serial.print(customHostName); Serial.println("\")");
1691  #endif
1692  this->customIP = INADDR_NONE;
1693  this->customHostName = customHostName;
1694  this->port = port;
1695  };
1696 
1697  void setServer(IPAddress customIP, unsigned int port)
1698  {
1699  #ifdef PRINT_DEBUG_MESSAGES
1700  Serial.print("ts::setServer (IP: \""); Serial.print(customIP); Serial.println("\")");
1701  #endif
1702  this->customIP = customIP;
1703  this->customHostName = NULL;
1704  this->port = port;
1705  };
1706 
1707  void setServer()
1708  {
1709  #ifdef PRINT_DEBUG_MESSAGES
1710  Serial.print("ts::setServer (default)");
1711  #endif
1712  this->customIP = INADDR_NONE;
1713  this->customHostName = NULL;
1714  this->port = THINGSPEAK_PORT_NUMBER;
1715  };
1716 
1717  void setClient(Client * client) {this->client = client;};
1718 
1719  Client * client = NULL;
1720  const char * customHostName = NULL;
1721  IPAddress customIP = INADDR_NONE;
1722  unsigned int port = THINGSPEAK_PORT_NUMBER;
1723  String nextWriteField[8];
1724  float nextWriteLatitude;
1725  float nextWriteLongitude;
1726  float nextWriteElevation;
1727  int lastReadStatus;
1728  String nextWriteStatus;
1729  String nextWriteTwitter;
1730  String nextWriteTweet;
1731  String nextWriteCreatedAt;
1732 
1733  bool connectThingSpeak()
1734  {
1735  bool connectSuccess = false;
1736  if(this->customIP == INADDR_NONE && NULL == this->customHostName)
1737  {
1738  #ifdef PRINT_DEBUG_MESSAGES
1739  Serial.print(" Connect to default ThingSpeak URL...");
1740  #endif
1741  connectSuccess = client->connect(THINGSPEAK_URL,THINGSPEAK_PORT_NUMBER);
1742  if(!connectSuccess)
1743  {
1744  #ifdef PRINT_DEBUG_MESSAGES
1745  Serial.print("Failed. Try default IP...");
1746  #endif
1747  connectSuccess = client->connect(THINGSPEAK_IPADDRESS,THINGSPEAK_PORT_NUMBER);
1748  }
1749  }
1750  else
1751  {
1752  if(!(this->customIP == INADDR_NONE))
1753  {
1754  // Connect to the server on port 80 (HTTP) at the customIP address
1755  #ifdef PRINT_DEBUG_MESSAGES
1756  Serial.print(" Connect to ");Serial.print(this->customIP);Serial.print("...");
1757  #endif
1758  connectSuccess = client->connect(this->customIP,this->port);
1759  }
1760  if(NULL != this->customHostName)
1761  {
1762  // Connect to the server on port 80 (HTTP) at the URL address
1763  #ifdef PRINT_DEBUG_MESSAGES
1764  Serial.print(" Connect to ");Serial.print(this->customHostName);Serial.print(" ...");
1765  #endif
1766  connectSuccess = client->connect(customHostName,this->port);
1767  }
1768  }
1769 
1770  #ifdef PRINT_DEBUG_MESSAGES
1771  if (connectSuccess)
1772  {
1773  Serial.println("Success.");
1774  }
1775  else
1776  {
1777  Serial.println("Failed.");
1778  }
1779  #endif
1780  return connectSuccess;
1781  };
1782 
1783  bool writeHTTPHeader(const char * APIKey)
1784  {
1785  if(NULL != this->customHostName)
1786  {
1787  if (!this->client->print("Host: ")) return false;
1788  if (!this->client->print(this->customHostName)) return false;
1789  if (!this->client->print("\r\n")) return false;
1790  }
1791  else
1792  {
1793  if (!this->client->print("Host: api.thingspeak.com\r\n")) return false;
1794  }
1795  if (!this->client->print("Connection: close\r\n")) return false;
1796  if (!this->client->print("User-Agent: ")) return false;
1797  if (!this->client->print(TS_USER_AGENT)) return false;
1798  if (!this->client->print("\r\n")) return false;
1799  if(NULL != APIKey)
1800  {
1801  if (!this->client->print("X-THINGSPEAKAPIKEY: ")) return false;
1802  if (!this->client->print(APIKey)) return false;
1803  if (!this->client->print("\r\n")) return false;
1804  }
1805  return true;
1806  };
1807 
1808  int getHTTPResponse(String & response)
1809  {
1810  long startWaitForResponseAt = millis();
1811  while(client->available() == 0 && millis() - startWaitForResponseAt < TIMEOUT_MS_SERVERRESPONSE)
1812  {
1813  delay(100);
1814  }
1815  if(client->available() == 0)
1816  {
1817  return ERR_TIMEOUT; // Didn't get server response in time
1818  }
1819 
1820  if(!client->find(const_cast<char *>("HTTP/1.1")))
1821  {
1822  #ifdef PRINT_HTTP
1823  Serial.println("ERROR: Didn't find HTTP/1.1");
1824  #endif
1825  return ERR_BAD_RESPONSE; // Couldn't parse response (didn't find HTTP/1.1)
1826  }
1827  int status = client->parseInt();
1828  #ifdef PRINT_HTTP
1829  Serial.print("Got Status of ");Serial.println(status);
1830  #endif
1831  if(status != OK_SUCCESS)
1832  {
1833  return status;
1834  }
1835 
1836  if(!client->find(const_cast<char *>("\r\n")))
1837  {
1838  #ifdef PRINT_HTTP
1839  Serial.println("ERROR: Didn't find end of status line");
1840  #endif
1841  return ERR_BAD_RESPONSE;
1842  }
1843  #ifdef PRINT_HTTP
1844  Serial.println("Found end of status line");
1845  #endif
1846 
1847  if(!client->find(const_cast<char *>("\n\r\n")))
1848  {
1849  #ifdef PRINT_HTTP
1850  Serial.println("ERROR: Didn't find end of header");
1851  #endif
1852  return ERR_BAD_RESPONSE;
1853  }
1854  #ifdef PRINT_HTTP
1855  Serial.println("Found end of header");
1856  #endif
1857 
1858  String tempString = client->readString();
1859  response = tempString;
1860  #ifdef PRINT_HTTP
1861  Serial.print("Response: \"");Serial.print(response);Serial.println("\"");
1862  #endif
1863  return status;
1864  };
1865 
1866  int convertFloatToChar(float value, char *valueString)
1867  {
1868  // Supported range is -999999000000 to 999999000000
1869  if(0 == isinf(value) && (value > 999999000000 || value < -999999000000))
1870  {
1871  // Out of range
1872  return ERR_OUT_OF_RANGE;
1873  }
1874  // assume that 5 places right of decimal should be sufficient for most applications
1875 
1876  #if defined(ARDUINO_ARCH_SAMD) || defined(ARDUINO_ARCH_SAM)
1877  sprintf(valueString, "%.5f", value);
1878  #else
1879  dtostrf(value,1,5, valueString);
1880  #endif
1881  return OK_SUCCESS;
1882  };
1883 
1884  float convertStringToFloat(String value)
1885  {
1886  // There's a bug in the AVR function strtod that it doesn't decode -INF correctly (it maps it to INF)
1887  float result = value.toFloat();
1888 
1889  if(1 == isinf(result) && *value.c_str() == '-')
1890  {
1891  result = (float)-INFINITY;
1892  }
1893  return result;
1894  };
1895 
1896  void resetWriteFields()
1897  {
1898  for(size_t iField = 0; iField < 8; iField++)
1899  {
1900  this->nextWriteField[iField] = "";
1901  }
1902  this->nextWriteLatitude = NAN;
1903  this->nextWriteLongitude = NAN;
1904  this->nextWriteElevation = NAN;
1905  this->nextWriteStatus = "";
1906  this->nextWriteTwitter = "";
1907  this->nextWriteTweet = "";
1908  this->nextWriteCreatedAt = "";
1909  };
1910 };
1911 
1912 extern ThingSpeakClass ThingSpeak;
1913 
1914 #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:1165
+
int setTwitterTweet(const char *twitter, const char *tweet)
Set the Twitter account and message to use for an update to be tweeted. To send a message to twitter ...
Definition: ThingSpeak.h:795
+
String readStringField(unsigned long channelNumber, unsigned int field, const char *readAPIKey)
Read the latest string from a private ThingSpeak channel.
Definition: ThingSpeak.h:1256
+
String readStringField(unsigned long channelNumber, unsigned int field)
Read the latest string from a public ThingSpeak channel.
Definition: ThingSpeak.h:1289
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
+
String readCreatedAt(unsigned long channelNumber)
Read the created-at timestamp associated with the latest update to a private ThingSpeak channel...
Definition: ThingSpeak.h:1503
+
int writeRaw(unsigned long channelNumber, String postMessage, const char *writeAPIKey)
Write a raw POST to a ThingSpeak channel.
Definition: ThingSpeak.h:1186
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 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:1038
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 setTwitterTweet(const char *twitter, String tweet)
Set the Twitter account and message to use for an update to be tweeted. To send a message to twitter ...
Definition: ThingSpeak.h:869
+
int setTwitterTweet(String twitter, const char *tweet)
Set the Twitter account and message to use for an update to be tweeted. To send a message to twitter ...
Definition: ThingSpeak.h:832
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
+
String readCreatedAt(unsigned long channelNumber, const char *readAPIKey)
Read the created-at timestamp associated with the latest update to a private ThingSpeak channel...
Definition: ThingSpeak.h:1479
+
int setStatus(String status)
Set the status of a multi-field update. To record a status message on a write, call setStatus() then ...
Definition: ThingSpeak.h:752
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 getLastReadStatus()
Get the status of the previous read.
Definition: ThingSpeak.h:1635
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
+
Enables an Arduino, ESP8266 or other compatible hardware to write or read data to or from ThingSpeak...
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:1353
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 setStatus(const char *status)
Set the status of a multi-field update. To record a status message on a write, call setStatus() then ...
Definition: ThingSpeak.h:715
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
+
String readRaw(unsigned long channelNumber, String URLSuffix)
Read a raw response from a public ThingSpeak channel.
Definition: ThingSpeak.h:1523
+
long readLongField(unsigned long channelNumber, unsigned int field)
Read the latest long from a public ThingSpeak channel.
Definition: ThingSpeak.h:1374
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 setCreatedAt(const char *createdAt)
Set the created-at date of a multi-field update. To record created-at of a write, call setField() for...
Definition: ThingSpeak.h:951
+
int readIntField(unsigned long channelNumber, unsigned int field, const char *readAPIKey)
Read the latest int from a private ThingSpeak channel.
Definition: ThingSpeak.h:1396
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 setCreatedAt(String createdAt)
Set the created-at date of a multi-field update. To record created-at of a write, call setField() for...
Definition: ThingSpeak.h:988
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
+
float readFloatField(unsigned long channelNumber, unsigned int field, const char *readAPIKey)
Read the latest float from a private ThingSpeak channel.
Definition: ThingSpeak.h:1311
+
int setTwitterTweet(String twitter, String tweet)
Set the Twitter account and message to use for an update to be tweeted. To send a message to twitter ...
Definition: ThingSpeak.h:906
+
String readStatus(unsigned long channelNumber, const char *readAPIKey)
Read the latest status from a private ThingSpeak channel.
Definition: ThingSpeak.h:1436
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
+
float readFloatField(unsigned long channelNumber, unsigned int field)
Read the latest float from a public ThingSpeak channel.
Definition: ThingSpeak.h:1332
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 readIntField(unsigned long channelNumber, unsigned int field)
Read the latest int from a public ThingSpeak channel.
Definition: ThingSpeak.h:1417
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
+
String readRaw(unsigned long channelNumber, String URLSuffix, const char *readAPIKey)
Read a raw response from a private ThingSpeak channel.
Definition: ThingSpeak.h:1544
+
String readStatus(unsigned long channelNumber)
Read the latest status from a public ThingSpeak channel.
Definition: ThingSpeak.h:1460
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
- diff --git a/extras/documentation/annotated.html b/extras/documentation/annotated.html index 28a7d51..419e2b3 100644 --- a/extras/documentation/annotated.html +++ b/extras/documentation/annotated.html @@ -1,7 +1,7 @@ - @@ -9,7 +9,7 @@ -ThingSpeak Communication Library For Arduino, ESP8266, and Particle +ThingSpeak Communication Library For Arduino and ESP8266 @@ -23,7 +23,7 @@
ThingSpeak Communication Library
-
Enables an Arduino, ESP8266, or Particle to write or read data to or from ThingSpeak™
+
Enables an Arduino or ESP8266 to write or read data to or from ThingSpeak™
Logo @@ -52,15 +52,15 @@
Here are the data structures with brief descriptions:
- +
 CThingSpeakClassEnables an Arduino, ESP8266, Particle or other compatible hardware to write or read data to or from ThingSpeak, an open data platform for the Internet of Things with MATLAB analytics and visualization
 CThingSpeakClassEnables an Arduino, ESP8266 or other compatible hardware to write or read data to or from ThingSpeak, an open data platform for the Internet of Things with MATLAB analytics and visualization
- diff --git a/extras/documentation/class_thing_speak_class.html b/extras/documentation/class_thing_speak_class.html index 199b6dc..83ff234 100644 --- a/extras/documentation/class_thing_speak_class.html +++ b/extras/documentation/class_thing_speak_class.html @@ -1,7 +1,7 @@ - @@ -9,7 +9,7 @@ -ThingSpeak Communication Library For Arduino, ESP8266, and Particle +ThingSpeak Communication Library For Arduino and ESP8266 @@ -23,7 +23,7 @@
ThingSpeak Communication Library
-
Enables an Arduino, ESP8266, or Particle to write or read data to or from ThingSpeak™
+
Enables an Arduino or ESP8266 to write or read data to or from ThingSpeak™
Logo @@ -53,7 +53,7 @@
-

Enables an Arduino, ESP8266, Particle or other compatible hardware to write or read data to or from ThingSpeak, an open data platform for the Internet of Things with MATLAB analytics and visualization. +

Enables an Arduino, ESP8266 or other compatible hardware to write or read data to or from ThingSpeak, an open data platform for the Internet of Things with MATLAB analytics and visualization. More...

+ + + + + + + + + + + + + + + + + + + + + + + + @@ -139,6 +163,18 @@ + + + + + + + + + + + + @@ -150,7 +186,7 @@

@@ -106,6 +106,30 @@

int setElevation (float elevation)
 Set the elevation of a multi-field update. To record latitude, longitude and elevation of a write, call setField() for each of the fields you want to write, setLatitude() / setLongitude() / setElevation(), and then call writeFields() More...
 
int setStatus (const char *status)
 Set the status of a multi-field update. To record a status message on a write, call setStatus() then call writeFields(). Use status to provide additonal details when writing a channel update. Additonally, status can be used by the ThingTweet App to send a message to Twitter. More...
 
int setStatus (String status)
 Set the status of a multi-field update. To record a status message on a write, call setStatus() then call writeFields(). Use status to provide additonal details when writing a channel update. Additonally, status can be used by the ThingTweet App to send a message to Twitter. More...
 
int setTwitterTweet (const char *twitter, const char *tweet)
 Set the Twitter account and message to use for an update to be tweeted. To send a message to twitter call setTwitterTweet() then call writeFields() More...
 
int setTwitterTweet (String twitter, const char *tweet)
 Set the Twitter account and message to use for an update to be tweeted. To send a message to twitter call setTwitterTweet() then call writeFields() More...
 
int setTwitterTweet (const char *twitter, String tweet)
 Set the Twitter account and message to use for an update to be tweeted. To send a message to twitter call setTwitterTweet() then call writeFields() More...
 
int setTwitterTweet (String twitter, String tweet)
 Set the Twitter account and message to use for an update to be tweeted. To send a message to twitter call setTwitterTweet() then call writeFields() More...
 
int setCreatedAt (const char *createdAt)
 Set the created-at date of a multi-field update. To record created-at of a write, call setField() for each of the fields you want to write, setCreatedAt(), and then call writeFields() More...
 
int setCreatedAt (String createdAt)
 Set the created-at date of a multi-field update. To record created-at of a write, call setField() for each of the fields you want to write, setCreatedAt(), and then call writeFields() More...
 
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() More...
 
int readIntField (unsigned long channelNumber, unsigned int field)
 Read the latest int from a public ThingSpeak channel. More...
 
String readStatus (unsigned long channelNumber, const char *readAPIKey)
 Read the latest status from a private ThingSpeak channel. More...
 
String readStatus (unsigned long channelNumber)
 Read the latest status from a public ThingSpeak channel. More...
 
String readCreatedAt (unsigned long channelNumber, const char *readAPIKey)
 Read the created-at timestamp associated with the latest update to a private ThingSpeak channel. More...
 
String readCreatedAt (unsigned long channelNumber)
 Read the created-at timestamp associated with the latest update to a private ThingSpeak channel. More...
 
String readRaw (unsigned long channelNumber, String URLSuffix)
 Read a raw response from a public ThingSpeak channel. More...
 
 

Detailed Description

-

Enables an Arduino, ESP8266, Particle or other compatible hardware to write or read data to or from ThingSpeak, an open data platform for the Internet of Things with MATLAB analytics and visualization.

+

Enables an Arduino, ESP8266 or other compatible hardware to write or read data to or from ThingSpeak, an open data platform for the Internet of Things with MATLAB analytics and visualization.

Member Function Documentation

@@ -292,6 +328,67 @@
Remarks
The read functions will return zero or empty if there is an error. Use this function to retrieve the details.
void loop() {
String message = ThingSpeak.readStringField(myChannelNumber, 1);
int resultCode = ThingSpeak.getLastReadStatus();
if(resultCode == 200)
{
Serial.print("Latest message is: ");
Serial.println(message);
}
else
{
Serial.print("Error reading message. Status was: ");
Serial.println(resultCode);
}
delay(30000);
}
+
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
String readCreatedAt (unsigned long channelNumber,
const char * readAPIKey 
)
+
+ +

Read the created-at timestamp associated with the latest update to a private ThingSpeak channel.

+
Parameters
+ + + +
channelNumberChannel number
readAPIKeyRead API key associated with the channel. If you share code with others, do not share this key
+
+
+
Returns
Value read (UTF8 string). An empty string is returned if there was no created-at timestamp written to the channel or in case of an error. Use getLastReadStatus() to get more specific information.
void loop() {
String value = ThingSpeak.readCreatedAt(myChannelNumber);
Serial.print("Latest update timestamp is: ");
Serial.print(value);
delay(30000);
}
+ +
+
+ +
+
+ + + + + + + + +
String readCreatedAt (unsigned long channelNumber)
+
+ +

Read the created-at timestamp associated with the latest update to a private ThingSpeak channel.

+
Parameters
+ + +
channelNumberChannel number
+
+
+
Returns
Value read (UTF8 string). An empty string is returned if there was no created-at timestamp written to the channel or in case of an error. Use getLastReadStatus() to get more specific information.
void loop() {
String value = ThingSpeak.readCreatedAt(myChannelNumber);
Serial.print("Latest update timestamp is: ");
Serial.print(value);
delay(30000);
}
+
@@ -612,6 +709,67 @@
Returns
Response if successful, or empty string. Use getLastReadStatus() to get more specific information.
Remarks
This is low level functionality that will not be required by most users.
void loop() {
String response = ThingSpeak.readRaw(myChannelNumber, String("feeds/days=1"), myReadAPIKey);
Serial.print("Response: ");
Serial.print(response);
delay(30000);
}
+
+ + +
+
+ + + + + + + + + + + + + + + + + + +
String readStatus (unsigned long channelNumber,
const char * readAPIKey 
)
+
+ +

Read the latest status from a private ThingSpeak channel.

+
Parameters
+ + + +
channelNumberChannel number
readAPIKeyRead API key associated with the channel. If you share code with others, do not share this key
+
+
+
Returns
Value read (UTF8 string). An empty string is returned if there was no status written to the channel or in case of an error. Use getLastReadStatus() to get more specific information.
void loop() {
String value = ThingSpeak.readStatus(myChannelNumber, myReadAPIKey);
Serial.print("Latest status is: ");
Serial.print(value);
delay(30000);
}
+ +
+
+ +
+
+ + + + + + + + +
String readStatus (unsigned long channelNumber)
+
+ +

Read the latest status from a public ThingSpeak channel.

+
Parameters
+ + +
channelNumberChannel number
+
+
+
Returns
Value read (UTF8 string). An empty string is returned if there was no status written to the channel or in case of an error. Use getLastReadStatus() to get more specific information.
void loop() {
String value = ThingSpeak.readStatus(myChannelNumber, myReadAPIKey);
Serial.print("Latest status is: ");
Serial.print(value);
delay(30000);
}
+
@@ -691,6 +849,60 @@
Returns
Value read (UTF8), or empty string if there is an error. Use getLastReadStatus() to get more specific information.
void loop() {
String message = ThingSpeak.readStringField(myChannelNumber, 1);
Serial.print("Latest message is: ");
Serial.println(message);
delay(30000);
}
+ + + +
+
+ + + + + + + + +
int setCreatedAt (const char * createdAt)
+
+ +

Set the created-at date of a multi-field update. To record created-at of a write, call setField() for each of the fields you want to write, setCreatedAt(), and then call writeFields()

+
Parameters
+ + +
createdAtDesired timestamp to be included with the channel update as a String. The timestamp string must be in the ISO 8601 format. Example "2017-01-12 13:22:54"
+
+
+
Returns
HTTP status code of 200 if successful. See getLastReadStatus() for other possible return values.
+
Remarks
Timezones can be set using the timezone hour offset parameter. For example, a timestamp for Eastern Standard Time is: "2017-01-12 13:22:54-05". If no timezone hour offset parameter is used, UTC time is assumed.
+
See also
setField(), writeFields()
void loop() {
int sensor1Value = analogRead(A0);
float sensor2Voltage = analogRead(A1) * (5.0 / 1023.0);
String sensor3Meaning;
int sensor3Value = analogRead(A2);
if (sensor3Value < 400) {
sensor3Meaning = String("Too Cold!");
} else if (sensor3Value > 600) {
sensor3Meaning = String("Too Hot!");
} else {
sensor3Meaning = String("Just Right");
}
long timeRead = millis();
ThingSpeak.setField(1, sensor1Value);
ThingSpeak.setField(2, sensor2Voltage);
ThingSpeak.setField(3, sensor3Meaning);
ThingSpeak.setField(4, timeRead);
ThingSpeak.setCreatedAt("2017-01-06T13:56:28");
ThingSpeak.writeFields(myChannelNumber, myWriteAPIKey);
delay(20000);
}
+ +
+
+ +
+
+ + + + + + + + +
int setCreatedAt (String createdAt)
+
+ +

Set the created-at date of a multi-field update. To record created-at of a write, call setField() for each of the fields you want to write, setCreatedAt(), and then call writeFields()

+
Parameters
+ + +
createdAtDesired timestamp to be included with the channel update as a String. The timestamp string must be in the ISO 8601 format. Example "2017-01-12 13:22:54"
+
+
+
Returns
HTTP status code of 200 if successful. See getLastReadStatus() for other possible return values.
+
Remarks
Timezones can be set using the timezone hour offset parameter. For example, a timestamp for Eastern Standard Time is: "2017-01-12 13:22:54-05". If no timezone hour offset parameter is used, UTC time is assumed.
+
See also
setField(), writeFields()
void loop() {
int sensor1Value = analogRead(A0);
float sensor2Voltage = analogRead(A1) * (5.0 / 1023.0);
String sensor3Meaning;
int sensor3Value = analogRead(A2);
if (sensor3Value < 400) {
sensor3Meaning = String("Too Cold!");
} else if (sensor3Value > 600) {
sensor3Meaning = String("Too Hot!");
} else {
sensor3Meaning = String("Just Right");
}
long timeRead = millis();
ThingSpeak.setField(1, sensor1Value);
ThingSpeak.setField(2, sensor2Voltage);
ThingSpeak.setField(3, sensor3Meaning);
ThingSpeak.setField(4, timeRead);
ThingSpeak.setCreatedAt("2017-01-06T13:56:28");
ThingSpeak.writeFields(myChannelNumber, myWriteAPIKey);
delay(20000);
}
+
@@ -954,6 +1166,210 @@
Returns
HTTP status code of 200 if successful. See getLastReadStatus() for other possible return values.
See also
setField(), setLatitude(), setElevation(), writeFields()
void loop() {
int sensor1Value = analogRead(A0);
float sensor2Voltage = analogRead(A1) * (5.0 / 1023.0);
String sensor3Meaning;
int sensor3Value = analogRead(A2);
if (sensor3Value < 400) {
sensor3Meaning = String("Too Cold!");
} else if (sensor3Value > 600) {
sensor3Meaning = String("Too Hot!");
} else {
sensor3Meaning = String("Just Right");
}
long timeRead = millis();
ThingSpeak.setField(1, sensor1Value);
ThingSpeak.setField(2, sensor2Voltage);
ThingSpeak.setField(3, sensor3Meaning);
ThingSpeak.setField(4, timeRead);
setLatitude(42.2833);
setLongitude(-71.3500);
ThingSpeak.writeFields(myChannelNumber, myWriteAPIKey);
delay(20000);
}
+ + + +
+
+ + + + + + + + +
int setStatus (const char * status)
+
+ +

Set the status of a multi-field update. To record a status message on a write, call setStatus() then call writeFields(). Use status to provide additonal details when writing a channel update. Additonally, status can be used by the ThingTweet App to send a message to Twitter.

+
Parameters
+ + +
statusString to write (UTF8). ThingSpeak limits this to 255 bytes.
+
+
+
Returns
HTTP status code of 200 if successful. See getLastReadStatus() for other possible return values.
+
See also
writeFields()
void loop() {
int sensor1Value = analogRead(A0);
float sensor2Voltage = analogRead(A1) * (5.0 / 1023.0);
String sensor3Meaning;
int sensor3Value = analogRead(A2);
if (sensor3Value < 400) {
sensor3Meaning = String("Too Cold!");
} else if (sensor3Value > 600) {
sensor3Meaning = String("Too Hot!");
} else {
sensor3Meaning = String("Just Right");
}
long timeRead = millis();
ThingSpeak.setField(1, sensor1Value);
ThingSpeak.setField(2, sensor2Voltage);
ThingSpeak.setField(3, timeRead);
ThingSpeak.setStatus(sensor3Meaning);
ThingSpeak.writeFields(myChannelNumber, myWriteAPIKey);
delay(20000);
}
+ +
+
+ +
+
+ + + + + + + + +
int setStatus (String status)
+
+ +

Set the status of a multi-field update. To record a status message on a write, call setStatus() then call writeFields(). Use status to provide additonal details when writing a channel update. Additonally, status can be used by the ThingTweet App to send a message to Twitter.

+
Parameters
+ + +
statusString to write (UTF8). ThingSpeak limits this to 255 bytes.
+
+
+
Returns
HTTP status code of 200 if successful. See getLastReadStatus() for other possible return values.
+
See also
writeFields()
void loop() {
int sensor1Value = analogRead(A0);
float sensor2Voltage = analogRead(A1) * (5.0 / 1023.0);
String sensor3Meaning;
int sensor3Value = analogRead(A2);
if (sensor3Value < 400) {
sensor3Meaning = String("Too Cold!");
} else if (sensor3Value > 600) {
sensor3Meaning = String("Too Hot!");
} else {
sensor3Meaning = String("Just Right");
}
long timeRead = millis();
ThingSpeak.setField(1, sensor1Value);
ThingSpeak.setField(2, sensor2Voltage);
ThingSpeak.setField(3, timeRead);
ThingSpeak.setStatus(sensor3Meaning);
ThingSpeak.writeFields(myChannelNumber, myWriteAPIKey);
delay(20000);
}
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
int setTwitterTweet (const char * twitter,
const char * tweet 
)
+
+ +

Set the Twitter account and message to use for an update to be tweeted. To send a message to twitter call setTwitterTweet() then call writeFields()

+
Parameters
+ + + +
twitterTwitter account name as a String.
tweetTwitter message as a String (UTF-8) limited to 140 character.
+
+
+
Returns
HTTP status code of 200 if successful. See getLastReadStatus() for other possible return values.
+
Remarks
Prior to using this feature, a twitter account must be linked to your ThingSpeak account. Do this by logging into ThingSpeak and going to Apps, then ThingTweet and clicking Link Twitter Account.
+
See also
writeFields(),getLastReadStatus()
void loop() {
int sensor1Value = analogRead(A0);
float sensor2Voltage = analogRead(A1) * (5.0 / 1023.0);
String sensor3Meaning;
int sensor3Value = analogRead(A2);
if (sensor3Value < 400) {
sensor3Meaning = String("Too Cold!");
} else if (sensor3Value > 600) {
sensor3Meaning = String("Too Hot!");
} else {
sensor3Meaning = String("Just Right");
}
long timeRead = millis();
ThingSpeak.setField(1, sensor1Value);
ThingSpeak.setField(2, sensor2Voltage);
ThingSpeak.setField(3, timeRead);
ThingSpeak.setTwitterTweet("YourTwitterAccountName",sensor3Meaning);
ThingSpeak.writeFields(myChannelNumber, myWriteAPIKey);
delay(20000);
}
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
int setTwitterTweet (String twitter,
const char * tweet 
)
+
+ +

Set the Twitter account and message to use for an update to be tweeted. To send a message to twitter call setTwitterTweet() then call writeFields()

+
Parameters
+ + + +
twitterTwitter account name as a String.
tweetTwitter message as a String (UTF-8) limited to 140 character.
+
+
+
Returns
HTTP status code of 200 if successful. See getLastReadStatus() for other possible return values.
+
Remarks
Prior to using this feature, a twitter account must be linked to your ThingSpeak account. Do this by logging into ThingSpeak and going to Apps, then ThingTweet and clicking Link Twitter Account.
+
See also
writeFields(),getLastReadStatus()
void loop() {
int sensor1Value = analogRead(A0);
float sensor2Voltage = analogRead(A1) * (5.0 / 1023.0);
String sensor3Meaning;
int sensor3Value = analogRead(A2);
if (sensor3Value < 400) {
sensor3Meaning = String("Too Cold!");
} else if (sensor3Value > 600) {
sensor3Meaning = String("Too Hot!");
} else {
sensor3Meaning = String("Just Right");
}
long timeRead = millis();
ThingSpeak.setField(1, sensor1Value);
ThingSpeak.setField(2, sensor2Voltage);
ThingSpeak.setField(3, timeRead);
ThingSpeak.setTwitterTweet("YourTwitterAccountName",sensor3Meaning);
ThingSpeak.writeFields(myChannelNumber, myWriteAPIKey);
delay(20000);
}
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
int setTwitterTweet (const char * twitter,
String tweet 
)
+
+ +

Set the Twitter account and message to use for an update to be tweeted. To send a message to twitter call setTwitterTweet() then call writeFields()

+
Parameters
+ + + +
twitterTwitter account name as a String.
tweetTwitter message as a String (UTF-8) limited to 140 character.
+
+
+
Returns
HTTP status code of 200 if successful. See getLastReadStatus() for other possible return values.
+
Remarks
Prior to using this feature, a twitter account must be linked to your ThingSpeak account. Do this by logging into ThingSpeak and going to Apps, then ThingTweet and clicking Link Twitter Account.
+
See also
writeFields(),getLastReadStatus()
void loop() {
int sensor1Value = analogRead(A0);
float sensor2Voltage = analogRead(A1) * (5.0 / 1023.0);
String sensor3Meaning;
int sensor3Value = analogRead(A2);
if (sensor3Value < 400) {
sensor3Meaning = String("Too Cold!");
} else if (sensor3Value > 600) {
sensor3Meaning = String("Too Hot!");
} else {
sensor3Meaning = String("Just Right");
}
long timeRead = millis();
ThingSpeak.setField(1, sensor1Value);
ThingSpeak.setField(2, sensor2Voltage);
ThingSpeak.setField(3, timeRead);
ThingSpeak.setTwitterTweet("YourTwitterAccountName",sensor3Meaning);
ThingSpeak.writeFields(myChannelNumber, myWriteAPIKey);
delay(20000);
}
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
int setTwitterTweet (String twitter,
String tweet 
)
+
+ +

Set the Twitter account and message to use for an update to be tweeted. To send a message to twitter call setTwitterTweet() then call writeFields()

+
Parameters
+ + + +
twitterTwitter account name as a String.
tweetTwitter message as a String (UTF-8) limited to 140 character.
+
+
+
Returns
HTTP status code of 200 if successful. See getLastReadStatus() for other possible return values.
+
Remarks
Prior to using this feature, a twitter account must be linked to your ThingSpeak account. Do this by logging into ThingSpeak and going to Apps, then ThingTweet and clicking Link Twitter Account.
+
See also
writeFields(),getLastReadStatus()
void loop() {
int sensor1Value = analogRead(A0);
float sensor2Voltage = analogRead(A1) * (5.0 / 1023.0);
String sensor3Meaning;
int sensor3Value = analogRead(A2);
if (sensor3Value < 400) {
sensor3Meaning = String("Too Cold!");
} else if (sensor3Value > 600) {
sensor3Meaning = String("Too Hot!");
} else {
sensor3Meaning = String("Just Right");
}
long timeRead = millis();
ThingSpeak.setField(1, sensor1Value);
ThingSpeak.setField(2, sensor2Voltage);
ThingSpeak.setField(3, timeRead);
ThingSpeak.setTwitterTweet("YourTwitterAccountName",sensor3Meaning);
ThingSpeak.writeFields(myChannelNumber, myWriteAPIKey);
delay(20000);
}
+
@@ -1338,10 +1754,10 @@ - diff --git a/extras/documentation/classes.html b/extras/documentation/classes.html index dbcb472..fc88f71 100644 --- a/extras/documentation/classes.html +++ b/extras/documentation/classes.html @@ -1,7 +1,7 @@ - @@ -9,7 +9,7 @@ -ThingSpeak Communication Library For Arduino, ESP8266, and Particle +ThingSpeak Communication Library For Arduino and ESP8266 @@ -23,7 +23,7 @@
ThingSpeak Communication Library
-
Enables an Arduino, ESP8266, or Particle to write or read data to or from ThingSpeak™
+
Enables an Arduino or ESP8266 to write or read data to or from ThingSpeak™
Logo @@ -61,10 +61,10 @@
T
- diff --git a/extras/documentation/dir_339e8c1d13ed9d171a31356d80f51341.html b/extras/documentation/dir_339e8c1d13ed9d171a31356d80f51341.html index e8e74d7..792ff98 100644 --- a/extras/documentation/dir_339e8c1d13ed9d171a31356d80f51341.html +++ b/extras/documentation/dir_339e8c1d13ed9d171a31356d80f51341.html @@ -1,7 +1,7 @@ - @@ -9,7 +9,7 @@ -ThingSpeak Communication Library For Arduino, ESP8266, and Particle +ThingSpeak Communication Library For Arduino and ESP8266 @@ -23,7 +23,7 @@
ThingSpeak Communication Library
-
Enables an Arduino, ESP8266, or Particle to write or read data to or from ThingSpeak™
+
Enables an Arduino or ESP8266 to write or read data to or from ThingSpeak™
Logo @@ -54,10 +54,10 @@ - diff --git a/extras/documentation/dir_9eb8a1162b9e86c4bf1f8e762bfe83d1.html b/extras/documentation/dir_9eb8a1162b9e86c4bf1f8e762bfe83d1.html index 5b7ea0a..2e3ae97 100644 --- a/extras/documentation/dir_9eb8a1162b9e86c4bf1f8e762bfe83d1.html +++ b/extras/documentation/dir_9eb8a1162b9e86c4bf1f8e762bfe83d1.html @@ -1,7 +1,7 @@ - @@ -9,7 +9,7 @@ -ThingSpeak Communication Library For Arduino, ESP8266, and Particle +ThingSpeak Communication Library For Arduino and ESP8266 @@ -23,7 +23,7 @@
ThingSpeak Communication Library
-
Enables an Arduino, ESP8266, or Particle to write or read data to or from ThingSpeak™
+
Enables an Arduino or ESP8266 to write or read data to or from ThingSpeak™
Logo @@ -54,10 +54,10 @@ - diff --git a/extras/documentation/functions.html b/extras/documentation/functions.html index 907e1ca..354de4c 100644 --- a/extras/documentation/functions.html +++ b/extras/documentation/functions.html @@ -1,7 +1,7 @@ - @@ -9,7 +9,7 @@ -ThingSpeak Communication Library For Arduino, ESP8266, and Particle +ThingSpeak Communication Library For Arduino and ESP8266 @@ -23,7 +23,7 @@
ThingSpeak Communication Library
-
Enables an Arduino, ESP8266, or Particle to write or read data to or from ThingSpeak™
+
Enables an Arduino or ESP8266 to write or read data to or from ThingSpeak™
Logo @@ -50,30 +50,62 @@
  • Functions
  • +
    -
    Here is a list of all documented struct and union fields with links to the struct/union documentation for each field:
    - diff --git a/extras/documentation/functions_func.html b/extras/documentation/functions_func.html index 5ab549b..3f32342 100644 --- a/extras/documentation/functions_func.html +++ b/extras/documentation/functions_func.html @@ -1,7 +1,7 @@ - @@ -9,7 +9,7 @@ -ThingSpeak Communication Library For Arduino, ESP8266, and Particle +ThingSpeak Communication Library For Arduino and ESP8266 @@ -23,7 +23,7 @@
    ThingSpeak Communication Library
    -
    Enables an Arduino, ESP8266, or Particle to write or read data to or from ThingSpeak™
    +
    Enables an Arduino or ESP8266 to write or read data to or from ThingSpeak™
    Logo @@ -50,30 +50,62 @@
  • Functions
  • +
    - diff --git a/extras/documentation/index.html b/extras/documentation/index.html index 0e114ed..0f3af04 100644 --- a/extras/documentation/index.html +++ b/extras/documentation/index.html @@ -1,7 +1,7 @@ - @@ -9,7 +9,7 @@ -ThingSpeak Communication Library For Arduino, ESP8266, and Particle +ThingSpeak Communication Library For Arduino and ESP8266 @@ -23,7 +23,7 @@
    ThingSpeak Communication Library
    -
    Enables an Arduino, ESP8266, or Particle to write or read data to or from ThingSpeak™
    +
    Enables an Arduino or ESP8266 to write or read data to or from ThingSpeak™
    Logo @@ -67,10 +67,10 @@

    Examples

    - diff --git a/extras/test/testBegin/testBegin.ino b/extras/test/testBegin/testBegin.ino index a737e29..7227af1 100644 --- a/extras/test/testBegin/testBegin.ino +++ b/extras/test/testBegin/testBegin.ino @@ -9,7 +9,7 @@ This test use the ArduinoUnit 2.1.0 unit test framework. Visit https://github.com/mmurdoch/arduinounit to learn more. - Copyright 2016, The MathWorks, Inc. + Copyright 2017, The MathWorks, Inc. Documentation for the ThingSpeak Communication Library for Arduino is in the extras/documentation folder where the library was installed. See the accompaning licence.txt file for licensing information. @@ -53,8 +53,8 @@ -unsigned long testChannelNumber = 31461; -const char * testChannelWriteAPIKey = "LD79EOAAWRVYF04Y"; +unsigned long testChannelNumber = 209617; +const char * testChannelWriteAPIKey = "514SX5OBP2OFEPL2"; test(beginCase) { @@ -68,9 +68,10 @@ test(beginCase) test(badAddresses) { - // Test for valid, but incorrect, URL (www.mathworks.com) that gives a 404 response + // Test for valid, but incorrect, URL (www.mathworks.com) assertTrue(ThingSpeak.begin(client,"www.mathworks.com",80)); - assertEqual(ERR_BADURL, ThingSpeak.writeField(testChannelNumber, 1, (float)1.0, testChannelWriteAPIKey) ); + // www.mathworks.com will sometimes sometimes return a 404 or a 301 depending on server settings. Test the negative case instead. + assertNotEqual(OK_SUCCESS, ThingSpeak.writeField(testChannelNumber, 1, (float)1.0, testChannelWriteAPIKey) ); // Test for non-existant URL (http://www.iwishthiswebsitewerereal.com/) #ifdef USE_ETHERNET_SHIELD diff --git a/extras/test/testReadField/testReadField.ino b/extras/test/testReadField/testReadField.ino index e4e0f3b..38bbc28 100644 --- a/extras/test/testReadField/testReadField.ino +++ b/extras/test/testReadField/testReadField.ino @@ -9,7 +9,7 @@ This test use the ArduinoUnit 2.1.0 unit test framework. Visit https://github.com/mmurdoch/arduinounit to learn more. - Copyright 2016, The MathWorks, Inc. + Copyright 2017, The MathWorks, Inc. Documentation for the ThingSpeak Communication Library for Arduino is in the extras/documentation folder where the library was installed. See the accompaning licence.txt file for licensing information. @@ -50,16 +50,35 @@ #endif #endif -unsigned long testPublicChannelNumber = 12397; -unsigned long testPrivateChannelNumber = 31461; -const char * testPrivateChannelReadAPIKey = "NKX4Z5JGO4M5I18A"; -const char * testPrivateChannelWriteAPIKey = "LD79EOAAWRVYF04Y"; +unsigned long testPublicChannelNumber = 209617; +const char * testPublicChannelWriteAPIKey = "514SX5OBP2OFEPL2"; + +unsigned long testPrivateChannelNumber = 209615; +const char * testPrivateChannelReadAPIKey = "D3MJBCYVNFX4Z2A8"; +const char * testPrivateChannelWriteAPIKey = "KI8B7DJTWXLZ6EBV"; #define WRITE_DELAY_FOR_THINGSPEAK 15000 +test(readPrivateFieldCase) +{ + // Test basic value read -- should give anything but 0 + assertNotEqual(0.0,ThingSpeak.readFloatField(testPrivateChannelNumber, 1, testPrivateChannelReadAPIKey)); + assertEqual(OK_SUCCESS,ThingSpeak.getLastReadStatus()); + + // Test read with invalid API key + // * Using the wrong API key causes a connection failure on the next attempt to connect to ThingSpeak + // * The cause is unknown, disable this test for now + //assertEqual(0.0,ThingSpeak.readFloatField(testPrivateChannelNumber, 1, "AFAKEAPIKEYFAKEX")); + //assertEqual(ERR_BADAPIKEY,ThingSpeak.getLastReadStatus()); +} + +#if defined(ARDUINO_AVR_MEGA2560) || defined(ARDUINO_SAMD_MKR1000) // Only the mega and mkr1000 has enough memory for all these tests test(readPublicFieldCase) -{ +{ + + delay(WRITE_DELAY_FOR_THINGSPEAK); + assertEqual(OK_SUCCESS, ThingSpeak.writeField(testPublicChannelNumber, 4, (float)1.0, testPublicChannelWriteAPIKey)); // Test basic value read -- should give anything but 0 assertNotEqual(0.0,ThingSpeak.readFloatField(testPublicChannelNumber, 4)); @@ -78,28 +97,15 @@ test(readPublicFieldCase) #endif // Test read of invalid channel # - assertEqual(0.0,ThingSpeak.readFloatField(0, 1)); - assertEqual(ERR_BADURL,ThingSpeak.getLastReadStatus()); - assertEqual(0.0,ThingSpeak.readFloatField(4294967295L, 1)); - assertEqual(ERR_BAD,ThingSpeak.getLastReadStatus()); -} - - -test(readPrivateFieldCase) -{ - // Test basic value read -- should give anything but 0 - assertNotEqual(0.0,ThingSpeak.readFloatField(testPrivateChannelNumber, 1, testPrivateChannelReadAPIKey)); - assertEqual(OK_SUCCESS,ThingSpeak.getLastReadStatus()); - - // Test read with invalid API key // * Using the wrong API key causes a connection failure on the next attempt to connect to ThingSpeak // * The cause is unknown, disable this test for now - //assertEqual(0.0,ThingSpeak.readFloatField(testPrivateChannelNumber, 1, "AFAKEAPIKEYFAKEX")); - //assertEqual(ERR_BADAPIKEY,ThingSpeak.getLastReadStatus()); - + //assertEqual(0.0,ThingSpeak.readFloatField(0, 1)); + //assertEqual(ERR_BADURL,ThingSpeak.getLastReadStatus()); + //assertEqual(0.0,ThingSpeak.readFloatField(4294967295L, 1)); + //assertEqual(ERR_BAD,ThingSpeak.getLastReadStatus()); } -#if defined(ARDUINO_AVR_MEGA2560) || defined(ARDUINO_SAMD_MKR1000) // Only the mega and mkr1000 has enough memory for all these tests + test(ReadFloatFieldCase) { // Always to ensure that rate limit isn't hit @@ -261,8 +267,58 @@ test(ReadStringFieldCase) assertEqual(String(NEG_INF_STR),ThingSpeak.readStringField(testPrivateChannelNumber, 7, testPrivateChannelReadAPIKey)); assertEqual(OK_SUCCESS,ThingSpeak.getLastReadStatus()); } + +test(readStatusPublicCase) +{ + // Always wait 15 seconds to ensure that rate limit isn't hit + delay(WRITE_DELAY_FOR_THINGSPEAK); + + ThingSpeak.setStatus("abcdef"); + assertEqual(OK_SUCCESS,ThingSpeak.writeFields(testPublicChannelNumber, testPublicChannelWriteAPIKey)); // string + //assertEqual(OK_SUCCESS,ThingSpeak.getLastReadStatus()); + assertEqual(String("abcdef"),ThingSpeak.readStatus(testPublicChannelNumber)); +} + +test(readStatusPrivateCase) +{ + // Always wait 15 seconds to ensure that rate limit isn't hit + delay(WRITE_DELAY_FOR_THINGSPEAK); + + ThingSpeak.setStatus("abcdef"); + assertEqual(OK_SUCCESS,ThingSpeak.writeFields(testPrivateChannelNumber, testPrivateChannelWriteAPIKey)); // string + //assertEqual(OK_SUCCESS,ThingSpeak.getLastReadStatus()); + assertEqual(String("abcdef"),ThingSpeak.readStatus(testPrivateChannelNumber, testPrivateChannelReadAPIKey)); +} + +test(readCreatedAtPublicCase) +{ + // Always wait 15 seconds to ensure that rate limit isn't hit + delay(WRITE_DELAY_FOR_THINGSPEAK); + + ThingSpeak.setCreatedAt("2016-12-21T11:11:11Z"); + assertEqual(OK_SUCCESS,ThingSpeak.writeFields(testPublicChannelNumber, testPublicChannelWriteAPIKey)); // string + //assertEqual(OK_SUCCESS,ThingSpeak.getLastReadStatus()); + assertEqual(String("2016-12-21T11:11:11Z"),ThingSpeak.readCreatedAt(testPublicChannelNumber)); +} + +test(readCreatedAtPrivateCase) +{ + // Always wait 15 seconds to ensure that rate limit isn't hit + delay(WRITE_DELAY_FOR_THINGSPEAK); + + ThingSpeak.setCreatedAt("2016-12-21T11:11:11Z"); + assertEqual(OK_SUCCESS,ThingSpeak.writeFields(testPrivateChannelNumber, testPrivateChannelWriteAPIKey)); // string + //assertEqual(OK_SUCCESS,ThingSpeak.getLastReadStatus()); + assertEqual(String("2016-12-21T11:11:11Z"),ThingSpeak.readCreatedAt(testPrivateChannelNumber, testPrivateChannelReadAPIKey)); +} + + #endif // Mega and MKR1000 only tests + + + + void setup() { Serial.begin(9600); diff --git a/extras/test/testSetField/testSetField.ino b/extras/test/testSetField/testSetField.ino index b2c15d0..0a174f2 100644 --- a/extras/test/testSetField/testSetField.ino +++ b/extras/test/testSetField/testSetField.ino @@ -9,7 +9,7 @@ This test use the ArduinoUnit 2.1.0 unit test framework. Visit https://github.com/mmurdoch/arduinounit to learn more. - Copyright 2016, The MathWorks, Inc. + Copyright 2017, The MathWorks, Inc. Documentation for the ThingSpeak Communication Library for Arduino is in the extras/documentation folder where the library was installed. See the accompaning licence.txt file for licensing information. @@ -50,8 +50,8 @@ #endif #endif -unsigned long testChannelNumber = 31461; -const char * testChannelWriteAPIKey = "LD79EOAAWRVYF04Y"; +unsigned long testChannelNumber = 209617; +const char * testChannelWriteAPIKey = "514SX5OBP2OFEPL2"; #define WRITE_DELAY_FOR_THINGSPEAK 15000 @@ -189,6 +189,175 @@ test(setFieldStringCase) assertEqual(OK_SUCCESS,ThingSpeak.writeFields(testChannelNumber, testChannelWriteAPIKey)); } + +test(setStatusCharStarCase) +{ + // Always wait to ensure that rate limit isn't hit + delay(WRITE_DELAY_FOR_THINGSPEAK); + + // Test empty string + assertEqual(OK_SUCCESS, ThingSpeak.setStatus("")); + + char longString[300]; + + // Test max string + memset(longString, '0',255); + longString[255] = 0; + assertEqual(OK_SUCCESS, ThingSpeak.setStatus(longString)); + + // Test long string + memset(longString, '0',sizeof(longString)/sizeof(longString[0]) - 1); + longString[sizeof(longString)] = 0; + + assertEqual(ERR_OUT_OF_RANGE, ThingSpeak.setStatus(longString)); + + assertEqual(OK_SUCCESS,ThingSpeak.writeFields(testChannelNumber, testChannelWriteAPIKey)); + +} + +test(setStatusStringCase) +{ + // Always wait to ensure that rate limit isn't hit + delay(WRITE_DELAY_FOR_THINGSPEAK); + + // Test empty string + assertEqual(OK_SUCCESS, ThingSpeak.setStatus(String())); + + unsigned int numChar = 300; + String longString; + longString.reserve(numChar); + + // Test max string + for(unsigned int i = 0; i < 255; i++) + { + longString += '0'; + } + assertEqual(OK_SUCCESS, ThingSpeak.setStatus(longString)); + + // Test long string + longString.reserve(numChar); + for(unsigned int i = 0; i < numChar; i++) + { + longString += '0'; + } + + assertEqual(ERR_OUT_OF_RANGE, ThingSpeak.setStatus(longString)); + + assertEqual(OK_SUCCESS,ThingSpeak.writeFields(testChannelNumber, testChannelWriteAPIKey)); +} + +test(setTwitterTweetTwitterCharStarCase) +{ + // Always wait to ensure that rate limit isn't hit + delay(WRITE_DELAY_FOR_THINGSPEAK); + + // Test empty string + assertEqual(OK_SUCCESS, ThingSpeak.setTwitterTweet("","")); + + char longString[300]; + char normalString[32] = "normalString"; + + // Test max string + memset(longString, '0',255); + longString[255] = 0; + assertEqual(OK_SUCCESS, ThingSpeak.setTwitterTweet(longString, normalString)); + assertEqual(OK_SUCCESS, ThingSpeak.setTwitterTweet(normalString, longString)); + + // Test long string + memset(longString, '0',sizeof(longString)/sizeof(longString[0]) - 1); + longString[sizeof(longString)] = 0; + + assertEqual(ERR_OUT_OF_RANGE, ThingSpeak.setTwitterTweet(longString, normalString)); + assertEqual(ERR_OUT_OF_RANGE, ThingSpeak.setTwitterTweet(normalString, longString)); + + assertEqual(OK_SUCCESS,ThingSpeak.writeFields(testChannelNumber, testChannelWriteAPIKey)); +} + +test(setTwitterTweetStringCase) +{ + // Always wait to ensure that rate limit isn't hit + delay(WRITE_DELAY_FOR_THINGSPEAK); + + // Test empty string + assertEqual(OK_SUCCESS, ThingSpeak.setTwitterTweet(String(),String())); + + unsigned int numChar = 300; + String longString; + longString.reserve(numChar); + + String normalString = "normalString"; + + // Test max string + for(unsigned int i = 0; i < 255; i++) + { + longString += '0'; + } + assertEqual(OK_SUCCESS, ThingSpeak.setTwitterTweet(longString, normalString)); + assertEqual(OK_SUCCESS, ThingSpeak.setTwitterTweet(normalString, longString)); + + // Test long string + longString.reserve(numChar); + for(unsigned int i = 0; i < numChar; i++) + { + longString += '0'; + } + + assertEqual(ERR_OUT_OF_RANGE, ThingSpeak.setTwitterTweet(longString, normalString)); + assertEqual(ERR_OUT_OF_RANGE, ThingSpeak.setTwitterTweet(normalString, longString)); + + assertEqual(OK_SUCCESS,ThingSpeak.writeFields(testChannelNumber, testChannelWriteAPIKey)); +} + +test(setCreatedAtCharStarCase) +{ + // Always wait to ensure that rate limit isn't hit + delay(WRITE_DELAY_FOR_THINGSPEAK); + + // Test empty string + assertEqual(OK_SUCCESS, ThingSpeak.setCreatedAt("")); + + char longString[300]; + + // Test timestamp string + strcpy(longString,"2016-12-21T11:11:11Z"); + assertEqual(OK_SUCCESS, ThingSpeak.setCreatedAt(longString)); + + // Test long string + memset(longString, '0',sizeof(longString)/sizeof(longString[0]) - 1); + longString[sizeof(longString)] = 0; + + assertEqual(ERR_OUT_OF_RANGE, ThingSpeak.setCreatedAt(longString)); + + assertEqual(OK_SUCCESS,ThingSpeak.writeFields(testChannelNumber, testChannelWriteAPIKey)); +} + +test(setCreatedAtStringCase) +{ + // Always wait to ensure that rate limit isn't hit + delay(WRITE_DELAY_FOR_THINGSPEAK); + + // Test empty string + assertEqual(OK_SUCCESS, ThingSpeak.setCreatedAt(String())); + + unsigned int numChar = 300; + String longString; + longString.reserve(numChar); + + // Test timestamp string + longString = "2016-12-21T11:11:11Z"; + assertEqual(OK_SUCCESS, ThingSpeak.setCreatedAt(longString)); + + // Test long string + longString.reserve(numChar); + for(unsigned int i = 0; i < numChar; i++) + { + longString += '0'; + } + + assertEqual(ERR_OUT_OF_RANGE, ThingSpeak.setCreatedAt(longString)); + + assertEqual(OK_SUCCESS,ThingSpeak.writeFields(testChannelNumber, testChannelWriteAPIKey)); +} #endif // Mega and MKR1000 only tests void setup() diff --git a/extras/test/testWriteField/testWriteField.ino b/extras/test/testWriteField/testWriteField.ino index 156d383..a0c3fde 100644 --- a/extras/test/testWriteField/testWriteField.ino +++ b/extras/test/testWriteField/testWriteField.ino @@ -9,7 +9,7 @@ This test use the ArduinoUnit 2.1.0 unit test framework. Visit https://github.com/mmurdoch/arduinounit to learn more. - Copyright 2016, The MathWorks, Inc. + Copyright 2017, The MathWorks, Inc. Documentation for the ThingSpeak Communication Library for Arduino is in the extras/documentation folder where the library was installed. See the accompaning licence.txt file for licensing information. @@ -50,8 +50,8 @@ #endif #endif -unsigned long testChannelNumber = 31461; -const char * testChannelWriteAPIKey = "LD79EOAAWRVYF04Y"; +unsigned long testChannelNumber = 209617; +const char * testChannelWriteAPIKey = "514SX5OBP2OFEPL2"; #define WRITE_DELAY_FOR_THINGSPEAK 15000