add ocpp
This commit is contained in:
@@ -1,7 +1,8 @@
|
||||
#include <inttypes.h> // For PRI macros
|
||||
#include <inttypes.h> // For PRI macros
|
||||
#include "evse_config.h"
|
||||
#include "board_config.h"
|
||||
#include "evse_limits.h"
|
||||
#include "evse_api.h" // <— para evse_get_state / evse_state_is_charging
|
||||
#include "esp_log.h"
|
||||
#include "nvs.h"
|
||||
#include "esp_timer.h"
|
||||
@@ -13,50 +14,63 @@ static nvs_handle_t nvs;
|
||||
// ========================
|
||||
// Configurable parameters
|
||||
// ========================
|
||||
static uint8_t max_charging_current = MAX_CHARGING_CURRENT_LIMIT;
|
||||
static uint16_t charging_current; // Persisted (NVS)
|
||||
static uint16_t charging_current_runtime = 0; // Runtime only
|
||||
static bool socket_outlet;
|
||||
static bool rcm;
|
||||
static uint8_t temp_threshold = 60;
|
||||
static bool require_auth;
|
||||
static uint8_t max_charging_current = MAX_CHARGING_CURRENT_LIMIT;
|
||||
static uint16_t charging_current; // Persisted (NVS)
|
||||
static uint16_t charging_current_runtime = 0; // Runtime only
|
||||
static bool socket_outlet;
|
||||
static bool rcm;
|
||||
static uint8_t temp_threshold = 60;
|
||||
static bool require_auth;
|
||||
|
||||
// Availability / Enable flags
|
||||
static bool is_available = true;
|
||||
static bool is_enabled = true;
|
||||
|
||||
// ========================
|
||||
// Initialization
|
||||
// ========================
|
||||
esp_err_t evse_config_init(void) {
|
||||
esp_err_t evse_config_init(void)
|
||||
{
|
||||
ESP_LOGD(TAG, "Initializing NVS configuration...");
|
||||
return nvs_open("evse", NVS_READWRITE, &nvs);
|
||||
}
|
||||
|
||||
void evse_check_defaults(void) {
|
||||
void evse_check_defaults(void)
|
||||
{
|
||||
esp_err_t err;
|
||||
uint8_t u8;
|
||||
uint16_t u16;
|
||||
uint32_t u32;
|
||||
bool needs_commit = false;
|
||||
uint8_t u8_bool;
|
||||
|
||||
ESP_LOGD(TAG, "Checking default parameters...");
|
||||
|
||||
// Max charging current
|
||||
err = nvs_get_u8(nvs, "max_chrg_curr", &u8);
|
||||
if (err != ESP_OK || u8 < MIN_CHARGING_CURRENT_LIMIT || u8 > MAX_CHARGING_CURRENT_LIMIT) {
|
||||
if (err != ESP_OK || u8 < MIN_CHARGING_CURRENT_LIMIT || u8 > MAX_CHARGING_CURRENT_LIMIT)
|
||||
{
|
||||
max_charging_current = MAX_CHARGING_CURRENT_LIMIT;
|
||||
nvs_set_u8(nvs, "max_chrg_curr", max_charging_current);
|
||||
needs_commit = true;
|
||||
ESP_LOGW(TAG, "Invalid or missing max_chrg_curr, resetting to %d", max_charging_current);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
max_charging_current = u8;
|
||||
}
|
||||
|
||||
// Charging current (default, persisted)
|
||||
err = nvs_get_u16(nvs, "def_chrg_curr", &u16);
|
||||
if (err != ESP_OK || u16 < (MIN_CHARGING_CURRENT_LIMIT) || u16 > (max_charging_current)) {
|
||||
if (err != ESP_OK || u16 < (MIN_CHARGING_CURRENT_LIMIT) || u16 > (max_charging_current))
|
||||
{
|
||||
charging_current = max_charging_current;
|
||||
nvs_set_u16(nvs, "def_chrg_curr", charging_current);
|
||||
needs_commit = true;
|
||||
ESP_LOGW(TAG, "Invalid or missing def_chrg_curr, resetting to %d", charging_current);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
charging_current = u16;
|
||||
}
|
||||
|
||||
@@ -67,7 +81,8 @@ void evse_check_defaults(void) {
|
||||
// Auth required
|
||||
err = nvs_get_u8(nvs, "require_auth", &u8);
|
||||
require_auth = (err == ESP_OK && u8 <= 1) ? u8 : false;
|
||||
if (err != ESP_OK) {
|
||||
if (err != ESP_OK)
|
||||
{
|
||||
nvs_set_u8(nvs, "require_auth", require_auth);
|
||||
needs_commit = true;
|
||||
}
|
||||
@@ -75,7 +90,8 @@ void evse_check_defaults(void) {
|
||||
// Socket outlet
|
||||
err = nvs_get_u8(nvs, "socket_outlet", &u8);
|
||||
socket_outlet = (err == ESP_OK && u8) && board_config.proximity;
|
||||
if (err != ESP_OK) {
|
||||
if (err != ESP_OK)
|
||||
{
|
||||
nvs_set_u8(nvs, "socket_outlet", socket_outlet);
|
||||
needs_commit = true;
|
||||
}
|
||||
@@ -83,7 +99,8 @@ void evse_check_defaults(void) {
|
||||
// RCM
|
||||
err = nvs_get_u8(nvs, "rcm", &u8);
|
||||
rcm = (err == ESP_OK && u8) && board_config.rcm;
|
||||
if (err != ESP_OK) {
|
||||
if (err != ESP_OK)
|
||||
{
|
||||
nvs_set_u8(nvs, "rcm", rcm);
|
||||
needs_commit = true;
|
||||
}
|
||||
@@ -91,7 +108,8 @@ void evse_check_defaults(void) {
|
||||
// Temp threshold
|
||||
err = nvs_get_u8(nvs, "temp_threshold", &u8);
|
||||
temp_threshold = (err == ESP_OK && u8 >= 40 && u8 <= 80) ? u8 : 60;
|
||||
if (err != ESP_OK) {
|
||||
if (err != ESP_OK)
|
||||
{
|
||||
nvs_set_u8(nvs, "temp_threshold", temp_threshold);
|
||||
needs_commit = true;
|
||||
}
|
||||
@@ -106,12 +124,42 @@ void evse_check_defaults(void) {
|
||||
if (nvs_get_u16(nvs, "def_un_pwr_lim", &u16) == ESP_OK)
|
||||
evse_set_under_power_limit(u16);
|
||||
|
||||
// Availability (persist)
|
||||
if (nvs_get_u8(nvs, "available", &u8_bool) == ESP_OK && u8_bool <= 1)
|
||||
{
|
||||
is_available = (u8_bool != 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
is_available = true; // default
|
||||
nvs_set_u8(nvs, "available", (uint8_t)is_available);
|
||||
needs_commit = true;
|
||||
ESP_LOGW(TAG, "Missing 'available' -> default=true (persisted).");
|
||||
}
|
||||
|
||||
// Enabled (persist)
|
||||
if (nvs_get_u8(nvs, "enabled", &u8_bool) == ESP_OK && u8_bool <= 1)
|
||||
{
|
||||
is_enabled = (u8_bool != 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
is_enabled = true; // default
|
||||
nvs_set_u8(nvs, "enabled", (uint8_t)is_enabled);
|
||||
needs_commit = true;
|
||||
ESP_LOGW(TAG, "Missing 'enabled' -> default=true (persisted).");
|
||||
}
|
||||
|
||||
// Save to NVS if needed
|
||||
if (needs_commit) {
|
||||
if (needs_commit)
|
||||
{
|
||||
err = nvs_commit(nvs);
|
||||
if (err == ESP_OK) {
|
||||
if (err == ESP_OK)
|
||||
{
|
||||
ESP_LOGD(TAG, "Configuration committed to NVS.");
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGE(TAG, "Failed to commit configuration to NVS: %s", esp_err_to_name(err));
|
||||
}
|
||||
}
|
||||
@@ -120,11 +168,13 @@ void evse_check_defaults(void) {
|
||||
// ========================
|
||||
// Charging current getters/setters
|
||||
// ========================
|
||||
uint8_t evse_get_max_charging_current(void) {
|
||||
uint8_t evse_get_max_charging_current(void)
|
||||
{
|
||||
return max_charging_current;
|
||||
}
|
||||
|
||||
esp_err_t evse_set_max_charging_current(uint8_t value) {
|
||||
esp_err_t evse_set_max_charging_current(uint8_t value)
|
||||
{
|
||||
if (value < MIN_CHARGING_CURRENT_LIMIT || value > MAX_CHARGING_CURRENT_LIMIT)
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
max_charging_current = value;
|
||||
@@ -133,11 +183,13 @@ esp_err_t evse_set_max_charging_current(uint8_t value) {
|
||||
return nvs_commit(nvs);
|
||||
}
|
||||
|
||||
uint16_t evse_get_charging_current(void) {
|
||||
uint16_t evse_get_charging_current(void)
|
||||
{
|
||||
return charging_current;
|
||||
}
|
||||
|
||||
esp_err_t evse_set_charging_current(uint16_t value) {
|
||||
esp_err_t evse_set_charging_current(uint16_t value)
|
||||
{
|
||||
if (value < (MIN_CHARGING_CURRENT_LIMIT) || value > (max_charging_current))
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
charging_current = value;
|
||||
@@ -145,14 +197,16 @@ esp_err_t evse_set_charging_current(uint16_t value) {
|
||||
return nvs_commit(nvs);
|
||||
}
|
||||
|
||||
uint16_t evse_get_default_charging_current(void) {
|
||||
uint16_t evse_get_default_charging_current(void)
|
||||
{
|
||||
uint16_t value;
|
||||
if (nvs_get_u16(nvs, "def_chrg_curr", &value) == ESP_OK)
|
||||
return value;
|
||||
return charging_current;
|
||||
}
|
||||
|
||||
esp_err_t evse_set_default_charging_current(uint16_t value) {
|
||||
esp_err_t evse_set_default_charging_current(uint16_t value)
|
||||
{
|
||||
if (value < (MIN_CHARGING_CURRENT_LIMIT) || value > (max_charging_current))
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
nvs_set_u16(nvs, "def_chrg_curr", value);
|
||||
@@ -162,49 +216,51 @@ esp_err_t evse_set_default_charging_current(uint16_t value) {
|
||||
// ========================
|
||||
// Runtime current (not saved)
|
||||
// ========================
|
||||
void evse_set_runtime_charging_current(uint16_t value) {
|
||||
void evse_set_runtime_charging_current(uint16_t value)
|
||||
{
|
||||
|
||||
ESP_LOGI(TAG, "Runtime charging current updated: %d", charging_current_runtime);
|
||||
|
||||
if (value > max_charging_current) {
|
||||
if (value > max_charging_current)
|
||||
{
|
||||
value = max_charging_current;
|
||||
} else if (value < MIN_CHARGING_CURRENT_LIMIT) {
|
||||
}
|
||||
else if (value < MIN_CHARGING_CURRENT_LIMIT)
|
||||
{
|
||||
value = MIN_CHARGING_CURRENT_LIMIT;
|
||||
}
|
||||
|
||||
charging_current_runtime = value;
|
||||
|
||||
ESP_LOGI(TAG, "Runtime charging current updated: %d", charging_current_runtime);
|
||||
|
||||
// --- PUBLICA ALTERAÇÃO DE CONFIG DO EVSE ---
|
||||
evse_config_event_data_t evt = {
|
||||
.charging = evse_state_is_charging(evse_get_state()),
|
||||
.hw_max_current = (float)evse_get_max_charging_current(),
|
||||
.runtime_current = (float)charging_current_runtime,
|
||||
.timestamp_us = esp_timer_get_time()
|
||||
};
|
||||
.charging = evse_state_is_charging(evse_get_state()),
|
||||
.hw_max_current = (float)evse_get_max_charging_current(),
|
||||
.runtime_current = (float)evse_get_runtime_charging_current(),
|
||||
.timestamp_us = esp_timer_get_time()};
|
||||
|
||||
esp_event_post(EVSE_EVENTS,
|
||||
EVSE_EVENT_CONFIG_UPDATED,
|
||||
&evt,
|
||||
sizeof(evt),
|
||||
portMAX_DELAY);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
uint16_t evse_get_runtime_charging_current(void) {
|
||||
uint16_t evse_get_runtime_charging_current(void)
|
||||
{
|
||||
return charging_current_runtime;
|
||||
}
|
||||
|
||||
|
||||
// ========================
|
||||
// Socket outlet
|
||||
// ========================
|
||||
bool evse_get_socket_outlet(void) {
|
||||
bool evse_get_socket_outlet(void)
|
||||
{
|
||||
return socket_outlet;
|
||||
}
|
||||
|
||||
esp_err_t evse_set_socket_outlet(bool value) {
|
||||
esp_err_t evse_set_socket_outlet(bool value)
|
||||
{
|
||||
if (value && !board_config.proximity)
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
socket_outlet = value;
|
||||
@@ -215,11 +271,13 @@ esp_err_t evse_set_socket_outlet(bool value) {
|
||||
// ========================
|
||||
// RCM
|
||||
// ========================
|
||||
bool evse_is_rcm(void) {
|
||||
bool evse_is_rcm(void)
|
||||
{
|
||||
return rcm;
|
||||
}
|
||||
|
||||
esp_err_t evse_set_rcm(bool value) {
|
||||
esp_err_t evse_set_rcm(bool value)
|
||||
{
|
||||
if (value && !board_config.rcm)
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
rcm = value;
|
||||
@@ -230,11 +288,13 @@ esp_err_t evse_set_rcm(bool value) {
|
||||
// ========================
|
||||
// Temperature
|
||||
// ========================
|
||||
uint8_t evse_get_temp_threshold(void) {
|
||||
uint8_t evse_get_temp_threshold(void)
|
||||
{
|
||||
return temp_threshold;
|
||||
}
|
||||
|
||||
esp_err_t evse_set_temp_threshold(uint8_t value) {
|
||||
esp_err_t evse_set_temp_threshold(uint8_t value)
|
||||
{
|
||||
if (value < 40 || value > 80)
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
temp_threshold = value;
|
||||
@@ -242,29 +302,58 @@ esp_err_t evse_set_temp_threshold(uint8_t value) {
|
||||
return nvs_commit(nvs);
|
||||
}
|
||||
|
||||
|
||||
// ========================
|
||||
// Availability
|
||||
// ========================
|
||||
static bool is_available = true;
|
||||
|
||||
bool evse_config_is_available(void) {
|
||||
bool evse_config_is_available(void)
|
||||
{
|
||||
return is_available;
|
||||
}
|
||||
|
||||
void evse_config_set_available(bool available) {
|
||||
is_available = available;
|
||||
void evse_config_set_available(bool available)
|
||||
{
|
||||
is_available = available ? true : false;
|
||||
|
||||
// Persist
|
||||
esp_err_t err = nvs_set_u8(nvs, "available", (uint8_t)is_available);
|
||||
if (err == ESP_OK)
|
||||
err = nvs_commit(nvs);
|
||||
if (err != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG, "Failed to persist 'available': %s", esp_err_to_name(err));
|
||||
}
|
||||
|
||||
// AVAILABLE_UPDATED
|
||||
evse_available_event_data_t e = {
|
||||
.available = is_available,
|
||||
.timestamp_us = esp_timer_get_time()};
|
||||
esp_event_post(EVSE_EVENTS, EVSE_EVENT_AVAILABLE_UPDATED, &e, sizeof(e), portMAX_DELAY);
|
||||
}
|
||||
|
||||
// ========================
|
||||
// Enable/Disable
|
||||
// ========================
|
||||
static bool is_enabled = true;
|
||||
|
||||
bool evse_config_is_enabled(void) {
|
||||
bool evse_config_is_enabled(void)
|
||||
{
|
||||
return is_enabled;
|
||||
}
|
||||
|
||||
void evse_config_set_enabled(bool enabled) {
|
||||
is_enabled = enabled;
|
||||
void evse_config_set_enabled(bool enabled)
|
||||
{
|
||||
is_enabled = enabled ? true : false;
|
||||
|
||||
// Persist
|
||||
esp_err_t err = nvs_set_u8(nvs, "enabled", (uint8_t)is_enabled);
|
||||
if (err == ESP_OK)
|
||||
err = nvs_commit(nvs);
|
||||
if (err != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG, "Failed to persist 'enabled': %s", esp_err_to_name(err));
|
||||
}
|
||||
|
||||
// ENABLE_UPDATED
|
||||
evse_enable_event_data_t e = {
|
||||
.enabled = is_enabled,
|
||||
.timestamp_us = esp_timer_get_time()};
|
||||
esp_event_post(EVSE_EVENTS, EVSE_EVENT_ENABLE_UPDATED, &e, sizeof(e), portMAX_DELAY);
|
||||
}
|
||||
|
||||
@@ -61,9 +61,7 @@ void evse_process(void) {
|
||||
|
||||
evse_state_t current = evse_get_state();
|
||||
if (current != last_state) {
|
||||
ESP_LOGI(TAG, "State changed: %s → %s",
|
||||
evse_state_to_str(last_state),
|
||||
evse_state_to_str(current));
|
||||
//ESP_LOGI(TAG, "State changed: %s → %s", evse_state_to_str(last_state), evse_state_to_str(current));
|
||||
last_state = current;
|
||||
}
|
||||
|
||||
|
||||
@@ -83,12 +83,13 @@ static void update_outputs(evse_state_t state) {
|
||||
break;
|
||||
|
||||
case EVSE_STATE_C1:
|
||||
case EVSE_STATE_D1:
|
||||
pilot_set_level(true);
|
||||
case EVSE_STATE_D1: {
|
||||
pilot_set_amps(MIN(current, cable_max_current)); // mantém PWM
|
||||
ac_relay_set_state(false); // relé ainda desligado
|
||||
c1_d1_waiting = true;
|
||||
c1_d1_relay_to = xTaskGetTickCount() + pdMS_TO_TICKS(6000);
|
||||
break;
|
||||
|
||||
}
|
||||
case EVSE_STATE_C2:
|
||||
case EVSE_STATE_D2:
|
||||
pilot_set_amps(MIN(current, cable_max_current));
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "evse_api.h"
|
||||
#include "evse_meter.h"
|
||||
#include "evse_session.h"
|
||||
#include "evse_config.h"
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
@@ -16,6 +17,7 @@
|
||||
|
||||
#include "auth_events.h"
|
||||
#include "loadbalancer_events.h"
|
||||
#include "ocpp_events.h"
|
||||
#include "esp_event.h"
|
||||
|
||||
static const char *TAG = "EVSE_Manager";
|
||||
@@ -23,66 +25,142 @@ static const char *TAG = "EVSE_Manager";
|
||||
static SemaphoreHandle_t evse_mutex;
|
||||
static bool auth_enabled = false;
|
||||
|
||||
#define EVSE_MANAGER_TICK_PERIOD_MS 1000 // 1 segundo
|
||||
#define EVSE_MANAGER_TICK_PERIOD_MS 1000 // 1 segundo
|
||||
|
||||
// ===== Task de ciclo principal =====
|
||||
static void evse_manager_task(void *arg) {
|
||||
while (true) {
|
||||
static void evse_manager_task(void *arg)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
evse_manager_tick();
|
||||
vTaskDelay(pdMS_TO_TICKS(EVSE_MANAGER_TICK_PERIOD_MS));
|
||||
}
|
||||
}
|
||||
|
||||
// ===== Tratador de eventos de autenticação =====
|
||||
static void on_auth_event(void* arg, esp_event_base_t base, int32_t id, void* data) {
|
||||
if (base != AUTH_EVENTS || data == NULL) return;
|
||||
static void on_auth_event(void *arg, esp_event_base_t base, int32_t id, void *data)
|
||||
{
|
||||
if (base != AUTH_EVENTS || !data)
|
||||
return;
|
||||
|
||||
switch (id) {
|
||||
case AUTH_EVENT_TAG_PROCESSED: {
|
||||
auth_tag_event_data_t *evt = (auth_tag_event_data_t*)data;
|
||||
ESP_LOGI("EVSE", "Tag: %s | Autorized: %s", evt->tag, evt->authorized ? "AUTHORIZED" : "DENIED");
|
||||
evse_state_set_authorized(evt->authorized);
|
||||
break;
|
||||
auth_mode_t g_mode = AUTH_MODE_OPEN;
|
||||
|
||||
switch (id)
|
||||
{
|
||||
case AUTH_EVENT_TAG_PROCESSED:
|
||||
{
|
||||
const auth_tag_event_data_t *evt = (const auth_tag_event_data_t *)data;
|
||||
ESP_LOGI(TAG, "Tag %s -> %s", evt->tag, evt->authorized ? "AUTHORIZED" : "DENIED");
|
||||
evse_state_set_authorized(evt->authorized);
|
||||
break;
|
||||
}
|
||||
|
||||
case AUTH_EVENT_MODE_CHANGED:
|
||||
case AUTH_EVENT_INIT:
|
||||
{
|
||||
const auth_mode_event_data_t *evt = (const auth_mode_event_data_t *)data;
|
||||
g_mode = evt->mode;
|
||||
ESP_LOGI(TAG, "Auth mode = %s", auth_mode_to_str(g_mode));
|
||||
if (g_mode == AUTH_MODE_OPEN)
|
||||
{
|
||||
evse_state_set_authorized(true);
|
||||
auth_enabled = false;
|
||||
}
|
||||
|
||||
case AUTH_EVENT_ENABLED_CHANGED:
|
||||
case AUTH_EVENT_INIT: {
|
||||
auth_enabled_event_data_t *evt = (auth_enabled_event_data_t*)data;
|
||||
auth_enabled = evt->enabled;
|
||||
|
||||
ESP_LOGI("EVSE", "Auth %s (%s)",
|
||||
id == AUTH_EVENT_ENABLED_CHANGED ? "ficou" : "init",
|
||||
evt->enabled ? "ATIVO" : "INATIVO");
|
||||
|
||||
if (!auth_enabled) {
|
||||
evse_state_set_authorized(true);
|
||||
ESP_LOGI("EVSE", "Autenticação desativada → autorização forçada.");
|
||||
} else {
|
||||
evse_state_set_authorized(false);
|
||||
ESP_LOGI("EVSE", "Autenticação ativada → aguardando autorização por tag.");
|
||||
}
|
||||
break;
|
||||
else
|
||||
{
|
||||
evse_state_set_authorized(false);
|
||||
auth_enabled = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ===== Tratador de eventos de loadbalancer =====
|
||||
static void on_loadbalancer_event(void* handler_arg, esp_event_base_t event_base,
|
||||
int32_t event_id, void* event_data) {
|
||||
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;
|
||||
static void on_loadbalancer_event(void *handler_arg, esp_event_base_t event_base,
|
||||
int32_t event_id, void *event_data)
|
||||
{
|
||||
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", evt->timestamp_us);
|
||||
// Ações adicionais podem ser adicionadas aqui conforme necessário
|
||||
} else if (event_id == LOADBALANCER_EVENT_MASTER_CURRENT_LIMIT) {
|
||||
const loadbalancer_master_limit_event_t* evt = (const loadbalancer_master_limit_event_t*) event_data;
|
||||
}
|
||||
else if (event_id == LOADBALANCER_EVENT_MASTER_CURRENT_LIMIT)
|
||||
{
|
||||
const loadbalancer_master_limit_event_t *evt = (const loadbalancer_master_limit_event_t *)event_data;
|
||||
ESP_LOGI(TAG, "Novo limite de corrente (master): %u A (ts: %lld)", evt->max_current, evt->timestamp_us);
|
||||
evse_set_runtime_charging_current(evt->max_current);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void on_ocpp_event(void *arg, esp_event_base_t base, int32_t id, void *data)
|
||||
{
|
||||
if (base != OCPP_EVENTS)
|
||||
return;
|
||||
|
||||
switch (id)
|
||||
{
|
||||
case OCPP_EVENT_AUTHORIZED:
|
||||
ESP_LOGI(TAG, "[OCPP] Authorized");
|
||||
evse_state_set_authorized(true);
|
||||
break;
|
||||
|
||||
case OCPP_EVENT_AUTH_REJECTED:
|
||||
ESP_LOGW(TAG, "[OCPP] Authorization rejected");
|
||||
evse_state_set_authorized(false);
|
||||
break;
|
||||
|
||||
case OCPP_EVENT_AUTH_TIMEOUT:
|
||||
ESP_LOGW(TAG, "[OCPP] Authorization timeout");
|
||||
evse_state_set_authorized(false);
|
||||
break;
|
||||
|
||||
case OCPP_EVENT_REMOTE_START:
|
||||
ESP_LOGI(TAG, "[OCPP] RemoteStart");
|
||||
evse_state_set_authorized(true);
|
||||
break;
|
||||
|
||||
case OCPP_EVENT_REMOTE_STOP:
|
||||
ESP_LOGI(TAG, "[OCPP] RemoteStop");
|
||||
evse_state_set_authorized(false);
|
||||
break;
|
||||
|
||||
case OCPP_EVENT_START_TX:
|
||||
ESP_LOGI(TAG, "[OCPP] StartTx");
|
||||
break;
|
||||
|
||||
case OCPP_EVENT_STOP_TX:
|
||||
ESP_LOGI(TAG, "[OCPP] StopTx");
|
||||
evse_state_set_authorized(false);
|
||||
break;
|
||||
|
||||
// hegou ChangeAvailability remoto (operative/inoperative)
|
||||
case OCPP_EVENT_OPERATIVE_UPDATED:
|
||||
{
|
||||
if (!data)
|
||||
{
|
||||
ESP_LOGW(TAG, "[OCPP] OperativeUpdated sem payload — ignorado");
|
||||
break;
|
||||
}
|
||||
const ocpp_operative_event_t *ev = (const ocpp_operative_event_t *)data;
|
||||
ESP_LOGI(TAG, "[OCPP] OperativeUpdated: operative=%d ts=%lld",
|
||||
(int)ev->operative, (long long)ev->timestamp_us);
|
||||
|
||||
// Mapear operative → enabled local (persiste e emite EVSE_EVENT_ENABLE_UPDATED)
|
||||
evse_config_set_enabled(ev->operative);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
ESP_LOGD(TAG, "[OCPP] Unhandled event id=%" PRId32, id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// ===== Inicialização =====
|
||||
void evse_manager_init(void) {
|
||||
void evse_manager_init(void)
|
||||
{
|
||||
evse_mutex = xSemaphoreCreateMutex();
|
||||
|
||||
evse_config_init();
|
||||
@@ -94,13 +172,15 @@ 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)); // <— AQUI
|
||||
|
||||
ESP_LOGI(TAG, "EVSE Manager inicializado.");
|
||||
xTaskCreate(evse_manager_task, "evse_manager_task", 4096, NULL, 5, NULL);
|
||||
}
|
||||
|
||||
// ===== Main Tick =====
|
||||
void evse_manager_tick(void) {
|
||||
void evse_manager_tick(void)
|
||||
{
|
||||
xSemaphoreTake(evse_mutex, portMAX_DELAY);
|
||||
|
||||
evse_hardware_tick();
|
||||
@@ -109,15 +189,20 @@ void evse_manager_tick(void) {
|
||||
evse_temperature_check();
|
||||
evse_session_tick();
|
||||
|
||||
if (auth_enabled) {
|
||||
if (auth_enabled)
|
||||
{
|
||||
// If the car is disconnected, revoke authorization
|
||||
if (evse_state_get_authorized() && evse_get_state() == EVSE_STATE_A) {
|
||||
if (evse_state_get_authorized() && evse_get_state() == EVSE_STATE_A)
|
||||
{
|
||||
ESP_LOGI(TAG, "Vehicle disconnected → revoking authorization.");
|
||||
evse_state_set_authorized(false);
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
// If authentication is disabled, ensure authorization is always granted
|
||||
if (!evse_state_get_authorized()) {
|
||||
if (!evse_state_get_authorized())
|
||||
{
|
||||
evse_state_set_authorized(true);
|
||||
ESP_LOGI(TAG, "Authentication disabled → forced authorization.");
|
||||
}
|
||||
|
||||
@@ -10,50 +10,57 @@
|
||||
static const char *TAG = "evse_meter";
|
||||
static SemaphoreHandle_t meter_mutex;
|
||||
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
uint32_t power_watts[EVSE_METER_PHASE_COUNT];
|
||||
float voltage[EVSE_METER_PHASE_COUNT];
|
||||
float current[EVSE_METER_PHASE_COUNT];
|
||||
float voltage[EVSE_METER_PHASE_COUNT];
|
||||
float current[EVSE_METER_PHASE_COUNT];
|
||||
uint32_t energy_wh;
|
||||
} evse_meter_data_t;
|
||||
|
||||
static evse_meter_data_t meter_data;
|
||||
|
||||
static void on_meter_event_dispatcher(void* arg, esp_event_base_t base, int32_t id, void* data) {
|
||||
if (base == METER_EVENT && id == METER_EVENT_DATA_READY && data) {
|
||||
static void on_meter_event_dispatcher(void *arg, esp_event_base_t base, int32_t id, void *data)
|
||||
{
|
||||
if (base == METER_EVENT && id == METER_EVENT_DATA_READY && data)
|
||||
{
|
||||
const meter_event_data_t *evt = (const meter_event_data_t *)data;
|
||||
if (strcmp(evt->source, "EVSE") == 0) {
|
||||
if (strcmp(evt->source, "EVSE") == 0)
|
||||
{
|
||||
evse_meter_on_meter_event(arg, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void evse_meter_on_meter_event(void* arg, void* event_data) {
|
||||
void evse_meter_on_meter_event(void *arg, void *event_data)
|
||||
{
|
||||
const meter_event_data_t *evt = (const meter_event_data_t *)event_data;
|
||||
if (!evt) return;
|
||||
if (!evt)
|
||||
return;
|
||||
|
||||
xSemaphoreTake(meter_mutex, portMAX_DELAY);
|
||||
for (int i = 0; i < EVSE_METER_PHASE_COUNT; ++i) {
|
||||
for (int i = 0; i < EVSE_METER_PHASE_COUNT; ++i)
|
||||
{
|
||||
meter_data.power_watts[i] = evt->watt[i];
|
||||
meter_data.voltage[i] = evt->vrms[i];
|
||||
meter_data.current[i] = evt->irms[i];
|
||||
meter_data.voltage[i] = evt->vrms[i];
|
||||
meter_data.current[i] = evt->irms[i];
|
||||
}
|
||||
meter_data.energy_wh = (uint32_t)(evt->total_energy * 1000.0f);
|
||||
xSemaphoreGive(meter_mutex);
|
||||
|
||||
ESP_LOGI(TAG,
|
||||
"Meter updated: power[W]={%" PRIu32 ",%" PRIu32 ",%" PRIu32 "}, "
|
||||
"voltage[V]={%.2f,%.2f,%.2f}, "
|
||||
"current[A]={%.2f,%.2f,%.2f}, "
|
||||
"total_energy=%" PRIu32 "Wh",
|
||||
meter_data.power_watts[0], meter_data.power_watts[1], meter_data.power_watts[2],
|
||||
meter_data.voltage[0], meter_data.voltage[1], meter_data.voltage[2],
|
||||
meter_data.current[0], meter_data.current[1], meter_data.current[2],
|
||||
meter_data.energy_wh
|
||||
);
|
||||
"Meter updated: power[W]={%" PRIu32 ",%" PRIu32 ",%" PRIu32 "}, "
|
||||
"voltage[V]={%.2f,%.2f,%.2f}, "
|
||||
"current[A]={%.2f,%.2f,%.2f}, "
|
||||
"total_energy=%" PRIu32 "Wh",
|
||||
meter_data.power_watts[0], meter_data.power_watts[1], meter_data.power_watts[2],
|
||||
meter_data.voltage[0], meter_data.voltage[1], meter_data.voltage[2],
|
||||
meter_data.current[0], meter_data.current[1], meter_data.current[2],
|
||||
meter_data.energy_wh);
|
||||
}
|
||||
|
||||
void evse_meter_init(void) {
|
||||
void evse_meter_init(void)
|
||||
{
|
||||
meter_mutex = xSemaphoreCreateMutex();
|
||||
ESP_ERROR_CHECK(meter_mutex ? ESP_OK : ESP_FAIL);
|
||||
ESP_ERROR_CHECK(esp_event_handler_register(
|
||||
@@ -63,42 +70,51 @@ void evse_meter_init(void) {
|
||||
ESP_LOGI(TAG, "EVSE Meter listener registered.");
|
||||
}
|
||||
|
||||
int evse_meter_get_instant_power(void) {
|
||||
int evse_meter_get_instant_power(void)
|
||||
{
|
||||
xSemaphoreTake(meter_mutex, portMAX_DELAY);
|
||||
int sum = 0;
|
||||
for (int i = 0; i < EVSE_METER_PHASE_COUNT; ++i) {
|
||||
for (int i = 0; i < EVSE_METER_PHASE_COUNT; ++i)
|
||||
{
|
||||
sum += meter_data.power_watts[i];
|
||||
}
|
||||
xSemaphoreGive(meter_mutex);
|
||||
return sum;
|
||||
}
|
||||
|
||||
int evse_meter_get_total_energy(void) {
|
||||
int evse_meter_get_total_energy(void)
|
||||
{
|
||||
xSemaphoreTake(meter_mutex, portMAX_DELAY);
|
||||
int val = meter_data.energy_wh;
|
||||
xSemaphoreGive(meter_mutex);
|
||||
return val;
|
||||
}
|
||||
|
||||
void evse_meter_get_power(int power[EVSE_METER_PHASE_COUNT]) {
|
||||
void evse_meter_get_power(int power[EVSE_METER_PHASE_COUNT])
|
||||
{
|
||||
xSemaphoreTake(meter_mutex, portMAX_DELAY);
|
||||
for (int i = 0; i < EVSE_METER_PHASE_COUNT; ++i) {
|
||||
for (int i = 0; i < EVSE_METER_PHASE_COUNT; ++i)
|
||||
{
|
||||
power[i] = meter_data.power_watts[i];
|
||||
}
|
||||
xSemaphoreGive(meter_mutex);
|
||||
}
|
||||
|
||||
void evse_meter_get_voltage(float voltage[EVSE_METER_PHASE_COUNT]) {
|
||||
void evse_meter_get_voltage(float voltage[EVSE_METER_PHASE_COUNT])
|
||||
{
|
||||
xSemaphoreTake(meter_mutex, portMAX_DELAY);
|
||||
for (int i = 0; i < EVSE_METER_PHASE_COUNT; ++i) {
|
||||
for (int i = 0; i < EVSE_METER_PHASE_COUNT; ++i)
|
||||
{
|
||||
voltage[i] = meter_data.voltage[i];
|
||||
}
|
||||
xSemaphoreGive(meter_mutex);
|
||||
}
|
||||
|
||||
void evse_meter_get_current(float current[EVSE_METER_PHASE_COUNT]) {
|
||||
void evse_meter_get_current(float current[EVSE_METER_PHASE_COUNT])
|
||||
{
|
||||
xSemaphoreTake(meter_mutex, portMAX_DELAY);
|
||||
for (int i = 0; i < EVSE_METER_PHASE_COUNT; ++i) {
|
||||
for (int i = 0; i < EVSE_METER_PHASE_COUNT; ++i)
|
||||
{
|
||||
current[i] = meter_data.current[i];
|
||||
}
|
||||
xSemaphoreGive(meter_mutex);
|
||||
|
||||
@@ -61,7 +61,7 @@ void pilot_init(void)
|
||||
};
|
||||
ESP_ERROR_CHECK(ledc_channel_config(&ledc_channel));
|
||||
ESP_ERROR_CHECK(ledc_stop(PILOT_PWM_SPEED_MODE, PILOT_PWM_CHANNEL, 0));
|
||||
ESP_ERROR_CHECK(ledc_fade_func_install(0));
|
||||
//ESP_ERROR_CHECK(ledc_fade_func_install(0));
|
||||
|
||||
// Inicializa ADC121S021 externo
|
||||
adc121s021_dma_init();
|
||||
@@ -107,6 +107,12 @@ void pilot_set_amps(uint16_t amps)
|
||||
ledc_update_duty(PILOT_PWM_SPEED_MODE, PILOT_PWM_CHANNEL);
|
||||
}
|
||||
|
||||
bool pilot_get_state(void) {
|
||||
// true se estamos em 12V fixo; false se PWM ou -12V
|
||||
// Se quiser diferenciar PWM, guarde um flag quando chamar set_amps.
|
||||
return (last_pilot_level == 1) && (last_pwm_duty == 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int compare_int(const void *a, const void *b) {
|
||||
|
||||
@@ -10,6 +10,8 @@ typedef enum {
|
||||
EVSE_EVENT_INIT,
|
||||
EVSE_EVENT_STATE_CHANGED,
|
||||
EVSE_EVENT_CONFIG_UPDATED,
|
||||
EVSE_EVENT_ENABLE_UPDATED,
|
||||
EVSE_EVENT_AVAILABLE_UPDATED,
|
||||
} evse_event_id_t;
|
||||
|
||||
typedef enum {
|
||||
@@ -30,4 +32,15 @@ typedef struct {
|
||||
int64_t timestamp_us; // Momento da atualização
|
||||
} evse_config_event_data_t;
|
||||
|
||||
// Eventos simples e específicos
|
||||
typedef struct {
|
||||
bool enabled; // novo estado de enabled
|
||||
int64_t timestamp_us; // epoch micros
|
||||
} evse_enable_event_data_t;
|
||||
|
||||
typedef struct {
|
||||
bool available; // novo estado de available
|
||||
int64_t timestamp_us; // epoch micros
|
||||
} evse_available_event_data_t;
|
||||
|
||||
#endif // EVSE_EVENTS_H
|
||||
|
||||
@@ -35,7 +35,7 @@ void pilot_set_level(bool level);
|
||||
/**
|
||||
* @brief Ativa o PWM do Pilot com corrente limitada
|
||||
*
|
||||
* @param amps Corrente em décimos de ampère (ex: 160 = 16A)
|
||||
* @param amps Corrente em ampères (ex: 16 = 16A)
|
||||
*/
|
||||
void pilot_set_amps(uint16_t amps);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user