fix ade7758

This commit is contained in:
2025-06-25 06:34:03 +01:00
parent a0b2e048d4
commit 84f106eee5
53 changed files with 7079 additions and 18456 deletions

View File

@@ -13,16 +13,21 @@
#include "timeout_utils.h"
#include "evse_error.h"
#include "evse_api.h"
#include "evse_limits.h"
#include "evse_state.h"
#include "evse_config.h"
#include "ocpp.h"
#include "board_config.h"
#include "socket_lock.h"
#include "proximity.h"
//#include "modbus.h"
//#include "modbus_tcp.h"
#include "rest.h"
//#include "rest.h"
#include "temp_sensor.h"
// #include "script.h"
#include "date_time.h"
#include "evse_meter.h"
#define RETURN_ON_ERROR(x) \
do \
@@ -335,9 +340,9 @@ cJSON *json_get_state(void)
cJSON *root = cJSON_CreateObject();
cJSON_AddStringToObject(root, "state", evse_state_to_str(evse_get_state()));
cJSON_AddBoolToObject(root, "available", evse_is_available());
cJSON_AddBoolToObject(root, "enabled", evse_is_enabled());
cJSON_AddBoolToObject(root, "pendingAuth", false);
cJSON_AddBoolToObject(root, "available", evse_config_is_available());
cJSON_AddBoolToObject(root, "enabled", evse_config_is_enabled());
cJSON_AddBoolToObject(root, "pendingAuth", evse_is_require_auth());
cJSON_AddBoolToObject(root, "limitReached", evse_is_limit_reached());
uint32_t error = evse_error_get_bits();
@@ -383,17 +388,33 @@ cJSON *json_get_state(void)
cJSON_AddItemToObject(root, "errors", errors);
}
/*
cJSON_AddNumberToObject(root, "sessionTime", energy_meter_get_session_time());
cJSON_AddNumberToObject(root, "chargingTime", energy_meter_get_charging_time());
cJSON_AddNumberToObject(root, "consumption", energy_meter_get_consumption());
cJSON_AddNumberToObject(root, "power", energy_meter_get_power());
float values[3];
energy_meter_get_voltage(values);
cJSON_AddItemToObject(root, "voltage", cJSON_CreateFloatArray(values, 3));
energy_meter_get_current(values);
cJSON_AddItemToObject(root, "current", cJSON_CreateFloatArray(values, 3));
*/
cJSON_AddNumberToObject(root, "sessionTime", evse_get_session_start());
cJSON_AddNumberToObject(root, "chargingTime", 0);
cJSON_AddNumberToObject(root, "consumption", 0);
// 1) Arrays temporários para ler dados do medidor
float voltage_f[EVSE_METER_PHASE_COUNT];
float current_f[EVSE_METER_PHASE_COUNT];
uint32_t power_w[ EVSE_METER_PHASE_COUNT];
// 2) Leitura dos valores via API pública
evse_meter_get_voltage(voltage_f); // já em volts
evse_meter_get_current(current_f); // já em amperes
evse_meter_get_power(power_w); // em watts por fase
// 4) Energia acumulada em kWh
//float consumption_kwh = evse_meter_get_total_energy() / 1000.0f; // Wh → kWh
// 6) Arrays de tensão e corrente
cJSON_AddItemToObject(root, "power",
cJSON_CreateFloatArray(power_w, EVSE_METER_PHASE_COUNT));
cJSON_AddItemToObject(root, "voltage",
cJSON_CreateFloatArray(voltage_f, EVSE_METER_PHASE_COUNT));
cJSON_AddItemToObject(root, "current",
cJSON_CreateFloatArray(current_f, EVSE_METER_PHASE_COUNT));
return root;
}

View File

@@ -5,7 +5,7 @@
#include "timeout_utils.h"
#include "wifi.h"
#include "rest.h"
//#include "rest.h"
static void restart_func(void* arg)
{

View File

@@ -9,6 +9,7 @@ set(srcs
evse_manager.c
evse_hardware.c
evse_pilot.c
evse_meter.c
)
idf_component_register(

View File

@@ -1,4 +1,4 @@
// evse_core.c - Função principal de controle do EVSE
// evse_core.c - Main EVSE control logic
#include "evse_fsm.h"
#include "evse_error.h"
@@ -13,23 +13,30 @@
static const char *TAG = "evse_core";
static SemaphoreHandle_t mutex;
static evse_state_t last_state = EVSE_STATE_A;
static void evse_core_task(void *arg);
// ================================
// Initialization
// ================================
void evse_init(void) {
ESP_LOGI(TAG, "EVSE Init");
mutex = xSemaphoreCreateMutex();
mutex = xSemaphoreCreateMutex(); // Optional: use static version for deterministic memory
evse_check_defaults();
evse_fsm_reset();
pilot_set_level(true); // Estado inicial do piloto
pilot_set_level(true); // Enable pilot output
xTaskCreate(evse_core_task, "evse_core_task", 4096, NULL, 5, NULL);
}
// ================================
// Main Processing Logic
// ================================
void evse_process(void) {
xSemaphoreTake(mutex, portMAX_DELAY);
@@ -39,42 +46,36 @@ void evse_process(void) {
pilot_measure(&pilot_voltage, &is_n12v);
ESP_LOGD(TAG, "Pilot: %d, -12V: %s", pilot_voltage, is_n12v ? "yes" : "no");
if (evse_get_error() == 0 && !evse_is_error_cleared()) {
evse_error_check(pilot_voltage, is_n12v);
evse_error_check(pilot_voltage, is_n12v);
// Só chama FSM, que decide tudo
evse_fsm_process(
pilot_voltage,
evse_state_get_authorized(),
evse_config_is_available(),
evse_config_is_enabled()
);
evse_fsm_process(
pilot_voltage,
evse_state_get_authorized(),
evse_config_is_available(),
evse_config_is_enabled()
);
evse_limits_check();
evse_limits_check();
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));
last_state = current;
}
evse_mark_error_cleared();
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));
last_state = current;
}
evse_mark_error_cleared();
xSemaphoreGive(mutex);
}
// ================================
// Interface pública
// Public Configuration Interface
// ================================
bool evse_is_enabled(void) {
return evse_config_is_enabled();
}
void evse_set_enabled(bool value) {
ESP_LOGI(TAG, "Set enabled %d", value);
evse_config_set_enabled(value);
@@ -90,21 +91,12 @@ void evse_set_available(bool value) {
}
// ================================
// Tarefa principal
// Background Task
// ================================
static void evse_core_task(void *arg) {
while (true) {
evse_process();
vTaskDelay(pdMS_TO_TICKS(100));
vTaskDelay(pdMS_TO_TICKS(100)); // 10 Hz cycle
}
}
uint32_t evse_get_total_energy(void) {
return 0; // Stub de 1 kWh
}
uint32_t evse_get_instant_power(void) {
return 0; // Stub de 2 kW
}
}

View File

