merged dev branch: TaskFactory is now TaskMgr, OTA is using HTTPS

This commit is contained in:
Miro Zmrzli 2024-05-23 18:23:01 -07:00
parent bf29ccda08
commit 51e0c72c04
19 changed files with 235 additions and 126 deletions

View File

@ -11,3 +11,5 @@ MQTT server:
This produces eventgrid.azure.pem certificate file.
openssl s_client -showcerts -connect www.bigfoot-inc.com:443

31
certs/bigfoot-inc.pem Executable file
View File

@ -0,0 +1,31 @@
-----BEGIN CERTIFICATE-----
MIIFFjCCAv6gAwIBAgIRAJErCErPDBinU/bWLiWnX1owDQYJKoZIhvcNAQELBQAw
TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh
cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMjAwOTA0MDAwMDAw
WhcNMjUwOTE1MTYwMDAwWjAyMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNTGV0J3Mg
RW5jcnlwdDELMAkGA1UEAxMCUjMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
AoIBAQC7AhUozPaglNMPEuyNVZLD+ILxmaZ6QoinXSaqtSu5xUyxr45r+XXIo9cP
R5QUVTVXjJ6oojkZ9YI8QqlObvU7wy7bjcCwXPNZOOftz2nwWgsbvsCUJCWH+jdx
sxPnHKzhm+/b5DtFUkWWqcFTzjTIUu61ru2P3mBw4qVUq7ZtDpelQDRrK9O8Zutm
NHz6a4uPVymZ+DAXXbpyb/uBxa3Shlg9F8fnCbvxK/eG3MHacV3URuPMrSXBiLxg
Z3Vms/EY96Jc5lP/Ooi2R6X/ExjqmAl3P51T+c8B5fWmcBcUr2Ok/5mzk53cU6cG
/kiFHaFpriV1uxPMUgP17VGhi9sVAgMBAAGjggEIMIIBBDAOBgNVHQ8BAf8EBAMC
AYYwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMBIGA1UdEwEB/wQIMAYB
Af8CAQAwHQYDVR0OBBYEFBQusxe3WFbLrlAJQOYfr52LFMLGMB8GA1UdIwQYMBaA
FHm0WeZ7tuXkAXOACIjIGlj26ZtuMDIGCCsGAQUFBwEBBCYwJDAiBggrBgEFBQcw
AoYWaHR0cDovL3gxLmkubGVuY3Iub3JnLzAnBgNVHR8EIDAeMBygGqAYhhZodHRw
Oi8veDEuYy5sZW5jci5vcmcvMCIGA1UdIAQbMBkwCAYGZ4EMAQIBMA0GCysGAQQB
gt8TAQEBMA0GCSqGSIb3DQEBCwUAA4ICAQCFyk5HPqP3hUSFvNVneLKYY611TR6W
PTNlclQtgaDqw+34IL9fzLdwALduO/ZelN7kIJ+m74uyA+eitRY8kc607TkC53wl
ikfmZW4/RvTZ8M6UK+5UzhK8jCdLuMGYL6KvzXGRSgi3yLgjewQtCPkIVz6D2QQz
CkcheAmCJ8MqyJu5zlzyZMjAvnnAT45tRAxekrsu94sQ4egdRCnbWSDtY7kh+BIm
lJNXoB1lBMEKIq4QDUOXoRgffuDghje1WrG9ML+Hbisq/yFOGwXD9RiX8F6sw6W4
avAuvDszue5L3sz85K+EC4Y/wFVDNvZo4TYXao6Z0f+lQKc0t8DQYzk1OXVu8rp2
yJMC6alLbBfODALZvYH7n7do1AZls4I9d1P4jnkDrQoxB3UqQ9hVl3LEKQ73xF1O
yK5GhDDX8oVfGKF5u+decIsH4YaTw7mP3GFxJSqv3+0lUFJoi5Lc5da149p90Ids
hCExroL1+7mryIkXPeFM5TgO9r0rvZaBFOvV2z0gp35Z0+L4WPlbuEjN/lxPFin+
HlUjr8gRsI3qfJOQFy/9rKIJR0Y/8Omwt/8oTWgy1mdeHmmjk7j1nYsvC9JSQ6Zv
MldlTTKB3zhThV1+XWYp6rjd5JW1zbVWEkLNxE7GJThEUG3szgBVGP7pSWTUTsqX
nLRbwHOoq7hHwg==
-----END CERTIFICATE-----

View File

