diff --git a/include/pinlist.h b/include/pinlist.h new file mode 100644 index 0000000..62f6f8f --- /dev/null +++ b/include/pinlist.h @@ -0,0 +1,3 @@ +#define DI_CONFRESET 0 +#define DI_RESTART 1 +#define DI_OTAENABLE 7 \ No newline at end of file diff --git a/lib/GPIO/LED_Driver.cpp b/lib/GPIO/LED_Driver.cpp index 4a1927d..feb7fe2 100644 --- a/lib/GPIO/LED_Driver.cpp +++ b/lib/GPIO/LED_Driver.cpp @@ -12,6 +12,7 @@ namespace drivers pinMode(c_ledPin, OUTPUT); m_blinkTask = NULL; m_flashTimer = NULL; + m_enforce = false; } Led::~Led() @@ -20,9 +21,16 @@ namespace drivers pinMode(c_ledPin, INPUT); } + void Led::setEnforce(const bool enf) + { + m_enforce = enf; + } + void Led::setColor(const color_t color) { std::lock_guard lock(m_ledMutex); + if (m_enforce) + return; blinkStop(); m_colorDefault = color; rgbLedWrite(c_ledPin, color.g, color.r, color.b); @@ -58,6 +66,8 @@ namespace drivers void Led::blinkColor(const uint16_t tOn, const uint16_t tOff, const color_t color) { std::lock_guard lock(m_ledMutex); + if (m_enforce) + return; blinkStop(); m_color1 = color; m_color2 = {0, 0, 0}; @@ -69,6 +79,8 @@ namespace drivers void Led::blinkAlternate(const uint16_t tOn, const uint16_t tOff, const color_t color1, const color_t color2) { std::lock_guard lock(m_ledMutex); + if (m_enforce) + return; blinkStop(); m_color1 = color1; m_color2 = color2; diff --git a/lib/GPIO/LED_Driver.h b/lib/GPIO/LED_Driver.h index fba7dad..25d8e07 100644 --- a/lib/GPIO/LED_Driver.h +++ b/lib/GPIO/LED_Driver.h @@ -21,6 +21,7 @@ namespace drivers uint8_t b; } color_t; + const color_t COLOR_OFF = {0, 0, 0}; const color_t COLOR_RED = {255, 0, 0}; const color_t COLOR_ORANGE = {255, 127, 0}; const color_t COLOR_YELLOW = {255, 255, 0}; @@ -36,6 +37,7 @@ namespace drivers Led(); ~Led(); + void setEnforce(const bool enf); void setColor(const color_t color); void flashColor(const uint16_t tOn, const color_t color); void blinkColor(const uint16_t tOn, const uint16_t tOff, const color_t color); @@ -60,6 +62,7 @@ namespace drivers TimerHandle_t m_flashTimer; bool m_flashing; + bool m_enforce; std::mutex m_ledMutex; }; diff --git a/platformio.ini b/platformio.ini index ba3b0ac..c71fdbb 100644 --- a/platformio.ini +++ b/platformio.ini @@ -23,6 +23,9 @@ build_type = release board_build.filesystem = ffat board_build.partitions = fatfs_partition.csv ; se stai usando uno custom +upload_protocol = espota +upload_port = 10.0.2.139 + [env:esp32-s3-waveshare8-debug] platform = ${env:esp32-s3-waveshare8.platform} diff --git a/src/main.cpp b/src/main.cpp index 694ebb4..2a91722 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -8,9 +8,11 @@ #include #include #include +#include #include -#include "utils.h" +#include +#include /////////////// GLOBALS /////////////// Config &conf = Config::getInstance(); @@ -40,8 +42,10 @@ void loop() auto seneca = drivers::S50140(bus, conf.m_modbusSenecaAddr); auto buzzer = drivers::Buzzer(); auto led = drivers::Led(); - delay(500); auto io = digitalIO(i2c, bus, {conf.m_modbusRelayAddr}); + // Create device structure to pass all devices in the callbacks as needed + devices_t devices(eth, rtc, tmp, seneca, buzzer, led, io); + // // get RTC time drift offset value rtc.setOffset(conf.m_ntpRtcOffsetRegister); LOG_INFO("RTC offset register -> ", printHex(rtc.getOffset()).c_str()); @@ -49,9 +53,16 @@ void loop() sensors = tmp.getNum(); tmp.setCorrection(conf.m_tempCorrectionValues); LOG_INFO("Temperature sensors connected ->", sensors); - - // Create device structure to pass all devices in the callbacks as needed - devices_t devices(eth, rtc, tmp, seneca, buzzer, led, io); + // Initialize OTA updater if needed + auto ota = OTA(devices); + if (io.digitalInRead(DI_OTAENABLE)) { + buzzer.beepRepeat(25,25, NOTE_A); + delay(1000); + if (io.digitalInRead(DI_OTAENABLE)) { // maintain keyPress for 1s + ota.begin(); + } + buzzer.beep(100, NOTE_G); + } //////////////// DEVICES //////////////// //////////////// MQTT //////////////// @@ -187,7 +198,7 @@ void loop() mqtt.publish(conf.m_mqttPublish["temperatures"], ti); }; - if (io.digitalInRead(0)) // ROSSO - Config Reset + if (io.digitalInRead(DI_CONFRESET)) // ROSSO - Config Reset { LOG_WARN("Config RESET!"); buzzer.beep(450, NOTE_E); @@ -195,7 +206,7 @@ void loop() conf.resetConfig(); } - if (io.digitalInRead(1)) // GIALLO - Restart + if (io.digitalInRead(DI_RESTART)) // GIALLO - Restart { LOG_WARN("RESTART!"); buzzer.beep(450, NOTE_D); diff --git a/src/ota.cpp b/src/ota.cpp new file mode 100644 index 0000000..134a4ba --- /dev/null +++ b/src/ota.cpp @@ -0,0 +1,122 @@ +#include + +#define STACK_DEPTH 4096 +#define TASK_PRIORITY 2 + +OTA::OTA(const devices_t &dev) : m_dev(dev), m_taskHandle(NULL), m_updating(false) +{ + LOG_WARN("OTA begin, waiting for connection on [", dev.eth.localIP().toString().c_str(), "]"); +} + +OTA::~OTA() +{ + end(); + LOG_WARN("OTA end"); +} + +void OTA::begin() +{ + if (m_taskHandle) + { + LOG_ERROR("OTA already started"); + return; + } + ArduinoOTA.setRebootOnSuccess(true); + ArduinoOTA.onStart(s_onStart); + ArduinoOTA.onEnd(s_onEnd); + ArduinoOTA.onProgress(s_onProgress); + ArduinoOTA.onError(s_onError); + if (!xTaskCreate(handle, "otaUpdate", STACK_DEPTH, this, TASK_PRIORITY, &m_taskHandle) != pdPASS) + { + m_taskHandle = NULL; + LOG_ERROR("OTA failed to create handle task"); + } + ArduinoOTA.begin(); // start the OTA server + m_dev.led.setEnforce(true); // take unique control of the LED + m_dev.led.blinkAlternate(50, 50, m_dev.led.COLOR_GREEN, m_dev.led.COLOR_YELLOW); + m_active = true; + return; +} + +void OTA::end() +{ + if (m_updating) + { + LOG_WARN("OTA cannot cancel update while running"); + return; + } + if (m_taskHandle) + { + vTaskDelete(m_taskHandle); + m_taskHandle = NULL; + m_updating = false; + ArduinoOTA.end(); + m_active = false; + m_dev.led.setColor(m_dev.led.COLOR_GREEN); + m_dev.led.setEnforce(false); + } +} + +bool OTA::isActive() +{ + return m_active; +} + +void OTA::onProgress(const uint32_t progress, const uint32_t total) +{ + LOG_INFO("OTA progress [", (progress * 100.0f) / total, "]%"); +} +void OTA::onStart() +{ + LOG_WARN("OTA update started"); + m_updating = true; + m_dev.led.setEnforce(false); + m_dev.led.blinkAlternate(25, 50, m_dev.led.COLOR_BLUE, m_dev.led.COLOR_OFF); + m_dev.led.setEnforce(true); +} +void OTA::onEnd() +{ + LOG_WARN("OTA update end"); + m_updating = false; + m_dev.led.setEnforce(false); + m_dev.led.blinkAlternate(50, 50, m_dev.led.COLOR_GREEN, m_dev.led.COLOR_YELLOW); + m_dev.led.setEnforce(true); +} +void OTA::onError(const ota_error_t err) +{ + LOG_ERROR("OTA Error [", err, "]"); + switch (err) + { + case OTA_AUTH_ERROR: + LOG_ERROR("OTA authentication error"); + break; + case OTA_BEGIN_ERROR: + LOG_ERROR("OTA begin errror"); + break; + case OTA_CONNECT_ERROR: + LOG_ERROR("OTA connection error"); + break; + case OTA_RECEIVE_ERROR: + LOG_ERROR("OTA receive error"); + break; + case OTA_END_ERROR: + LOG_ERROR("OTA end error"); + break; + default: + LOG_ERROR("OTA unknown error"); + }; + m_updating = false; + end(); //end ota on error +} + +void OTA::handle(void *params) +{ + OTA *ota = (OTA *)params; + while (true) + { // task never returns + ArduinoOTA.handle(); + delay(50); + } + vTaskDelete(ota->m_taskHandle); + ota->m_taskHandle = NULL; +} diff --git a/src/ota.h b/src/ota.h new file mode 100644 index 0000000..c47efa2 --- /dev/null +++ b/src/ota.h @@ -0,0 +1,51 @@ +#pragma once + +#define DEBUGLOG_DEFAULT_LOG_LEVEL_INFO + +#include +#include +#include +#include + +class OTA +{ + +public: + OTA(const devices_t &dev); + ~OTA(); + + void begin(); + void end(); + bool isActive(); + +private: + void onProgress(const uint32_t progress, const uint32_t total); + void onStart(); + void onEnd(); + void onError(const ota_error_t err); + static void handle(void *params); + +private: + const devices_t &m_dev; + TaskHandle_t m_taskHandle; + bool m_updating; + bool m_active; + +private: // callbacks, do not init in code + ArduinoOTAClass::THandlerFunction s_onStart = [this]() + { + this->onStart(); + }; + ArduinoOTAClass::THandlerFunction s_onEnd = [this]() + { + this->onEnd(); + }; + ArduinoOTAClass::THandlerFunction_Progress s_onProgress = [this](const uint32_t progress, const uint32_t total) + { + this->onProgress(progress, total); + }; + ArduinoOTAClass::THandlerFunction_Error s_onError = [this](const ota_error_t err) + { + this->onError(err); + }; +};