@@ -1,5 +1,3 @@
// evse_fsm.c - Máquina de Estados EVSE com controle centralizado
#include "evse_fsm.h"
#include "evse_api.h"
#include "evse_pilot.h"
@@ -11,6 +9,7 @@
#include "proximity.h"
#include "rcm.h"
#include "evse_state.h"
#include "evse_error.h"
static const char *TAG = "evse_fsm";
@@ -27,6 +26,8 @@ void evse_fsm_reset(void) {
c1_d1_relay_to = 0;
}
// ... includes e defines como já estão
static void update_outputs(evse_state_t state) {
const uint16_t current = evse_get_runtime_charging_current();
uint8_t cable_max_current = evse_get_max_charging_current();
@@ -36,6 +37,21 @@ static void update_outputs(evse_state_t state) {
cable_max_current = proximity_get_max_current();
}
// Segurança: relé sempre off e outputs seguros em caso de erro
if (evse_get_error() != 0) {
if (ac_relay_get_state()) {
ac_relay_set_state(false);
ESP_LOGW(TAG, "ERRO ativo: relé estava ligado, agora desligado por segurança!");
}
ac_relay_set_state(false); // redundância tolerável
pilot_set_level(true); // sinal pilot sempre 12V (A)
if (board_config.socket_lock && socket_outlet) {
socket_lock_set_locked(false);
}
return;
}
// Fluxo normal
switch (state) {
case EVSE_STATE_A:
case EVSE_STATE_E:
@@ -53,7 +69,6 @@ static void update_outputs(evse_state_t state) {
if (board_config.socket_lock && socket_outlet) {
socket_lock_set_locked(true);
}
if (rcm_test()) {
ESP_LOGI(TAG, "RCM self test passed");
} else {
@@ -76,12 +91,28 @@ static void update_outputs(evse_state_t state) {
case EVSE_STATE_C2:
case EVSE_STATE_D2:
pilot_set_amps(MIN(current * 10, cable_max_current * 10));
ac_relay_set_state(true);
ac_relay_set_state(true); // Só chega aqui se não há erro!
break;
}
}
void evse_fsm_process(pilot_voltage_t pilot_voltage, bool authorized, bool available, bool enabled) {
// FSM principal - centraliza a lógica de erro e de todos os estados
void evse_fsm_process(
pilot_voltage_t pilot_voltage,
bool authorized,
bool available,
bool enabled
) {
// Proteção total: erro força F sempre!
if (evse_get_error() != 0) {
if (evse_get_state() != EVSE_STATE_F) {
ESP_LOGW(TAG, "Erro ativo detectado: forçando estado FAULT (F)");
evse_set_state(EVSE_STATE_F);
}
update_outputs(EVSE_STATE_F);
return;
}
TickType_t now = xTaskGetTickCount();
evse_state_t prev = evse_get_state();
evse_state_t curr = prev;
@@ -101,7 +132,6 @@ void evse_fsm_process(pilot_voltage_t pilot_voltage, bool authorized, bool avail
evse_set_state(EVSE_STATE_F);
break;
}
switch (pilot_voltage) {
case PILOT_VOLTAGE_12:
evse_set_state(EVSE_STATE_A);
@@ -127,15 +157,15 @@ void evse_fsm_process(pilot_voltage_t pilot_voltage, bool authorized, bool avail
break;
}
}
__attribute__((fallthrough)); // Evita warning de fallthrough implícito
__attribute__((fallthrough));
case EVSE_STATE_C2:
case EVSE_STATE_D2:
if (!enabled || !available) {
evse_set_state((curr == EVSE_STATE_D2 || curr == EVSE_STATE_D1) ? EVSE_STATE_D1 : EVSE_STATE_C1);
evse_set_state((curr == EVSE_STATE_D2 || curr == EVSE_STATE_D1)
? EVSE_STATE_D1 : EVSE_STATE_C1);
break;
}
switch (pilot_voltage) {
case PILOT_VOLTAGE_6:
evse_set_state((authorized && enabled) ? EVSE_STATE_C2 : EVSE_STATE_C1);
@@ -155,18 +185,23 @@ void evse_fsm_process(pilot_voltage_t pilot_voltage, bool authorized, bool avail
break;
case EVSE_STATE_E:
break; // Sem transições a partir de E
// Estado elétrico grave: só reset manual
break;
case EVSE_STATE_F:
if (available) {
// Fault: só sai se disponível e sem erro
if (available && evse_get_error() == 0) {
evse_set_state(EVSE_STATE_A);
}
break;
}
evse_state_t next = evse_get_state();
update_outputs(next);
if (next != prev) {
ESP_LOGI(TAG, "State changed: %s -> %s", evse_state_to_str(prev), evse_state_to_str(next));
update_outputs(next);
ESP_LOGI(TAG, "State changed: %s -> %s",
evse_state_to_str(prev),
evse_state_to_str(next));
}
}

View File

@@ -1,6 +1,7 @@
#include "evse_state.h"
#include "evse_api.h"
#include "evse_limits.h"
#include "evse_meter.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
@@ -146,8 +147,8 @@ void evse_limits_check(void) {
bool reached = false;
uint32_t energy = evse_get_total_energy();
uint32_t power = evse_get_instant_power();
uint32_t energy = evse_meter_get_total_energy();
uint32_t power = evse_meter_get_instant_power();
TickType_t now = xTaskGetTickCount();
TickType_t start = evse_get_session_start();

View File

@@ -4,6 +4,7 @@
#include "evse_hardware.h"
#include "evse_config.h"
#include "evse_api.h"
#include "evse_meter.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
@@ -87,6 +88,7 @@ void evse_manager_init(void) {
evse_error_init();
evse_hardware_init();
evse_state_init();
evse_meter_init();
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));
@@ -120,29 +122,3 @@ void evse_manager_tick(void) {
xSemaphoreGive(evse_mutex);
}
// ===== API pública =====
bool evse_manager_is_available(void) {
return evse_config_is_available();
}
void evse_manager_set_available(bool available) {
evse_config_set_available(available);
}
void evse_manager_set_authorized(bool authorized) {
evse_state_set_authorized(authorized);
}
bool evse_manager_is_charging(void) {
return evse_state_is_charging(evse_get_state());
}
void evse_manager_set_enabled(bool enabled) {
evse_config_set_enabled(enabled);
}
bool evse_manager_is_enabled(void) {
return evse_config_is_enabled();
}

View File

@@ -0,0 +1,105 @@
#include "evse_meter.h"
#include "meter_events.h"
#include "esp_event.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#include <string.h>
#include <inttypes.h>
static const char *TAG = "evse_meter";
static SemaphoreHandle_t meter_mutex;
typedef struct {
uint32_t power_watts[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) {
const meter_event_data_t *evt = (const meter_event_data_t *)data;
if (strcmp(evt->source, "EVSE") == 0) {
evse_meter_on_meter_event(arg, 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;
xSemaphoreTake(meter_mutex, portMAX_DELAY);
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.energy_wh = (uint32_t)(evt->total_energy * 1000.0f);
xSemaphoreGive(meter_mutex);
ESP_LOGD(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
);
}
void evse_meter_init(void) {
meter_mutex = xSemaphoreCreateMutex();
ESP_ERROR_CHECK(meter_mutex ? ESP_OK : ESP_FAIL);
ESP_ERROR_CHECK(esp_event_handler_register(
METER_EVENT, METER_EVENT_DATA_READY,
on_meter_event_dispatcher, NULL));
memset(&meter_data, 0, sizeof(meter_data));
ESP_LOGI(TAG, "EVSE Meter listener registered.");
}
uint32_t evse_meter_get_instant_power(void) {
xSemaphoreTake(meter_mutex, portMAX_DELAY);
uint32_t sum = 0;
for (int i = 0; i < EVSE_METER_PHASE_COUNT; ++i) {
sum += meter_data.power_watts[i];
}
xSemaphoreGive(meter_mutex);
return sum;
}
uint32_t evse_meter_get_total_energy(void) {
xSemaphoreTake(meter_mutex, portMAX_DELAY);
uint32_t val = meter_data.energy_wh;
xSemaphoreGive(meter_mutex);
return val;
}
void evse_meter_get_power(uint32_t power[EVSE_METER_PHASE_COUNT]) {
xSemaphoreTake(meter_mutex, portMAX_DELAY);
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]) {
xSemaphoreTake(meter_mutex, portMAX_DELAY);
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]) {
xSemaphoreTake(meter_mutex, portMAX_DELAY);
for (int i = 0; i < EVSE_METER_PHASE_COUNT; ++i) {
current[i] = meter_data.current[i];
}
xSemaphoreGive(meter_mutex);
}

View File

@@ -10,7 +10,7 @@
#include "esp_rom_sys.h"
#include "evse_pilot.h"
#include "adc.h"
#include "adc121s021_dma.h"
#include "board_config.h"
#define PILOT_PWM_TIMER LEDC_TIMER_0
@@ -23,10 +23,24 @@
#define MAX_SAMPLE_ATTEMPTS 1000
#define PILOT_EXTREME_PERCENT 10 // 10% superior e inferior
// ADC121S021 setup
#define ADC121_VREF_MV 3300 // AJUSTE conforme Vref do seu hardware!
#define ADC121_MAX 4095 // 12 bits
static const char *TAG = "evse_pilot";
// Memoização de estado para evitar comandos/logs desnecessários
static int last_pilot_level = -1;
static uint32_t last_pwm_duty = 0;
// Função para converter leitura bruta do ADC para mV
static int adc_raw_to_mv(uint16_t raw) {
return (raw * ADC121_VREF_MV) / ADC121_MAX;
}
void pilot_init(void)
{
// PWM (LEDC) configuração
ledc_timer_config_t ledc_timer = {
.speed_mode = PILOT_PWM_SPEED_MODE,
.timer_num = PILOT_PWM_TIMER,
@@ -47,27 +61,24 @@ 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));
adc_oneshot_chan_cfg_t config = {
.bitwidth = ADC_BITWIDTH_DEFAULT,
.atten = ADC_ATTEN_DB_12,
};
ESP_ERROR_CHECK(adc_oneshot_config_channel(adc_handle, board_config.pilot_adc_channel, &config));
// Inicializa ADC121S021 externo
adc121s021_dma_init();
}
void pilot_set_level(bool level)
{
if (last_pilot_level == level) return; // só muda se necessário
last_pilot_level = level;
ESP_LOGI(TAG, "Set level %d", level);
ledc_stop(PILOT_PWM_SPEED_MODE, PILOT_PWM_CHANNEL, level ? 1 : 0);
last_pwm_duty = 0; // PWM parado
}
void pilot_set_amps(uint16_t amps)
{
ESP_LOGI(TAG, "Set amps %d", amps);
if (amps < 60 || amps > 800) {
ESP_LOGE(TAG, "Invalid ampere value: %d A*10", amps);
return;
@@ -79,14 +90,17 @@ void pilot_set_amps(uint16_t amps)
} else {
duty = ((PILOT_PWM_MAX_DUTY * amps) / 2500) + (64 * (PILOT_PWM_MAX_DUTY / 100));
}
if (duty > PILOT_PWM_MAX_DUTY) duty = PILOT_PWM_MAX_DUTY;
if (duty > PILOT_PWM_MAX_DUTY)
duty = PILOT_PWM_MAX_DUTY;
if (last_pilot_level == 0 && last_pwm_duty == duty) return;
last_pilot_level = 0;
last_pwm_duty = duty;
ESP_LOGI(TAG, "Set amp %dA*10 -> duty %lu/%d", amps, duty, PILOT_PWM_MAX_DUTY);
ledc_set_duty(PILOT_PWM_SPEED_MODE, PILOT_PWM_CHANNEL, duty);
ledc_update_duty(PILOT_PWM_SPEED_MODE, PILOT_PWM_CHANNEL);
}
static int compare_int(const void *a, const void *b) {
return (*(int *)a - *(int *)b);
}
@@ -94,10 +108,8 @@ static int compare_int(const void *a, const void *b) {
static int select_low_median_qsort(int *src, int n, int percent) {
int k = (n * percent) / 100;
if (k == 0) k = 1;
int *copy = alloca(n * sizeof(int));
memcpy(copy, src, n * sizeof(int));
qsort(copy, n, sizeof(int), compare_int);
return copy[k / 2];
}
@@ -105,10 +117,8 @@ static int select_low_median_qsort(int *src, int n, int percent) {
static int select_high_median_qsort(int *src, int n, int percent) {
int k = (n * percent) / 100;
if (k == 0) k = 1;
int *copy = alloca(n * sizeof(int));
memcpy(copy, src, n * sizeof(int));
qsort(copy, n, sizeof(int), compare_int);
return copy[n - k + (k / 2)];
}
@@ -119,11 +129,13 @@ void pilot_measure(pilot_voltage_t *up_voltage, bool *down_voltage_n12)
int samples[NUM_PILOT_SAMPLES];
int collected = 0, attempts = 0;
int sample;
uint16_t adc_sample = 0;
// Lê samples usando ADC121S021 externo
while (collected < NUM_PILOT_SAMPLES && attempts < MAX_SAMPLE_ATTEMPTS) {
if (adc_oneshot_read(adc_handle, board_config.pilot_adc_channel, &sample) == ESP_OK) {
samples[collected++] = sample;
adc_sample = 0;
if (adc121s021_dma_get_sample(&adc_sample)) {
samples[collected++] = adc_sample;
esp_rom_delay_us(10);
} else {
esp_rom_delay_us(100);
@@ -141,20 +153,10 @@ void pilot_measure(pilot_voltage_t *up_voltage, bool *down_voltage_n12)
int high_raw = select_high_median_qsort(samples, collected, PILOT_EXTREME_PERCENT);
int low_raw = select_low_median_qsort(samples, collected, PILOT_EXTREME_PERCENT);
int high_mv = adc_raw_to_mv(high_raw);
int low_mv = adc_raw_to_mv(low_raw);
ESP_LOGD(TAG, "Final: high_raw=%d, low_raw=%d", high_raw, low_raw);
int high_mv = 0;
int low_mv = 0;
if (adc_cali_raw_to_voltage(adc_cali_handle, high_raw, &high_mv) != ESP_OK ||
adc_cali_raw_to_voltage(adc_cali_handle, low_raw, &low_mv) != ESP_OK) {
ESP_LOGW(TAG, "ADC calibration failed");
*up_voltage = PILOT_VOLTAGE_1;
*down_voltage_n12 = false;
return;
}
// Aplica thresholds definidos em board_config (em mV)
if (high_mv >= board_config.pilot_down_threshold_12)
*up_voltage = PILOT_VOLTAGE_12;
else if (high_mv >= board_config.pilot_down_threshold_9)

View File

@@ -46,9 +46,14 @@ void evse_set_state(evse_state_t state) {
current_state = state;
changed = true;
// When entering a charging state, record the start tick
if (evse_state_is_charging(state) && !evse_state_is_charging(previous_state)) {
session_start_tick = xTaskGetTickCount();
}
// When exiting a charging state, reset the start tick
else if (!evse_state_is_charging(state) && evse_state_is_charging(previous_state)) {
session_start_tick = 0;
}
}
portEXIT_CRITICAL(&state_mux);
@@ -60,7 +65,11 @@ void evse_set_state(evse_state_t state) {
evse_state_event_data_t evt = {
.state = map_state_to_event(state)
};
esp_event_post(EVSE_EVENTS, EVSE_EVENT_STATE_CHANGED, &evt, sizeof(evt), portMAX_DELAY);
esp_event_post(EVSE_EVENTS,
EVSE_EVENT_STATE_CHANGED,
&evt,
sizeof(evt),
portMAX_DELAY);
}
}

View File

@@ -3,73 +3,77 @@
#include <stdint.h>
#include <stdbool.h>
#include "esp_err.h"
#include "evse_state.h" // Define evse_state_t
#include "evse_state.h" // Tipos e estados
#include "freertos/FreeRTOS.h"
// Inicialização
void evse_init(void);
void evse_process(void);
#ifdef __cplusplus
extern "C" {
#endif
// Estado
// ===============================
// Core EVSE State
// ===============================
/**
* @brief Get current EVSE state (e.g., A, B1, C2).
*/
evse_state_t evse_get_state(void);
const char* evse_state_to_str(evse_state_t state);
bool evse_is_connector_plugged(evse_state_t state);
/**
* @brief Set the EVSE state (e.g., called by FSM or hardware layer).
*/
void evse_set_state(evse_state_t state);
/**
* @brief Get timestamp when the current session started (for timing limits).
*/
TickType_t evse_get_session_start(void);
// ===============================
// Charging Session Info
// ===============================
/**
* @brief Returns true if the EV is charging (C1 or C2).
*/
bool evse_state_is_charging(evse_state_t state);
/**
* @brief Returns true if the EV is connected (plugged).
*/
bool evse_state_is_plugged(evse_state_t state);
/**
* @brief Returns true if a charging session is active (B2, C1, C2).
*/
bool evse_state_is_session(evse_state_t state);
// ===============================
// Authorization
// ===============================
/**
* @brief Set whether the vehicle is authorized to charge.
*/
void evse_state_set_authorized(bool authorized);
/**
* @brief Get current authorization status.
*/
bool evse_state_get_authorized(void);
// ===============================
// Limit Status
// ===============================
/**
* @brief Returns true if any runtime charging limit has been reached.
*/
bool evse_is_limit_reached(void);
// Autorização e disponibilidade
bool evse_is_enabled(void);
void evse_set_enabled(bool value);
bool evse_is_available(void);
void evse_set_available(bool value);
bool evse_is_require_auth(void);
void evse_set_require_auth(bool value);
// Corrente
uint16_t evse_get_charging_current(void);
esp_err_t evse_set_charging_current(uint16_t value);
uint16_t evse_get_default_charging_current(void);
esp_err_t evse_set_default_charging_current(uint16_t value);
uint8_t evse_get_max_charging_current(void);
esp_err_t evse_set_max_charging_current(uint8_t value);
// Temperatura
uint8_t evse_get_temp_threshold(void);
esp_err_t evse_set_temp_threshold(uint8_t value);
// RCM / Socket
bool evse_get_socket_outlet(void);
esp_err_t evse_set_socket_outlet(bool value);
bool evse_is_rcm(void);
esp_err_t evse_set_rcm(bool value);
// Limites
uint32_t evse_get_consumption_limit(void);
void evse_set_consumption_limit(uint32_t value);
uint32_t evse_get_charging_time_limit(void);
void evse_set_charging_time_limit(uint32_t value);
uint16_t evse_get_under_power_limit(void);
void evse_set_under_power_limit(uint16_t value);
void evse_set_limit_reached(bool value);
// Energia total acumulada da sessão (em Wh)
uint32_t evse_get_total_energy(void);
// Potência instantânea medida (em W)
uint32_t evse_get_instant_power(void);
// Limites default
uint32_t evse_get_default_consumption_limit(void);
void evse_set_default_consumption_limit(uint32_t value);
uint32_t evse_get_default_charging_time_limit(void);
void evse_set_default_charging_time_limit(uint32_t value);
uint16_t evse_get_default_under_power_limit(void);
void evse_set_default_under_power_limit(uint16_t value);
uint32_t evse_get_total_energy(void);
uint32_t evse_get_instant_power(void);
#ifdef __cplusplus
}
#endif
#endif // EVSE_API_H

View File

@@ -0,0 +1,17 @@
#ifndef EVSE_CORE_H
#define EVSE_CORE_H
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Initializes the EVSE system and starts core task loop.
*/
void evse_init(void);
#ifdef __cplusplus
}
#endif
#endif // EVSE_CORE_H

View File

@@ -9,47 +9,58 @@
extern "C" {
#endif
// ========================
// Limit state control
// ========================
// ============================
// Limit Status & Evaluation
// ============================
/**
* @brief Sets the 'limit reached' flag. Used internally when a session exceeds defined thresholds.
* @brief Sets the internal 'limit reached' flag.
* Called internally when a limit condition is triggered.
*/
void evse_set_limit_reached(bool value);
/**
* @brief Returns whether any session limit has been reached (energy, time or power).
* @brief Returns true if any runtime charging limit has been reached.
*/
bool evse_get_limit_reached(void);
// ========================
// Limit checking
// ========================
/**
* @brief Evaluates if the session has exceeded any configured limits.
* Should be called periodically while in charging state.
* @brief Checks if any session limit has been exceeded (energy, time or power).
* Should be called periodically during charging.
*/
void evse_limits_check(void);
// ========================
// Runtime limit configuration
// ========================
// ============================
// Runtime Limit Configuration
// ============================
/**
* @brief Get/set energy consumption limit (in Wh).
*/
uint32_t evse_get_consumption_limit(void);
void evse_set_consumption_limit(uint32_t value); // in Wh
void evse_set_consumption_limit(uint32_t value);
/**
* @brief Get/set maximum charging time (in seconds).
*/
uint32_t evse_get_charging_time_limit(void);
void evse_set_charging_time_limit(uint32_t value); // in seconds
void evse_set_charging_time_limit(uint32_t value);
/**
* @brief Get/set minimum acceptable power level (in Watts).
* If the power remains below this for a long time, the session may be interrupted.
*/
uint16_t evse_get_under_power_limit(void);
void evse_set_under_power_limit(uint16_t value); // in Watts
void evse_set_under_power_limit(uint16_t value);
// ========================
// Default (persistent) limits
// ========================
// ============================
// Default (Persistent) Limits
// ============================
/**
* @brief Default values used after system boot or reset.
* These can be restored from NVS or fallback values.
*/
uint32_t evse_get_default_consumption_limit(void);
void evse_set_default_consumption_limit(uint32_t value);

View File

@@ -26,38 +26,6 @@ void evse_manager_init(void);
*/
void evse_manager_tick(void);
/**
* @brief Verifica se o EVSE está disponível para uso.
*
* Isso considera falhas críticas, disponibilidade configurada, etc.
*/
bool evse_manager_is_available(void);
/**
* @brief Define se o EVSE deve estar disponível (ex: via controle remoto).
*/
void evse_manager_set_available(bool available);
/**
* @brief Define se o EVSE está autorizado a carregar (ex: após autenticação).
*/
void evse_manager_set_authorized(bool authorized);
/**
* @brief Verifica se o EVSE está atualmente carregando.
*/
bool evse_manager_is_charging(void);
/**
* @brief Ativa ou desativa logicamente o EVSE (controla habilitação geral).
*/
void evse_manager_set_enabled(bool enabled);
/**
* @brief Verifica se o EVSE está ativado logicamente.
*/
bool evse_manager_is_enabled(void);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,37 @@
#ifndef EVSE_METER_H
#define EVSE_METER_H
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
#define EVSE_METER_PHASE_COUNT 3
/// Inicializa o módulo EVSE Meter e registra os tratadores de eventos
void evse_meter_init(void);
/// Retorna a potência instantânea (soma das 3 fases, em watts)
uint32_t evse_meter_get_instant_power(void);
/// Retorna a energia total acumulada (em Wh)
uint32_t evse_meter_get_total_energy(void);
/// Retorna as potências instantâneas nas fases L1, L2 e L3 (em watts)
void evse_meter_get_power(uint32_t power[EVSE_METER_PHASE_COUNT]);
/// Retorna as tensões medidas nas fases L1, L2 e L3 (em volts)
void evse_meter_get_voltage(float voltage[EVSE_METER_PHASE_COUNT]);
/// Retorna as correntes medidas nas fases L1, L2 e L3 (em amperes)
void evse_meter_get_current(float current[EVSE_METER_PHASE_COUNT]);
/// Handler interno para eventos do medidor (não chamar externamente)
void evse_meter_on_meter_event(void* arg, void* event_data);
#ifdef __cplusplus
}
#endif
#endif // EVSE_METER_H

View File

@@ -5,6 +5,10 @@
#include "freertos/FreeRTOS.h"
#include "evse_events.h"
#ifdef __cplusplus
extern "C" {
#endif
// ============================
// EVSE Pilot Signal States
// ============================
@@ -22,21 +26,21 @@ typedef enum {
} evse_state_t;
// ============================
// Initialization & Core Control
// Initialization
// ============================
/**
* @brief Initializes the EVSE state machine.
* @brief Initializes the EVSE state machine and default state.
*/
void evse_state_init(void);
/**
* @brief Periodic tick function for the state machine.
* @brief Periodic tick for state handling (optional hook).
*/
void evse_state_tick(void);
// ============================
// State Access
// State Access & Control
// ============================
/**
@@ -45,51 +49,55 @@ void evse_state_tick(void);
evse_state_t evse_get_state(void);
/**
* @brief Updates the current EVSE state and triggers events.
* @brief Sets the current EVSE state and emits a change event if needed.
*/
void evse_set_state(evse_state_t state);
/**
* @brief Returns the tick count when charging session started.
* @brief Returns the tick count when the current charging session began.
*/
TickType_t evse_get_session_start(void);
/**
* @brief Converts the state enum to a human-readable string.
* @brief Converts the state enum into a human-readable string.
*/
const char* evse_state_to_str(evse_state_t state);
// ============================
// State Evaluators
// State Evaluation Helpers
// ============================
/**
* @brief Returns true if the state represents an active session (B2, C1, C2).
* @brief True if EV is in an active session (B2, C1, C2).
*/
bool evse_state_is_session(evse_state_t state);
/**
* @brief Returns true if the state represents active charging (C1, C2).
* @brief True if EV is actively charging (C1, C2).
*/
bool evse_state_is_charging(evse_state_t state);
/**
* @brief Returns true if the vehicle is plugged in.
* @brief True if EV is physically plugged in (B1 and beyond).
*/
bool evse_state_is_plugged(evse_state_t state);
// ============================
// Authorization
// Authorization Control
// ============================
/**
* @brief Sets the vehicle authorization state.
* @brief Sets whether the EV is authorized to charge.
*/
void evse_state_set_authorized(bool authorized);
/**
* @brief Returns the current vehicle authorization state.
* @brief Gets whether the EV is currently authorized.
*/
bool evse_state_get_authorized(void);
#ifdef __cplusplus
}
#endif
#endif // EVSE_STATE_H

View File

@@ -22,4 +22,4 @@ set(includes
idf_component_register(SRCS "${srcs}"
INCLUDE_DIRS "${includes}"
PRIV_REQUIRES nvs_flash
REQUIRES esp_event esp-modbus)
REQUIRES esp_event esp-modbus spi_bus_manager)

View File

@@ -1,186 +1,184 @@
#include <stdio.h>
#include <stdlib.h>
#include "driver/spi_master.h"
#include "sdkconfig.h"
#include "esp_log.h"
#include "ade7758.h"
#include "driver/gpio.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_rom_sys.h"
spi_bus_config_t _spi_bus_cfg;
// spi_device_interface_config_t _spi_interface_cfg;
spi_device_handle_t _handle;
spi_host_device_t _spi_peripheral;
spi_transaction_t _spi_transaction;
esp_err_t transferByte(const uint8_t reg_addr, const uint8_t data, const uint8_t command)
{
_spi_transaction.flags = SPI_TRANS_USE_RXDATA | SPI_TRANS_USE_TXDATA;
_spi_transaction.length = 8;
//_spi_transaction.rxlength = 8;
_spi_transaction.cmd = command;
_spi_transaction.addr = reg_addr;
_spi_transaction.tx_data[0] = data;
#define PIN_ADUM_EN 4 // ou o pino real conectado ao VE1 do ADUM1401
return spi_device_transmit(_handle, &_spi_transaction);
static const char *TAG = "ade7758";
// --- SPI internals ---
static spi_device_handle_t ade7758_spi_handle = NULL;
static spi_host_device_t spi_host = SPI2_HOST; // default
static spi_transaction_t spi_transaction;
// --- Configuração SPI do dispositivo ---
static const uint8_t MODE = 2;
static const uint8_t ADDR_BITS = 7;
static const uint8_t CMD_BITS = 1;
static const uint8_t SPI_WRITE = 1;
static const uint8_t SPI_READ = 0;
static const int BUS_SPEED_HZ = 1000000;
static void adum1401_select(void) {
gpio_set_level(PIN_ADUM_EN, 1);
esp_rom_delay_us(2); // curto delay para estabilização
}
esp_err_t transferMultiplesBytes(const uint8_t reg_addr, uint8_t *tx_buf, uint8_t *rx_buf, size_t data_length, const uint8_t command)
{
spi_transaction_t spi_transaction_multibyte; // spi_transaction_t to use the tx and rx buffers
if (data_length < 1)
{
data_length = 1;
}
spi_transaction_multibyte.flags = 0; // SPI_TRANS_USE_RXDATA | SPI_TRANS_USE_TXDATA;
spi_transaction_multibyte.length = (8 * data_length);
spi_transaction_multibyte.rxlength = 0;
spi_transaction_multibyte.cmd = command;
spi_transaction_multibyte.addr = reg_addr;
spi_transaction_multibyte.tx_buffer = tx_buf;
spi_transaction_multibyte.rx_buffer = rx_buf;
return spi_device_transmit(_handle, &spi_transaction_multibyte);
static void adum1401_deselect(void) {
esp_rom_delay_us(2); // opcional: aguarde para evitar glitch
gpio_set_level(PIN_ADUM_EN, 0);
}
esp_err_t Init(const spi_host_device_t spi_peripheral, const int pin_miso, const int pin_mosi, const int pin_sclk)
{
esp_err_t status = ESP_OK;
// === Transações básicas ===
_spi_peripheral = spi_peripheral;
static esp_err_t transfer_byte(uint8_t reg_addr, uint8_t data, uint8_t command) {
adum1401_select();
_spi_transaction.tx_buffer = NULL;
_spi_transaction.rx_buffer = NULL;
spi_transaction.flags = SPI_TRANS_USE_RXDATA | SPI_TRANS_USE_TXDATA;
spi_transaction.length = 8;
spi_transaction.cmd = command;
spi_transaction.addr = reg_addr;
spi_transaction.tx_data[0] = data;
_spi_bus_cfg.mosi_io_num = pin_mosi;
_spi_bus_cfg.miso_io_num = pin_miso;
_spi_bus_cfg.sclk_io_num = pin_sclk;
_spi_bus_cfg.quadwp_io_num = -1;
_spi_bus_cfg.quadhd_io_num = -1;
esp_err_t err = spi_device_transmit(ade7758_spi_handle, &spi_transaction);
status |= spi_bus_initialize(spi_peripheral, &_spi_bus_cfg, SPI_DMA_CH_AUTO);
return status;
adum1401_deselect();
return err;
}
esp_err_t RegisterDevice(const uint8_t mode, const int ss, const int addr_length, const int command_length, const int bus_speed)
{
esp_err_t status = ESP_OK;
spi_device_interface_config_t _spi_interface_cfg = {
.command_bits = command_length,
.address_bits = addr_length,
.mode = mode,
.clock_speed_hz = bus_speed,
.spics_io_num = ss,
static esp_err_t transfer_bytes(uint8_t reg_addr, uint8_t *tx_buf, uint8_t *rx_buf, size_t len, uint8_t command) {
if (len < 1) len = 1;
spi_transaction_t t = {
.flags = 0,
.length = 8 * len,
.cmd = command,
.addr = reg_addr,
.tx_buffer = tx_buf,
.rx_buffer = rx_buf
};
adum1401_select();
esp_err_t err = spi_device_transmit(ade7758_spi_handle, &t);
adum1401_deselect();
return err;
}
// === Interface pública ===
esp_err_t Init(spi_host_device_t host, int pin_miso, int pin_mosi, int pin_sclk) {
// Essa função não inicializa o barramento SPI
// Apenas armazena os parâmetros
spi_host = host;
return ESP_OK;
}
esp_err_t InitSpi(int cs_gpio) {
spi_device_interface_config_t devcfg = {
.command_bits = CMD_BITS,
.address_bits = ADDR_BITS,
.mode = MODE,
.clock_speed_hz = BUS_SPEED_HZ,
.spics_io_num = cs_gpio,
.queue_size = 5,
};
status |= spi_bus_add_device(_spi_peripheral, &_spi_interface_cfg, &_handle);
gpio_config_t io_conf = {
.pin_bit_mask = BIT64(PIN_ADUM_EN),
.mode = GPIO_MODE_OUTPUT,
.pull_up_en = GPIO_PULLUP_DISABLE,
.pull_down_en = GPIO_PULLDOWN_DISABLE,
.intr_type = GPIO_INTR_DISABLE
};
gpio_config(&io_conf);
gpio_set_level(PIN_ADUM_EN, 0); // inicialmente desativado
return status;
return spi_bus_add_device(spi_host, &devcfg, &ade7758_spi_handle);
}
uint8_t ReadRegister(const uint8_t reg_addr, const uint8_t command)
{
transferByte(reg_addr, 0, command);
return _spi_transaction.rx_data[0];
spi_device_handle_t GetHandle(void) {
return ade7758_spi_handle;
}
esp_err_t WriteRegister(const uint8_t reg_addr, const uint8_t reg_data, const uint8_t command)
{
esp_err_t status = ESP_OK;
// === Registro de acesso ===
status |= transferByte(reg_addr, reg_data, command);
return status;
uint8_t ReadRegister(uint8_t reg_addr, uint8_t command) {
transfer_byte(reg_addr, 0, command);
return spi_transaction.rx_data[0];
}
esp_err_t WriteRegisterMultipleBytes(const uint8_t reg_addr, uint8_t *reg_data_buffer, const uint8_t byte_count, const uint8_t command)
{
return transferMultiplesBytes(reg_addr, reg_data_buffer, NULL, byte_count, command);
esp_err_t WriteRegister(uint8_t reg_addr, uint8_t data, uint8_t command) {
return transfer_byte(reg_addr, data, command);
}
esp_err_t ReadRegisterMultipleBytes(const uint8_t reg_addr, uint8_t *reg_data_buffer, const uint8_t byte_count, const uint8_t command)
{
return transferMultiplesBytes(reg_addr, NULL, reg_data_buffer, byte_count, command);
esp_err_t WriteRegisterMultipleBytes(uint8_t reg, uint8_t *data, uint8_t count, uint8_t command) {
return transfer_bytes(reg, data, NULL, count, command);
}
spi_device_handle_t GetHandle(void)
{
return _handle;
esp_err_t ReadRegisterMultipleBytes(uint8_t reg, uint8_t *buf, uint8_t count, uint8_t command) {
return transfer_bytes(reg, NULL, buf, count, command);
}
static uint8_t MODE = 2;
static uint8_t ADDR_BITS = 7;
static uint8_t CMD_BITS = 1;
// === Leitura e escrita de tamanho fixo ===
static uint8_t SPI_WRITE = 1;
static uint8_t SPI_READ = 0;
static int BUSSPEED = 1000000;
// static const char TAG[] = "ade7758";
esp_err_t write8(uint8_t reg, uint8_t value)
{
esp_err_t write8(uint8_t reg, uint8_t value) {
return WriteRegister(reg, value, SPI_WRITE);
}
esp_err_t write16(uint8_t reg, uint32_t value)
{
uint8_t buff[2];
buff[0] = (value >> 8) & 0xFF;
buff[1] = (value >> 0) & 0xFF;
return WriteRegisterMultipleBytes(reg, buff, 3, SPI_WRITE);
esp_err_t write16(uint8_t reg, uint32_t value) {
uint8_t buf[2] = {
(value >> 8) & 0xFF,
(value >> 0) & 0xFF
};
return WriteRegisterMultipleBytes(reg, buf, 2, SPI_WRITE);
}
esp_err_t write24(uint8_t reg, uint32_t value)
{
uint8_t buff[2];
buff[0] = (value >> 16) & 0xFF;
buff[1] = (value >> 8) & 0xFF;
buff[2] = (value >> 0) & 0xFF;
return WriteRegisterMultipleBytes(reg, buff, 4, SPI_WRITE);
esp_err_t write24(uint8_t reg, uint32_t value) {
uint8_t buf[3] = {
(value >> 16) & 0xFF,
(value >> 8) & 0xFF,
(value >> 0) & 0xFF
};
return WriteRegisterMultipleBytes(reg, buf, 3, SPI_WRITE);
}
uint8_t read8(const uint8_t reg)
{
uint8_t buff[1];
ReadRegisterMultipleBytes(reg, buff, 2, SPI_READ);
return buff[0];
uint8_t read8(uint8_t reg) {
uint8_t buf[1];
ReadRegisterMultipleBytes(reg, buf, 1, SPI_READ);
return buf[0];
}
uint32_t read16(const uint8_t reg)
{
uint8_t buff[2];
ReadRegisterMultipleBytes(reg, buff, 3, SPI_READ);
return buff[0] << 8 | buff[1];
uint32_t read16(uint8_t reg) {
uint8_t buf[2];
ReadRegisterMultipleBytes(reg, buf, 2, SPI_READ);
return (buf[0] << 8) | buf[1];
}
uint32_t read24(const uint8_t reg)
{
uint8_t buff[3];
ReadRegisterMultipleBytes(reg, buff, 4, SPI_READ);
return buff[0] << 16 | buff[1] << 8 | buff[2];
uint32_t read24(uint8_t reg) {
uint8_t buf[3];
ReadRegisterMultipleBytes(reg, buf, 3, SPI_READ);
return (buf[0] << 16) | (buf[1] << 8) | buf[2];
}
esp_err_t readBlockData(const uint8_t reg, uint8_t *buf, const int length)
{
return ReadRegisterMultipleBytes(reg, buf, length, SPI_READ);
esp_err_t readBlockData(uint8_t reg, uint8_t *buf, int len) {
return ReadRegisterMultipleBytes(reg, buf, len, SPI_READ);
}
esp_err_t InitSpi(const int ss)
{
return RegisterDevice(MODE, ss, ADDR_BITS, CMD_BITS, BUSSPEED);
}
/*****************************
*

View File

@@ -1,4 +1,5 @@
#include "meter_ade7758.h"
#include "spi_bus_manager.h"
#include "ade7758.h"
#include "meter_events.h"
@@ -11,16 +12,13 @@
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "driver/spi_master.h"
#include "driver/gpio.h"
#define TAG "meter_ade7758"
// === Configurações de hardware ===
#define PIN_NUM_CLK 15
#define PIN_NUM_MOSI 2
#define PIN_NUM_MISO 4
#define PIN_NUM_CS 23
#define EEPROM_HOST HSPI_HOST
// === Pinos ===
#define PIN_NUM_CS 15
#define PIN_ADUM_EN 4
// === Constantes de calibração ===
#define VRMS_CAL 4732.78f
@@ -28,13 +26,13 @@
#define METER_READ_INTERVAL_MS 5000
// === Dados internos ===
// === Estrutura interna ===
typedef struct {
float vrms[3];
float irms[3];
int watt[3];
int var[3]; // reservados
int va[3]; // reservados
int var[3]; // reservado
int va[3]; // reservado
} meter_ade7758_internal_data_t;
static meter_ade7758_internal_data_t meter_data;
@@ -42,7 +40,8 @@ static TaskHandle_t meter_task = NULL;
static SemaphoreHandle_t meter_mutex = NULL;
static uint32_t meter_watchdog_counter = 0;
// === Utilitários internos ===
// === Post de evento ===
static void meter_ade7758_post_event(const meter_ade7758_internal_data_t *data) {
meter_event_data_t evt = {
.frequency = 0,
@@ -54,22 +53,23 @@ static void meter_ade7758_post_event(const meter_ade7758_internal_data_t *data)
memcpy(evt.irms, data->irms, sizeof(evt.irms));
memcpy(evt.watt, data->watt, sizeof(evt.watt));
esp_err_t err = esp_event_post(METER_EVENT, METER_EVENT_DATA_READY,
&evt, sizeof(evt), pdMS_TO_TICKS(10));
esp_err_t err = esp_event_post(METER_EVENT, METER_EVENT_DATA_READY, &evt, sizeof(evt), pdMS_TO_TICKS(10));
if (err != ESP_OK) {
ESP_LOGW(TAG, "Falha ao emitir evento: %s", esp_err_to_name(err));
}
}
// === Task de leitura ===
static void meter_ade7758_task_func(void *param) {
ESP_LOGI(TAG, "Meter task started");
ESP_LOGI(TAG, "Tarefa de medição ADE7758 iniciada");
meter_ade7758_internal_data_t previous = {0};
while (true) {
meter_ade7758_internal_data_t meterData = {0};
//ESP_LOGI(TAG, "Tarefa de medição ADE7758 iniciada %d",getVersion());
meterData.vrms[0] = avrms() / VRMS_CAL;
meterData.vrms[1] = bvrms() / VRMS_CAL;
meterData.vrms[2] = cvrms() / VRMS_CAL;
@@ -97,10 +97,9 @@ static void meter_ade7758_task_func(void *param) {
}
}
// === Interface pública: controle ===
// === Inicialização ===
esp_err_t meter_ade7758_init(void) {
ESP_LOGI(TAG, "Inicializando medidor ADE7758...");
ESP_LOGI(TAG, "Inicializando ADE7758...");
if (!meter_mutex) {
meter_mutex = xSemaphoreCreateMutex();
@@ -110,21 +109,38 @@ esp_err_t meter_ade7758_init(void) {
}
}
esp_err_t err = Init(EEPROM_HOST, PIN_NUM_MISO, PIN_NUM_MOSI, PIN_NUM_CLK);
if (!spi_bus_manager_is_initialized()) {
esp_err_t err = spi_bus_manager_init(); // usa pinos padrão
if (err != ESP_OK) {
ESP_LOGE(TAG, "Erro ao inicializar SPI: %s", esp_err_to_name(err));
return err;
}
}
vTaskDelay(pdMS_TO_TICKS(10)); // Delay de estabilização
esp_err_t err = Init(spi_bus_manager_get_host(), -1, -1, -1);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Erro ao inicializar SPI (%d)", err);
ESP_LOGE(TAG, "Erro Init SPI ADE7758: %s", esp_err_to_name(err));
return err;
}
err = InitSpi(PIN_NUM_CS);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Erro ao registrar dispositivo SPI: %s", esp_err_to_name(err));
return err;
}
InitSpi(PIN_NUM_CS);
gainSetup(INTEGRATOR_OFF, FULLSCALESELECT_0_5V, GAIN_1, GAIN_1);
setupDivs(1, 1, 1);
setLcycMode(0x00);
resetStatus();
ESP_LOGI(TAG, "ADE7758 inicializado com sucesso.");
return ESP_OK;
}
// === Execução ===
esp_err_t meter_ade7758_start(void) {
if (meter_task) return ESP_ERR_INVALID_STATE;

View File

@@ -165,7 +165,7 @@ void wifi_ini(void)
char chargeid[6];
uint8_t mac[6];
esp_wifi_get_mac(ESP_IF_WIFI_AP, mac);
sprintf((char *)chargeid, MDNS_SSID, mac[5]);
sprintf((char *)chargeid, MDNS_SSID, 0);
ESP_ERROR_CHECK(mdns_init());
ESP_ERROR_CHECK(mdns_hostname_set(chargeid));
@@ -188,7 +188,9 @@ esp_netif_t *wifi_get_ap_netif(void)
esp_err_t wifi_set_config(bool enabled, const char *ssid, const char *password)
{
ESP_LOGI(TAG, "Wifi set config");
ESP_LOGI(TAG, "wifi_set_config(enabled=%d, ssid=\"%s\")", enabled, ssid?:"<nil>");
if (enabled)
{

View File

@@ -1,143 +0,0 @@
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/event_groups.h"
#include "esp_log.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_netif.h"
#include "esp_mac.h"
#include "nvs.h"
#include "mdns.h"
#include "wifi.h"
#include "nvs_flash.h"
#include <string.h>
#define WIFI_STORAGE_NAMESPACE "wifi_config"
#define TAG "wifi"
#define AP_SSID "plx-%02x%02x%02x"
#define MDNS_HOSTNAME "plx%02x"
#define NVS_NAMESPACE "wifi"
static nvs_handle_t nvs;
static esp_netif_t *ap_netif;
EventGroupHandle_t wifi_event_group;
//
// Event handler para modo AP
//
static void event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data)
{
if (event_base == WIFI_EVENT) {
switch (event_id) {
case WIFI_EVENT_AP_STACONNECTED: {
wifi_event_ap_staconnected_t *event = event_data;
ESP_LOGI(TAG, "STA " MACSTR " conectou, AID=%d", MAC2STR(event->mac), event->aid);
xEventGroupSetBits(wifi_event_group, WIFI_AP_CONNECTED_BIT);
break;
}
case WIFI_EVENT_AP_STADISCONNECTED: {
wifi_event_ap_stadisconnected_t *event = event_data;
ESP_LOGI(TAG, "STA " MACSTR " desconectou, AID=%d", MAC2STR(event->mac), event->aid);
xEventGroupClearBits(wifi_event_group, WIFI_AP_CONNECTED_BIT);
break;
}
}
}
}
//
// Iniciar o AP com SSID baseado no MAC
//
void wifi_ap_start(void)
{
ESP_LOGI(TAG, "Iniciando AP");
ESP_ERROR_CHECK(esp_wifi_stop());
wifi_config_t ap_config = {
.ap = {
.ssid = "",
.ssid_len = 0,
.channel = 1,
.password = "",
.max_connection = 4,
.authmode = WIFI_AUTH_OPEN
}
};
uint8_t mac[6];
ESP_ERROR_CHECK(esp_read_mac(mac, ESP_MAC_WIFI_SOFTAP));
snprintf((char *)ap_config.ap.ssid, sizeof(ap_config.ap.ssid), AP_SSID, mac[3], mac[4], mac[5]);
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_AP));
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_AP, &ap_config));
ESP_ERROR_CHECK(esp_wifi_start());
xEventGroupSetBits(wifi_event_group, WIFI_AP_MODE_BIT);
}
//
// Inicializar Wi-Fi em modo AP
//
void wifi_ini(void)
{
ESP_LOGI(TAG, "Inicializando Wi-Fi (modo AP)");
ESP_ERROR_CHECK(nvs_open(NVS_NAMESPACE, NVS_READWRITE, &nvs));
wifi_event_group = xEventGroupCreate();
ESP_ERROR_CHECK(esp_netif_init());
/*
if (!esp_event_loop_is_running()) {
ESP_ERROR_CHECK(esp_event_loop_create_default());
}*/
ap_netif = esp_netif_create_default_wifi_ap();
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL));
uint8_t mac[6];
ESP_ERROR_CHECK(esp_read_mac(mac, ESP_MAC_WIFI_SOFTAP));
char hostname[16];
snprintf(hostname, sizeof(hostname), MDNS_HOSTNAME, mac[5]);
ESP_ERROR_CHECK(mdns_init());
ESP_ERROR_CHECK(mdns_hostname_set(hostname));
ESP_ERROR_CHECK(mdns_instance_name_set("EVSE Controller"));
wifi_ap_start();
}
esp_netif_t *wifi_get_ap_netif(void)
{
return ap_netif;
}
esp_err_t wifi_set_config(bool enabled, const char *ssid, const char *password) {
return ESP_OK;
}
void wifi_get_ssid(char *value) {
// Your implementation here
}
void wifi_get_password(char *value) {
// Your implementation here
}
bool wifi_get_enabled(void)
{
return true;
}

View File

@@ -4,6 +4,7 @@
#include "evse_api.h"
#include "evse_error.h"
#include "evse_state.h"
#include "evse_config.h"
#include "esp_wifi.h"
#include "nvs.h"
@@ -48,10 +49,10 @@ static void ocpp_task_func(void *param)
mg_mgr_poll(&mgr, 10);
ocpp_loop();
if (evse_is_enabled() != ocpp_isOperative())
if (evse_config_is_enabled() != ocpp_isOperative())
{
printf("ocpp_isOperative()");
evse_set_enabled(ocpp_isOperative());
evse_config_set_enabled(ocpp_isOperative());
}
}
vTaskDelay(pdMS_TO_TICKS(500));
@@ -129,7 +130,7 @@ void ocpp_set_rfid(char *value)
bool setConnectorPluggedInput()
{
// ESP_LOGI(TAG, "setConnectorPluggedInput");
return evse_is_connector_plugged(evse_get_state());
return evse_state_is_plugged(evse_get_state());
// return true;
}
@@ -143,8 +144,8 @@ bool setEvReadyInput()
bool setEvseReadyInput()
{
// ESP_LOGI(TAG, "EvseReadyInput");
return evse_is_enabled();
// return false;
return evse_config_is_enabled();
//return false;
}
float setPowerMeterInput()

View File

@@ -18,4 +18,4 @@ set(srcs
idf_component_register(SRCS "${srcs}"
INCLUDE_DIRS "include"
PRIV_REQUIRES nvs_flash driver esp_adc esp_timer
REQUIRES config evse api ntc_driver)
REQUIRES config evse api ntc_driver spi_bus_manager)

View File

@@ -6,6 +6,9 @@
static const char* TAG = "ac_relay";
// Memoization do estado atual do relé (salvo em RAM)
static int last_state = -1;
/**
* @brief Initialize the AC relay GPIO.
*
@@ -16,7 +19,7 @@ void ac_relay_init(void)
gpio_config_t conf = {
.pin_bit_mask = BIT64(board_config.ac_relay_gpio),
.mode = GPIO_MODE_OUTPUT,
.pull_down_en = GPIO_PULLDOWN_DISABLE, ///< Disabled unless required
.pull_down_en = GPIO_PULLDOWN_DISABLE,
.pull_up_en = GPIO_PULLUP_DISABLE,
.intr_type = GPIO_INTR_DISABLE
};
@@ -27,7 +30,8 @@ void ac_relay_init(void)
return;
}
gpio_set_level(board_config.ac_relay_gpio, false); ///< Ensure relay starts OFF
gpio_set_level(board_config.ac_relay_gpio, 0); ///< Ensure relay starts OFF
last_state = 0;
ESP_LOGI(TAG, "AC relay initialized. Pin: %d", board_config.ac_relay_gpio);
}
@@ -38,9 +42,15 @@ void ac_relay_init(void)
*/
void ac_relay_set_state(bool state)
{
if (state == last_state) {
// Estado não mudou; evita log e escrita desnecessária.
return;
}
last_state = state;
ESP_LOGI(TAG, "Setting AC relay state: Pin: %d, State: %d", board_config.ac_relay_gpio, state);
esp_err_t ret = gpio_set_level(board_config.ac_relay_gpio, state);
esp_err_t ret = gpio_set_level(board_config.ac_relay_gpio, state ? 1 : 0);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to set GPIO level (error: %s)", esp_err_to_name(ret));
}
@@ -55,5 +65,5 @@ bool ac_relay_get_state(void)
{
int level = gpio_get_level(board_config.ac_relay_gpio);
ESP_LOGD(TAG, "Current AC relay state: Pin: %d, State: %d", board_config.ac_relay_gpio, level);
return level;
return (level != 0);
}

View File

@@ -1,53 +1,64 @@
#include "driver/spi_master.h"
#include "driver/gpio.h"
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "adc121s021_dma.h"
#include "spi_bus_manager.h"
#define TAG "adc_dma"
#define PIN_NUM_MOSI 23
#define PIN_NUM_MISO 19
#define PIN_NUM_CLK 18
#define PIN_NUM_CS 5
#define PIN_NUM_CS 5
#define SAMPLE_SIZE_BYTES 2
#define ADC_BITS 12
#define SPI_CLOCK_HZ (6 * 1000 * 1000) // 6 MHz
#define SPI_HOST_USED SPI2_HOST
#define SAMPLE_SIZE_BYTES 2
#define ADC_BITS 12
static spi_device_handle_t adc_spi;
static spi_device_handle_t adc_spi = NULL;
void adc121s021_dma_init(void)
{
spi_bus_config_t buscfg = {
.mosi_io_num = PIN_NUM_MOSI,
.miso_io_num = PIN_NUM_MISO,
.sclk_io_num = PIN_NUM_CLK,
.quadwp_io_num = -1,
.quadhd_io_num = -1,
.max_transfer_sz = SAMPLE_SIZE_BYTES,
};
if (adc_spi) {
ESP_LOGW(TAG, "ADC121S021 já foi inicializado.");
return;
}
if (!spi_bus_manager_is_initialized()) {
ESP_LOGI(TAG, "SPI bus não inicializado. Inicializando...");
esp_err_t err = spi_bus_manager_init(); // 🔧 CORRIGIDO: sem argumentos
if (err != ESP_OK) {
ESP_LOGE(TAG, "Falha ao inicializar o SPI bus: %s", esp_err_to_name(err));
return;
}
}
spi_device_interface_config_t devcfg = {
.clock_speed_hz = 6000000, // 6 MHz
.clock_speed_hz = SPI_CLOCK_HZ,
.mode = 0,
.spics_io_num = PIN_NUM_CS,
.queue_size = 2,
.flags = SPI_DEVICE_NO_DUMMY,
.pre_cb = NULL,
.post_cb = NULL,
};
ESP_ERROR_CHECK(spi_bus_initialize(SPI_HOST_USED, &buscfg, SPI_DMA_CH_AUTO));
ESP_ERROR_CHECK(spi_bus_add_device(SPI_HOST_USED, &devcfg, &adc_spi));
esp_err_t err = spi_bus_add_device(spi_bus_manager_get_host(), &devcfg, &adc_spi);
if (err != ESP_OK) {
ESP_LOGE(TAG, "Falha ao registrar ADC121S021 no SPI: %s", esp_err_to_name(err));
return;
}
ESP_LOGI(TAG, "ADC121S021 registrado no SPI com sucesso.");
}
bool adc121s021_dma_get_sample(uint16_t *sample)
{
uint8_t tx_buffer[2] = {0x00, 0x00}; // Dummy TX
if (!adc_spi) {
ESP_LOGE(TAG, "ADC SPI não inicializado!");
return false;
}
uint8_t tx_buffer[2] = {0x00, 0x00}; // Dummy
uint8_t rx_buffer[2] = {0};
spi_transaction_t t = {
.length = 16, // 16 bits
.length = 16,
.tx_buffer = tx_buffer,
.rx_buffer = rx_buffer,
.flags = 0
@@ -55,12 +66,10 @@ bool adc121s021_dma_get_sample(uint16_t *sample)
esp_err_t err = spi_device_transmit(adc_spi, &t);
if (err != ESP_OK) {
ESP_LOGE(TAG, "SPI transmit error: %s", esp_err_to_name(err));
ESP_LOGE(TAG, "Erro na transmissão SPI: %s", esp_err_to_name(err));
return false;
}
// Extrai os 12 bits significativos da resposta do ADC121S021
*sample = ((rx_buffer[0] << 8) | rx_buffer[1]) & 0x0FFF;
return true;
}

View File

@@ -91,7 +91,7 @@ static void buzzer_worker_task(void *arg) {
while (true) {
if (xQueueReceive(buzzer_queue, &pattern_id, portMAX_DELAY)) {
//buzzer_execute_pattern(pattern_id);
buzzer_execute_pattern(pattern_id);
}
}
}

View File

@@ -1,6 +1,5 @@
set(srcs
"src/protocols.c"
"src/rest.c"
"src/mqtt.c"
"src/date_time.c"
)

View File

@@ -1,14 +0,0 @@
#ifndef REST_H_
#define REST_H_
#include "esp_err.h"
/**
* @brief Initialize REST server
*
* @param base_path Path on the SPIFFS filesystem where static files reside
* @return ESP_OK on success, ESP_FAIL otherwise
*/
esp_err_t rest_init(const char *base_path);
#endif /* REST_H_ */

View File

@@ -31,31 +31,31 @@ static esp_err_t open_mqtt_nvs(nvs_handle_t *handle) {
static void subcribe_topics(void)
{
ESP_LOGI(TAG, "subcribe_topics");
ESP_LOGI(TAG, "[MQTT] Subscribing to topics");
char base[32];
mqtt_get_base_topic(base);
char topic[64];
mqtt_get_base_topic(topic);
strcat(topic, "/request/#");
snprintf(topic, sizeof(topic), "%s/request/#", base);
esp_mqtt_client_subscribe(client, topic, 0);
ESP_LOGI(TAG, "subscribed: %s", topic);
ESP_LOGI(TAG, " subscribed: %s", topic);
mqtt_get_base_topic(topic);
strcat(topic, "/set/config/#");
snprintf(topic, sizeof(topic), "%s/set/config/#", base);
esp_mqtt_client_subscribe(client, topic, 0);
ESP_LOGI(TAG, "subscribed: %s", topic);
ESP_LOGI(TAG, " subscribed: %s", topic);
mqtt_get_base_topic(topic);
strcat(topic, "/enable");
snprintf(topic, sizeof(topic), "%s/enable", base);
esp_mqtt_client_subscribe(client, topic, 0);
ESP_LOGI(TAG, "subscribed: %s", topic);
ESP_LOGI(TAG, " subscribed: %s", topic);
}
static void publish_message(const char* topic, cJSON* root)
{
char target_topic[64];
mqtt_get_base_topic(target_topic);
strcat(target_topic, topic);
strncat(target_topic, topic, sizeof(target_topic) - strlen(target_topic) - 1);
const char* json = cJSON_PrintUnformatted(root);
esp_mqtt_client_publish(client, target_topic, json, 0, 1, 0);
@@ -67,34 +67,51 @@ static void handle_message(const char* topic, const char* data)
char base_topic[32];
mqtt_get_base_topic(base_topic);
ESP_LOGI(TAG, "[MQTT] Message received");
ESP_LOGI(TAG, " > Topic: %s", topic);
ESP_LOGI(TAG, " > Payload: %s", data);
if (strncmp(topic, base_topic, strlen(base_topic)) == 0) {
const char* sub_topic = &topic[strlen(base_topic)];
ESP_LOGI(TAG, " > Subtopic detected: %s", sub_topic);
if (strcmp(sub_topic, "/request/config/evse") == 0) {
ESP_LOGI(TAG, " → Responding with EVSE configuration");
cJSON* root = json_get_evse_config();
publish_message("/response/config/evse", root);
cJSON_Delete(root);
} else {
ESP_LOGW(TAG, " ! Unknown command: %s", sub_topic);
}
// [Outros comandos omitidos para brevidade...]
} else {
ESP_LOGW(TAG, " ! Topic does not match base: %s", topic);
}
}
static void event_handler(void* handler_args, esp_event_base_t base, int32_t event_id, void* event_data)
{
esp_mqtt_event_handle_t event = event_data;
char topic[48], data[256];
switch (event_id) {
case MQTT_EVENT_CONNECTED:
ESP_LOGI(TAG, "MQTT conectado");
ESP_LOGI(TAG, "[MQTT] Connected to broker");
if (client_task) vTaskResume(client_task);
subcribe_topics();
break;
case MQTT_EVENT_DATA:
strncpy(topic, event->topic, MIN(event->topic_len, sizeof(topic)-1));
strncpy(data, event->data, MIN(event->data_len, sizeof(data)-1));
case MQTT_EVENT_DATA: {
char topic[64] = {0};
char data[256] = {0};
int tlen = MIN(event->topic_len, sizeof(topic) - 1);
int dlen = MIN(event->data_len, sizeof(data) - 1);
memcpy(topic, event->topic, tlen);
memcpy(data, event->data, dlen);
handle_message(topic, data);
break;
}
default:
break;
}
@@ -257,4 +274,4 @@ void mqtt_get_password(char* value)
uint16_t mqtt_get_periodicity(void)
{
return periodicity;
}
}

View File

@@ -1,907 +0,0 @@
/* HTTP Restful API Server
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <string.h>
#include <fcntl.h>
#include "esp_http_server.h"
#include "esp_chip_info.h"
#include "esp_random.h"
#include "esp_log.h"
#include "esp_vfs.h"
#include "cJSON.h"
#include "rest.h"
#include "evse_api.h"
#include "cJSON.h"
#include "esp_log.h"
#include "esp_http_server.h"
#include "auth.h"
static const char *REST_TAG = "esp-rest";
#define REST_CHECK(a, str, goto_tag, ...) \
do \
{ \
if (!(a)) \
{ \
ESP_LOGE(REST_TAG, "%s(%d): " str, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
goto goto_tag; \
} \
} while (0)
#define FILE_PATH_MAX (ESP_VFS_PATH_MAX + 128)
#define SCRATCH_BUFSIZE (10240)
typedef struct rest_server_context {
char base_path[ESP_VFS_PATH_MAX + 1];
char scratch[SCRATCH_BUFSIZE];
} rest_server_context_t;
#define CHECK_FILE_EXTENSION(filename, ext) (strcasecmp(&filename[strlen(filename) - strlen(ext)], ext) == 0)
// Estruturas para armazenar as configurações
static struct {
bool enabled;
char ssid[128];
char password[128];
} wifi_config = {false, "", ""};
static struct {
bool enabled;
char host[256];
int port;
char username[128];
char password[128];
char topic[128];
} mqtt_config = {false, "", 1883, "", "", ""};
// Estrutura para armazenar as configurações OCPP em memória
static struct {
char url[256];
char chargeBoxId[128];
char certificate[256];
char privateKey[256];
} ocpp_config = {"", "", "", ""};
// Estrutura para armazenar as configurações de energia
static struct {
int currentLimit;
int powerLimit;
int energyLimit;
int chargingTimeLimit;
int temperatureLimit;
} settings_config = {0, 0, 0, 0, 0};
static struct {
char username[128];
} users[10] = {{"admin"}, {"user1"}};
static int num_users = 2; // Contador de usuários cadastrados
// Set HTTP response content type according to file extension
static esp_err_t set_content_type_from_file(httpd_req_t *req, const char *filepath)
{
const char *type = "text/plain";
if (CHECK_FILE_EXTENSION(filepath, ".html")) {
type = "text/html";
} else if (CHECK_FILE_EXTENSION(filepath, ".js")) {
type = "application/javascript";
} else if (CHECK_FILE_EXTENSION(filepath, ".css")) {
type = "text/css";
} else if (CHECK_FILE_EXTENSION(filepath, ".png")) {
type = "image/png";
} else if (CHECK_FILE_EXTENSION(filepath, ".ico")) {
type = "image/x-icon";
} else if (CHECK_FILE_EXTENSION(filepath, ".svg")) {
type = "text/xml";
}
return httpd_resp_set_type(req, type);
}
/* Send HTTP response with the contents of the requested file */
static esp_err_t rest_common_get_handler(httpd_req_t *req)
{
char filepath[FILE_PATH_MAX];
rest_server_context_t *rest_context = (rest_server_context_t *)req->user_ctx;
strlcpy(filepath, rest_context->base_path, sizeof(filepath));
if (req->uri[strlen(req->uri) - 1] == '/') {
strlcat(filepath, "/index.html", sizeof(filepath));
} else {
strlcat(filepath, req->uri, sizeof(filepath));
}
int fd = open(filepath, O_RDONLY, 0);
if (fd == -1) {
ESP_LOGW(REST_TAG, "Failed to open file : %s, redirecting to index", filepath);
/* Try to serve index.html for SPA routing */
strlcpy(filepath, rest_context->base_path, sizeof(filepath));
strlcat(filepath, "/index.html", sizeof(filepath));
fd = open(filepath, O_RDONLY, 0);
if (fd == -1) {
ESP_LOGE(REST_TAG, "Failed to open index file : %s", filepath);
httpd_resp_send_err(req, HTTPD_404_NOT_FOUND, "File not found");
return ESP_FAIL;
}
}
set_content_type_from_file(req, filepath);
char *chunk = rest_context->scratch;
ssize_t read_bytes;
do {
/* Read file in chunks into the scratch buffer */
read_bytes = read(fd, chunk, SCRATCH_BUFSIZE);
if (read_bytes == -1) {
ESP_LOGE(REST_TAG, "Failed to read file : %s", filepath);
} else if (read_bytes > 0) {
/* Send the buffer contents as HTTP response chunk */
if (httpd_resp_send_chunk(req, chunk, read_bytes) != ESP_OK) {
close(fd);
ESP_LOGE(REST_TAG, "File sending failed!");
/* Abort sending file */
httpd_resp_sendstr_chunk(req, NULL);
/* Respond with 500 Internal Server Error */
httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Failed to send file");
return ESP_FAIL;
}
}
} while (read_bytes > 0);
/* Close file after sending complete */
close(fd);
ESP_LOGI(REST_TAG, "File sending complete");
/* Respond with an empty chunk to signal HTTP response completion */
httpd_resp_send_chunk(req, NULL, 0);
return ESP_OK;
}
// Manipulador para o endpoint GET /api/v1/config/electrical
static esp_err_t electrical_config_get_handler(httpd_req_t *req)
{
httpd_resp_set_type(req, "application/json");
// Criar objeto JSON com as configurações de rede elétrica
cJSON *config = cJSON_CreateObject();
cJSON *monitor = cJSON_CreateObject();
cJSON_AddStringToObject(monitor, "voltage", "230");
cJSON_AddStringToObject(monitor, "current", "10");
cJSON_AddStringToObject(monitor, "quality", "1");
cJSON_AddItemToObject(config, "monitor", monitor);
cJSON_AddBoolToObject(config, "alerts", true);
// Adicionar mais configurações (security, loadBalancing, solar) no objeto config
// ...
// Enviar a resposta
const char *config_str = cJSON_Print(config);
httpd_resp_sendstr(req, config_str);
// Liberar memória
free((void *)config_str);
cJSON_Delete(config);
return ESP_OK;
}
// Manipulador para o endpoint POST /api/v1/config/electrical
static esp_err_t electrical_config_post_handler(httpd_req_t *req)
{
char buf[512];
int len = httpd_req_recv(req, buf, sizeof(buf) - 1);
if (len <= 0) {
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Request body is empty");
return ESP_FAIL;
}
buf[len] = '\0'; // Garantir que a string esteja terminada
// Parse JSON recebido
cJSON *json = cJSON_Parse(buf);
if (json == NULL) {
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Invalid JSON");
return ESP_FAIL;
}
// Processar os dados recebidos e atualizar as configurações (monitor, alerts, etc.)
// Exemplo de configuração:
cJSON *monitor = cJSON_GetObjectItem(json, "monitor");
if (monitor) {
// Atualizar configurações do monitor
// ...
}
// Atualizar outras configurações...
// Responder com sucesso
httpd_resp_sendstr(req, "Configuração gravada com sucesso!");
cJSON_Delete(json);
return ESP_OK;
}
// Manipulador para o endpoint /api/v1/config/load-balancing
static esp_err_t config_load_balancing_get_handler(httpd_req_t *req)
{
httpd_resp_set_type(req, "application/json");
// Criar objeto JSON de configuração
cJSON *config = cJSON_CreateObject();
// Configuração de load balancing
cJSON_AddBoolToObject(config, "enabled", true); // Exemplo: load balancing ativado
cJSON_AddNumberToObject(config, "maxChargingCurrent", 32); // Exemplo: corrente máxima de 32A
// Lista de dispositivos disponíveis
cJSON *devices = cJSON_CreateArray();
cJSON_AddItemToArray(devices, cJSON_CreateString("Device 1")); // Exemplo de dispositivo
cJSON_AddItemToArray(devices, cJSON_CreateString("Device 2")); // Outro exemplo de dispositivo
cJSON_AddItemToObject(config, "devices", devices);
// Convertendo para string e enviando a resposta
const char *config_str = cJSON_Print(config);
httpd_resp_sendstr(req, config_str);
// Liberando a memória
free((void *)config_str);
cJSON_Delete(config);
return ESP_OK;
}
// Manipulador para o endpoint GET /api/v1/ocpp (Status do OCPP)
static esp_err_t ocpp_status_get_handler(httpd_req_t *req)
{
httpd_resp_set_type(req, "application/json");
// Criar objeto JSON de status
cJSON *status = cJSON_CreateObject();
cJSON_AddStringToObject(status, "status", "connected"); // Status de exemplo, você pode adaptar conforme sua lógica
// Convertendo para string e enviando a resposta
const char *status_str = cJSON_Print(status);
httpd_resp_sendstr(req, status_str);
// Liberando a memória
free((void *)status_str);
cJSON_Delete(status);
return ESP_OK;
}
// Manipulador para o endpoint GET /api/v1/config/ocpp (Configuração OCPP)
static esp_err_t config_ocpp_get_handler(httpd_req_t *req)
{
httpd_resp_set_type(req, "application/json");
// Criar objeto JSON com as configurações do OCPP
cJSON *config = cJSON_CreateObject();
cJSON_AddStringToObject(config, "url", ocpp_config.url);
cJSON_AddStringToObject(config, "chargeBoxId", ocpp_config.chargeBoxId);
cJSON_AddStringToObject(config, "certificate", ocpp_config.certificate);
cJSON_AddStringToObject(config, "privateKey", ocpp_config.privateKey);
// Convertendo para string e enviando a resposta
const char *config_str = cJSON_Print(config);
httpd_resp_sendstr(req, config_str);
// Liberando a memória
free((void *)config_str);
cJSON_Delete(config);
return ESP_OK;
}
// Manipulador para o endpoint POST /api/v1/config/ocpp (Salvar configuração OCPP)
static esp_err_t config_ocpp_post_handler(httpd_req_t *req)
{
char buf[512]; // Buffer para armazenar a requisição
int len = httpd_req_recv(req, buf, sizeof(buf) - 1);
if (len <= 0) {
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Invalid request body");
return ESP_FAIL;
}
buf[len] = '\0'; // Garantir que a string esteja terminada
// Parse JSON recebido
cJSON *json = cJSON_Parse(buf);
if (json == NULL) {
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Invalid JSON");
return ESP_FAIL;
}
// Atualizando as configurações OCPP
cJSON *url = cJSON_GetObjectItem(json, "url");
if (url) strlcpy(ocpp_config.url, url->valuestring, sizeof(ocpp_config.url));
cJSON *chargeBoxId = cJSON_GetObjectItem(json, "chargeBoxId");
if (chargeBoxId) strlcpy(ocpp_config.chargeBoxId, chargeBoxId->valuestring, sizeof(ocpp_config.chargeBoxId));
cJSON *certificate = cJSON_GetObjectItem(json, "certificate");
if (certificate) strlcpy(ocpp_config.certificate, certificate->valuestring, sizeof(ocpp_config.certificate));
cJSON *privateKey = cJSON_GetObjectItem(json, "privateKey");
if (privateKey) strlcpy(ocpp_config.privateKey, privateKey->valuestring, sizeof(ocpp_config.privateKey));
cJSON_Delete(json);
// Responder com uma mensagem de sucesso
httpd_resp_sendstr(req, "Configuração OCPP atualizada com sucesso");
return ESP_OK;
}
// Manipulador para o endpoint POST /api/v1/config/settings
static esp_err_t config_settings_post_handler(httpd_req_t *req)
{
char buf[512]; // Buffer para armazenar a requisição
int len = httpd_req_recv(req, buf, sizeof(buf) - 1);
if (len <= 0) {
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Invalid request body");
return ESP_FAIL;
}
buf[len] = '\0'; // Garantir que a string esteja terminada
// Parse JSON recebido
cJSON *json = cJSON_Parse(buf);
if (json == NULL) {
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Invalid JSON");
return ESP_FAIL;
}
// Atualizando as configurações
cJSON *currentLimit = cJSON_GetObjectItem(json, "currentLimit");
if (currentLimit)
evse_set_max_charging_current(currentLimit->valueint);
//settings_config.currentLimit = currentLimit->valueint;
cJSON *powerLimit = cJSON_GetObjectItem(json, "powerLimit");
if (powerLimit) settings_config.powerLimit = powerLimit->valueint;
cJSON *energyLimit = cJSON_GetObjectItem(json, "energyLimit");
if (energyLimit) settings_config.energyLimit = energyLimit->valueint;
cJSON *chargingTimeLimit = cJSON_GetObjectItem(json, "chargingTimeLimit");
if (chargingTimeLimit) settings_config.chargingTimeLimit = chargingTimeLimit->valueint;
cJSON *temperatureLimit = cJSON_GetObjectItem(json, "temperatureLimit");
if (temperatureLimit)
evse_set_temp_threshold(temperatureLimit->valueint);
//settings_config.temperatureLimit = temperatureLimit->valueint;
cJSON_Delete(json);
// Responder com uma mensagem de sucesso
httpd_resp_sendstr(req, "Configurações de energia atualizadas com sucesso");
return ESP_OK;
}
// Manipulador para o endpoint GET /api/v1/config/settings
static esp_err_t config_settings_get_handler(httpd_req_t *req)
{
httpd_resp_set_type(req, "application/json");
// Criar objeto JSON para enviar as configurações atuais
cJSON *config = cJSON_CreateObject();
//cJSON_AddNumberToObject(config, "maxCurrentLimit", evse_get_max_charging_current());
cJSON_AddNumberToObject(config, "currentLimit", evse_get_max_charging_current());
cJSON_AddNumberToObject(config, "powerLimit", settings_config.powerLimit);
cJSON_AddNumberToObject(config, "energyLimit", settings_config.energyLimit);
cJSON_AddNumberToObject(config, "chargingTimeLimit", settings_config.chargingTimeLimit);
cJSON_AddNumberToObject(config, "temperatureLimit", evse_get_temp_threshold());
// Convertendo para string e enviando a resposta
const char *config_str = cJSON_Print(config);
httpd_resp_sendstr(req, config_str);
// Liberando a memória
free((void *)config_str);
cJSON_Delete(config);
return ESP_OK;
}
// Manipulador para o endpoint GET /api/v1/dashboard
static esp_err_t dashboard_get_handler(httpd_req_t *req)
{
httpd_resp_set_type(req, "application/json");
// Criar objeto JSON com os dados do Dashboard
cJSON *dashboard = cJSON_CreateObject();
// Status do sistema
cJSON_AddStringToObject(dashboard, "status", "Ativo");
// Carregadores (exemplo)
cJSON *chargers = cJSON_CreateArray();
cJSON *charger1 = cJSON_CreateObject();
cJSON_AddNumberToObject(charger1, "id", 1);
cJSON_AddStringToObject(charger1, "status", "Ativo");
cJSON_AddNumberToObject(charger1, "current", 12);
cJSON_AddNumberToObject(charger1, "power", 2200);
cJSON_AddItemToArray(chargers, charger1);
cJSON_AddItemToObject(dashboard, "chargers", chargers);
// Consumo de energia
cJSON_AddNumberToObject(dashboard, "energyConsumed", 50.3);
// Tempo de carregamento
cJSON_AddNumberToObject(dashboard, "chargingTime", 120);
// Alertas
cJSON *alerts = cJSON_CreateArray();
cJSON_AddItemToArray(alerts, cJSON_CreateString("Aviso: Carregador 1 está com erro."));
cJSON_AddItemToObject(dashboard, "alerts", alerts);
// Convertendo para string e enviando a resposta
const char *dashboard_str = cJSON_Print(dashboard);
httpd_resp_sendstr(req, dashboard_str);
// Liberando a memória
free((void *)dashboard_str);
cJSON_Delete(dashboard);
return ESP_OK;
}
static esp_err_t config_wifi_get_handler(httpd_req_t *req)
{
httpd_resp_set_type(req, "application/json");
// Criar objeto JSON com as configurações de Wi-Fi
cJSON *config = cJSON_CreateObject();
cJSON_AddBoolToObject(config, "enabled", wifi_config.enabled);
cJSON_AddStringToObject(config, "ssid", wifi_config.ssid);
cJSON_AddStringToObject(config, "password", wifi_config.password);
// Convertendo para string e enviando a resposta
const char *config_str = cJSON_Print(config);
httpd_resp_sendstr(req, config_str);
// Liberando a memória
free((void *)config_str);
cJSON_Delete(config);
return ESP_OK;
}
/* Manipulador para o endpoint POST /api/v1/config/wifi */
static esp_err_t config_wifi_post_handler(httpd_req_t *req)
{
char buf[512]; // Buffer para armazenar a requisição
int len = httpd_req_recv(req, buf, sizeof(buf) - 1);
if (len <= 0) {
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Invalid request body");
return ESP_FAIL;
}
buf[len] = '\0'; // Garantir que a string esteja terminada
// Parse JSON recebido
cJSON *json = cJSON_Parse(buf);
if (json == NULL) {
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Invalid JSON");
return ESP_FAIL;
}
// Atualizando as configurações Wi-Fi
cJSON *enabled = cJSON_GetObjectItem(json, "enabled");
if (enabled) wifi_config.enabled = enabled->valueint;
cJSON *ssid = cJSON_GetObjectItem(json, "ssid");
if (ssid) strlcpy(wifi_config.ssid, ssid->valuestring, sizeof(wifi_config.ssid));
cJSON *password = cJSON_GetObjectItem(json, "password");
if (password) strlcpy(wifi_config.password, password->valuestring, sizeof(wifi_config.password));
cJSON_Delete(json);
// Responder com uma mensagem de sucesso
httpd_resp_sendstr(req, "Configuração Wi-Fi atualizada com sucesso");
return ESP_OK;
}
/* Manipulador para o endpoint GET /api/v1/config/mqtt */
static esp_err_t config_mqtt_get_handler(httpd_req_t *req)
{
httpd_resp_set_type(req, "application/json");
// Criar objeto JSON com as configurações de MQTT
cJSON *config = cJSON_CreateObject();
cJSON_AddBoolToObject(config, "enabled", mqtt_config.enabled);
cJSON_AddStringToObject(config, "host", mqtt_config.host);
cJSON_AddNumberToObject(config, "port", mqtt_config.port);
cJSON_AddStringToObject(config, "username", mqtt_config.username);
cJSON_AddStringToObject(config, "password", mqtt_config.password);
cJSON_AddStringToObject(config, "topic", mqtt_config.topic);
// Convertendo para string e enviando a resposta
const char *config_str = cJSON_Print(config);
httpd_resp_sendstr(req, config_str);
// Liberando a memória
free((void *)config_str);
cJSON_Delete(config);
return ESP_OK;
}
/* Manipulador para o endpoint POST /api/v1/config/mqtt */
static esp_err_t config_mqtt_post_handler(httpd_req_t *req)
{
char buf[512]; // Buffer para armazenar a requisição
int len = httpd_req_recv(req, buf, sizeof(buf) - 1);
if (len <= 0) {
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Invalid request body");
return ESP_FAIL;
}
buf[len] = '\0'; // Garantir que a string esteja terminada
// Parse JSON recebido
cJSON *json = cJSON_Parse(buf);
if (json == NULL) {
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Invalid JSON");
return ESP_FAIL;
}
// Atualizando as configurações MQTT
cJSON *enabled = cJSON_GetObjectItem(json, "enabled");
if (enabled) mqtt_config.enabled = enabled->valueint;
cJSON *host = cJSON_GetObjectItem(json, "host");
if (host) strlcpy(mqtt_config.host, host->valuestring, sizeof(mqtt_config.host));
cJSON *port = cJSON_GetObjectItem(json, "port");
if (port) mqtt_config.port = port->valueint;
cJSON *username = cJSON_GetObjectItem(json, "username");
if (username) strlcpy(mqtt_config.username, username->valuestring, sizeof(mqtt_config.username));
cJSON *password = cJSON_GetObjectItem(json, "password");
if (password) strlcpy(mqtt_config.password, password->valuestring, sizeof(mqtt_config.password));
cJSON *topic = cJSON_GetObjectItem(json, "topic");
if (topic) strlcpy(mqtt_config.topic, topic->valuestring, sizeof(mqtt_config.topic));
cJSON_Delete(json);
// Responder com uma mensagem de sucesso
httpd_resp_sendstr(req, "Configuração MQTT atualizada com sucesso");
return ESP_OK;
}
// GET /api/v1/config/auth-methods
static esp_err_t config_auth_methods_get_handler(httpd_req_t *req)
{
httpd_resp_set_type(req, "application/json");
cJSON *config = cJSON_CreateObject();
cJSON_AddBoolToObject(config, "RFID", auth_is_enabled());
cJSON_AddBoolToObject(config, "App", false);
cJSON_AddBoolToObject(config, "Password", false);
char *config_str = cJSON_PrintUnformatted(config);
httpd_resp_sendstr(req, config_str);
free(config_str);
cJSON_Delete(config);
return ESP_OK;
}
// POST /api/v1/config/auth-methods
static esp_err_t config_auth_methods_post_handler(httpd_req_t *req)
{
char buf[512];
int len = httpd_req_recv(req, buf, sizeof(buf) - 1);
if (len <= 0) {
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Invalid request body");
return ESP_FAIL;
}
buf[len] = '\0';
cJSON *json = cJSON_Parse(buf);
if (!json) {
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Invalid JSON");
return ESP_FAIL;
}
cJSON *RFID = cJSON_GetObjectItem(json, "RFID");
if (cJSON_IsBool(RFID)) {
auth_set_enabled(cJSON_IsTrue(RFID));
}
/*
cJSON *App = cJSON_GetObjectItem(json, "App");
if (cJSON_IsBool(App)) {
auth_methods.App = cJSON_IsTrue(App);
}
cJSON *Password = cJSON_GetObjectItem(json, "Password");
if (cJSON_IsBool(Password)) {
auth_methods.Password = cJSON_IsTrue(Password);
}*/
cJSON_Delete(json);
httpd_resp_sendstr(req, "Configurações de autenticação atualizadas com sucesso");
return ESP_OK;
}
// Manipulador para o endpoint GET /api/v1/config/users
static esp_err_t config_users_get_handler(httpd_req_t *req)
{
httpd_resp_set_type(req, "application/json");
// Criar objeto JSON com a lista de usuários
cJSON *config = cJSON_CreateObject();
cJSON *users_list = cJSON_CreateArray();
for (int i = 0; i < num_users; i++) {
cJSON *user = cJSON_CreateObject();
cJSON_AddStringToObject(user, "username", users[i].username);
cJSON_AddItemToArray(users_list, user);
}
cJSON_AddItemToObject(config, "users", users_list);
// Convertendo para string e enviando a resposta
const char *config_str = cJSON_Print(config);
httpd_resp_sendstr(req, config_str);
// Liberando a memória
free((void *)config_str);
cJSON_Delete(config);
return ESP_OK;
}
// Manipulador para o endpoint POST /api/v1/config/users
static esp_err_t config_users_post_handler(httpd_req_t *req)
{
char buf[128]; // Buffer para armazenar o nome do novo usuário
int len = httpd_req_recv(req, buf, sizeof(buf) - 1);
if (len <= 0) {
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Invalid request body");
return ESP_FAIL;
}
buf[len] = '\0'; // Garantir que a string esteja terminada
// Adicionar o novo usuário
if (num_users < 10) {
strlcpy(users[num_users].username, buf, sizeof(users[num_users].username));
num_users++;
httpd_resp_sendstr(req, "Usuário adicionado com sucesso");
} else {
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Máximo de usuários atingido");
}
return ESP_OK;
}
// Manipulador para o endpoint DELETE /api/v1/config/users/{username}
static esp_err_t config_users_delete_handler(httpd_req_t *req)
{
char username[128]; // Nome do usuário a ser removido
if (httpd_req_get_url_query_str(req, username, sizeof(username)) == ESP_OK) {
// Verificar e remover o usuário
for (int i = 0; i < num_users; i++) {
if (strcmp(users[i].username, username) == 0) {
// Remover o usuário
for (int j = i; j < num_users - 1; j++) {
users[j] = users[j + 1];
}
num_users--;
httpd_resp_sendstr(req, "Usuário removido com sucesso");
return ESP_OK;
}
}
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Usuário não encontrado");
}
return ESP_FAIL;
}
esp_err_t rest_init(const char *base_path)
{
/*
REST_CHECK(base_path, "wrong base path", err);
rest_server_context_t *rest_context = calloc(1, sizeof(rest_server_context_t));
REST_CHECK(rest_context, "No memory for rest context", err_start);
strlcpy(rest_context->base_path, base_path, sizeof(rest_context->base_path));
httpd_handle_t server = NULL;
httpd_config_t config = HTTPD_DEFAULT_CONFIG();
config.max_uri_handlers = 30; // Ajuste conforme necessário
config.uri_match_fn = httpd_uri_match_wildcard;
ESP_LOGI(REST_TAG, "Starting HTTP Server");
REST_CHECK(httpd_start(&server, &config) == ESP_OK, "Start server failed", err_start);
// Registrar manipuladores de URI para as configurações
httpd_uri_t config_load_balancing_get_uri = {
.uri = "/api/v1/config/load-balancing",
.method = HTTP_GET,
.handler = config_load_balancing_get_handler,
.user_ctx = rest_context
};
httpd_register_uri_handler(server, &config_load_balancing_get_uri);
// URI handler for fetching OCPP status
httpd_uri_t ocpp_status_get_uri = {
.uri = "/api/v1/ocpp",
.method = HTTP_GET,
.handler = ocpp_status_get_handler,
.user_ctx = rest_context
};
httpd_register_uri_handler(server, &ocpp_status_get_uri);
// URI handler for fetching OCPP config
httpd_uri_t config_ocpp_get_uri = {
.uri = "/api/v1/config/ocpp",
.method = HTTP_GET,
.handler = config_ocpp_get_handler,
.user_ctx = rest_context
};
httpd_register_uri_handler(server, &config_ocpp_get_uri);
// URI handler for posting OCPP config
httpd_uri_t config_ocpp_post_uri = {
.uri = "/api/v1/config/ocpp",
.method = HTTP_POST,
.handler = config_ocpp_post_handler,
.user_ctx = rest_context
};
httpd_register_uri_handler(server, &config_ocpp_post_uri);
// Manipulador para o endpoint POST /api/v1/config/settings
httpd_uri_t config_settings_post_uri = {
.uri = "/api/v1/config/settings",
.method = HTTP_POST,
.handler = config_settings_post_handler,
.user_ctx = rest_context
};
httpd_register_uri_handler(server, &config_settings_post_uri);
// Manipulador para o endpoint GET /api/v1/config/settings
httpd_uri_t config_settings_get_uri = {
.uri = "/api/v1/config/settings",
.method = HTTP_GET,
.handler = config_settings_get_handler,
.user_ctx = rest_context
};
httpd_register_uri_handler(server, &config_settings_get_uri);
// Manipulador para o endpoint GET /api/v1/dashboard
httpd_uri_t dashboard_get_uri = {
.uri = "/api/v1/dashboard",
.method = HTTP_GET,
.handler = dashboard_get_handler,
.user_ctx = rest_context
};
httpd_register_uri_handler(server, &dashboard_get_uri);
// Register URI Handlers for electrical configuration
httpd_uri_t electrical_config_get_uri = {
.uri = "/api/v1/config/electrical",
.method = HTTP_GET,
.handler = electrical_config_get_handler,
.user_ctx = rest_context
};
httpd_register_uri_handler(server, &electrical_config_get_uri);
httpd_uri_t electrical_config_post_uri = {
.uri = "/api/v1/config/electrical",
.method = HTTP_POST,
.handler = electrical_config_post_handler,
.user_ctx = rest_context
};
httpd_register_uri_handler(server, &electrical_config_post_uri);
// URI handler for getting Wi-Fi config
httpd_uri_t config_wifi_get_uri = {
.uri = "/api/v1/config/wifi",
.method = HTTP_GET,
.handler = config_wifi_get_handler,
.user_ctx = rest_context
};
httpd_register_uri_handler(server, &config_wifi_get_uri);
// URI handler for posting Wi-Fi config
httpd_uri_t config_wifi_post_uri = {
.uri = "/api/v1/config/wifi",
.method = HTTP_POST,
.handler = config_wifi_post_handler,
.user_ctx = rest_context
};
httpd_register_uri_handler(server, &config_wifi_post_uri);
// URI handler for getting MQTT config
httpd_uri_t config_mqtt_get_uri = {
.uri = "/api/v1/config/mqtt",
.method = HTTP_GET,
.handler = config_mqtt_get_handler,
.user_ctx = rest_context
};
httpd_register_uri_handler(server, &config_mqtt_get_uri);
// URI handler for posting MQTT config
httpd_uri_t config_mqtt_post_uri = {
.uri = "/api/v1/config/mqtt",
.method = HTTP_POST,
.handler = config_mqtt_post_handler,
.user_ctx = rest_context
};
httpd_register_uri_handler(server, &config_mqtt_post_uri);
// Registrar manipuladores para as configurações de autenticação
httpd_uri_t config_auth_methods_get_uri = {
.uri = "/api/v1/config/auth-methods",
.method = HTTP_GET,
.handler = config_auth_methods_get_handler,
.user_ctx = rest_context
};
httpd_register_uri_handler(server, &config_auth_methods_get_uri);
httpd_uri_t config_auth_methods_post_uri = {
.uri = "/api/v1/config/auth-methods",
.method = HTTP_POST,
.handler = config_auth_methods_post_handler,
.user_ctx = rest_context
};
httpd_register_uri_handler(server, &config_auth_methods_post_uri);
// Registrar manipuladores para as configurações de usuários
httpd_uri_t config_users_get_uri = {
.uri = "/api/v1/config/users",
.method = HTTP_GET,
.handler = config_users_get_handler,
.user_ctx = rest_context
};
httpd_register_uri_handler(server, &config_users_get_uri);
httpd_uri_t config_users_post_uri = {
.uri = "/api/v1/config/users",
.method = HTTP_POST,
.handler = config_users_post_handler,
.user_ctx = rest_context
};
httpd_register_uri_handler(server, &config_users_post_uri);
httpd_uri_t config_users_delete_uri = {
.uri = "/api/v1/config/users",
.method = HTTP_DELETE,
.handler = config_users_delete_handler,
.user_ctx = rest_context
};
httpd_register_uri_handler(server, &config_users_delete_uri);
// URI handler for getting web server files
httpd_uri_t common_get_uri = {
.uri = "/",
.method = HTTP_GET,
.handler = rest_common_get_handler,
.user_ctx = rest_context
};
httpd_register_uri_handler(server, &common_get_uri);
*/
return ESP_OK;
}

View File

@@ -3,6 +3,9 @@
#include "cJSON.h"
#include "evse_api.h"
#include "evse_error.h"
#include "evse_config.h"
#include "evse_limits.h"
static const char *TAG = "dashboard_api";
@@ -40,10 +43,10 @@ static esp_err_t dashboard_get_handler(httpd_req_t *req) {
if (evse_is_limit_reached()) {
cJSON_AddItemToArray(alerts, cJSON_CreateString("Limite de consumo atingido."));
}
if (!evse_is_available()) {
if (!evse_config_is_available()) {
cJSON_AddItemToArray(alerts, cJSON_CreateString("Estação indisponível."));
}
if (!evse_is_enabled()) {
if (!evse_config_is_enabled()) {
cJSON_AddItemToArray(alerts, cJSON_CreateString("EVSE desativado."));
}
cJSON_AddItemToObject(dashboard, "alerts", alerts);

View File

@@ -3,6 +3,7 @@
// =========================
#include "evse_settings_api.h"
#include "evse_api.h"
#include "evse_config.h"
#include "esp_log.h"
#include "cJSON.h"

View File

@@ -87,7 +87,7 @@ static esp_err_t meters_config_post_handler(httpd_req_t *req) {
// Registrando os manipuladores de URI para os contadores
void register_meters_settings_handlers(httpd_handle_t server, void *ctx) {
ESP_LOGI(TAG, "Registering URI handlers for meters settings");
ESP_LOGD(TAG, "Registering URI handlers for meters settings");
// URI para o método GET
httpd_uri_t meters_get_uri = {
@@ -96,7 +96,7 @@ void register_meters_settings_handlers(httpd_handle_t server, void *ctx) {
.handler = meters_config_get_handler,
.user_ctx = ctx
};
ESP_LOGI(TAG, "Registering GET handler for /api/v1/config/meters");
ESP_LOGD(TAG, "Registering GET handler for /api/v1/config/meters");
httpd_register_uri_handler(server, &meters_get_uri);
// URI para o método POST
@@ -106,6 +106,6 @@ void register_meters_settings_handlers(httpd_handle_t server, void *ctx) {
.handler = meters_config_post_handler,
.user_ctx = ctx
};
ESP_LOGI(TAG, "Registering POST handler for /api/v1/config/meters");
ESP_LOGD(TAG, "Registering POST handler for /api/v1/config/meters");
httpd_register_uri_handler(server, &meters_post_uri);
}

View File

@@ -19,6 +19,9 @@
// #include "inc/version_autogen.h"
#include "sync_master.h"
#include "evse_api.h"
#include "evse_error.h"
#include "evse_state.h"
#include "evse_config.h"
#define VERSION_STRING "2.2"

View File

@@ -20,6 +20,9 @@
#include "sync_slave.h"
#include "loadbalancer.h"
#include "evse_api.h"
#include "evse_error.h"
#include "evse_state.h"
#include "evse_config.h"
#define VERSION_STRING "2.2"

View File

@@ -0,0 +1,10 @@
set(srcs
"src/spi_bus_manager.c"
)
idf_component_register(
SRCS ${srcs}
INCLUDE_DIRS include
PRIV_REQUIRES driver esp_timer
REQUIRES config
)

View File

@@ -0,0 +1,20 @@
#ifndef SPI_BUS_MANAGER_H_
#define SPI_BUS_MANAGER_H_
#include "driver/spi_master.h"
#include "esp_err.h"
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
esp_err_t spi_bus_manager_init(void);
spi_host_device_t spi_bus_manager_get_host(void);
bool spi_bus_manager_is_initialized(void);
#ifdef __cplusplus
}
#endif
#endif // SPI_BUS_MANAGER_H_

View File

@@ -0,0 +1,48 @@
#include "spi_bus_manager.h"
#include "esp_log.h"
#include "esp_err.h"
#define TAG "spi_bus_mgr"
#define SHARED_SPI_HOST SPI2_HOST
// Pinos padrão (podem ser futuramente configuráveis)
#define PIN_NUM_MOSI 23
#define PIN_NUM_MISO 19
#define PIN_NUM_CLK 18
static bool initialized = false;
esp_err_t spi_bus_manager_init(void) {
if (initialized) {
ESP_LOGW(TAG, "SPI bus already initialized on host %d", SHARED_SPI_HOST);
return ESP_OK;
}
spi_bus_config_t buscfg = {
.mosi_io_num = PIN_NUM_MOSI,
.miso_io_num = PIN_NUM_MISO,
.sclk_io_num = PIN_NUM_CLK,
.quadwp_io_num = -1,
.quadhd_io_num = -1,
.max_transfer_sz = 64, // Ajustável conforme necessidade
};
esp_err_t ret = spi_bus_initialize(SHARED_SPI_HOST, &buscfg, SPI_DMA_CH_AUTO);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to initialize SPI bus: %s", esp_err_to_name(ret));
return ret;
}
initialized = true;
ESP_LOGI(TAG, "SPI bus initialized on host %d", SHARED_SPI_HOST);
return ESP_OK;
}
spi_host_device_t spi_bus_manager_get_host(void) {
return SHARED_SPI_HOST;
}
bool spi_bus_manager_is_initialized(void) {
return initialized;
}