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

- Main Page
- Data Structures

ThingSpeak.h
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
108 class ThingSpeakClass
109 {
110 public:
111 ThingSpeakClass()
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
1635 int getLastReadStatus()
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
ThingSpeakClass::writeRaw
int writeRaw(unsigned long channelNumber, const char *postMessage, const char *writeAPIKey)
Write a raw POST to a ThingSpeak channel.
Definition: ThingSpeak.h:1165
ThingSpeakClass::setTwitterTweet
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
ThingSpeakClass::readStringField
String readStringField(unsigned long channelNumber, unsigned int field, const char *readAPIKey)
Read the latest string from a private ThingSpeak channel.
Definition: ThingSpeak.h:1256
ThingSpeakClass::readStringField
String readStringField(unsigned long channelNumber, unsigned int field)
Read the latest string from a public ThingSpeak channel.
Definition: ThingSpeak.h:1289
ThingSpeakClass::setField
int setField(unsigned int field, long value)
Set the value of a single field that will be part of a multi-field update. To write multiple fields a...
Definition: ThingSpeak.h:426
ThingSpeakClass::readCreatedAt
String readCreatedAt(unsigned long channelNumber)
Read the created-at timestamp associated with the latest update to a private ThingSpeak channel...
Definition: ThingSpeak.h:1503
ThingSpeakClass::writeRaw
int writeRaw(unsigned long channelNumber, String postMessage, const char *writeAPIKey)
Write a raw POST to a ThingSpeak channel.
Definition: ThingSpeak.h:1186
ThingSpeakClass::begin
bool begin(Client &client, IPAddress customIP, unsigned int port)
Initializes the ThingSpeak library and network settings using a custom installation of ThingSpeak...
Definition: ThingSpeak.h:171
ThingSpeakClass::writeFields
int writeFields(unsigned long channelNumber, const char *writeAPIKey)
Write a multi-field update. Call setField() for each of the fields you want to write, setLatitude() / setLongitude() / setElevation(), and then call writeFields()
Definition: ThingSpeak.h:1038
ThingSpeakClass::setField
int setField(unsigned int field, int value)
Set the value of a single field that will be part of a multi-field update. To write multiple fields a...
Definition: ThingSpeak.h:385
ThingSpeakClass::setTwitterTweet
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
ThingSpeakClass::setTwitterTweet
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
ThingSpeakClass::setLatitude
int setLatitude(float latitude)
Set the latitude of a multi-field update. To record latitude, longitude and elevation of a write...
Definition: ThingSpeak.h:587
ThingSpeakClass::readCreatedAt
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
ThingSpeakClass::setStatus
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
ThingSpeakClass::begin
bool begin(Client &client, const char *customHostName, unsigned int port)
Initializes the ThingSpeak library and network settings using a custom installation of ThingSpeak...
Definition: ThingSpeak.h:138
ThingSpeakClass::getLastReadStatus
int getLastReadStatus()
Get the status of the previous read.
Definition: ThingSpeak.h:1635
ThingSpeakClass::writeField
int writeField(unsigned long channelNumber, unsigned int field, int value, const char *writeAPIKey)
Write an integer value to a single field in a ThingSpeak channel.
Definition: ThingSpeak.h:230
ThingSpeakClass
Enables an Arduino, ESP8266 or other compatible hardware to write or read data to or from ThingSpeak...
Definition: ThingSpeak.h:108
ThingSpeakClass::readLongField
long readLongField(unsigned long channelNumber, unsigned int field, const char *readAPIKey)
Read the latest long from a private ThingSpeak channel.
Definition: ThingSpeak.h:1353
ThingSpeakClass::writeField
int writeField(unsigned long channelNumber, unsigned int field, String value, const char *writeAPIKey)
Write a String to a single field in a ThingSpeak channel.
Definition: ThingSpeak.h:339
ThingSpeakClass::setStatus
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
ThingSpeakClass::setField
int setField(unsigned int field, const char *value)
Set the value of a single field that will be part of a multi-field update. To write multiple fields a...
Definition: ThingSpeak.h:505
ThingSpeakClass::readRaw
String readRaw(unsigned long channelNumber, String URLSuffix)
Read a raw response from a public ThingSpeak channel.
Definition: ThingSpeak.h:1523
ThingSpeakClass::readLongField
long readLongField(unsigned long channelNumber, unsigned int field)
Read the latest long from a public ThingSpeak channel.
Definition: ThingSpeak.h:1374
ThingSpeakClass::writeField
int writeField(unsigned long channelNumber, unsigned int field, float value, const char *writeAPIKey)
Write a floating point value to a single field in a ThingSpeak channel.
Definition: ThingSpeak.h:277
ThingSpeakClass::setCreatedAt
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
ThingSpeakClass::readIntField
int readIntField(unsigned long channelNumber, unsigned int field, const char *readAPIKey)
Read the latest int from a private ThingSpeak channel.
Definition: ThingSpeak.h:1396
ThingSpeakClass::setField
int setField(unsigned int field, String value)
Set the value of a single field that will be part of a multi-field update. To write multiple fields a...
Definition: ThingSpeak.h:541
ThingSpeakClass::setCreatedAt
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
ThingSpeakClass::setLongitude
int setLongitude(float longitude)
Set the longitude of a multi-field update. To record latitude, longitude and elevation of a write...
Definition: ThingSpeak.h:630
ThingSpeakClass::readFloatField
float readFloatField(unsigned long channelNumber, unsigned int field, const char *readAPIKey)
Read the latest float from a private ThingSpeak channel.
Definition: ThingSpeak.h:1311
ThingSpeakClass::setTwitterTweet
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
ThingSpeakClass::readStatus
String readStatus(unsigned long channelNumber, const char *readAPIKey)
Read the latest status from a private ThingSpeak channel.
Definition: ThingSpeak.h:1436
ThingSpeakClass::begin
bool begin(Client &client)
Initializes the ThingSpeak library and network settings using the ThingSpeak.com service.
Definition: ThingSpeak.h:202
ThingSpeakClass::readFloatField
float readFloatField(unsigned long channelNumber, unsigned int field)
Read the latest float from a public ThingSpeak channel.
Definition: ThingSpeak.h:1332
ThingSpeakClass::writeField
int writeField(unsigned long channelNumber, unsigned int field, const char *value, const char *writeAPIKey)
Write a string to a single field in a ThingSpeak channel.
Definition: ThingSpeak.h:310
ThingSpeakClass::readIntField
int readIntField(unsigned long channelNumber, unsigned int field)
Read the latest int from a public ThingSpeak channel.
Definition: ThingSpeak.h:1417
ThingSpeakClass::setField
int setField(unsigned int field, float value)
Set the value of a single field that will be part of a multi-field update. To write multiple fields a...
Definition: ThingSpeak.h:465
ThingSpeakClass::readRaw
String readRaw(unsigned long channelNumber, String URLSuffix, const char *readAPIKey)
Read a raw response from a private ThingSpeak channel.
Definition: ThingSpeak.h:1544
ThingSpeakClass::readStatus
String readStatus(unsigned long channelNumber)
Read the latest status from a public ThingSpeak channel.
Definition: ThingSpeak.h:1460
ThingSpeakClass::setElevation
int setElevation(float elevation)
Set the elevation of a multi-field update. To record latitude, longitude and elevation of a write...
Definition: ThingSpeak.h:673
ThingSpeakClass::writeField
int writeField(unsigned long channelNumber, unsigned int field, long value, const char *writeAPIKey)
Write a long value to a single field in a ThingSpeak channel.
Definition: ThingSpeak.h:253