@ -72,16 +72,13 @@ void App::init()
void App::otaCheck()
{
ota_update::OTA ota(*this);
OTA ota(*this);
ota.start();
}
void App::start()
{
// while(true)
// {
// vTaskDelay(pdMS_TO_TICKS(10020));
// }
}
void App::readSensors()

View File

@ -1,8 +1,8 @@
idf_component_register(SRCS main.cpp App.cpp Settings.cpp Led.cpp TaskFactory.cpp Wifi.cpp utilities.cpp
idf_component_register(SRCS main.cpp App.cpp Settings.cpp Led.cpp TaskMgr.cpp Wifi.cpp utilities.cpp
ProvisionSoftAP.cpp ReaderWriter.cpp OTA.cpp Mqtt.cpp
INCLUDE_DIRS "."
EMBED_TXTFILES ../html/logo.png ../html/provision.html
EMBED_TXTFILES ../certs/eventgrid.azure.pem ../certs/client1-authn-ID.key ../certs/client1-authn-ID.pem
EMBED_TXTFILES ../certs/eventgrid.azure.pem ../certs/client1-authn-ID.key ../certs/client1-authn-ID.pem ../certs/bigfoot-inc.pem
)
#message(FATAL_ERROR "error ${ROLE}")

View File

@ -1,6 +1,7 @@
/// © MiroZ 2024
#include "Settings.h"
#include "app_config.h"
#include "Led.h"
@ -106,7 +107,7 @@ Led::Led(uint32_t pin)
assert(m_queue = xQueueCreate(5, sizeof(struct LED_QUEUE)));
// create the led task
m_task = TASK_FACTORY.createTask(std::bind(&Led::run, this), "led task", 2096, 5, 0);
m_task = TaskMgr::getInstance().createTask(std::bind(&Led::run, this), LED_TASK_NAME, LED_TASK_STACK_SIZE, LED_TASK_PRIORITY, LED_TASK_CORE);
}
Led::~Led()

View File

@ -5,7 +5,7 @@
#include <stdint.h>
#include <Adafruit_NeoPixel.h>
#include "TaskFactory.h"
#include "TaskMgr.h"
class Led
{

View File

@ -3,7 +3,8 @@
#include "Mqtt.h"
#include <esp_log.h>
#include "TaskFactory.h"
#include "TaskMgr.h"
#include "app_config.h"
static const char * mqtt_broker = "mqtt-dev-server.westus2-1.ts.eventgrid.azure.net";
static const char * topic = "wellnuotopics/topic1";
@ -51,9 +52,7 @@ void Mqtt::task()
else
ESP_LOGE(TAG, "%d publish failed", n);
ESP_LOGI(TAG, "%d", TaskFactory::getStackHighWaterMark());
delay(50000);
delay(20000);
n++;
}
@ -73,6 +72,8 @@ void Mqtt::start()
m_mqtt_client->setServer(mqtt_broker, mqtt_port);
m_mqtt_client->setCallback(std::bind(&Mqtt::callback, this, _1, _2, _3));
m_mqtt_client->setKeepAlive(30);
m_mqtt_client->setSocketTimeout(30);
m_task = TASK_FACTORY.createTask(std::bind(&Mqtt::task, this), "mqtt task", 6144, 5, 0);
m_task = TaskMgr::getInstance().createTask(std::bind(&Mqtt::task, this), MQTT_TASK_NAME, MQTT_TASK_STACK_SIZE, MQTT_TASK_PRIORITY, MQTT_TASK_CORE);
}

View File

