new module

This commit is contained in:
2025-12-09 11:48:31 +00:00
parent 4820d9111e
commit e6e2622a95
98 changed files with 5349 additions and 8607 deletions

View File

@@ -7,29 +7,35 @@
#include "evse_api.h"
#include "evse_meter.h"
#include "evse_session.h"
#include "evse_config.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "freertos/queue.h"
#include "esp_log.h"
#include "esp_event.h"
#include <string.h>
#include <inttypes.h>
#include "auth_events.h"
#include "loadbalancer_events.h"
#include "ocpp_events.h"
#include "esp_event.h"
#include "scheduler_events.h"
static const char *TAG = "EVSE_Manager";
static SemaphoreHandle_t evse_mutex;
static bool auth_enabled = false;
static volatile bool auth_enabled = false;
// Estado de pausa controlado pelo Load Balancer
static bool lb_paused = false;
static bool lb_prev_authorized = false;
static volatile bool lb_paused = false;
static volatile bool lb_prev_authorized = false;
// Estado de janela do scheduler
static volatile bool s_sched_allowed = true;
static portMUX_TYPE s_sched_mux = portMUX_INITIALIZER_UNLOCKED;
#define EVSE_MANAGER_TICK_PERIOD_MS 1000 // 1 segundo
@@ -41,8 +47,20 @@ static void lb_clear_pause_state(void)
lb_prev_authorized = false;
}
// Exposto para outros módulos (se quiserem saber se o scheduler permite)
bool evse_sched_is_allowed(void)
{
bool v;
portENTER_CRITICAL(&s_sched_mux);
v = s_sched_allowed;
portEXIT_CRITICAL(&s_sched_mux);
return v;
}
static void evse_manager_handle_auth_on_tick(void)
{
bool sched_allowed = evse_sched_is_allowed();
if (auth_enabled)
{
// Se o carro foi desconectado, revoga autorização
@@ -53,23 +71,38 @@ static void evse_manager_handle_auth_on_tick(void)
// Desconexão física invalida qualquer pausa pendente do LB
lb_clear_pause_state();
}
// Em modos RFID/OCPP, o scheduler pode também forçar paragem
if (!sched_allowed && evse_state_get_authorized())
{
ESP_LOGI(TAG, "[SCHED] window closed (auth mode) → revoking authorization.");
evse_state_set_authorized(false);
}
}
else
{
// Se autenticação está desativada, garante autorização sempre ativa
if (!evse_state_get_authorized())
// Modo OPEN: só autoriza se LB e Scheduler permitirem
if (!lb_paused && sched_allowed && !evse_state_get_authorized())
{
evse_state_set_authorized(true);
ESP_LOGI(TAG, "Authentication disabled → forced authorization.");
// Em modo OPEN, pausa do LB não é tão relevante, mas limpamos mesmo assim
ESP_LOGI(TAG, "Authentication disabled → forced authorization (within schedule).");
lb_clear_pause_state();
}
// Fora da janela, garantir que não fica autorizado
if (!sched_allowed && evse_state_get_authorized())
{
ESP_LOGI(TAG, "[SCHED] window closed (OPEN mode) → revoking authorization.");
evse_state_set_authorized(false);
}
}
}
// ===== Task de ciclo principal =====
static void evse_manager_task(void *arg)
{
(void)arg;
while (true)
{
evse_manager_tick();
@@ -77,8 +110,11 @@ static void evse_manager_task(void *arg)
}
}
// ===== Tratador de eventos de AUTH =====
static void on_auth_event(void *arg, esp_event_base_t base, int32_t id, void *data)
{
(void)arg;
if (base != AUTH_EVENTS || !data)
return;
@@ -105,7 +141,9 @@ static void on_auth_event(void *arg, esp_event_base_t base, int32_t id, void *da
ESP_LOGI(TAG, "Auth mode = %s", auth_mode_to_str(g_mode));
if (g_mode == AUTH_MODE_OPEN)
{
evse_state_set_authorized(true);
// Em OPEN, a autorização passa a ser gerida por evse_manager_handle_auth_on_tick(),
// que também respeita o scheduler.
evse_state_set_authorized(false); // vai ser forçado no próximo tick se permitido
auth_enabled = false;
}
else
@@ -121,17 +159,22 @@ static void on_auth_event(void *arg, esp_event_base_t base, int32_t id, void *da
}
}
// ===== Tratador de eventos de loadbalancer =====
// ===== Tratador de eventos de Load Balancer =====
static void on_loadbalancer_event(void *handler_arg, esp_event_base_t event_base,
int32_t event_id, void *event_data)
{
(void)handler_arg;
(void)event_base;
if (!event_data)
return;
if (event_id == LOADBALANCER_EVENT_INIT || event_id == LOADBALANCER_EVENT_STATE_CHANGED)
{
const loadbalancer_state_event_t *evt = (const loadbalancer_state_event_t *)event_data;
ESP_LOGI(TAG, "Loadbalancer %s (ts: %lld)",
evt->enabled ? "ENABLED" : "DISABLED",
(long long)evt->timestamp_us);
// Ações adicionais podem ser adicionadas aqui conforme necessário
}
else if (event_id == LOADBALANCER_EVENT_MASTER_CURRENT_LIMIT)
{
@@ -167,16 +210,17 @@ static void on_loadbalancer_event(void *handler_arg, esp_event_base_t event_base
{
lb_paused = false;
// Só retomamos se EVSE estiver operacional
// Só retomamos se EVSE estiver operacional e scheduler permitir
bool can_resume =
(evse_get_error() == 0) &&
evse_config_is_available() &&
evse_config_is_enabled();
evse_config_is_enabled() &&
evse_sched_is_allowed();
if (!can_resume)
{
ESP_LOGW(TAG,
"[LB] limit=%uA → não retoma automaticamente (erro/indisponível/desabilitado)",
"[LB] limit=%uA → não retoma automaticamente (erro/indisponível/desabilitado/fora de horário)",
evt->max_current);
lb_clear_pause_state();
return;
@@ -184,7 +228,7 @@ static void on_loadbalancer_event(void *handler_arg, esp_event_base_t event_base
if (!auth_enabled)
{
// Modo OPEN: retoma sempre
// Modo OPEN: retoma sempre (se dentro da janela do scheduler)
ESP_LOGI(TAG,
"[LB] limit=%uA → modo OPEN, reautorizando (authorized=true)",
evt->max_current);
@@ -222,8 +266,11 @@ static void on_loadbalancer_event(void *handler_arg, esp_event_base_t event_base
}
}
// ===== Tratador de eventos de OCPP =====
static void on_ocpp_event(void *arg, esp_event_base_t base, int32_t id, void *data)
{
(void)arg;
if (base != OCPP_EVENTS)
return;
@@ -261,7 +308,6 @@ static void on_ocpp_event(void *arg, esp_event_base_t base, int32_t id, void *da
case OCPP_EVENT_START_TX:
ESP_LOGI(TAG, "[OCPP] StartTx");
// StartTx em si não precisa mexer em auth, mas limpamos estado de pausa por segurança
lb_clear_pause_state();
break;
@@ -285,8 +331,6 @@ static void on_ocpp_event(void *arg, esp_event_base_t base, int32_t id, void *da
// Mapear operative → enabled local (persiste e emite EVSE_EVENT_ENABLE_UPDATED)
evse_config_set_enabled(ev->operative);
// Opcional: poderias também limpar a pausa aqui, dependendo da política
// lb_clear_pause_state();
break;
}
@@ -296,10 +340,44 @@ static void on_ocpp_event(void *arg, esp_event_base_t base, int32_t id, void *da
}
}
// ===== Tratador de eventos de Scheduler =====
static void on_sched_event(void *arg,
esp_event_base_t base,
int32_t id,
void *data)
{
(void)arg;
if (base != SCHED_EVENTS || data == NULL)
return;
const sched_event_state_t *ev = (const sched_event_state_t *)data;
portENTER_CRITICAL(&s_sched_mux);
s_sched_allowed = ev->allowed_now;
portEXIT_CRITICAL(&s_sched_mux);
ESP_LOGI(TAG,
"[SCHED] event id=%" PRIi32 " allowed_now=%d",
id, (int)ev->allowed_now);
// Se a janela fechou, parar sessão (revogar autorização)
if (!ev->allowed_now && evse_state_get_authorized())
{
ESP_LOGI(TAG, "[SCHED] window closed → stopping session (authorized=false)");
evse_state_set_authorized(false);
}
// Se a janela abriu de novo, não auto-reautorizamos aqui.
// Deixamos que o utilizador / OCPP decida iniciar nova sessão.
// (Em modo OPEN, o tick trata disso respeitando o scheduler.)
}
// ===== Inicialização =====
void evse_manager_init(void)
{
evse_mutex = xSemaphoreCreateMutex();
configASSERT(evse_mutex != NULL);
evse_config_init();
evse_error_init();
@@ -311,9 +389,12 @@ void evse_manager_init(void)
ESP_ERROR_CHECK(esp_event_handler_register(AUTH_EVENTS, ESP_EVENT_ANY_ID, &on_auth_event, NULL));
ESP_ERROR_CHECK(esp_event_handler_register(LOADBALANCER_EVENTS, ESP_EVENT_ANY_ID, &on_loadbalancer_event, NULL));
ESP_ERROR_CHECK(esp_event_handler_register(OCPP_EVENTS, ESP_EVENT_ANY_ID, &on_ocpp_event, NULL));
ESP_ERROR_CHECK(esp_event_handler_register(SCHED_EVENTS, ESP_EVENT_ANY_ID, &on_sched_event, NULL));
ESP_LOGI(TAG, "EVSE Manager inicializado.");
xTaskCreate(evse_manager_task, "evse_manager_task", 4096, NULL, 5, NULL);
BaseType_t rc = xTaskCreate(evse_manager_task, "evse_manager_task", 4096, NULL, 5, NULL);
configASSERT(rc == pdPASS);
}
// ===== Main Tick =====
@@ -331,4 +412,5 @@ void evse_manager_tick(void)
xSemaphoreGive(evse_mutex);
}
// === Fim de: components/evse/evse_manager.c ===