Merge pull request #264 from airgradienthq/feat/ssl

Airgradient API calls using https
This commit is contained in:
Samuel Siburian
2024-12-05 13:23:52 +07:00
committed by GitHub
12 changed files with 408 additions and 257 deletions

View File

@ -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 ||

View File

@ -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 ||

View File

@ -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 ||

View File

@ -36,20 +36,21 @@ CC BY-SA 4.0 Attribution-ShareAlike 4.0 International License
*/
#include <HardwareSerial.h>
#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 <HardwareSerial.h>
#include <WebServer.h>
#include <WiFi.h>
@ -111,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();
@ -136,6 +136,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();
@ -514,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 {
@ -545,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 {
@ -555,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 {
@ -565,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 {
@ -575,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 {
@ -584,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;
@ -634,7 +636,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 +1137,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()) {
@ -1149,6 +1152,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) {

View File

@ -1,206 +0,0 @@
#ifndef _OTA_HANDLER_H_
#define _OTA_HANDLER_H_
#include <Arduino.h>
#include <esp_err.h>
#include <esp_http_client.h>
#include <esp_ota_ops.h>
#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