From aad12fc8689d141273f9885b27c733bf2a00bd4a Mon Sep 17 00:00:00 2001 From: samuelbles07 Date: Thu, 21 Nov 2024 01:18:51 +0700 Subject: [PATCH 01/13] Using https For get config and post measurements --- src/AgApiClient.cpp | 46 +++++++++++++++++++++++++++++++-------------- src/AgApiClient.h | 39 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+), 14 deletions(-) diff --git a/src/AgApiClient.cpp b/src/AgApiClient.cpp index 8a72a67..1516d83 100644 --- a/src/AgApiClient.cpp +++ b/src/AgApiClient.cpp @@ -59,9 +59,20 @@ bool AgApiClient::fetchServerConfiguration(void) { #else HTTPClient client; client.setTimeout(timeoutMs); - if (client.begin(uri) == false) { - getConfigFailed = true; - return false; + if (apiRootChanged) { + // If apiRoot is changed, assume not using https + if (client.begin(uri) == false) { + logError("Begin HTTPClient failed (GET)"); + getConfigFailed = true; + return false; + } + } else { + // By default, airgradient using https + if (client.begin(uri, agCA) == false) { + logError("Begin HTTPClient using tls failed (GET)"); + getConfigFailed = true; + return false; + } } #endif @@ -90,8 +101,6 @@ bool AgApiClient::fetchServerConfiguration(void) { String respContent = client.getString(); client.end(); - // logInfo("Get configuration: " + respContent); - /** Parse configuration and return result */ return config.parse(respContent, false); } @@ -115,22 +124,28 @@ bool AgApiClient::postToServer(String data) { } String uri = apiRoot + "/sensors/airgradient:" + ag->deviceId() + "/measures"; - // logInfo("Post uri: " + uri); - // logInfo("Post data: " + data); - - WiFiClient wifiClient; HTTPClient client; client.setTimeout(timeoutMs); - if (client.begin(wifiClient, uri.c_str()) == false) { - logError("Init client failed"); - return false; + if (apiRootChanged) { + // If apiRoot is changed, assume not using https + if (client.begin(uri) == false) { + logError("Begin HTTPClient failed (POST)"); + getConfigFailed = true; + return false; + } + } else { + // By default, airgradient using https + if (client.begin(uri, agCA) == false) { + logError("Begin HTTPClient using tls failed (POST)"); + getConfigFailed = true; + return false; + } } client.addHeader("content-type", "application/json"); int retCode = client.POST(data); client.end(); logInfo(String("POST: ") + uri); - // logInfo(String("DATA: ") + data); logInfo(String("Return code: ") + String(retCode)); if ((retCode == 200) || (retCode == 429)) { @@ -189,7 +204,10 @@ bool AgApiClient::sendPing(int rssi, int bootCount) { String AgApiClient::getApiRoot() const { return apiRoot; } -void AgApiClient::setApiRoot(const String &apiRoot) { this->apiRoot = apiRoot; } +void AgApiClient::setApiRoot(const String &apiRoot) { + this->apiRootChanged = true; + this->apiRoot = apiRoot; +} /** * @brief Set http request timeout. (Default: 10s) diff --git a/src/AgApiClient.h b/src/AgApiClient.h index 7035323..2d8b162 100644 --- a/src/AgApiClient.h +++ b/src/AgApiClient.h @@ -20,8 +20,47 @@ class AgApiClient : public PrintLog { private: Configuration &config; AirGradient *ag; +#ifdef ESP8266 String apiRoot = "http://hw.airgradient.com"; +#else + String apiRoot = "https://hw.airgradient.com"; + const char *agCA = "-----BEGIN CERTIFICATE-----\n" + "MIIF4jCCA8oCCQD7MgvcaVWxkTANBgkqhkiG9w0BAQsFADCBsjELMAkGA1UEBhMC\n" + "VEgxEzARBgNVBAgMCkNoaWFuZyBNYWkxEDAOBgNVBAcMB01hZSBSaW0xGTAXBgNV\n" + "BAoMEEFpckdyYWRpZW50IEx0ZC4xFDASBgNVBAsMC1NlbnNvciBMYWJzMSgwJgYD\n" + "VQQDDB9BaXJHcmFkaWVudCBTZW5zb3IgTGFicyBSb290IENBMSEwHwYJKoZIhvcN\n" + "AQkBFhJjYUBhaXJncmFkaWVudC5jb20wHhcNMjEwOTE3MTE0NDE3WhcNNDEwOTEy\n" + "MTE0NDE3WjCBsjELMAkGA1UEBhMCVEgxEzARBgNVBAgMCkNoaWFuZyBNYWkxEDAO\n" + "BgNVBAcMB01hZSBSaW0xGTAXBgNVBAoMEEFpckdyYWRpZW50IEx0ZC4xFDASBgNV\n" + "BAsMC1NlbnNvciBMYWJzMSgwJgYDVQQDDB9BaXJHcmFkaWVudCBTZW5zb3IgTGFi\n" + "cyBSb290IENBMSEwHwYJKoZIhvcNAQkBFhJjYUBhaXJncmFkaWVudC5jb20wggIi\n" + "MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC6XkVQ4O9d5GcUjPYRgF/uaY6O\n" + "5ry1xCGvotxkEeKkBk99lB1oNUUfNsP5bwuDci4XKfY9Ro6/jmkfHSVcPAwUnjAt\n" + "BcHqZtA/cMXykaynf9yXPxPQN7XLu/Rk32RIfb90sIGS318xgNziCYvzWZmlxpxc\n" + "3gUcAgGtamlgZ6wD3yOHVo8B9aFNvmP16QwkUm8fKDHunJG+iX2Bxa4ka5FJovhG\n" + "TnUwtso6Vrn0JaWF9qWcPZE0JZMjFW8PYRriyJmHwr/nAXfPPKphD1oRO+oA7/jq\n" + "dYkrJw6+OHfFXnPB1xkeh4OPBzcCZHT5XWNfwBYazYpjcJa9ngGFSmg8lX1ac23C\n" + "zea1XJmSrPwbZbWxoQznnf7Y78mRjruYKgSP8rf74KYvBe/HGPL5NQyXQ3l6kwmu\n" + "CCUqfcC0wCWEtWESxwSdFE2qQii8CZ12kQExzvR2PrOIyKQYSdkGx9/RBZtAVPXP\n" + "hmLuRBQYHrF5Cxf1oIbBK8OMoNVgBm6ftt15t9Sq9dH5Aup2YR6WEJkVaYkYzZzK\n" + "X7M+SQcdbXp+hAO8PFpABJxkaDAO2kiB5Ov7pDYPAcmNFqnJT48AY0TZJeVeCa5W\n" + "sIv3lPvB/XcFjP0+aZxxNSEEwpGPUYgvKUYUUmb0NammlYQwZHKaShPEmZ3UZ0bp\n" + "VNt4p6374nzO376sSwIDAQABMA0GCSqGSIb3DQEBCwUAA4ICAQB/LfBPgTx7xKQB\n" + "JNMUhah17AFAn050NiviGJOHdPQely6u3DmJGg+ijEVlPWO1FEW3it+LOuNP5zOu\n" + "bhq8paTYIxPxtALIxw5ksykX9woDuX3H6FF9mPdQIbL7ft+3ZtZ4FWPui9dUtaPe\n" + "ZBmDFDi4U29nhWZK68JSp5QkWjfaYLV/vtag7120eVyGEPFZ0UAuTUNqpw+stOt9\n" + "gJ2ZxNx13xJ8ZnLK7qz1crPe8/8IVAdxbVLoY7JaWPLc//+VF+ceKicy8+4gV7zN\n" + "Gnq2IyM+CHFz8VYMLbW+3eVp4iJjTa72vae116kozboEIUVN9rgLqIKyVqQXiuoN\n" + "g3xY+yfncPB2+H/+lfyy6mepPIfgksd3+KeNxFADSc5EVY2JKEdorRodnAh7a8K6\n" + "WjTYgq+GjWXU2uQW2SyPt6Tu33OT8nBnu3NB80eT8WXgdVCkgsuyCuLvNRf1Xmze\n" + "igvurpU6JmQ1GlLgLJo8omJHTh1zIbkR9injPYne2v9ciHCoP6+LDEqe+rOsvPCB\n" + "C/o/iZ4svmYX4fWGuU7GgqZE8hhrC3+GdOTf2ADC752cYCZxBidXGtkrGNoHQKmQ\n" + "KCOMFBxZIvWteB3tUo3BKYz1D2CvKWz1wV4moc5JHkOgS+jqxhvOkQ/vfQBQ1pUY\n" + "TMui9BSwU7B1G2XjdLbfF3Dc67zaSg==\n" + "-----END CERTIFICATE-----\n"; +#endif + bool apiRootChanged = false; // Indicate if setApiRoot() is called bool getConfigFailed; bool postToServerFailed; bool notAvailableOnDashboard = false; // Device not setup on Airgradient cloud dashboard. From 3ca2d1d20871e461c3d9d0887d4027548c4a1291 Mon Sep 17 00:00:00 2001 From: samuelbles07 Date: Thu, 21 Nov 2024 01:26:05 +0700 Subject: [PATCH 02/13] Fix esp8266 build issue --- src/AgApiClient.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/AgApiClient.cpp b/src/AgApiClient.cpp index 1516d83..b34a242 100644 --- a/src/AgApiClient.cpp +++ b/src/AgApiClient.cpp @@ -124,6 +124,14 @@ bool AgApiClient::postToServer(String data) { } String uri = apiRoot + "/sensors/airgradient:" + ag->deviceId() + "/measures"; +#ifdef ESP8266 + HTTPClient client; + WiFiClient wifiClient; + if (client.begin(wifiClient, uri) == false) { + getConfigFailed = true; + return false; + } +#else HTTPClient client; client.setTimeout(timeoutMs); if (apiRootChanged) { @@ -141,6 +149,7 @@ bool AgApiClient::postToServer(String data) { return false; } } +#endif client.addHeader("content-type", "application/json"); int retCode = client.POST(data); client.end(); From 2be91b3968866dea56742044c4e72c193b399985 Mon Sep 17 00:00:00 2001 From: samuelbles07 Date: Thu, 21 Nov 2024 02:30:03 +0700 Subject: [PATCH 03/13] Boot count using setter and getter --- examples/BASIC/BASIC.ino | 5 +++-- examples/DiyProIndoorV3_3/DiyProIndoorV3_3.ino | 5 +++-- examples/DiyProIndoorV4_2/DiyProIndoorV4_2.ino | 5 +++-- examples/OneOpenAir/OneOpenAir.ino | 5 +++-- src/AgValue.cpp | 10 +++++++--- src/AgValue.h | 5 +++-- 6 files changed, 22 insertions(+), 13 deletions(-) diff --git a/examples/BASIC/BASIC.ino b/examples/BASIC/BASIC.ino index 78da232..97105fb 100644 --- a/examples/BASIC/BASIC.ino +++ b/examples/BASIC/BASIC.ino @@ -331,7 +331,7 @@ static void sendDataToAg() { stateMachine.displayHandle(AgStateMachineWiFiOkServerConnecting); delay(1500); - if (apiClient.sendPing(wifiConnector.RSSI(), measurements.bootCount)) { + if (apiClient.sendPing(wifiConnector.RSSI(), measurements.bootCount())) { stateMachine.displayHandle(AgStateMachineWiFiOkServerConnected); } else { stateMachine.displayHandle(AgStateMachineWiFiOkServerConnectFailed); @@ -518,7 +518,8 @@ static void updatePm(void) { static void sendDataToServer(void) { /** Increment bootcount when send measurements data is scheduled */ - measurements.bootCount++; + int bootCount = measurements.bootCount() + 1; + measurements.setBootCount(bootCount); /** Ignore send data to server if postToAirGradient disabled */ if (configuration.isPostDataToAirGradient() == false || diff --git a/examples/DiyProIndoorV3_3/DiyProIndoorV3_3.ino b/examples/DiyProIndoorV3_3/DiyProIndoorV3_3.ino index 04430e3..bd19b86 100644 --- a/examples/DiyProIndoorV3_3/DiyProIndoorV3_3.ino +++ b/examples/DiyProIndoorV3_3/DiyProIndoorV3_3.ino @@ -388,7 +388,7 @@ static void sendDataToAg() { stateMachine.displayHandle(AgStateMachineWiFiOkServerConnecting); delay(1500); - if (apiClient.sendPing(wifiConnector.RSSI(), measurements.bootCount)) { + if (apiClient.sendPing(wifiConnector.RSSI(), measurements.bootCount())) { stateMachine.displayHandle(AgStateMachineWiFiOkServerConnected); } else { stateMachine.displayHandle(AgStateMachineWiFiOkServerConnectFailed); @@ -570,7 +570,8 @@ static void updatePm(void) { static void sendDataToServer(void) { /** Increment bootcount when send measurements data is scheduled */ - measurements.bootCount++; + int bootCount = measurements.bootCount() + 1; + measurements.setBootCount(bootCount); /** Ignore send data to server if postToAirGradient disabled */ if (configuration.isPostDataToAirGradient() == false || diff --git a/examples/DiyProIndoorV4_2/DiyProIndoorV4_2.ino b/examples/DiyProIndoorV4_2/DiyProIndoorV4_2.ino index 8bfb466..f29c2cf 100644 --- a/examples/DiyProIndoorV4_2/DiyProIndoorV4_2.ino +++ b/examples/DiyProIndoorV4_2/DiyProIndoorV4_2.ino @@ -411,7 +411,7 @@ static void sendDataToAg() { stateMachine.displayHandle(AgStateMachineWiFiOkServerConnecting); delay(1500); - if (apiClient.sendPing(wifiConnector.RSSI(), measurements.bootCount)) { + if (apiClient.sendPing(wifiConnector.RSSI(), measurements.bootCount())) { stateMachine.displayHandle(AgStateMachineWiFiOkServerConnected); } else { stateMachine.displayHandle(AgStateMachineWiFiOkServerConnectFailed); @@ -611,7 +611,8 @@ static void updatePm(void) { static void sendDataToServer(void) { /** Increment bootcount when send measurements data is scheduled */ - measurements.bootCount++; + int bootCount = measurements.bootCount() + 1; + measurements.setBootCount(bootCount); /** Ignore send data to server if postToAirGradient disabled */ if (configuration.isPostDataToAirGradient() == false || diff --git a/examples/OneOpenAir/OneOpenAir.ino b/examples/OneOpenAir/OneOpenAir.ino index fce0feb..448284d 100644 --- a/examples/OneOpenAir/OneOpenAir.ino +++ b/examples/OneOpenAir/OneOpenAir.ino @@ -634,7 +634,7 @@ static void sendDataToAg() { "task_led", 2048, NULL, 5, NULL); delay(1500); - if (apiClient.sendPing(wifiConnector.RSSI(), measurements.bootCount)) { + if (apiClient.sendPing(wifiConnector.RSSI(), measurements.bootCount())) { if (ag->isOne()) { stateMachine.displayHandle(AgStateMachineWiFiOkServerConnected); } @@ -1135,7 +1135,8 @@ static void updatePm(void) { static void sendDataToServer(void) { /** Increment bootcount when send measurements data is scheduled */ - measurements.bootCount++; + int bootCount = measurements.bootCount() + 1; + measurements.setBootCount(bootCount); /** Ignore send data to server if postToAirGradient disabled */ if (configuration.isPostDataToAirGradient() == false || configuration.isOfflineMode()) { diff --git a/src/AgValue.cpp b/src/AgValue.cpp index 0df5db8..769fddd 100644 --- a/src/AgValue.cpp +++ b/src/AgValue.cpp @@ -601,8 +601,8 @@ String Measurements::toString(bool localServer, AgFirmwareMode fwMode, int rssi, } } - root["boot"] = bootCount; - root["bootCount"] = bootCount; + root["boot"] = _bootCount; + root["bootCount"] = _bootCount; root["wifi"] = rssi; if (localServer) { @@ -1065,4 +1065,8 @@ JSONVar Measurements::buildPMS(AirGradient &ag, int ch, bool allCh, bool withTem return pms; } -void Measurements::setDebug(bool debug) { _debug = debug; } \ No newline at end of file +void Measurements::setDebug(bool debug) { _debug = debug; } + +int Measurements::bootCount() { return _bootCount; } + +void Measurements::setBootCount(int bootCount) { _bootCount = bootCount; } \ No newline at end of file diff --git a/src/AgValue.h b/src/AgValue.h index f6ae46d..3546115 100644 --- a/src/AgValue.h +++ b/src/AgValue.h @@ -147,8 +147,8 @@ public: */ void setDebug(bool debug); - // TODO: update this to use setter - int bootCount; + int bootCount(); + void setBootCount(int bootCount); private: // Some declared as an array (channel), because FW_MODE_O_1PPx has two PMS5003T @@ -171,6 +171,7 @@ private: IntegerValue _pm_25_pc[2]; // particle count 2.5 IntegerValue _pm_5_pc[2]; // particle count 5.0 IntegerValue _pm_10_pc[2]; // particle count 10 + int _bootCount; bool _debug = false; From 4c165b31f59599ce35d3f9406077c98ae9552a3f Mon Sep 17 00:00:00 2001 From: samuelbles07 Date: Thu, 21 Nov 2024 02:36:56 +0700 Subject: [PATCH 04/13] Add freeheap to cloud payload --- examples/OneOpenAir/OneOpenAir.ino | 3 +++ src/AgValue.cpp | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/examples/OneOpenAir/OneOpenAir.ino b/examples/OneOpenAir/OneOpenAir.ino index 448284d..7230e14 100644 --- a/examples/OneOpenAir/OneOpenAir.ino +++ b/examples/OneOpenAir/OneOpenAir.ino @@ -1150,6 +1150,9 @@ static void sendDataToServer(void) { "Online mode and isPostToAirGradient = true: watchdog reset"); Serial.println(); } + + /** Log current free heap size */ + Serial.printf("Free heap: %u\n", ESP.getFreeHeap()); } static void tempHumUpdate(void) { diff --git a/src/AgValue.cpp b/src/AgValue.cpp index 769fddd..ab3e731 100644 --- a/src/AgValue.cpp +++ b/src/AgValue.cpp @@ -612,6 +612,10 @@ String Measurements::toString(bool localServer, AgFirmwareMode fwMode, int rssi, root["serialno"] = ag.deviceId(); root["firmware"] = ag.getVersion(); root["model"] = AgFirmwareModeName(fwMode); + } else { +#ifndef ESP8266 + root["freeHeap"] = ESP.getFreeHeap(); +#endif } String result = JSON.stringify(root); From 40d38a75d8fafe4d9f12891c88d27a62aacae7ad Mon Sep 17 00:00:00 2001 From: samuelbles07 Date: Fri, 29 Nov 2024 18:01:14 +0700 Subject: [PATCH 05/13] Add reset reason to transmission payload --- examples/OneOpenAir/OneOpenAir.ino | 11 ++++++++--- src/AgValue.h | 4 +++- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/examples/OneOpenAir/OneOpenAir.ino b/examples/OneOpenAir/OneOpenAir.ino index 7230e14..971a5c8 100644 --- a/examples/OneOpenAir/OneOpenAir.ino +++ b/examples/OneOpenAir/OneOpenAir.ino @@ -36,20 +36,21 @@ CC BY-SA 4.0 Attribution-ShareAlike 4.0 International License */ -#include -#include "AirGradient.h" -#include "OtaHandler.h" #include "AgApiClient.h" #include "AgConfigure.h" #include "AgSchedule.h" #include "AgStateMachine.h" #include "AgWiFiConnector.h" +#include "AirGradient.h" #include "EEPROM.h" #include "ESPmDNS.h" #include "LocalServer.h" #include "MqttClient.h" #include "OpenMetrics.h" +#include "OtaHandler.h" #include "WebServer.h" +#include "esp32c3/rom/rtc.h" +#include #include #include @@ -136,6 +137,10 @@ void setup() { /** Print device ID into log */ Serial.println("Serial nr: " + ag->deviceId()); + // Set reason why esp is reset + esp_reset_reason_t reason = esp_reset_reason(); + measurements.setResetReason(reason); + /** Initialize local configure */ configuration.begin(); diff --git a/src/AgValue.h b/src/AgValue.h index 3546115..f74018e 100644 --- a/src/AgValue.h +++ b/src/AgValue.h @@ -150,6 +150,8 @@ public: int bootCount(); void setBootCount(int bootCount); + void setResetReason(esp_reset_reason_t reason); + private: // Some declared as an array (channel), because FW_MODE_O_1PPx has two PMS5003T FloatValue _temperature[2]; @@ -172,7 +174,7 @@ private: IntegerValue _pm_5_pc[2]; // particle count 5.0 IntegerValue _pm_10_pc[2]; // particle count 10 int _bootCount; - + int _resetReason; bool _debug = false; /** From c1f22674e2bbba01ed27079b40c62705562b74de Mon Sep 17 00:00:00 2001 From: samuelbles07 Date: Fri, 29 Nov 2024 18:01:34 +0700 Subject: [PATCH 06/13] Add reset reason to transmission payload --- src/AgValue.cpp | 48 +++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 43 insertions(+), 5 deletions(-) diff --git a/src/AgValue.cpp b/src/AgValue.cpp index ab3e731..fac99f3 100644 --- a/src/AgValue.cpp +++ b/src/AgValue.cpp @@ -604,6 +604,8 @@ String Measurements::toString(bool localServer, AgFirmwareMode fwMode, int rssi, root["boot"] = _bootCount; root["bootCount"] = _bootCount; root["wifi"] = rssi; + root["resetReason"] = _resetReason; + root["freeHeap"] = ESP.getFreeHeap(); if (localServer) { if (ag.isOne()) { @@ -612,10 +614,6 @@ String Measurements::toString(bool localServer, AgFirmwareMode fwMode, int rssi, root["serialno"] = ag.deviceId(); root["firmware"] = ag.getVersion(); root["model"] = AgFirmwareModeName(fwMode); - } else { -#ifndef ESP8266 - root["freeHeap"] = ESP.getFreeHeap(); -#endif } String result = JSON.stringify(root); @@ -1073,4 +1071,44 @@ void Measurements::setDebug(bool debug) { _debug = debug; } int Measurements::bootCount() { return _bootCount; } -void Measurements::setBootCount(int bootCount) { _bootCount = bootCount; } \ No newline at end of file +void Measurements::setBootCount(int bootCount) { _bootCount = bootCount; } + +void Measurements::setResetReason(esp_reset_reason_t reason) { + switch (reason) { + case ESP_RST_UNKNOWN: + Serial.println("Reset reason: ESP_RST_UNKNOWN"); + break; + case ESP_RST_POWERON: + Serial.println("Reset reason: ESP_RST_POWERON"); + break; + case ESP_RST_EXT: + Serial.println("Reset reason: ESP_RST_EXT"); + break; + case ESP_RST_SW: + Serial.println("Reset reason: ESP_RST_SW"); + break; + case ESP_RST_PANIC: + Serial.println("Reset reason: ESP_RST_PANIC"); + break; + case ESP_RST_INT_WDT: + Serial.println("Reset reason: ESP_RST_INT_WDT"); + break; + case ESP_RST_TASK_WDT: + Serial.println("Reset reason: ESP_RST_TASK_WDT"); + break; + case ESP_RST_WDT: + Serial.println("Reset reason: ESP_RST_WDT"); + break; + case ESP_RST_BROWNOUT: + Serial.println("Reset reason: ESP_RST_BROWNOUT"); + break; + case ESP_RST_SDIO: + Serial.println("Reset reason: ESP_RST_SDIO"); + break; + default: + Serial.println("Reset reason: unknown"); + break; + } + + _resetReason = (int)reason; +} \ No newline at end of file From 6312612ada9da004a898cdf9324f292b9997b6aa Mon Sep 17 00:00:00 2001 From: samuelbles07 Date: Sat, 30 Nov 2024 00:45:46 +0700 Subject: [PATCH 07/13] resetReason and freeheap only for esp32 based mcu --- src/AgValue.cpp | 17 ++++++++++++++--- src/AgValue.h | 4 +++- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/AgValue.cpp b/src/AgValue.cpp index fac99f3..cef79b9 100644 --- a/src/AgValue.cpp +++ b/src/AgValue.cpp @@ -27,6 +27,12 @@ #define json_prop_noxRaw "noxRaw" #define json_prop_co2 "rco2" +Measurements::Measurements() { +#ifndef ESP8266 + _resetReason = (int)ESP_RST_UNKNOWN; +#endif +} + void Measurements::maxPeriod(MeasurementType type, int max) { switch (type) { case Temperature: @@ -604,8 +610,6 @@ String Measurements::toString(bool localServer, AgFirmwareMode fwMode, int rssi, root["boot"] = _bootCount; root["bootCount"] = _bootCount; root["wifi"] = rssi; - root["resetReason"] = _resetReason; - root["freeHeap"] = ESP.getFreeHeap(); if (localServer) { if (ag.isOne()) { @@ -614,6 +618,11 @@ String Measurements::toString(bool localServer, AgFirmwareMode fwMode, int rssi, root["serialno"] = ag.deviceId(); root["firmware"] = ag.getVersion(); root["model"] = AgFirmwareModeName(fwMode); + } else { +#ifndef ESP8266 + root["resetReason"] = _resetReason; + root["freeHeap"] = ESP.getFreeHeap(); +#endif } String result = JSON.stringify(root); @@ -1073,6 +1082,7 @@ int Measurements::bootCount() { return _bootCount; } void Measurements::setBootCount(int bootCount) { _bootCount = bootCount; } +#ifndef ESP8266 void Measurements::setResetReason(esp_reset_reason_t reason) { switch (reason) { case ESP_RST_UNKNOWN: @@ -1111,4 +1121,5 @@ void Measurements::setResetReason(esp_reset_reason_t reason) { } _resetReason = (int)reason; -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/src/AgValue.h b/src/AgValue.h index f74018e..6cc7a05 100644 --- a/src/AgValue.h +++ b/src/AgValue.h @@ -34,7 +34,7 @@ private: }; public: - Measurements() {} + Measurements(); ~Measurements() {} // Enumeration for every AG measurements @@ -150,7 +150,9 @@ public: int bootCount(); void setBootCount(int bootCount); +#ifndef ESP8266 void setResetReason(esp_reset_reason_t reason); +#endif private: // Some declared as an array (channel), because FW_MODE_O_1PPx has two PMS5003T From 283646a69936d1c18f111c8e4b247056129034ba Mon Sep 17 00:00:00 2001 From: samuelbles07 Date: Sat, 30 Nov 2024 02:47:05 +0700 Subject: [PATCH 08/13] Move OtaHandler to src OTA only valid for esp32 based monitor --- examples/OneOpenAir/OneOpenAir.ino | 35 +++-- examples/OneOpenAir/OtaHandler.h | 206 ----------------------------- src/OtaHandler.cpp | 164 +++++++++++++++++++++++ src/OtaHandler.h | 43 ++++++ 4 files changed, 223 insertions(+), 225 deletions(-) delete mode 100644 examples/OneOpenAir/OtaHandler.h create mode 100644 src/OtaHandler.cpp create mode 100644 src/OtaHandler.h diff --git a/examples/OneOpenAir/OneOpenAir.ino b/examples/OneOpenAir/OneOpenAir.ino index 971a5c8..ee4b680 100644 --- a/examples/OneOpenAir/OneOpenAir.ino +++ b/examples/OneOpenAir/OneOpenAir.ino @@ -112,9 +112,8 @@ static void wdgFeedUpdate(void); static void ledBarEnabledUpdate(void); static bool sgp41Init(void); static void firmwareCheckForUpdate(void); -static void otaHandlerCallback(OtaState state, String mesasge); -static void displayExecuteOta(OtaState state, String msg, - int processing); +static void otaHandlerCallback(OtaHandler::OtaState state, String mesasge); +static void displayExecuteOta(OtaHandler::OtaState state, String msg, int processing); static int calculateMaxPeriod(int updateInterval); static void setMeasurementMaxPeriod(); @@ -519,29 +518,27 @@ static void firmwareCheckForUpdate(void) { Serial.println(); } -static void otaHandlerCallback(OtaState state, String mesasge) { - Serial.println("OTA message: " + mesasge); +static void otaHandlerCallback(OtaHandler::OtaState state, String message) { + Serial.println("OTA message: " + message); switch (state) { - case OtaState::OTA_STATE_BEGIN: + case OtaHandler::OTA_STATE_BEGIN: displayExecuteOta(state, fwNewVersion, 0); break; - case OtaState::OTA_STATE_FAIL: + case OtaHandler::OTA_STATE_FAIL: displayExecuteOta(state, "", 0); break; - case OtaState::OTA_STATE_PROCESSING: - displayExecuteOta(state, "", mesasge.toInt()); - break; - case OtaState::OTA_STATE_SUCCESS: - displayExecuteOta(state, "", mesasge.toInt()); + case OtaHandler::OTA_STATE_PROCESSING: + case OtaHandler::OTA_STATE_SUCCESS: + displayExecuteOta(state, "", message.toInt()); break; default: break; } } -static void displayExecuteOta(OtaState state, String msg, int processing) { +static void displayExecuteOta(OtaHandler::OtaState state, String msg, int processing) { switch (state) { - case OtaState::OTA_STATE_BEGIN: { + case OtaHandler::OTA_STATE_BEGIN: { if (ag->isOne()) { oledDisplay.showFirmwareUpdateVersion(msg); } else { @@ -550,7 +547,7 @@ static void displayExecuteOta(OtaState state, String msg, int processing) { delay(2500); break; } - case OtaState::OTA_STATE_FAIL: { + case OtaHandler::OTA_STATE_FAIL: { if (ag->isOne()) { oledDisplay.showFirmwareUpdateFailed(); } else { @@ -560,7 +557,7 @@ static void displayExecuteOta(OtaState state, String msg, int processing) { delay(2500); break; } - case OtaState::OTA_STATE_SKIP: { + case OtaHandler::OTA_STATE_SKIP: { if (ag->isOne()) { oledDisplay.showFirmwareUpdateSkipped(); } else { @@ -570,7 +567,7 @@ static void displayExecuteOta(OtaState state, String msg, int processing) { delay(2500); break; } - case OtaState::OTA_STATE_UP_TO_DATE: { + case OtaHandler::OTA_STATE_UP_TO_DATE: { if (ag->isOne()) { oledDisplay.showFirmwareUpdateUpToDate(); } else { @@ -580,7 +577,7 @@ static void displayExecuteOta(OtaState state, String msg, int processing) { delay(2500); break; } - case OtaState::OTA_STATE_PROCESSING: { + case OtaHandler::OTA_STATE_PROCESSING: { if (ag->isOne()) { oledDisplay.showFirmwareUpdateProgress(processing); } else { @@ -589,7 +586,7 @@ static void displayExecuteOta(OtaState state, String msg, int processing) { break; } - case OtaState::OTA_STATE_SUCCESS: { + case OtaHandler::OTA_STATE_SUCCESS: { int i = 6; while(i != 0) { i = i - 1; diff --git a/examples/OneOpenAir/OtaHandler.h b/examples/OneOpenAir/OtaHandler.h deleted file mode 100644 index a845f8b..0000000 --- a/examples/OneOpenAir/OtaHandler.h +++ /dev/null @@ -1,206 +0,0 @@ -#ifndef _OTA_HANDLER_H_ -#define _OTA_HANDLER_H_ -#include -#include -#include -#include - -#define OTA_BUF_SIZE 1024 -#define URL_BUF_SIZE 256 - -enum OtaUpdateOutcome { - UPDATE_PERFORMED, - ALREADY_UP_TO_DATE, - UPDATE_FAILED, - UDPATE_SKIPPED -}; - -enum OtaState { - OTA_STATE_BEGIN, - OTA_STATE_FAIL, - OTA_STATE_SKIP, - OTA_STATE_UP_TO_DATE, - OTA_STATE_PROCESSING, - OTA_STATE_SUCCESS -}; - -typedef void(*OtaHandlerCallback_t)(OtaState state, - String message); - -class OtaHandler { -public: - void updateFirmwareIfOutdated(String deviceId) { - String url = "http://hw.airgradient.com/sensors/airgradient:" + deviceId + - "/generic/os/firmware.bin"; - url += "?current_firmware="; - url += GIT_VERSION; - char urlAsChar[URL_BUF_SIZE]; - url.toCharArray(urlAsChar, URL_BUF_SIZE); - Serial.printf("checking for new OTA update @ %s\n", urlAsChar); - - esp_http_client_config_t config = {}; - config.url = urlAsChar; - OtaUpdateOutcome ret = attemptToPerformOta(&config); - Serial.println(ret); - if (this->callback) { - switch (ret) { - case OtaUpdateOutcome::UPDATE_PERFORMED: - this->callback(OtaState::OTA_STATE_SUCCESS, ""); - break; - case OtaUpdateOutcome::UDPATE_SKIPPED: - this->callback(OtaState::OTA_STATE_SKIP, ""); - break; - case OtaUpdateOutcome::ALREADY_UP_TO_DATE: - this->callback(OtaState::OTA_STATE_UP_TO_DATE, ""); - break; - case OtaUpdateOutcome::UPDATE_FAILED: - this->callback(OtaState::OTA_STATE_FAIL, ""); - break; - default: - break; - } - } - } - - void setHandlerCallback(OtaHandlerCallback_t callback) { - this->callback = callback; - } - -private: - OtaHandlerCallback_t callback; - - OtaUpdateOutcome attemptToPerformOta(const esp_http_client_config_t *config) { - esp_http_client_handle_t client = esp_http_client_init(config); - if (client == NULL) { - Serial.println("Failed to initialize HTTP connection"); - return OtaUpdateOutcome::UPDATE_FAILED; - } - - esp_err_t err = esp_http_client_open(client, 0); - if (err != ESP_OK) { - esp_http_client_cleanup(client); - Serial.printf("Failed to open HTTP connection: %s\n", - esp_err_to_name(err)); - return OtaUpdateOutcome::UPDATE_FAILED; - } - esp_http_client_fetch_headers(client); - - int httpStatusCode = esp_http_client_get_status_code(client); - if (httpStatusCode == 304) { - Serial.println("Firmware is already up to date"); - cleanupHttp(client); - return OtaUpdateOutcome::ALREADY_UP_TO_DATE; - } else if (httpStatusCode != 200) { - Serial.printf("Firmware update skipped, the server returned %d\n", - httpStatusCode); - cleanupHttp(client); - return OtaUpdateOutcome::UDPATE_SKIPPED; - } - - esp_ota_handle_t update_handle = 0; - const esp_partition_t *update_partition = NULL; - Serial.println("Starting OTA update ..."); - update_partition = esp_ota_get_next_update_partition(NULL); - if (update_partition == NULL) { - Serial.println("Passive OTA partition not found"); - cleanupHttp(client); - return OtaUpdateOutcome::UPDATE_FAILED; - } - Serial.printf("Writing to partition subtype %d at offset 0x%x\n", - update_partition->subtype, update_partition->address); - - err = esp_ota_begin(update_partition, OTA_SIZE_UNKNOWN, &update_handle); - if (err != ESP_OK) { - Serial.printf("esp_ota_begin failed, error=%d\n", err); - cleanupHttp(client); - return OtaUpdateOutcome::UPDATE_FAILED; - } - - esp_err_t ota_write_err = ESP_OK; - char *upgrade_data_buf = (char *)malloc(OTA_BUF_SIZE); - if (!upgrade_data_buf) { - Serial.println("Couldn't allocate memory for data buffer"); - return OtaUpdateOutcome::UPDATE_FAILED; - } - - int binary_file_len = 0; - int totalSize = esp_http_client_get_content_length(client); - Serial.println("File size: " + String(totalSize) + String(" bytes")); - - // Show display start update new firmware. - if (this->callback) { - this->callback(OtaState::OTA_STATE_BEGIN, ""); - } - - // Download file and write new firmware to OTA partition - uint32_t lastUpdate = millis(); - while (1) { - int data_read = - esp_http_client_read(client, upgrade_data_buf, OTA_BUF_SIZE); - if (data_read == 0) { - if (this->callback) { - this->callback(OtaState::OTA_STATE_PROCESSING, String(100)); - } - Serial.println("Connection closed, all data received"); - break; - } - if (data_read < 0) { - Serial.println("Data read error"); - if (this->callback) { - this->callback(OtaState::OTA_STATE_FAIL, ""); - } - break; - } - if (data_read > 0) { - ota_write_err = esp_ota_write( - update_handle, (const void *)upgrade_data_buf, data_read); - if (ota_write_err != ESP_OK) { - if (this->callback) { - this->callback(OtaState::OTA_STATE_FAIL, ""); - } - break; - } - binary_file_len += data_read; - - int percent = (binary_file_len * 100) / totalSize; - uint32_t ms = (uint32_t)(millis() - lastUpdate); - if (ms >= 250) { - // sm.executeOTA(StateMachine::OtaState::OTA_STATE_PROCESSING, "", - // percent); - if (this->callback) { - this->callback(OtaState::OTA_STATE_PROCESSING, - String(percent)); - } - lastUpdate = millis(); - } - } - } - free(upgrade_data_buf); - cleanupHttp(client); - Serial.printf("# of bytes written: %d\n", binary_file_len); - - esp_err_t ota_end_err = esp_ota_end(update_handle); - if (ota_write_err != ESP_OK) { - Serial.printf("Error: esp_ota_write failed! err=0x%d\n", err); - return OtaUpdateOutcome::UPDATE_FAILED; - } else if (ota_end_err != ESP_OK) { - Serial.printf("Error: esp_ota_end failed! err=0x%d. Image is invalid", - ota_end_err); - return OtaUpdateOutcome::UPDATE_FAILED; - } - - err = esp_ota_set_boot_partition(update_partition); - if (err != ESP_OK) { - Serial.printf("esp_ota_set_boot_partition failed! err=0x%d\n", err); - return OtaUpdateOutcome::UPDATE_FAILED; - } - return OtaUpdateOutcome::UPDATE_PERFORMED; - } - - void cleanupHttp(esp_http_client_handle_t client) { - esp_http_client_close(client); - esp_http_client_cleanup(client); - } -}; - -#endif diff --git a/src/OtaHandler.cpp b/src/OtaHandler.cpp new file mode 100644 index 0000000..1e2ec64 --- /dev/null +++ b/src/OtaHandler.cpp @@ -0,0 +1,164 @@ +#include "OtaHandler.h" + +void OtaHandler::setHandlerCallback(OtaHandlerCallback_t callback) { _callback = callback; } + +void OtaHandler::updateFirmwareIfOutdated(String deviceId) { + String url = + "http://hw.airgradient.com/sensors/airgradient:" + deviceId + "/generic/os/firmware.bin"; + url += "?current_firmware="; + url += GIT_VERSION; + char urlAsChar[URL_BUF_SIZE]; + url.toCharArray(urlAsChar, URL_BUF_SIZE); + Serial.printf("checking for new OTA update @ %s\n", urlAsChar); + + esp_http_client_config_t config = {}; + config.url = urlAsChar; + OtaUpdateOutcome ret = attemptToPerformOta(&config); + Serial.println(ret); + if (_callback) { + switch (ret) { + case OtaUpdateOutcome::UPDATE_PERFORMED: + _callback(OtaState::OTA_STATE_SUCCESS, ""); + break; + case OtaUpdateOutcome::UPDATE_SKIPPED: + _callback(OtaState::OTA_STATE_SKIP, ""); + break; + case OtaUpdateOutcome::ALREADY_UP_TO_DATE: + _callback(OtaState::OTA_STATE_UP_TO_DATE, ""); + break; + case OtaUpdateOutcome::UPDATE_FAILED: + _callback(OtaState::OTA_STATE_FAIL, ""); + break; + default: + break; + } + } +} + +OtaHandler::OtaUpdateOutcome +OtaHandler::attemptToPerformOta(const esp_http_client_config_t *config) { + esp_http_client_handle_t client = esp_http_client_init(config); + if (client == NULL) { + Serial.println("Failed to initialize HTTP connection"); + return OtaUpdateOutcome::UPDATE_FAILED; + } + + esp_err_t err = esp_http_client_open(client, 0); + if (err != ESP_OK) { + esp_http_client_cleanup(client); + Serial.printf("Failed to open HTTP connection: %s\n", esp_err_to_name(err)); + return OtaUpdateOutcome::UPDATE_FAILED; + } + esp_http_client_fetch_headers(client); + + int httpStatusCode = esp_http_client_get_status_code(client); + if (httpStatusCode == 304) { + Serial.println("Firmware is already up to date"); + cleanupHttp(client); + return OtaUpdateOutcome::ALREADY_UP_TO_DATE; + } else if (httpStatusCode != 200) { + Serial.printf("Firmware update skipped, the server returned %d\n", httpStatusCode); + cleanupHttp(client); + return OtaUpdateOutcome::UPDATE_SKIPPED; + } + + esp_ota_handle_t update_handle = 0; + const esp_partition_t *update_partition = NULL; + Serial.println("Starting OTA update ..."); + update_partition = esp_ota_get_next_update_partition(NULL); + if (update_partition == NULL) { + Serial.println("Passive OTA partition not found"); + cleanupHttp(client); + return OtaUpdateOutcome::UPDATE_FAILED; + } + Serial.printf("Writing to partition subtype %d at offset 0x%x\n", update_partition->subtype, + update_partition->address); + + err = esp_ota_begin(update_partition, OTA_SIZE_UNKNOWN, &update_handle); + if (err != ESP_OK) { + Serial.printf("esp_ota_begin failed, error=%d\n", err); + cleanupHttp(client); + return OtaUpdateOutcome::UPDATE_FAILED; + } + + esp_err_t ota_write_err = ESP_OK; + char *upgrade_data_buf = (char *)malloc(OTA_BUF_SIZE); + if (!upgrade_data_buf) { + Serial.println("Couldn't allocate memory for data buffer"); + return OtaUpdateOutcome::UPDATE_FAILED; + } + + int binary_file_len = 0; + int totalSize = esp_http_client_get_content_length(client); + Serial.println("File size: " + String(totalSize) + String(" bytes")); + + // Show display start update new firmware. + if (_callback) { + _callback(OtaState::OTA_STATE_BEGIN, ""); + } + + // Download file and write new firmware to OTA partition + uint32_t lastUpdate = millis(); + while (1) { + int data_read = esp_http_client_read(client, upgrade_data_buf, OTA_BUF_SIZE); + if (data_read == 0) { + if (_callback) { + _callback(OtaState::OTA_STATE_PROCESSING, String(100)); + } + Serial.println("Connection closed, all data received"); + break; + } + if (data_read < 0) { + Serial.println("Data read error"); + if (_callback) { + _callback(OtaState::OTA_STATE_FAIL, ""); + } + break; + } + if (data_read > 0) { + ota_write_err = esp_ota_write(update_handle, (const void *)upgrade_data_buf, data_read); + if (ota_write_err != ESP_OK) { + if (_callback) { + _callback(OtaState::OTA_STATE_FAIL, ""); + } + break; + } + binary_file_len += data_read; + + int percent = (binary_file_len * 100) / totalSize; + uint32_t ms = (uint32_t)(millis() - lastUpdate); + if (ms >= 250) { + // sm.executeOTA(StateMachine::OtaState::OTA_STATE_PROCESSING, "", + // percent); + if (_callback) { + _callback(OtaState::OTA_STATE_PROCESSING, String(percent)); + } + lastUpdate = millis(); + } + } + } + free(upgrade_data_buf); + cleanupHttp(client); + Serial.printf("# of bytes written: %d\n", binary_file_len); + + esp_err_t ota_end_err = esp_ota_end(update_handle); + if (ota_write_err != ESP_OK) { + Serial.printf("Error: esp_ota_write failed! err=0x%d\n", err); + return OtaUpdateOutcome::UPDATE_FAILED; + } else if (ota_end_err != ESP_OK) { + Serial.printf("Error: esp_ota_end failed! err=0x%d. Image is invalid", ota_end_err); + return OtaUpdateOutcome::UPDATE_FAILED; + } + + err = esp_ota_set_boot_partition(update_partition); + if (err != ESP_OK) { + Serial.printf("esp_ota_set_boot_partition failed! err=0x%d\n", err); + return OtaUpdateOutcome::UPDATE_FAILED; + } + return OtaUpdateOutcome::UPDATE_PERFORMED; +} + +void OtaHandler::cleanupHttp(esp_http_client_handle_t client) { + esp_http_client_close(client); + esp_http_client_cleanup(client); +} \ No newline at end of file diff --git a/src/OtaHandler.h b/src/OtaHandler.h new file mode 100644 index 0000000..8863f9e --- /dev/null +++ b/src/OtaHandler.h @@ -0,0 +1,43 @@ +#ifndef OTA_HANDLER_H +#define OTA_HANDLER_H +#ifndef ESP8266 // Only for esp32 based mcu + +#include +#include +#include +#include + +#define OTA_BUF_SIZE 1024 +#define URL_BUF_SIZE 256 + +class OtaHandler { +public: + enum OtaState { + OTA_STATE_BEGIN, + OTA_STATE_FAIL, + OTA_STATE_SKIP, + OTA_STATE_UP_TO_DATE, + OTA_STATE_PROCESSING, + OTA_STATE_SUCCESS + }; + + typedef void (*OtaHandlerCallback_t)(OtaState state, String message); + void setHandlerCallback(OtaHandlerCallback_t callback); + void updateFirmwareIfOutdated(String deviceId); + +private: + OtaHandlerCallback_t _callback; + + enum OtaUpdateOutcome { + UPDATE_PERFORMED = 0, + ALREADY_UP_TO_DATE, + UPDATE_FAILED, + UPDATE_SKIPPED + }; // Internal use + + OtaUpdateOutcome attemptToPerformOta(const esp_http_client_config_t *config); + void cleanupHttp(esp_http_client_handle_t client); +}; + +#endif // ESP8266 +#endif // OTA_HANDLER_H \ No newline at end of file From 3556e4a96a22ab7420e9c118e5f7a298bed49048 Mon Sep 17 00:00:00 2001 From: samuelbles07 Date: Sat, 30 Nov 2024 03:42:45 +0700 Subject: [PATCH 09/13] Fix CI error --- src/OtaHandler.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/OtaHandler.cpp b/src/OtaHandler.cpp index 1e2ec64..b2179db 100644 --- a/src/OtaHandler.cpp +++ b/src/OtaHandler.cpp @@ -1,5 +1,7 @@ #include "OtaHandler.h" +#ifndef ESP8266 // Only for esp32 based mcu + void OtaHandler::setHandlerCallback(OtaHandlerCallback_t callback) { _callback = callback; } void OtaHandler::updateFirmwareIfOutdated(String deviceId) { @@ -161,4 +163,6 @@ OtaHandler::attemptToPerformOta(const esp_http_client_config_t *config) { void OtaHandler::cleanupHttp(esp_http_client_handle_t client) { esp_http_client_close(client); esp_http_client_cleanup(client); -} \ No newline at end of file +} + +#endif \ No newline at end of file From fb0dcad54d0b43ba73ae4dc51749882ddd5d8fd3 Mon Sep 17 00:00:00 2001 From: samuelbles07 Date: Sat, 30 Nov 2024 03:52:32 +0700 Subject: [PATCH 10/13] Fix CI error esp32 --- src/OtaHandler.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/OtaHandler.cpp b/src/OtaHandler.cpp index b2179db..84c2080 100644 --- a/src/OtaHandler.cpp +++ b/src/OtaHandler.cpp @@ -2,6 +2,8 @@ #ifndef ESP8266 // Only for esp32 based mcu +#include "AirGradient.h" + void OtaHandler::setHandlerCallback(OtaHandlerCallback_t callback) { _callback = callback; } void OtaHandler::updateFirmwareIfOutdated(String deviceId) { From 401326d00d0c247d8f803366dd89f69e2f901764 Mon Sep 17 00:00:00 2001 From: samuelbles07 Date: Sat, 30 Nov 2024 04:13:25 +0700 Subject: [PATCH 11/13] Move airgradient server CA const to AirGradient.h file Constant will be used by api client and otahandler --- src/AgApiClient.cpp | 4 ++-- src/AgApiClient.h | 38 -------------------------------------- src/AirGradient.h | 38 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 40 insertions(+), 40 deletions(-) diff --git a/src/AgApiClient.cpp b/src/AgApiClient.cpp index b34a242..b7b5bc8 100644 --- a/src/AgApiClient.cpp +++ b/src/AgApiClient.cpp @@ -68,7 +68,7 @@ bool AgApiClient::fetchServerConfiguration(void) { } } else { // By default, airgradient using https - if (client.begin(uri, agCA) == false) { + if (client.begin(uri, AIRGRADIENT_SERVER_CA) == false) { logError("Begin HTTPClient using tls failed (GET)"); getConfigFailed = true; return false; @@ -143,7 +143,7 @@ bool AgApiClient::postToServer(String data) { } } else { // By default, airgradient using https - if (client.begin(uri, agCA) == false) { + if (client.begin(uri, AIRGRADIENT_SERVER_CA) == false) { logError("Begin HTTPClient using tls failed (POST)"); getConfigFailed = true; return false; diff --git a/src/AgApiClient.h b/src/AgApiClient.h index 2d8b162..167a4eb 100644 --- a/src/AgApiClient.h +++ b/src/AgApiClient.h @@ -20,45 +20,7 @@ class AgApiClient : public PrintLog { private: Configuration &config; AirGradient *ag; -#ifdef ESP8266 - String apiRoot = "http://hw.airgradient.com"; -#else String apiRoot = "https://hw.airgradient.com"; - const char *agCA = "-----BEGIN CERTIFICATE-----\n" - "MIIF4jCCA8oCCQD7MgvcaVWxkTANBgkqhkiG9w0BAQsFADCBsjELMAkGA1UEBhMC\n" - "VEgxEzARBgNVBAgMCkNoaWFuZyBNYWkxEDAOBgNVBAcMB01hZSBSaW0xGTAXBgNV\n" - "BAoMEEFpckdyYWRpZW50IEx0ZC4xFDASBgNVBAsMC1NlbnNvciBMYWJzMSgwJgYD\n" - "VQQDDB9BaXJHcmFkaWVudCBTZW5zb3IgTGFicyBSb290IENBMSEwHwYJKoZIhvcN\n" - "AQkBFhJjYUBhaXJncmFkaWVudC5jb20wHhcNMjEwOTE3MTE0NDE3WhcNNDEwOTEy\n" - "MTE0NDE3WjCBsjELMAkGA1UEBhMCVEgxEzARBgNVBAgMCkNoaWFuZyBNYWkxEDAO\n" - "BgNVBAcMB01hZSBSaW0xGTAXBgNVBAoMEEFpckdyYWRpZW50IEx0ZC4xFDASBgNV\n" - "BAsMC1NlbnNvciBMYWJzMSgwJgYDVQQDDB9BaXJHcmFkaWVudCBTZW5zb3IgTGFi\n" - "cyBSb290IENBMSEwHwYJKoZIhvcNAQkBFhJjYUBhaXJncmFkaWVudC5jb20wggIi\n" - "MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC6XkVQ4O9d5GcUjPYRgF/uaY6O\n" - "5ry1xCGvotxkEeKkBk99lB1oNUUfNsP5bwuDci4XKfY9Ro6/jmkfHSVcPAwUnjAt\n" - "BcHqZtA/cMXykaynf9yXPxPQN7XLu/Rk32RIfb90sIGS318xgNziCYvzWZmlxpxc\n" - "3gUcAgGtamlgZ6wD3yOHVo8B9aFNvmP16QwkUm8fKDHunJG+iX2Bxa4ka5FJovhG\n" - "TnUwtso6Vrn0JaWF9qWcPZE0JZMjFW8PYRriyJmHwr/nAXfPPKphD1oRO+oA7/jq\n" - "dYkrJw6+OHfFXnPB1xkeh4OPBzcCZHT5XWNfwBYazYpjcJa9ngGFSmg8lX1ac23C\n" - "zea1XJmSrPwbZbWxoQznnf7Y78mRjruYKgSP8rf74KYvBe/HGPL5NQyXQ3l6kwmu\n" - "CCUqfcC0wCWEtWESxwSdFE2qQii8CZ12kQExzvR2PrOIyKQYSdkGx9/RBZtAVPXP\n" - "hmLuRBQYHrF5Cxf1oIbBK8OMoNVgBm6ftt15t9Sq9dH5Aup2YR6WEJkVaYkYzZzK\n" - "X7M+SQcdbXp+hAO8PFpABJxkaDAO2kiB5Ov7pDYPAcmNFqnJT48AY0TZJeVeCa5W\n" - "sIv3lPvB/XcFjP0+aZxxNSEEwpGPUYgvKUYUUmb0NammlYQwZHKaShPEmZ3UZ0bp\n" - "VNt4p6374nzO376sSwIDAQABMA0GCSqGSIb3DQEBCwUAA4ICAQB/LfBPgTx7xKQB\n" - "JNMUhah17AFAn050NiviGJOHdPQely6u3DmJGg+ijEVlPWO1FEW3it+LOuNP5zOu\n" - "bhq8paTYIxPxtALIxw5ksykX9woDuX3H6FF9mPdQIbL7ft+3ZtZ4FWPui9dUtaPe\n" - "ZBmDFDi4U29nhWZK68JSp5QkWjfaYLV/vtag7120eVyGEPFZ0UAuTUNqpw+stOt9\n" - "gJ2ZxNx13xJ8ZnLK7qz1crPe8/8IVAdxbVLoY7JaWPLc//+VF+ceKicy8+4gV7zN\n" - "Gnq2IyM+CHFz8VYMLbW+3eVp4iJjTa72vae116kozboEIUVN9rgLqIKyVqQXiuoN\n" - "g3xY+yfncPB2+H/+lfyy6mepPIfgksd3+KeNxFADSc5EVY2JKEdorRodnAh7a8K6\n" - "WjTYgq+GjWXU2uQW2SyPt6Tu33OT8nBnu3NB80eT8WXgdVCkgsuyCuLvNRf1Xmze\n" - "igvurpU6JmQ1GlLgLJo8omJHTh1zIbkR9injPYne2v9ciHCoP6+LDEqe+rOsvPCB\n" - "C/o/iZ4svmYX4fWGuU7GgqZE8hhrC3+GdOTf2ADC752cYCZxBidXGtkrGNoHQKmQ\n" - "KCOMFBxZIvWteB3tUo3BKYz1D2CvKWz1wV4moc5JHkOgS+jqxhvOkQ/vfQBQ1pUY\n" - "TMui9BSwU7B1G2XjdLbfF3Dc67zaSg==\n" - "-----END CERTIFICATE-----\n"; -#endif bool apiRootChanged = false; // Indicate if setApiRoot() is called bool getConfigFailed; diff --git a/src/AirGradient.h b/src/AirGradient.h index 754db60..edfa2f4 100644 --- a/src/AirGradient.h +++ b/src/AirGradient.h @@ -18,6 +18,44 @@ #define GIT_VERSION "3.1.12-snap" #endif +#ifndef ESP8266 +const char *const AIRGRADIENT_SERVER_CA = + "-----BEGIN CERTIFICATE-----\n" + "MIIF4jCCA8oCCQD7MgvcaVWxkTANBgkqhkiG9w0BAQsFADCBsjELMAkGA1UEBhMC\n" + "VEgxEzARBgNVBAgMCkNoaWFuZyBNYWkxEDAOBgNVBAcMB01hZSBSaW0xGTAXBgNV\n" + "BAoMEEFpckdyYWRpZW50IEx0ZC4xFDASBgNVBAsMC1NlbnNvciBMYWJzMSgwJgYD\n" + "VQQDDB9BaXJHcmFkaWVudCBTZW5zb3IgTGFicyBSb290IENBMSEwHwYJKoZIhvcN\n" + "AQkBFhJjYUBhaXJncmFkaWVudC5jb20wHhcNMjEwOTE3MTE0NDE3WhcNNDEwOTEy\n" + "MTE0NDE3WjCBsjELMAkGA1UEBhMCVEgxEzARBgNVBAgMCkNoaWFuZyBNYWkxEDAO\n" + "BgNVBAcMB01hZSBSaW0xGTAXBgNVBAoMEEFpckdyYWRpZW50IEx0ZC4xFDASBgNV\n" + "BAsMC1NlbnNvciBMYWJzMSgwJgYDVQQDDB9BaXJHcmFkaWVudCBTZW5zb3IgTGFi\n" + "cyBSb290IENBMSEwHwYJKoZIhvcNAQkBFhJjYUBhaXJncmFkaWVudC5jb20wggIi\n" + "MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC6XkVQ4O9d5GcUjPYRgF/uaY6O\n" + "5ry1xCGvotxkEeKkBk99lB1oNUUfNsP5bwuDci4XKfY9Ro6/jmkfHSVcPAwUnjAt\n" + "BcHqZtA/cMXykaynf9yXPxPQN7XLu/Rk32RIfb90sIGS318xgNziCYvzWZmlxpxc\n" + "3gUcAgGtamlgZ6wD3yOHVo8B9aFNvmP16QwkUm8fKDHunJG+iX2Bxa4ka5FJovhG\n" + "TnUwtso6Vrn0JaWF9qWcPZE0JZMjFW8PYRriyJmHwr/nAXfPPKphD1oRO+oA7/jq\n" + "dYkrJw6+OHfFXnPB1xkeh4OPBzcCZHT5XWNfwBYazYpjcJa9ngGFSmg8lX1ac23C\n" + "zea1XJmSrPwbZbWxoQznnf7Y78mRjruYKgSP8rf74KYvBe/HGPL5NQyXQ3l6kwmu\n" + "CCUqfcC0wCWEtWESxwSdFE2qQii8CZ12kQExzvR2PrOIyKQYSdkGx9/RBZtAVPXP\n" + "hmLuRBQYHrF5Cxf1oIbBK8OMoNVgBm6ftt15t9Sq9dH5Aup2YR6WEJkVaYkYzZzK\n" + "X7M+SQcdbXp+hAO8PFpABJxkaDAO2kiB5Ov7pDYPAcmNFqnJT48AY0TZJeVeCa5W\n" + "sIv3lPvB/XcFjP0+aZxxNSEEwpGPUYgvKUYUUmb0NammlYQwZHKaShPEmZ3UZ0bp\n" + "VNt4p6374nzO376sSwIDAQABMA0GCSqGSIb3DQEBCwUAA4ICAQB/LfBPgTx7xKQB\n" + "JNMUhah17AFAn050NiviGJOHdPQely6u3DmJGg+ijEVlPWO1FEW3it+LOuNP5zOu\n" + "bhq8paTYIxPxtALIxw5ksykX9woDuX3H6FF9mPdQIbL7ft+3ZtZ4FWPui9dUtaPe\n" + "ZBmDFDi4U29nhWZK68JSp5QkWjfaYLV/vtag7120eVyGEPFZ0UAuTUNqpw+stOt9\n" + "gJ2ZxNx13xJ8ZnLK7qz1crPe8/8IVAdxbVLoY7JaWPLc//+VF+ceKicy8+4gV7zN\n" + "Gnq2IyM+CHFz8VYMLbW+3eVp4iJjTa72vae116kozboEIUVN9rgLqIKyVqQXiuoN\n" + "g3xY+yfncPB2+H/+lfyy6mepPIfgksd3+KeNxFADSc5EVY2JKEdorRodnAh7a8K6\n" + "WjTYgq+GjWXU2uQW2SyPt6Tu33OT8nBnu3NB80eT8WXgdVCkgsuyCuLvNRf1Xmze\n" + "igvurpU6JmQ1GlLgLJo8omJHTh1zIbkR9injPYne2v9ciHCoP6+LDEqe+rOsvPCB\n" + "C/o/iZ4svmYX4fWGuU7GgqZE8hhrC3+GdOTf2ADC752cYCZxBidXGtkrGNoHQKmQ\n" + "KCOMFBxZIvWteB3tUo3BKYz1D2CvKWz1wV4moc5JHkOgS+jqxhvOkQ/vfQBQ1pUY\n" + "TMui9BSwU7B1G2XjdLbfF3Dc67zaSg==\n" + "-----END CERTIFICATE-----\n"; +#endif + /** * @brief Class with define all the sensor has supported by Airgradient. Each * sensor usage must be init before use. From aeee0cad0181b3694617145ec9e6a0de2eb72a25 Mon Sep 17 00:00:00 2001 From: samuelbles07 Date: Sat, 30 Nov 2024 04:33:58 +0700 Subject: [PATCH 12/13] OTA bin download using https rename server root ca constant name --- src/AgApiClient.cpp | 4 ++-- src/AirGradient.h | 3 ++- src/OtaHandler.cpp | 3 ++- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/AgApiClient.cpp b/src/AgApiClient.cpp index b7b5bc8..8de2596 100644 --- a/src/AgApiClient.cpp +++ b/src/AgApiClient.cpp @@ -68,7 +68,7 @@ bool AgApiClient::fetchServerConfiguration(void) { } } else { // By default, airgradient using https - if (client.begin(uri, AIRGRADIENT_SERVER_CA) == false) { + if (client.begin(uri, AG_SERVER_ROOT_CA) == false) { logError("Begin HTTPClient using tls failed (GET)"); getConfigFailed = true; return false; @@ -143,7 +143,7 @@ bool AgApiClient::postToServer(String data) { } } else { // By default, airgradient using https - if (client.begin(uri, AIRGRADIENT_SERVER_CA) == false) { + if (client.begin(uri, AG_SERVER_ROOT_CA) == false) { logError("Begin HTTPClient using tls failed (POST)"); getConfigFailed = true; return false; diff --git a/src/AirGradient.h b/src/AirGradient.h index edfa2f4..f580ed0 100644 --- a/src/AirGradient.h +++ b/src/AirGradient.h @@ -19,7 +19,8 @@ #endif #ifndef ESP8266 -const char *const AIRGRADIENT_SERVER_CA = +// Airgradient server root ca certificate +const char *const AG_SERVER_ROOT_CA = "-----BEGIN CERTIFICATE-----\n" "MIIF4jCCA8oCCQD7MgvcaVWxkTANBgkqhkiG9w0BAQsFADCBsjELMAkGA1UEBhMC\n" "VEgxEzARBgNVBAgMCkNoaWFuZyBNYWkxEDAOBgNVBAcMB01hZSBSaW0xGTAXBgNV\n" diff --git a/src/OtaHandler.cpp b/src/OtaHandler.cpp index 84c2080..c451581 100644 --- a/src/OtaHandler.cpp +++ b/src/OtaHandler.cpp @@ -8,7 +8,7 @@ void OtaHandler::setHandlerCallback(OtaHandlerCallback_t callback) { _callback = void OtaHandler::updateFirmwareIfOutdated(String deviceId) { String url = - "http://hw.airgradient.com/sensors/airgradient:" + deviceId + "/generic/os/firmware.bin"; + "https://hw.airgradient.com/sensors/airgradient:" + deviceId + "/generic/os/firmware.bin"; url += "?current_firmware="; url += GIT_VERSION; char urlAsChar[URL_BUF_SIZE]; @@ -17,6 +17,7 @@ void OtaHandler::updateFirmwareIfOutdated(String deviceId) { esp_http_client_config_t config = {}; config.url = urlAsChar; + config.cert_pem = AG_SERVER_ROOT_CA; OtaUpdateOutcome ret = attemptToPerformOta(&config); Serial.println(ret); if (_callback) { From 38e792b88d7e8726547eb2a82e441e0936402aca Mon Sep 17 00:00:00 2001 From: samuelbles07 Date: Sat, 30 Nov 2024 04:45:04 +0700 Subject: [PATCH 13/13] if guard uri for esp8266 --- src/AgApiClient.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/AgApiClient.h b/src/AgApiClient.h index 167a4eb..9f39ceb 100644 --- a/src/AgApiClient.h +++ b/src/AgApiClient.h @@ -20,7 +20,12 @@ class AgApiClient : public PrintLog { private: Configuration &config; AirGradient *ag; +#ifdef ESP8266 + // ESP8266 not support HTTPS + String apiRoot = "http://hw.airgradient.com"; +#else String apiRoot = "https://hw.airgradient.com"; +#endif bool apiRootChanged = false; // Indicate if setApiRoot() is called bool getConfigFailed;