Merge pull request #612 from Fribur:development

- fix to HttpPowermeter not using explicitly specified non standard ports
- Revert back to using FirebaseJson instead of ArduinoJson
This commit is contained in:
helgeerbe 2024-01-17 13:24:08 +01:00 committed by helgeerbe
parent 63205f88be
commit f305b40be0
3 changed files with 60 additions and 37 deletions

View File

@ -19,9 +19,9 @@ private:
float power[POWERMETER_MAX_PHASES]; float power[POWERMETER_MAX_PHASES];
HTTPClient httpClient; HTTPClient httpClient;
String httpResponse; String httpResponse;
bool httpRequest(int phase, WiFiClient &wifiClient, const String& host, const String& uri, bool https, Auth authType, const char* username, bool httpRequest(int phase, WiFiClient &wifiClient, const String& host, uint16_t port, const String& uri, bool https, Auth authType, const char* username,
const char* password, const char* httpHeader, const char* httpValue, uint32_t timeout, const char* jsonPath); const char* password, const char* httpHeader, const char* httpValue, uint32_t timeout, const char* jsonPath);
void extractUrlComponents(const String& url, String& protocol, String& host, String& uri); bool extractUrlComponents(String url, String& _protocol, String& _hostname, String& _uri, uint16_t& uint16_t, String& _base64Authorization);
String extractParam(String& authReq, const String& param, const char delimit); String extractParam(String& authReq, const String& param, const char delimit);
String getcNonce(const int len); String getcNonce(const int len);
String getDigestAuth(String& authReq, const String& username, const String& password, const String& method, const String& uri, unsigned int counter); String getDigestAuth(String& authReq, const String& username, const String& password, const String& method, const String& uri, unsigned int counter);

View File

@ -47,6 +47,7 @@ lib_deps =
https://github.com/coryjfowler/MCP_CAN_lib https://github.com/coryjfowler/MCP_CAN_lib
plerup/EspSoftwareSerial @ ^8.0.1 plerup/EspSoftwareSerial @ ^8.0.1
https://github.com/dok-net/ghostl @ ^1.0.1 https://github.com/dok-net/ghostl @ ^1.0.1
mobizt/FirebaseJson @ ^3.0.6
rweather/Crypto@^0.4.0 rweather/Crypto@^0.4.0
extra_scripts = extra_scripts =

View File

