fix ade7758
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
#include "timeout_utils.h"
|
||||
#include "wifi.h"
|
||||
#include "rest.h"
|
||||
//#include "rest.h"
|
||||
|
||||
static void restart_func(void* arg)
|
||||
{
|
||||
|
||||
@@ -9,6 +9,7 @@ set(srcs
|
||||
evse_manager.c
|
||||
evse_hardware.c
|
||||
evse_pilot.c
|
||||
evse_meter.c
|
||||
)
|
||||
|
||||
idf_component_register(
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
105
components/evse/evse_meter.c
Normal file
105
components/evse/evse_meter.c
Normal 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);
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
17
components/evse/include/evse_core.h
Normal file
17
components/evse/include/evse_core.h
Normal 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
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
37
components/evse/include/evse_meter.h
Normal file
37
components/evse/include/evse_meter.h
Normal 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
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/*****************************
|
||||
*
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
set(srcs
|
||||
"src/protocols.c"
|
||||
"src/rest.c"
|
||||
"src/mqtt.c"
|
||||
"src/date_time.c"
|
||||
)
|
||||
|
||||
@@ -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_ */
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
// =========================
|
||||
#include "evse_settings_api.h"
|
||||
#include "evse_api.h"
|
||||
#include "evse_config.h"
|
||||
#include "esp_log.h"
|
||||
#include "cJSON.h"
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
10
components/spi_bus_manager/CMakeLists.txt
Executable file
10
components/spi_bus_manager/CMakeLists.txt
Executable 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
|
||||
)
|
||||
20
components/spi_bus_manager/include/spi_bus_manager.h
Executable file
20
components/spi_bus_manager/include/spi_bus_manager.h
Executable 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_
|
||||
48
components/spi_bus_manager/src/spi_bus_manager.c
Executable file
48
components/spi_bus_manager/src/spi_bus_manager.c
Executable 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;
|
||||
}
|
||||
Reference in New Issue
Block a user