@ -18,25 +18,21 @@
#include "OTA.h"
#include <HTTPClient.h>
#define OTA_URL "https://bigfoot-inc.com/fw/wellhub.bin"
extern const uint8_t server_cert[] asm("_binary_bigfoot_inc_pem_start");
#define OTA_URL "http://192.168.1.131/wellhub.bin"
static const char *TAG = "OTA";
namespace ota_update
{
OTA::OTA(App & app) : m_app(app)
{
}
void OTA::httpCleanup(esp_http_client_handle_t client)
{
esp_http_client_close(client);
esp_http_client_cleanup(client);
}
void OTA::taskFatalError()
{
ESP_LOGE(TAG, "Exiting task due to fatal error...");
@ -57,6 +53,25 @@ void OTA::start()
ESP_LOGW(TAG, "Starting OTA check...");
HTTPClient client;
client.begin(OTA_URL, (const char *)server_cert);
int http_code = client.GET();
if(http_code != HTTP_CODE_OK)
{
ESP_LOGE(TAG, "Server error %d", http_code);
return;
}
int remote_len = client.getSize();
ESP_LOGI(TAG, "remote file len %d", remote_len);
if(remote_len < 4096)
return;
WiFiClient* stream = client.getStreamPtr();
const esp_partition_t *configured = esp_ota_get_boot_partition();
const esp_partition_t *running = esp_ota_get_running_partition();
@ -70,27 +85,6 @@ void OTA::start()
ESP_LOGI(TAG, "Running partition type %d subtype %d (offset 0x%08x)", running->type, running->subtype,
running->address);
esp_http_client_config_t config = { };
config.url = OTA_URL;
esp_http_client_handle_t client = esp_http_client_init(&config);
if (client == NULL)
{
ESP_LOGE(TAG, "Failed to initialize HTTP connection");
}
err = esp_http_client_open(client, 0);
if (err != ESP_OK)
{
ESP_LOGE(TAG, "Failed to open HTTP connection: %s", esp_err_to_name(err));
esp_http_client_cleanup(client);
return;
}
esp_http_client_fetch_headers(client);
int remote_len = esp_http_client_get_content_length(client);
ESP_LOGI(TAG,"remote len %d", remote_len);
update_partition = esp_ota_get_next_update_partition(NULL);
ESP_LOGI(TAG, "Writing to partition subtype %d at offset 0x%x", update_partition->subtype,
update_partition->address);
@ -101,17 +95,15 @@ void OTA::start()
bool image_header_was_checked = false;
while (1)
{
int data_read = esp_http_client_read(client, otaWriteData, BUFFSIZE);
// int len = stream->available();
int data_read = stream->readBytes(otaWriteData, BUFFSIZE);
if (data_read < 0)
{
ESP_LOGE(TAG, "Error: SSL data read error");
esp_http_client_close(client);
esp_http_client_cleanup(client);
taskFatalError();
return;
}
else if (data_read > 0)
{
//printf(".");
if (image_header_was_checked == false)
{
// this is the first 1k of received image
@ -159,15 +151,15 @@ void OTA::start()
ESP_LOGW(TAG, "Previously, there was an attempt to launch the firmware with %s version, but it failed.",
invalid_app_info.version);
ESP_LOGW(TAG, "The firmware has been rolled back to the previous version.");
httpCleanup(client);
// httpCleanup(client);
return;
}
}
// TODO: add date/time check
if (memcmp(new_app_info.version, running_app_info.version, sizeof(new_app_info.version) + sizeof(new_app_info.project_name) + sizeof(new_app_info.time) + sizeof(new_app_info.date)) == 0)
{
ESP_LOGI(TAG, "Current running version is the same as a remote. No need for update.");
httpCleanup(client);
return;
}
@ -180,22 +172,22 @@ void OTA::start()
if (err != ESP_OK)
{
ESP_LOGE(TAG, "esp_ota_begin failed (%s)", esp_err_to_name(err));
httpCleanup(client);
// httpCleanup(client);
taskFatalError();
}
}
else
{
ESP_LOGE(TAG, "received package does not fit len");
httpCleanup(client);
taskFatalError();
return;
}
}
err = esp_ota_write(update_handle, (const void *) otaWriteData, data_read);
if (err != ESP_OK)
{
httpCleanup(client);
ESP_LOGE(TAG, "Error: esp_ota_write error");
taskFatalError();
}
binary_file_length += data_read;
@ -208,11 +200,10 @@ void OTA::start()
last_reported = progress;
ESP_LOGI(TAG, "%d%%", last_reported);
}
}
else if (data_read == 0)
{
ESP_LOGI(TAG, "Connection closed,all data received");
ESP_LOGI(TAG, "All data received");
break;
}
}
@ -222,7 +213,7 @@ void OTA::start()
if (esp_ota_end(update_handle) != ESP_OK)
{
ESP_LOGE(TAG, "esp_ota_end failed!");
httpCleanup(client);
// httpCleanup(client);
taskFatalError();
}
@ -232,7 +223,7 @@ void OTA::start()
if (err != ESP_OK)
{
ESP_LOGE(TAG, "esp_ota_set_boot_partition failed (%s)!", esp_err_to_name(err));
httpCleanup(client);
// httpCleanup(client);
taskFatalError();
}
ESP_LOGI(TAG, "Prepare to restart system!");
@ -243,4 +234,3 @@ void OTA::start()
OTA::~OTA()
{
}
}

View File

@ -12,10 +12,7 @@
#define BUFFSIZE 1024
#define HASH_LEN 32 /* SHA-256 digest length */
namespace ota_update
{
#include "App.h"
#include "esp_http_client.h"
class OTA
@ -25,7 +22,6 @@ public:
private:
char otaWriteData[BUFFSIZE + 1] = { 0 };
void httpCleanup(esp_http_client_handle_t client);
App & m_app;
private:
@ -35,6 +31,5 @@ public:
OTA(App & app);
virtual ~OTA();
};
}
#endif /* __OTA_H__ */

