From b94feaa52188218cbad73f9d07d55c12fce5c31d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20St=C3=B6r?= Date: Tue, 17 Mar 2020 23:30:43 +0100 Subject: [PATCH] Dump use of HTTPClient Use plain TCP communication to fetch & process remote resources Fixes #178 --- src/AerisForecasts.cpp | 43 ++++++++++++++--------------- src/AerisForecasts.h | 2 ++ src/AerisObservations.cpp | 44 ++++++++++++++---------------- src/AerisObservations.h | 2 ++ src/AerisSunMoon.cpp | 47 ++++++++++++++++---------------- src/AerisSunMoon.h | 2 ++ src/ESPHTTPClient.h | 5 ---- src/MetOfficeClient.cpp | 8 ++++-- src/OpenWeatherMapCurrent.cpp | 50 ++++++++++++++++------------------ src/OpenWeatherMapCurrent.h | 6 ++-- src/OpenWeatherMapForecast.cpp | 50 ++++++++++++++++------------------ src/OpenWeatherMapForecast.h | 6 ++-- src/ThingspeakClient.cpp | 17 ++++++------ src/TimeClient.cpp | 8 ++++-- src/WorldClockClient.cpp | 8 ++++-- 15 files changed, 151 insertions(+), 147 deletions(-) delete mode 100644 src/ESPHTTPClient.h diff --git a/src/AerisForecasts.cpp b/src/AerisForecasts.cpp index 44e259b..4ceb7b4 100644 --- a/src/AerisForecasts.cpp +++ b/src/AerisForecasts.cpp @@ -23,7 +23,6 @@ #include #include -#include #include "AerisForecasts.h" AerisForecasts::AerisForecasts() { @@ -31,10 +30,10 @@ AerisForecasts::AerisForecasts() { } void AerisForecasts::updateForecasts(AerisForecastData *forecasts, String clientId, String clientSecret, String location, uint8_t maxForecasts) { - doUpdate(forecasts, "http://api.aerisapi.com/forecasts/closest?p=" + location + "&client_id=" + clientId + "&client_secret=" + clientSecret, maxForecasts); + doUpdate(forecasts, "/forecasts/closest?p=" + location + "&client_id=" + clientId + "&client_secret=" + clientSecret, maxForecasts); } -void AerisForecasts::doUpdate(AerisForecastData *forecasts, String url, uint8_t maxForecasts) { +void AerisForecasts::doUpdate(AerisForecastData *forecasts, String path, uint8_t maxForecasts) { this->maxForecasts = maxForecasts; this->currentForecast = 0; unsigned long lostTest = 10000UL; @@ -43,38 +42,38 @@ void AerisForecasts::doUpdate(AerisForecastData *forecasts, String url, uint8_t this->forecasts = forecasts; JsonStreamingParser parser; parser.setListener(this); - Serial.printf("Getting url: %s\n", url.c_str()); - HTTPClient http; + Serial.printf("[HTTP] Requesting resource at http://%s:%u%s\n", host.c_str(), port, path.c_str()); - http.begin(url); - bool isBody = false; - char c; - Serial.print("[HTTP] GET...\n"); - // start connection and send HTTP header - int httpCode = http.GET(); - Serial.printf("[HTTP] GET... code: %d\n", httpCode); - if(httpCode > 0) { + WiFiClient client; + if(client.connect(host, port)) { + bool isBody = false; + char c; + Serial.println("[HTTP] connected, now GETting data"); + client.print("GET " + path + " HTTP/1.1\r\n" + "Host: " + host + "\r\n" + "Connection: close\r\n\r\n"); - WiFiClient * client = http.getStreamPtr(); - - while (client->available() || client->connected()) { - while (client->available()) { + while (client.connected() || client.available()) { + if (client.available()) { if ((millis() - lost_do) > lostTest) { - Serial.println("lost in client with a timeout"); - client->stop(); + Serial.println("[HTTP] lost in client with a timeout"); + client.stop(); ESP.restart(); } - c = client->read(); + c = client.read(); if (c == '{' || c == '[') { - isBody = true; } if (isBody) { parser.parse(c); } } - client->stop(); + // give WiFi and TCP/IP libraries a chance to handle pending events + yield(); } + client.stop(); + } else { + Serial.println("[HTTP] failed to connect to host"); } this->forecasts = nullptr; } diff --git a/src/AerisForecasts.h b/src/AerisForecasts.h index f2418c0..8a98a75 100644 --- a/src/AerisForecasts.h +++ b/src/AerisForecasts.h @@ -120,6 +120,8 @@ typedef struct AerisForecastData { class AerisForecasts: public JsonListener { private: + const String host = "api.aerisapi.com"; + const uint8_t port = 80; boolean isMetric = true; String currentKey; String currentParent; diff --git a/src/AerisObservations.cpp b/src/AerisObservations.cpp index 21a49b8..f7cdee3 100644 --- a/src/AerisObservations.cpp +++ b/src/AerisObservations.cpp @@ -23,7 +23,6 @@ #include #include -#include #include "AerisObservations.h" AerisObservations::AerisObservations() { @@ -31,49 +30,48 @@ AerisObservations::AerisObservations() { } void AerisObservations::updateObservations(AerisObservationsData *observations, String clientId, String clientSecret, String location) { - doUpdate(observations, "http://api.aerisapi.com/observations/closest?p=" + location + "&client_id=" + clientId + "&client_secret=" + clientSecret); + doUpdate(observations, "/observations/closest?p=" + location + "&client_id=" + clientId + "&client_secret=" + clientSecret); } -void AerisObservations::doUpdate(AerisObservationsData *observations, String url) { +void AerisObservations::doUpdate(AerisObservationsData *observations, String path) { unsigned long lostTest = 10000UL; unsigned long lost_do = millis(); this->observations = observations; JsonStreamingParser parser; parser.setListener(this); - Serial.printf("Getting url: %s\n", url.c_str()); - HTTPClient http; + Serial.printf("[HTTP] Requesting resource at http://%s:%u%s\n", host.c_str(), port, path.c_str()); - http.begin(url); - bool isBody = false; - char c; - int size; - Serial.print("[HTTP] GET...\n"); - // start connection and send HTTP header - int httpCode = http.GET(); - Serial.printf("[HTTP] GET... code: %d\n", httpCode); - if(httpCode > 0) { + WiFiClient client; + if(client.connect(host, port)) { + bool isBody = false; + char c; + Serial.println("[HTTP] connected, now GETting data"); + client.print("GET " + path + " HTTP/1.1\r\n" + "Host: " + host + "\r\n" + "Connection: close\r\n\r\n"); - WiFiClient * client = http.getStreamPtr(); - - while (client->available() || client->connected()) { - while (client->available()) { + while (client.connected() || client.available()) { + if (client.available()) { if ((millis() - lost_do) > lostTest) { - Serial.println("lost in client with a timeout"); - client->stop(); + Serial.println("[HTTP] lost in client with a timeout"); + client.stop(); ESP.restart(); } - c = client->read(); + c = client.read(); if (c == '{' || c == '[') { - isBody = true; } if (isBody) { parser.parse(c); } } - client->stop(); + // give WiFi and TCP/IP libraries a chance to handle pending events + yield(); } + client.stop(); + } else { + Serial.println("[HTTP] failed to connect to host"); } this->observations = nullptr; } diff --git a/src/AerisObservations.h b/src/AerisObservations.h index 80e4a43..a25ebc5 100644 --- a/src/AerisObservations.h +++ b/src/AerisObservations.h @@ -83,6 +83,8 @@ typedef struct AerisObservationsData { class AerisObservations: public JsonListener { private: + const String host = "api.aerisapi.com"; + const uint8_t port = 80; boolean isMetric = true; String currentKey; String currentParent; diff --git a/src/AerisSunMoon.cpp b/src/AerisSunMoon.cpp index 1d4facb..b3fbc76 100644 --- a/src/AerisSunMoon.cpp +++ b/src/AerisSunMoon.cpp @@ -23,7 +23,6 @@ #include #include -#include #include "AerisSunMoon.h" AerisSunMoon::AerisSunMoon() { @@ -31,10 +30,10 @@ AerisSunMoon::AerisSunMoon() { } void AerisSunMoon::updateSunMoon(AerisSunMoonData *sunMoonData, String clientId, String clientSecret, String location) { - doUpdate(sunMoonData, "http://api.aerisapi.com/sunmoon/" + location + "?client_id=" + clientId + "&client_secret=" + clientSecret); + doUpdate(sunMoonData, "/sunmoon/" + location + "?client_id=" + clientId + "&client_secret=" + clientSecret); } -void AerisSunMoon::doUpdate(AerisSunMoonData *sunMoonData, String url) { +void AerisSunMoon::doUpdate(AerisSunMoonData *sunMoonData, String path) { this->sunMoonData = sunMoonData; unsigned long lostTest = 10000UL; @@ -42,38 +41,38 @@ void AerisSunMoon::doUpdate(AerisSunMoonData *sunMoonData, String url) { JsonStreamingParser parser; parser.setListener(this); - Serial.printf("Getting url: %s\n", url.c_str()); - HTTPClient http; - - http.begin(url); - bool isBody = false; - char c; - Serial.print("[HTTP] GET...\n"); - // start connection and send HTTP header - int httpCode = http.GET(); - Serial.printf("[HTTP] GET... code: %d\n", httpCode); - if(httpCode > 0) { - - WiFiClient * client = http.getStreamPtr(); - - while (client->available() || client->connected()) { - while (client->available()) { + Serial.printf("[HTTP] Requesting resource at http://%s:%u%s\n", host.c_str(), port, path.c_str()); + + WiFiClient client; + if(client.connect(host, port)) { + bool isBody = false; + char c; + Serial.println("[HTTP] connected, now GETting data"); + client.print("GET " + path + " HTTP/1.1\r\n" + "Host: " + host + "\r\n" + "Connection: close\r\n\r\n"); + + while (client.connected() || client.available()) { + if (client.available()) { if ((millis() - lost_do) > lostTest) { - Serial.println("lost in client with a timeout"); - client->stop(); + Serial.println("[HTTP] lost in client with a timeout"); + client.stop(); ESP.restart(); } - c = client->read(); + c = client.read(); if (c == '{' || c == '[') { - isBody = true; } if (isBody) { parser.parse(c); } } - client->stop(); + // give WiFi and TCP/IP libraries a chance to handle pending events + yield(); } + client.stop(); + } else { + Serial.println("[HTTP] failed to connect to host"); } this->sunMoonData = nullptr; } diff --git a/src/AerisSunMoon.h b/src/AerisSunMoon.h index 74934a4..dcc7406 100644 --- a/src/AerisSunMoon.h +++ b/src/AerisSunMoon.h @@ -52,6 +52,8 @@ typedef struct AerisSunMoonData { class AerisSunMoon: public JsonListener { private: + const String host = "api.aerisapi.com"; + const uint8_t port = 80; boolean isMetric = true; String currentKey; String currentParent; diff --git a/src/ESPHTTPClient.h b/src/ESPHTTPClient.h deleted file mode 100644 index 6d3e492..0000000 --- a/src/ESPHTTPClient.h +++ /dev/null @@ -1,5 +0,0 @@ -#if defined(ESP8266) -#include -#else -#include -#endif diff --git a/src/MetOfficeClient.cpp b/src/MetOfficeClient.cpp index ab47da4..ef3e6c5 100644 --- a/src/MetOfficeClient.cpp +++ b/src/MetOfficeClient.cpp @@ -97,8 +97,8 @@ void MetOfficeClient::doUpdate(String url) { char c; client.setNoDelay(false); - while (client.connected()) { - while (client.available()) { + while (client.connected() || client.available()) { + if (client.available()) { c = client.read(); if (c == '{' || c == '[') { isBody = true; @@ -107,8 +107,10 @@ void MetOfficeClient::doUpdate(String url) { parser.parse(c); } } - client.stop(); + // give WiFi and TCP/IP libraries a chance to handle pending events + yield(); } + client.stop(); } void MetOfficeClient::whitespace(char c) { diff --git a/src/OpenWeatherMapCurrent.cpp b/src/OpenWeatherMapCurrent.cpp index 1bb45c2..013d111 100644 --- a/src/OpenWeatherMapCurrent.cpp +++ b/src/OpenWeatherMapCurrent.cpp @@ -23,7 +23,6 @@ #include #include -#include #include "OpenWeatherMapCurrent.h" OpenWeatherMapCurrent::OpenWeatherMapCurrent() { @@ -31,58 +30,57 @@ OpenWeatherMapCurrent::OpenWeatherMapCurrent() { } void OpenWeatherMapCurrent::updateCurrent(OpenWeatherMapCurrentData *data, String appId, String location) { - doUpdate(data, buildUrl(appId, "q=" + location)); + doUpdate(data, buildPath(appId, "q=" + location)); } void OpenWeatherMapCurrent::updateCurrentById(OpenWeatherMapCurrentData *data, String appId, String locationId) { - doUpdate(data, buildUrl(appId, "id=" + locationId)); + doUpdate(data, buildPath(appId, "id=" + locationId)); } -String OpenWeatherMapCurrent::buildUrl(String appId, String locationParameter) { +String OpenWeatherMapCurrent::buildPath(String appId, String locationParameter) { String units = metric ? "metric" : "imperial"; - return "http://api.openweathermap.org/data/2.5/weather?" + locationParameter + "&appid=" + appId + "&units=" + units + "&lang=" + language; + return "/data/2.5/weather?" + locationParameter + "&appid=" + appId + "&units=" + units + "&lang=" + language; } -void OpenWeatherMapCurrent::doUpdate(OpenWeatherMapCurrentData *data, String url) { +void OpenWeatherMapCurrent::doUpdate(OpenWeatherMapCurrentData *data, String path) { unsigned long lostTest = 10000UL; unsigned long lost_do = millis(); this->weatherItemCounter = 0; this->data = data; JsonStreamingParser parser; parser.setListener(this); - Serial.printf("Getting url: %s\n", url.c_str()); - HTTPClient http; + Serial.printf("[HTTP] Requesting resource at http://%s:%u%s\n", host.c_str(), port, path.c_str()); - http.begin(url); - bool isBody = false; - char c; - Serial.print("[HTTP] GET...\n"); - // start connection and send HTTP header - int httpCode = http.GET(); - Serial.printf("[HTTP] GET... code: %d\n", httpCode); - if(httpCode > 0) { + WiFiClient client; + if(client.connect(host, port)) { + bool isBody = false; + char c; + Serial.println("[HTTP] connected, now GETting data"); + client.print("GET " + path + " HTTP/1.1\r\n" + "Host: " + host + "\r\n" + "Connection: close\r\n\r\n"); - WiFiClient * client = http.getStreamPtr(); - - while (client->connected() || client->available()) { - while (client->available()) { + while (client.connected() || client.available()) { + if (client.available()) { if ((millis() - lost_do) > lostTest) { - Serial.println("lost in client with a timeout"); - client->stop(); + Serial.println("[HTTP] lost in client with a timeout"); + client.stop(); ESP.restart(); } - c = client->read(); + c = client.read(); if (c == '{' || c == '[') { isBody = true; } if (isBody) { parser.parse(c); } - // give WiFi and TCP/IP libraries a chance to handle pending events - yield(); } - client->stop(); + // give WiFi and TCP/IP libraries a chance to handle pending events + yield(); } + client.stop(); + } else { + Serial.println("[HTTP] failed to connect to host"); } this->data = nullptr; } diff --git a/src/OpenWeatherMapCurrent.h b/src/OpenWeatherMapCurrent.h index fa4d0eb..c575f0e 100644 --- a/src/OpenWeatherMapCurrent.h +++ b/src/OpenWeatherMapCurrent.h @@ -71,6 +71,8 @@ typedef struct OpenWeatherMapCurrentData { class OpenWeatherMapCurrent: public JsonListener { private: + const String host = "api.openweathermap.org"; + const uint8_t port = 80; String currentKey; String currentParent; OpenWeatherMapCurrentData *data; @@ -78,8 +80,8 @@ class OpenWeatherMapCurrent: public JsonListener { boolean metric = true; String language; - void doUpdate(OpenWeatherMapCurrentData *data, String url); - String buildUrl(String appId, String locationParameter); + void doUpdate(OpenWeatherMapCurrentData *data, String path); + String buildPath(String appId, String locationParameter); public: OpenWeatherMapCurrent(); diff --git a/src/OpenWeatherMapForecast.cpp b/src/OpenWeatherMapForecast.cpp index 7a9d5fe..64717fc 100644 --- a/src/OpenWeatherMapForecast.cpp +++ b/src/OpenWeatherMapForecast.cpp @@ -23,7 +23,6 @@ #include #include -#include #include "OpenWeatherMapForecast.h" OpenWeatherMapForecast::OpenWeatherMapForecast() { @@ -32,20 +31,20 @@ OpenWeatherMapForecast::OpenWeatherMapForecast() { uint8_t OpenWeatherMapForecast::updateForecasts(OpenWeatherMapForecastData *data, String appId, String location, uint8_t maxForecasts) { this->maxForecasts = maxForecasts; - return doUpdate(data, buildUrl(appId, "q=" + location)); + return doUpdate(data, buildPath(appId, "q=" + location)); } uint8_t OpenWeatherMapForecast::updateForecastsById(OpenWeatherMapForecastData *data, String appId, String locationId, uint8_t maxForecasts) { this->maxForecasts = maxForecasts; - return doUpdate(data, buildUrl(appId, "id=" + locationId)); + return doUpdate(data, buildPath(appId, "id=" + locationId)); } -String OpenWeatherMapForecast::buildUrl(String appId, String locationParameter) { +String OpenWeatherMapForecast::buildPath(String appId, String locationParameter) { String units = metric ? "metric" : "imperial"; - return "http://api.openweathermap.org/data/2.5/forecast?" + locationParameter + "&appid=" + appId + "&units=" + units + "&lang=" + language; + return "/data/2.5/forecast?" + locationParameter + "&appid=" + appId + "&units=" + units + "&lang=" + language; } -uint8_t OpenWeatherMapForecast::doUpdate(OpenWeatherMapForecastData *data, String url) { +uint8_t OpenWeatherMapForecast::doUpdate(OpenWeatherMapForecastData *data, String path) { unsigned long lostTest = 10000UL; unsigned long lost_do = millis(); this->weatherItemCounter = 0; @@ -53,39 +52,38 @@ uint8_t OpenWeatherMapForecast::doUpdate(OpenWeatherMapForecastData *data, Strin this->data = data; JsonStreamingParser parser; parser.setListener(this); - Serial.printf("Getting url: %s\n", url.c_str()); - HTTPClient http; + Serial.printf("[HTTP] Requesting resource at http://%s:%u%s\n", host.c_str(), port, path.c_str()); - http.begin(url); - bool isBody = false; - char c; - Serial.print("[HTTP] GET...\n"); - // start connection and send HTTP header - int httpCode = http.GET(); - Serial.printf("[HTTP] GET... code: %d\n", httpCode); - if(httpCode > 0) { + WiFiClient client; + if(client.connect(host, port)) { + bool isBody = false; + char c; + Serial.println("[HTTP] connected, now GETting data"); + client.print("GET " + path + " HTTP/1.1\r\n" + "Host: " + host + "\r\n" + "Connection: close\r\n\r\n"); - WiFiClient * client = http.getStreamPtr(); - - while (client->connected() || client->available()) { - while (client->available()) { + while (client.connected() || client.available()) { + if (client.available()) { if ((millis() - lost_do) > lostTest) { - Serial.println("lost in client with a timeout"); - client->stop(); + Serial.println("[HTTP] lost in client with a timeout"); + client.stop(); ESP.restart(); } - c = client->read(); + c = client.read(); if (c == '{' || c == '[') { isBody = true; } if (isBody) { parser.parse(c); } - // give WiFi and TCP/IP libraries a chance to handle pending events - yield(); } - client->stop(); + // give WiFi and TCP/IP libraries a chance to handle pending events + yield(); } + client.stop(); + } else { + Serial.println("[HTTP] failed to connect to host"); } this->data = nullptr; return currentForecast; diff --git a/src/OpenWeatherMapForecast.h b/src/OpenWeatherMapForecast.h index 909e7d9..69748a9 100644 --- a/src/OpenWeatherMapForecast.h +++ b/src/OpenWeatherMapForecast.h @@ -72,6 +72,8 @@ typedef struct OpenWeatherMapForecastData { class OpenWeatherMapForecast: public JsonListener { private: + const String host = "api.openweathermap.org"; + const uint8_t port = 80; String currentKey; String currentParent; OpenWeatherMapForecastData *data; @@ -84,8 +86,8 @@ class OpenWeatherMapForecast: public JsonListener { uint8_t allowedHoursCount = 0; boolean isCurrentForecastAllowed = true; - uint8_t doUpdate(OpenWeatherMapForecastData *data, String url); - String buildUrl(String appId, String locationParameter); + uint8_t doUpdate(OpenWeatherMapForecastData *data, String path); + String buildPath(String appId, String locationParameter); public: OpenWeatherMapForecast(); diff --git a/src/ThingspeakClient.cpp b/src/ThingspeakClient.cpp index 3a954df..d4d7141 100644 --- a/src/ThingspeakClient.cpp +++ b/src/ThingspeakClient.cpp @@ -12,7 +12,7 @@ void ThingspeakClient::getLastChannelItem(String channelId, String readApiKey) { // http://api.thingspeak.com/channels/CHANNEL_ID/feeds.json?results=2&api_key=API_KEY const char host[] = "api.thingspeak.com"; - String url = "/channels/" + channelId +"/feeds.json?results=1&api_key=" + readApiKey; + String path = "/channels/" + channelId +"/feeds.json?results=1&api_key=" + readApiKey; const int httpPort = 80; if (!client.connect(host, httpPort)) { @@ -20,12 +20,11 @@ void ThingspeakClient::getLastChannelItem(String channelId, String readApiKey) { return; } - - Serial.print("Requesting URL: "); - Serial.println(url); + Serial.print("Requesting path: "); + Serial.println(path); // This will send the request to the server - client.print(String("GET ") + url + " HTTP/1.1\r\n" + + client.print(String("GET ") + path + " HTTP/1.1\r\n" + "Host: " + host + "\r\n" + "Connection: close\r\n\r\n"); @@ -44,8 +43,8 @@ void ThingspeakClient::getLastChannelItem(String channelId, String readApiKey) { char c; client.setNoDelay(false); - while (client.available() || client.connected()) { - while (client.available()) { + while (client.connected() || client.available()) { + if (client.available()) { c = client.read(); if (c == '{' || c == '[') { isBody = true; @@ -54,8 +53,10 @@ void ThingspeakClient::getLastChannelItem(String channelId, String readApiKey) { parser.parse(c); } } - client.stop(); + // give WiFi and TCP/IP libraries a chance to handle pending events + yield(); } + client.stop(); } void ThingspeakClient::whitespace(char c) { diff --git a/src/TimeClient.cpp b/src/TimeClient.cpp index 840f934..57eba0b 100644 --- a/src/TimeClient.cpp +++ b/src/TimeClient.cpp @@ -54,8 +54,8 @@ void TimeClient::updateTime() { String line; client.setNoDelay(false); - while (client.available() || client.connected()) { - while (client.available()) { + while (client.connected() || client.available()) { + if (client.available()) { line = client.readStringUntil('\n'); line.toUpperCase(); // example: @@ -72,8 +72,10 @@ void TimeClient::updateTime() { localMillisAtUpdate = millis(); } } - client.stop(); + // give WiFi and TCP/IP libraries a chance to handle pending events + yield(); } + client.stop(); } String TimeClient::getHours() { diff --git a/src/WorldClockClient.cpp b/src/WorldClockClient.cpp index a82d9a7..adc7cf6 100644 --- a/src/WorldClockClient.cpp +++ b/src/WorldClockClient.cpp @@ -91,8 +91,8 @@ void WorldClockClient::updateTime() { boolean isBody = false; char c; client.setNoDelay(false); - while (client.available() || client.connected()) { - while (client.available()) { + while (client.connected() || client.available()) { + if (client.available()) { c = client.read(); if (c == '{' || c == '[') { isBody = true; @@ -101,8 +101,10 @@ void WorldClockClient::updateTime() { parser.parse(c); } } - client.stop(); + // give WiFi and TCP/IP libraries a chance to handle pending events + yield(); } + client.stop(); }