Merge branch 'develop' of https://github.com/airgradienthq/arduino into develop

This commit is contained in:
Phat Nguyen
2024-04-25 06:49:18 +07:00
7 changed files with 148 additions and 9 deletions

1
.gitignore vendored
View File

@ -1,4 +1,5 @@
*.DS_Store *.DS_Store
build build
.vscode .vscode
/.idea/
.pio .pio

View File

@ -37,7 +37,8 @@ CC BY-SA 4.0 Attribution-ShareAlike 4.0 International License
*/ */
#include <HardwareSerial.h> #include <HardwareSerial.h>
#include "AirGradient.h"
#include "OtaHandler.h"
#include "AgApiClient.h" #include "AgApiClient.h"
#include "AgConfigure.h" #include "AgConfigure.h"
#include "AgSchedule.h" #include "AgSchedule.h"
@ -49,7 +50,6 @@ CC BY-SA 4.0 Attribution-ShareAlike 4.0 International License
#include "MqttClient.h" #include "MqttClient.h"
#include "OpenMetrics.h" #include "OpenMetrics.h"
#include "WebServer.h" #include "WebServer.h"
#include <AirGradient.h>
#include <WebServer.h> #include <WebServer.h>
#define LED_BAR_ANIMATION_PERIOD 100 /** ms */ #define LED_BAR_ANIMATION_PERIOD 100 /** ms */
@ -82,6 +82,7 @@ static WifiConnector wifiConnector(oledDisplay, Serial, stateMachine,
configuration); configuration);
static OpenMetrics openMetrics(measurements, configuration, wifiConnector, static OpenMetrics openMetrics(measurements, configuration, wifiConnector,
apiClient); apiClient);
static OtaHandler otaHandler;
static LocalServer localServer(Serial, openMetrics, measurements, configuration, static LocalServer localServer(Serial, openMetrics, measurements, configuration,
wifiConnector); wifiConnector);
@ -180,6 +181,12 @@ void setup() {
initMqtt(); initMqtt();
sendDataToAg(); sendDataToAg();
#ifdef ESP8266
// ota not supported
#else
otaHandler.updateFirmwareIfOutdated(ag->deviceId());
#endif
apiClient.fetchServerConfiguration(); apiClient.fetchServerConfiguration();
configSchedule.update(); configSchedule.update();
if (apiClient.isFetchConfigureFailed()) { if (apiClient.isFetchConfigureFailed()) {
@ -483,6 +490,7 @@ static void oneIndoorInit(void) {
/** Show boot display */ /** Show boot display */
Serial.println("Firmware Version: " + ag->getVersion()); Serial.println("Firmware Version: " + ag->getVersion());
oledDisplay.setText("AirGradient ONE", oledDisplay.setText("AirGradient ONE",
"FW Version: ", ag->getVersion().c_str()); "FW Version: ", ag->getVersion().c_str());
delay(DISPLAY_DELAY_SHOW_CONTENT_MS); delay(DISPLAY_DELAY_SHOW_CONTENT_MS);

View File

@ -0,0 +1,128 @@
#ifndef _OTA_HANDLER_H_
#define _OTA_HANDLER_H_
#include <esp_ota_ops.h>
#include <esp_http_client.h>
#include <esp_err.h>
#include <Arduino.h>
#define OTA_BUF_SIZE 512
#define URL_BUF_SIZE 256
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 @ %s\n", urlAsChar);
esp_http_client_config_t config = {};
config.url = urlAsChar;
esp_err_t ret = attemptToPerformOta(&config);
Serial.println(ret);
if (ret == 0) {
Serial.println("OTA completed");
esp_restart();
} else {
Serial.println("OTA failed, maybe already up to date");
}
}
private:
int 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 -1;
}
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 -1;
}
esp_http_client_fetch_headers(client);
esp_ota_handle_t update_handle = 0;
const esp_partition_t *update_partition = NULL;
Serial.println("Starting OTA ...");
update_partition = esp_ota_get_next_update_partition(NULL);
if (update_partition == NULL) {
Serial.println("Passive OTA partition not found");
cleanupHttp(client);
return ESP_FAIL;
}
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 err;
}
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 ESP_ERR_NO_MEM;
}
int binary_file_len = 0;
while (1) {
int data_read = esp_http_client_read(client, upgrade_data_buf, OTA_BUF_SIZE);
if (data_read == 0) {
Serial.println("Connection closed, all data received");
break;
}
if (data_read < 0) {
Serial.println("Data read error");
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) {
break;
}
binary_file_len += data_read;
// Serial.printf("Written image length %d\n", binary_file_len);
}
}
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 ota_write_err;
} else if (ota_end_err != ESP_OK) {
Serial.printf("Error: esp_ota_end failed! err=0x%d. Image is invalid", ota_end_err);
return ota_end_err;
}
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 err;
}
return 0;
}
void cleanupHttp(esp_http_client_handle_t client) {
esp_http_client_close(client);
esp_http_client_cleanup(client);
}
};
#endif

View File

@ -12,13 +12,13 @@
platform = espressif32 platform = espressif32
board = esp32-c3-devkitm-1 board = esp32-c3-devkitm-1
framework = arduino framework = arduino
build_flags = build_flags = !echo '-D ARDUINO_USB_CDC_ON_BOOT=1 -D ARDUINO_USB_MODE=1 -D GIT_VERSION=\\"'$(git describe --tags --always --dirty)'\\"'
-DARDUINO_USB_CDC_ON_BOOT=1
-DARDUINO_USB_MODE=1
board_build.partitions = partitions.csv board_build.partitions = partitions.csv
monitor_speed = 115200 monitor_speed = 115200
lib_deps = lib_deps =
aglib=symlink://../arduino aglib=symlink://../arduino
monitor_filters = time
[platformio] [platformio]
src_dir = examples/OneOpenAir src_dir = examples/OneOpenAir

View File

@ -5,8 +5,6 @@
#include "WiFi.h" #include "WiFi.h"
#endif #endif
#define AG_LIB_VER "3.0.10beta2"
AirGradient::AirGradient(BoardType type) AirGradient::AirGradient(BoardType type)
: pms5003(type), pms5003t_1(type), pms5003t_2(type), s8(type), sgp41(type), : pms5003(type), pms5003t_1(type), pms5003t_2(type), s8(type), sgp41(type),
display(type), boardType(type), button(type), statusLed(type), display(type), boardType(type), button(type), statusLed(type),
@ -38,7 +36,7 @@ int AirGradient::getI2cSclPin(void) {
return bsp->I2C.scl_pin; return bsp->I2C.scl_pin;
} }
String AirGradient::getVersion(void) { return AG_LIB_VER; } String AirGradient::getVersion(void) { return GIT_VERSION; }
BoardType AirGradient::getBoardType(void) { return boardType; } BoardType AirGradient::getBoardType(void) { return boardType; }

View File

@ -13,6 +13,10 @@
#include "Sgp41/Sgp41.h" #include "Sgp41/Sgp41.h"
#include "Sht/Sht.h" #include "Sht/Sht.h"
#ifndef GIT_VERSION
#define GIT_VERSION "snapshot"
#endif
/** /**
* @brief Class with define all the sensor has supported by Airgradient. Each * @brief Class with define all the sensor has supported by Airgradient. Each
* sensor usage must be init before use. * sensor usage must be init before use.