View File

@ -121,6 +121,7 @@ protected:
private:
Settings();
public:
static Settings & getInstance();

View File

@ -1,38 +0,0 @@
/// © MiroZ 2024
#include "TaskFactory.h"
TaskFactory::TaskFactory()
{
#ifdef USE_MUTEX
m_xMutex = xSemaphoreCreateMutex();
assert(m_xMutex);
#endif
}
TaskFactory::~TaskFactory()
{
#ifdef USE_MUTEX
if(m_xMutex != NULL)
vSemaphoreDelete(m_xMutex);
#endif
}
TaskHandle_t TaskFactory::createTask(TASK_FUNCTION task_function, const char *name, uint32_t stack_size, UBaseType_t priority, BaseType_t core)
{
TaskHandle_t task_handle = nullptr;
#ifdef USE_MUTEX
if (xSemaphoreTake(m_xMutex, portMAX_DELAY))
{
#endif
m_task_function = task_function;
xTaskCreatePinnedToCore(taskStarter, name, stack_size, this, priority, &task_handle, core);
#ifdef USE_MUTEX
xSemaphoreGive(m_xMutex);
}
#endif
return task_handle;
}
TaskFactory TASK_FACTORY;

88
main/TaskMgr.cpp Normal file
View File

@ -0,0 +1,88 @@
/// © MiroZ 2024
#include "TaskMgr.h"
#include <Arduino.h>
#include <esp_log.h>
static const char * TAG = "taskmgr";
TaskMgr::TaskMgr()
{
m_xMutex = xSemaphoreCreateMutex();
assert(m_xMutex);
#ifdef TASKMGR_TASK_NAME
createTask(std::bind(&TaskMgr::task, this), TASKMGR_TASK_NAME, TASKMGR_TASK_STACK_SIZE, TASKMGR_TASK_PRIORITY, TASKMGR_TASK_CORE);
#endif
}
TaskMgr::~TaskMgr()
{
if(m_xMutex != NULL)
vSemaphoreDelete(m_xMutex);
}
#ifdef TASKMGR_TASK_NAME
void TaskMgr::task()
{
while(true)
{
delay(TASKMGR_TASK_DELAY);
getInfo();
}
}
#endif
TaskMgr & TaskMgr::getInstance()
{
static TaskMgr taskmgr;
return taskmgr;
}
TaskHandle_t TaskMgr::createTask(TASK_FUNCTION task_function, const char *name, uint32_t stack_size, UBaseType_t priority, BaseType_t core)
{
TaskHandle_t task_handle = nullptr;
if (xSemaphoreTake(m_xMutex, portMAX_DELAY))
{
m_task_function = task_function;
xTaskCreatePinnedToCore(taskStarter, name, stack_size, this, priority, &task_handle, core);
m_tasks.push_back(task_handle);
xSemaphoreGive(m_xMutex);
}
return task_handle;
}
void TaskMgr::deleteTask(TaskHandle_t task)
{
if(task == nullptr)
return;
if (xSemaphoreTake(m_xMutex, portMAX_DELAY))
{
vTaskDelete(task);
m_tasks.remove(task);
xSemaphoreGive(m_xMutex);
}
}
void TaskMgr::getInfo()
{
if (xSemaphoreTake(m_xMutex, portMAX_DELAY))
{
ESP_LOGW(TAG, "Current running tasks:");
for(auto i : m_tasks)
{
const char * name = pcTaskGetName(i);
uint32_t hwm = (uint32_t)uxTaskGetStackHighWaterMark(i);
if(hwm < 256)
ESP_LOGW(TAG, "%10s (%d)", name, hwm);
else
ESP_LOGI(TAG, "%10s (%d)", name, hwm);
}
xSemaphoreGive(m_xMutex);
}
}

View File