@ -3,7 +3,7 @@
#include "HttpPowerMeter.h" #include "HttpPowerMeter.h"
#include "MessageOutput.h" #include "MessageOutput.h"
#include <WiFiClientSecure.h> #include <WiFiClientSecure.h>
#include <ArduinoJson.h> #include <FirebaseJson.h>
#include <Crypto.h> #include <Crypto.h>
#include <SHA256.h> #include <SHA256.h>
#include <base64.h> #include <base64.h>
@ -54,7 +54,9 @@ bool HttpPowerMeterClass::queryPhase(int phase, const String& url, Auth authType
String protocol; String protocol;
String host; String host;
String uri; String uri;
extractUrlComponents(url, protocol, host, uri); String base64Authorization;
uint16_t port;
extractUrlComponents(url, protocol, host, uri, port, base64Authorization);
IPAddress ipaddr((uint32_t)0); IPAddress ipaddr((uint32_t)0);
//first check if "host" is already an IP adress //first check if "host" is already an IP adress
@ -96,13 +98,12 @@ bool HttpPowerMeterClass::queryPhase(int phase, const String& url, Auth authType
wifiClient = std::make_unique<WiFiClient>(); wifiClient = std::make_unique<WiFiClient>();
} }
return httpRequest(phase, *wifiClient, ipaddr.toString(), uri, https, authType, username, password, httpHeader, httpValue, timeout, jsonPath); return httpRequest(phase, *wifiClient, ipaddr.toString(), port, uri, https, authType, username, password, httpHeader, httpValue, timeout, jsonPath);
} }
bool HttpPowerMeterClass::httpRequest(int phase, WiFiClient &wifiClient, const String& host, const String& uri, bool https, Auth authType, const char* username, bool HttpPowerMeterClass::httpRequest(int phase, WiFiClient &wifiClient, const String& host, uint16_t port, const String& uri, bool https, Auth authType, const char* username,
const char* password, const char* httpHeader, const char* httpValue, uint32_t timeout, const char* jsonPath) const char* password, const char* httpHeader, const char* httpValue, uint32_t timeout, const char* jsonPath)
{ {
int port = (https ? 443 : 80);
if(!httpClient.begin(wifiClient, host, port, uri, https)){ if(!httpClient.begin(wifiClient, host, port, uri, https)){
snprintf_P(httpPowerMeterError, sizeof(httpPowerMeterError), PSTR("httpClient.begin() failed for %s://%s"), (https ? "https" : "http"), host.c_str()); snprintf_P(httpPowerMeterError, sizeof(httpPowerMeterError), PSTR("httpClient.begin() failed for %s://%s"), (https ? "https" : "http"), host.c_str());
return false; return false;
@ -203,13 +204,13 @@ bool HttpPowerMeterClass::tryGetFloatValueForPhase(int phase, int httpCode, cons
bool success = false; bool success = false;
if (httpCode == HTTP_CODE_OK) { if (httpCode == HTTP_CODE_OK) {
httpResponse = httpClient.getString(); //very unfortunate that we cannot parse WifiClient stream directly httpResponse = httpClient.getString(); //very unfortunate that we cannot parse WifiClient stream directly
StaticJsonDocument<2048> json; //however creating these allocations on stack should be fine to avoid heap fragmentation FirebaseJson json;
deserializeJson(json, httpResponse); json.setJsonData(httpResponse);
if(!json.containsKey(jsonPath)) FirebaseJsonData value;
{ if (!json.get(value, jsonPath)) {
snprintf_P(httpPowerMeterError, sizeof(httpPowerMeterError), PSTR("[HttpPowerMeter] Couldn't find a value for phase %i with Json query \"%s\""), phase, jsonPath); snprintf_P(httpPowerMeterError, sizeof(httpPowerMeterError), PSTR("[HttpPowerMeter] Couldn't find a value for phase %i with Json query \"%s\""), phase, jsonPath);
}else { }else {
power[phase] = json[jsonPath].as<float>(); power[phase] = value.to<float>();
//MessageOutput.printf("Power for Phase %i: %5.2fW\r\n", phase, power[phase]); //MessageOutput.printf("Power for Phase %i: %5.2fW\r\n", phase, power[phase]);
success = true; success = true;
} }
@ -221,34 +222,55 @@ bool HttpPowerMeterClass::tryGetFloatValueForPhase(int phase, int httpCode, cons
return success; return success;
} }
void HttpPowerMeterClass::extractUrlComponents(const String& url, String& protocol, String& hostname, String& uri) { //extract url component as done by httpClient::begin(String url, const char* expectedProtocol) https://github.com/espressif/arduino-esp32/blob/da6325dd7e8e152094b19fe63190907f38ef1ff0/libraries/HTTPClient/src/HTTPClient.cpp#L250
// Find protocol delimiter bool HttpPowerMeterClass::extractUrlComponents(String url, String& _protocol, String& _host, String& _uri, uint16_t& _port, String& _base64Authorization)
int protocolEndIndex = url.indexOf(":"); {
if (protocolEndIndex != -1) { // check for : (http: or https:
protocol = url.substring(0, protocolEndIndex); int index = url.indexOf(':');
if(index < 0) {
snprintf_P(httpPowerMeterError, sizeof(httpPowerMeterError), PSTR("failed to parse protocol"));
return false;
}
// Find double slash delimiter _protocol = url.substring(0, index);
int doubleSlashIndex = url.indexOf("//", protocolEndIndex);
if (doubleSlashIndex != -1) { //initialize port to default values for http or https.
// Find slash after double slash delimiter //port will be overwritten below in case port is explicitly defined
int slashIndex = url.indexOf("/", doubleSlashIndex + 2); _port = (_protocol == "https" ? 443 : 80);
if (slashIndex != -1) {
// Extract hostname and uri url.remove(0, (index + 3)); // remove http:// or https://
hostname = url.substring(doubleSlashIndex + 2, slashIndex);
uri = url.substring(slashIndex); index = url.indexOf('/');
if (index == -1) {
index = url.length();
url += '/';
}
String host = url.substring(0, index);
url.remove(0, index); // remove host part
// get Authorization
index = host.indexOf('@');
if(index >= 0) {
// auth info
String auth = host.substring(0, index);
host.remove(0, index + 1); // remove auth part including @
_base64Authorization = base64::encode(auth);
}
// get port
index = host.indexOf(':');
String the_host;
if(index >= 0) {
the_host = host.substring(0, index); // hostname
host.remove(0, (index + 1)); // remove hostname + :
_port = host.toInt(); // get port
} else { } else {
// No slash after double slash delimiter, so the whole remaining part is the hostname the_host = host;
hostname = url.substring(doubleSlashIndex + 2);
uri = "/";
}
}
} }
// Remove username:password if present in the hostname _host = the_host;
int atIndex = hostname.indexOf("@"); _uri = url;
if (atIndex != -1) { return true;
hostname = hostname.substring(atIndex + 1);
}
} }
#define HASH_SIZE 32 #define HASH_SIZE 32