new upgrade
This commit is contained in:
@@ -3,5 +3,5 @@ set(srcs "src/scheduler_types.c" "src/scheduler.c" "src/scheduler_events.c")
|
||||
idf_component_register(SRCS "${srcs}"
|
||||
INCLUDE_DIRS "include"
|
||||
PRIV_INCLUDE_DIRS "src"
|
||||
PRIV_REQUIRES nvs_flash esp_timer
|
||||
PRIV_REQUIRES esp_timer
|
||||
REQUIRES esp_event evse)
|
||||
@@ -8,8 +8,9 @@
|
||||
|
||||
#include "esp_log.h"
|
||||
#include "esp_event.h"
|
||||
#include "nvs_flash.h"
|
||||
#include "nvs.h"
|
||||
#include "esp_err.h"
|
||||
|
||||
#include "storage_service.h"
|
||||
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
@@ -26,112 +27,154 @@ static sched_config_t s_cfg = {
|
||||
static bool s_allowed_now = true;
|
||||
static TaskHandle_t s_task_handle = NULL;
|
||||
|
||||
/* ===== NVS ===== */
|
||||
/* ===== Storage ===== */
|
||||
#define NVS_NAMESPACE "scheduler"
|
||||
#define NVS_KEY_ENABLED "enabled"
|
||||
#define NVS_KEY_MODE "mode"
|
||||
#define NVS_KEY_START_MIN "start_min"
|
||||
#define NVS_KEY_END_MIN "end_min"
|
||||
#define NVS_KEY_ENABLED "enabled" // u8
|
||||
#define NVS_KEY_MODE "mode" // u8
|
||||
#define NVS_KEY_START_MIN "start_min" // u16
|
||||
#define NVS_KEY_END_MIN "end_min" // u16
|
||||
|
||||
static void load_config_from_nvs(sched_config_t *out)
|
||||
static inline TickType_t TO_TICKS_MS(uint32_t ms) { return pdMS_TO_TICKS(ms); }
|
||||
|
||||
static bool cfg_sanitize(sched_config_t *cfg)
|
||||
{
|
||||
if (!cfg)
|
||||
return false;
|
||||
|
||||
bool changed = false;
|
||||
|
||||
// enabled é bool
|
||||
cfg->enabled = cfg->enabled ? true : false;
|
||||
|
||||
// mode válido
|
||||
if (cfg->mode > SCHED_MODE_SIMPLE)
|
||||
{
|
||||
cfg->mode = SCHED_MODE_DISABLED;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
// start/end em minutos (0..1440)
|
||||
if (cfg->start_min > (24 * 60))
|
||||
{
|
||||
cfg->start_min = 0;
|
||||
changed = true;
|
||||
}
|
||||
if (cfg->end_min > (24 * 60))
|
||||
{
|
||||
cfg->end_min = 24 * 60;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
static void load_config_from_storage(sched_config_t *out)
|
||||
{
|
||||
if (!out)
|
||||
return;
|
||||
|
||||
*out = s_cfg; // defaults
|
||||
// defaults
|
||||
*out = s_cfg;
|
||||
|
||||
nvs_handle_t h;
|
||||
esp_err_t err = nvs_open(NVS_NAMESPACE, NVS_READONLY, &h);
|
||||
if (err != ESP_OK)
|
||||
{
|
||||
ESP_LOGW(TAG, "No scheduler namespace in NVS (%s), using defaults",
|
||||
esp_err_to_name(err));
|
||||
return;
|
||||
}
|
||||
bool needs_flush = false;
|
||||
|
||||
uint8_t u8;
|
||||
uint16_t u16;
|
||||
uint8_t u8 = 0;
|
||||
uint16_t u16 = 0;
|
||||
esp_err_t err;
|
||||
|
||||
if (nvs_get_u8(h, NVS_KEY_ENABLED, &u8) == ESP_OK)
|
||||
// enabled
|
||||
err = storage_get_u8_sync(NVS_NAMESPACE, NVS_KEY_ENABLED, &u8, TO_TICKS_MS(800));
|
||||
if (err == ESP_OK && u8 <= 1)
|
||||
{
|
||||
out->enabled = (u8 != 0);
|
||||
}
|
||||
if (nvs_get_u8(h, NVS_KEY_MODE, &u8) == ESP_OK)
|
||||
else
|
||||
{
|
||||
if (u8 <= (uint8_t)SCHED_MODE_SIMPLE)
|
||||
{
|
||||
out->mode = (sched_mode_t)u8;
|
||||
}
|
||||
out->enabled = false;
|
||||
(void)storage_set_u8_async(NVS_NAMESPACE, NVS_KEY_ENABLED, 0);
|
||||
needs_flush = true;
|
||||
ESP_LOGW(TAG, "Missing/invalid enabled (%s) -> default=false (persisted)",
|
||||
esp_err_to_name(err));
|
||||
}
|
||||
if (nvs_get_u16(h, NVS_KEY_START_MIN, &u16) == ESP_OK)
|
||||
|
||||
// mode
|
||||
err = storage_get_u8_sync(NVS_NAMESPACE, NVS_KEY_MODE, &u8, TO_TICKS_MS(800));
|
||||
if (err == ESP_OK && u8 <= (uint8_t)SCHED_MODE_SIMPLE)
|
||||
{
|
||||
out->mode = (sched_mode_t)u8;
|
||||
}
|
||||
else
|
||||
{
|
||||
out->mode = SCHED_MODE_DISABLED;
|
||||
(void)storage_set_u8_async(NVS_NAMESPACE, NVS_KEY_MODE, (uint8_t)out->mode);
|
||||
needs_flush = true;
|
||||
ESP_LOGW(TAG, "Missing/invalid mode (%s) -> default=DISABLED (persisted)",
|
||||
esp_err_to_name(err));
|
||||
}
|
||||
|
||||
// start_min
|
||||
err = storage_get_u16_sync(NVS_NAMESPACE, NVS_KEY_START_MIN, &u16, TO_TICKS_MS(800));
|
||||
if (err == ESP_OK && u16 <= (24 * 60))
|
||||
{
|
||||
out->start_min = u16;
|
||||
}
|
||||
if (nvs_get_u16(h, NVS_KEY_END_MIN, &u16) == ESP_OK)
|
||||
else
|
||||
{
|
||||
out->start_min = 0;
|
||||
(void)storage_set_u16_async(NVS_NAMESPACE, NVS_KEY_START_MIN, out->start_min);
|
||||
needs_flush = true;
|
||||
ESP_LOGW(TAG, "Missing/invalid start_min (%s) -> default=0 (persisted)",
|
||||
esp_err_to_name(err));
|
||||
}
|
||||
|
||||
// end_min
|
||||
err = storage_get_u16_sync(NVS_NAMESPACE, NVS_KEY_END_MIN, &u16, TO_TICKS_MS(800));
|
||||
if (err == ESP_OK && u16 <= (24 * 60))
|
||||
{
|
||||
out->end_min = u16;
|
||||
}
|
||||
else
|
||||
{
|
||||
out->end_min = 24 * 60;
|
||||
(void)storage_set_u16_async(NVS_NAMESPACE, NVS_KEY_END_MIN, out->end_min);
|
||||
needs_flush = true;
|
||||
ESP_LOGW(TAG, "Missing/invalid end_min (%s) -> default=1440 (persisted)",
|
||||
esp_err_to_name(err));
|
||||
}
|
||||
|
||||
nvs_close(h);
|
||||
// sanity final (e persistir se ajustou algo)
|
||||
if (cfg_sanitize(out))
|
||||
{
|
||||
(void)storage_set_u8_async(NVS_NAMESPACE, NVS_KEY_ENABLED, out->enabled ? 1 : 0);
|
||||
(void)storage_set_u8_async(NVS_NAMESPACE, NVS_KEY_MODE, (uint8_t)out->mode);
|
||||
(void)storage_set_u16_async(NVS_NAMESPACE, NVS_KEY_START_MIN, out->start_min);
|
||||
(void)storage_set_u16_async(NVS_NAMESPACE, NVS_KEY_END_MIN, out->end_min);
|
||||
needs_flush = true;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Loaded from NVS: enabled=%d mode=%d start=%u end=%u",
|
||||
out->enabled, out->mode,
|
||||
if (needs_flush)
|
||||
{
|
||||
(void)storage_flush_sync(TO_TICKS_MS(2000));
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Loaded: enabled=%d mode=%d start=%u end=%u",
|
||||
out->enabled, (int)out->mode,
|
||||
(unsigned)out->start_min, (unsigned)out->end_min);
|
||||
}
|
||||
|
||||
static void save_config_to_nvs(const sched_config_t *cfg)
|
||||
static void save_config_to_storage(const sched_config_t *cfg)
|
||||
{
|
||||
if (!cfg)
|
||||
return;
|
||||
|
||||
nvs_handle_t h;
|
||||
esp_err_t err = nvs_open(NVS_NAMESPACE, NVS_READWRITE, &h);
|
||||
if (err != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG, "nvs_open failed: %s", esp_err_to_name(err));
|
||||
return;
|
||||
}
|
||||
// Debounced writes
|
||||
(void)storage_set_u8_async(NVS_NAMESPACE, NVS_KEY_ENABLED, cfg->enabled ? 1 : 0);
|
||||
(void)storage_set_u8_async(NVS_NAMESPACE, NVS_KEY_MODE, (uint8_t)cfg->mode);
|
||||
(void)storage_set_u16_async(NVS_NAMESPACE, NVS_KEY_START_MIN, cfg->start_min);
|
||||
(void)storage_set_u16_async(NVS_NAMESPACE, NVS_KEY_END_MIN, cfg->end_min);
|
||||
|
||||
err = nvs_set_u8(h, NVS_KEY_ENABLED, cfg->enabled ? 1 : 0);
|
||||
if (err != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG, "nvs_set_u8(enabled) failed: %s", esp_err_to_name(err));
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = nvs_set_u8(h, NVS_KEY_MODE, (uint8_t)cfg->mode);
|
||||
if (err != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG, "nvs_set_u8(mode) failed: %s", esp_err_to_name(err));
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = nvs_set_u16(h, NVS_KEY_START_MIN, cfg->start_min);
|
||||
if (err != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG, "nvs_set_u16(start_min) failed: %s", esp_err_to_name(err));
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = nvs_set_u16(h, NVS_KEY_END_MIN, cfg->end_min);
|
||||
if (err != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG, "nvs_set_u16(end_min) failed: %s", esp_err_to_name(err));
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = nvs_commit(h);
|
||||
if (err != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG, "nvs_commit failed: %s", esp_err_to_name(err));
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGI(TAG, "Scheduler config saved to NVS");
|
||||
}
|
||||
|
||||
out:
|
||||
nvs_close(h);
|
||||
// opcional: flush imediato
|
||||
// (void)storage_flush_async();
|
||||
}
|
||||
|
||||
/* ===== Lógica de janelas ===== */
|
||||
@@ -173,17 +216,18 @@ static void scheduler_recompute_and_emit(void)
|
||||
|
||||
sched_event_state_t ev = {
|
||||
.allowed_now = s_allowed_now};
|
||||
esp_event_post(SCHED_EVENTS,
|
||||
SCHED_EVENT_WINDOW_CHANGED,
|
||||
&ev,
|
||||
sizeof(ev),
|
||||
portMAX_DELAY);
|
||||
(void)esp_event_post(SCHED_EVENTS,
|
||||
SCHED_EVENT_WINDOW_CHANGED,
|
||||
&ev,
|
||||
sizeof(ev),
|
||||
portMAX_DELAY);
|
||||
}
|
||||
}
|
||||
|
||||
/* ===== Task do scheduler ===== */
|
||||
static void scheduler_task(void *arg)
|
||||
{
|
||||
(void)arg;
|
||||
const TickType_t period = pdMS_TO_TICKS(60000); // 60s
|
||||
|
||||
ESP_LOGI(TAG, "Scheduler task started");
|
||||
@@ -198,8 +242,18 @@ static void scheduler_task(void *arg)
|
||||
/* ===== API pública ===== */
|
||||
void scheduler_init(void)
|
||||
{
|
||||
// 1) carregar config
|
||||
load_config_from_nvs(&s_cfg);
|
||||
// 0) garante storage
|
||||
esp_err_t se = storage_service_init();
|
||||
if (se != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG, "storage_service_init failed: %s (using defaults in RAM)", esp_err_to_name(se));
|
||||
// segue com defaults
|
||||
}
|
||||
else
|
||||
{
|
||||
// 1) carregar config
|
||||
load_config_from_storage(&s_cfg);
|
||||
}
|
||||
|
||||
// 2) calcular estado inicial
|
||||
s_allowed_now = compute_allowed_now(&s_cfg);
|
||||
@@ -207,23 +261,23 @@ void scheduler_init(void)
|
||||
// 3) enviar evento INIT
|
||||
sched_event_state_t ev = {
|
||||
.allowed_now = s_allowed_now};
|
||||
esp_event_post(SCHED_EVENTS,
|
||||
SCHED_EVENT_INIT,
|
||||
&ev,
|
||||
sizeof(ev),
|
||||
portMAX_DELAY);
|
||||
(void)esp_event_post(SCHED_EVENTS,
|
||||
SCHED_EVENT_INIT,
|
||||
&ev,
|
||||
sizeof(ev),
|
||||
portMAX_DELAY);
|
||||
|
||||
ESP_LOGI(TAG, "Init: allowed_now=%d", s_allowed_now);
|
||||
|
||||
// 4) criar a task
|
||||
if (s_task_handle == NULL)
|
||||
{
|
||||
xTaskCreate(
|
||||
(void)xTaskCreate(
|
||||
scheduler_task,
|
||||
"scheduler_task",
|
||||
4 * 1024,
|
||||
NULL,
|
||||
3, // prioridade razoável
|
||||
3,
|
||||
&s_task_handle);
|
||||
}
|
||||
}
|
||||
@@ -234,7 +288,9 @@ void scheduler_set_config(const sched_config_t *cfg)
|
||||
return;
|
||||
|
||||
s_cfg = *cfg;
|
||||
save_config_to_nvs(&s_cfg);
|
||||
(void)cfg_sanitize(&s_cfg);
|
||||
|
||||
save_config_to_storage(&s_cfg);
|
||||
|
||||
// recomputa imediatamente para refletir mudança
|
||||
scheduler_recompute_and_emit();
|
||||
|
||||
Reference in New Issue
Block a user