@ -3,39 +3,43 @@
#ifndef __TASK_FACTORY_H__
#define __TASK_FACTORY_H__
#include "app_config.h"
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <freertos/semphr.h>
#include <stdint.h>
#include <esp_err.h>
#include <functional>
#include <list>
typedef std::function<void()> TASK_FUNCTION;
// no need for mutex here
#define _USE_MUTEX
class TaskFactory
class TaskMgr
{
protected:
#ifdef USE_MUTEX
SemaphoreHandle_t m_xMutex = NULL;
#endif
TASK_FUNCTION m_task_function = nullptr;
std::list<TaskHandle_t> m_tasks;
protected:
static void taskStarter(void * ptr) { (static_cast<TaskFactory*>(ptr)->run()); }
static void taskStarter(void * ptr) { (static_cast<TaskMgr*>(ptr)->run()); }
void run(){ m_task_function(); }
public:
TaskHandle_t createTask(TASK_FUNCTION task_function, const char *name, uint32_t stack_size, UBaseType_t priority, BaseType_t core);
static uint32_t getStackHighWaterMark(TaskHandle_t task = NULL){ return (uint32_t)uxTaskGetStackHighWaterMark(task); }
static void deleteTask(TaskHandle_t task = NULL){ vTaskDelete(task); }
#ifdef TASKMGR_TASK_NAME
void task();
#endif
TaskFactory();
~TaskFactory();
private:
TaskMgr();
public:
static TaskMgr & getInstance();
TaskHandle_t createTask(TASK_FUNCTION task_function, const char *name, uint32_t stack_size, UBaseType_t priority, BaseType_t core);
void deleteTask(TaskHandle_t task = NULL);
void getInfo();
~TaskMgr();
};
extern TaskFactory TASK_FACTORY;
#endif /* __TASK_FACTORY_H__ */

View File

@ -6,6 +6,7 @@
#include <WiFi.h>
#include <functional>
#include "utilities.h"
#include "app_config.h"
static const char *TAG = "Wifi";
#define IGNORE_SSID_MINS 20
@ -101,7 +102,7 @@ int Wifi::start()
if(m_task == nullptr)
{
ESP_LOGW(TAG, "Starting wifi");
m_task = TASK_FACTORY.createTask(std::bind(&Wifi::task, this), "wifi task", 4096, 5, 0);
m_task = TaskMgr::getInstance().createTask(std::bind(&Wifi::task, this), WIFI_TASK_NAME, WIFI_TASK_STACK_SIZE, WIFI_TASK_PRIORITY, WIFI_TASK_CORE);
}
return 0;
}

View File

@ -6,7 +6,7 @@
#include <WiFi.h>
#include <esp_timer.h>
#include "Settings.h"
#include "TaskFactory.h"
#include "TaskMgr.h"
#define _USE_TIMER

31
main/app_config.h Normal file
View File

@ -0,0 +1,31 @@
/// © MiroZ 2024
#ifndef __APP_CONFIG_H__
#define __APP_CONFIG_H__
// LED task
#define LED_TASK_NAME "led"
#define LED_TASK_STACK_SIZE 2096
#define LED_TASK_PRIORITY 5
#define LED_TASK_CORE 0
// WIFI task
#define WIFI_TASK_NAME "wifi"
#define WIFI_TASK_STACK_SIZE 4096
#define WIFI_TASK_PRIORITY 5
#define WIFI_TASK_CORE 0
// MQTT task
#define MQTT_TASK_NAME "mqtt"
#define MQTT_TASK_STACK_SIZE 6144
#define MQTT_TASK_PRIORITY 5
#define MQTT_TASK_CORE 0
// task mgr task
#define TASKMGR_TASK_NAME "task mgr"
#define TASKMGR_TASK_STACK_SIZE 2048
#define TASKMGR_TASK_PRIORITY 5
#define TASKMGR_TASK_CORE 0
#define TASKMGR_TASK_DELAY 60000
#endif

View File

@ -6,7 +6,7 @@
#include <esp_log.h>
#include <SPI.h>
#include <errno.h>
#include "TaskFactory.h"
#include "TaskMgr.h"
#include "esp_task_wdt.h"
#include "App.h"
@ -25,8 +25,7 @@ extern "C" void app_main(void)
App * app = new App();
app->init();
app->start();
ESP_LOGI(TAG, "stack high water mark %d", TaskFactory::getStackHighWaterMark());
// we're no longer needed
TaskFactory::deleteTask();
vTaskDelete(NULL);
}

3
ota.sh
View File

@ -12,6 +12,5 @@ if (($ret_val != 0)); then
fi
cp build/wellhub.bin /var/www/esp_ota
idf.py -p /dev/ttyUSB1 monitor -B 450000
lftp -c "open -u mirozmrzli@bigfoot-inc.com,3445trGGDSa9 ftp.bigfoot-inc.com; put build/wellhub.bin"

7
upload.sh Executable file
View File

@ -0,0 +1,7 @@
#!/bin/bash
#!/bin/bash
lftp -u mirozmrzli@bigfoot-inc.com,3445trGGDSa9 mirozmrzli@ftp.bigfoot-inc.com
put build/wellhub.bin
bye