new upgrade

This commit is contained in:
2025-12-21 23:28:26 +00:00
parent 82fa194bd8
commit 023644a887
99 changed files with 7457 additions and 7079 deletions

View File

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

View File

@@ -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();