Files
chargeflow/components/ocpp/src/ocpp.c
2025-12-21 23:28:26 +00:00

885 lines
23 KiB
C
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// components/ocpp/src/ocpp.c
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <inttypes.h>
#include <math.h>
#include "esp_log.h"
#include "esp_err.h"
#include "esp_timer.h"
#include "esp_event.h"
#include "esp_wifi.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "ocpp.h"
#include "ocpp_events.h"
#include "evse_error.h"
#include "auth_events.h"
#include "evse_events.h"
#include "evse_state.h"
#include "meter_events.h"
/* MicroOcpp includes */
#include <mongoose.h>
#include <MicroOcpp_c.h> // C-facade of MicroOcpp
#include <MicroOcppMongooseClient_c.h> // WebSocket integration for ESP-IDF
// NEW storage layer
#include "storage_service.h"
#define NVS_NAMESPACE "ocpp"
#define NVS_OCPP_ENABLED "enabled"
#define NVS_OCPP_SERVER "ocpp_server"
#define NVS_OCPP_CHARGE_ID "charge_id"
static const char *TAG = "ocpp";
static bool enabled = false;
static TaskHandle_t ocpp_task = NULL;
static struct mg_mgr mgr; // Event manager
static OCPP_Connection *g_ocpp_conn = NULL; // Para shutdown limpo
static esp_event_handler_instance_t s_auth_verify_inst = NULL;
// Flags refletindo o estado do EVSE (atualizadas por eventos)
static volatile bool s_ev_plugged = false;
static volatile bool s_ev_ready = false;
static esp_event_handler_instance_t s_evse_state_inst = NULL;
// Flags de config (vindas de EVSE_EVENTS)
static volatile bool s_evse_enabled = true;
static volatile bool s_evse_available = true;
static esp_event_handler_instance_t s_evse_enable_inst = NULL;
static esp_event_handler_instance_t s_evse_available_inst = NULL;
// --- cache de medições vindas de METER_EVENT_DATA_READY ---
typedef struct
{
float vrms[3];
float irms[3];
int32_t watt[3]; // ativo por fase (W)
float frequency;
float power_factor;
float total_energy_Wh;
int32_t sum_watt;
float avg_voltage;
float sum_current;
bool have_data;
} ocpp_meter_cache_t;
static ocpp_meter_cache_t s_meter = {0};
static portMUX_TYPE s_meter_mux = portMUX_INITIALIZER_UNLOCKED;
static esp_event_handler_instance_t s_meter_inst = NULL;
// valor de oferta (A por conector)
static float s_current_offered_A = 16.0f;
static float getCurrentOffered(void)
{
return s_current_offered_A;
}
// -----------------------------------------------------------------------------
// Storage helpers (robustos)
// -----------------------------------------------------------------------------
#define STORE_TO pdMS_TO_TICKS(800)
#define STORE_FLUSH_TO pdMS_TO_TICKS(2000)
static void storage_init_best_effort(void)
{
esp_err_t e = storage_service_init();
if (e != ESP_OK)
ESP_LOGW(TAG, "storage_service_init failed: %s", esp_err_to_name(e));
}
static esp_err_t store_flush_best_effort(void)
{
esp_err_t e = storage_flush_sync(STORE_FLUSH_TO);
if (e != ESP_OK)
ESP_LOGW(TAG, "storage_flush_sync failed: %s", esp_err_to_name(e));
return e;
}
static esp_err_t store_set_u8_best_effort(const char *ns, const char *key, uint8_t v)
{
for (int attempt = 0; attempt < 3; ++attempt)
{
esp_err_t e = storage_set_u8_async(ns, key, v);
if (e == ESP_OK)
return ESP_OK;
if (e == ESP_ERR_TIMEOUT)
{
(void)store_flush_best_effort();
vTaskDelay(pdMS_TO_TICKS(10));
continue;
}
return e;
}
return ESP_ERR_TIMEOUT;
}
static esp_err_t store_set_str_best_effort(const char *ns, const char *key, const char *s)
{
for (int attempt = 0; attempt < 3; ++attempt)
{
esp_err_t e = storage_set_str_async(ns, key, s ? s : "");
if (e == ESP_OK)
return ESP_OK;
if (e == ESP_ERR_TIMEOUT)
{
(void)store_flush_best_effort();
vTaskDelay(portMAX_DELAY);
continue;
}
return e;
}
return ESP_ERR_TIMEOUT;
}
// Lê string de forma segura (buffer grande -> truncagem segura para out)
static esp_err_t store_get_str_safe(const char *ns, const char *key, char *out, size_t out_sz)
{
if (!out || out_sz == 0)
return ESP_ERR_INVALID_ARG;
out[0] = '\0';
char tmp[STORAGE_MAX_VALUE_BYTES + 1];
memset(tmp, 0, sizeof(tmp));
esp_err_t e = storage_get_str_sync(ns, key, tmp, sizeof(tmp), STORE_TO);
if (e == ESP_ERR_NOT_FOUND)
return ESP_OK;
if (e != ESP_OK)
return e;
size_t n = strnlen(tmp, out_sz - 1);
memcpy(out, tmp, n);
out[n] = '\0';
return ESP_OK;
}
// -----------------------------------------------------------------------------
// Task / Main Loop
// -----------------------------------------------------------------------------
static void ocpp_task_func(void *param)
{
(void)param;
while (true)
{
if (enabled)
{
mg_mgr_poll(&mgr, 100);
ocpp_loop();
bool operative = ocpp_isOperative();
if (operative != s_evse_enabled)
{
s_evse_enabled = operative;
ocpp_operative_event_t ev = {
.operative = operative,
.timestamp_us = esp_timer_get_time()};
esp_event_post(OCPP_EVENTS,
OCPP_EVENT_OPERATIVE_UPDATED,
&ev, sizeof(ev),
portMAX_DELAY);
ESP_LOGI(TAG, "[OCPP] ChangeAvailability remoto → operative=%d", (int)operative);
}
}
else
{
vTaskDelay(pdMS_TO_TICKS(500));
}
}
}
// -----------------------------------------------------------------------------
// Storage GETs
// -----------------------------------------------------------------------------
bool ocpp_get_enabled(void)
{
storage_init_best_effort();
uint8_t value = 0;
esp_err_t err = storage_get_u8_sync(NVS_NAMESPACE, NVS_OCPP_ENABLED, &value, STORE_TO);
if (err == ESP_ERR_NOT_FOUND)
return false;
if (err != ESP_OK)
{
ESP_LOGW(TAG, "storage_get_u8_sync(enabled) failed: %s", esp_err_to_name(err));
return false;
}
return value != 0;
}
void ocpp_get_server(char *value /* out, size>=64 */)
{
if (!value)
return;
value[0] = '\0';
storage_init_best_effort();
esp_err_t e = store_get_str_safe(NVS_NAMESPACE, NVS_OCPP_SERVER, value, 64);
if (e != ESP_OK)
{
ESP_LOGW(TAG, "store_get_str_safe(server) failed: %s", esp_err_to_name(e));
value[0] = '\0';
}
}
void ocpp_get_charge_id(char *value /* out, size>=64 */)
{
if (!value)
return;
value[0] = '\0';
storage_init_best_effort();
esp_err_t e = store_get_str_safe(NVS_NAMESPACE, NVS_OCPP_CHARGE_ID, value, 64);
if (e != ESP_OK)
{
ESP_LOGW(TAG, "store_get_str_safe(charge_id) failed: %s", esp_err_to_name(e));
value[0] = '\0';
}
}
// -----------------------------------------------------------------------------
// Storage SETs
// -----------------------------------------------------------------------------
void ocpp_set_enabled(bool value)
{
storage_init_best_effort();
ESP_LOGI(TAG, "set enabled %d", value);
esp_err_t e = store_set_u8_best_effort(NVS_NAMESPACE, NVS_OCPP_ENABLED, value ? 1 : 0);
if (e != ESP_OK)
{
ESP_LOGE(TAG, "store_set_u8_best_effort(enabled) failed: %s", esp_err_to_name(e));
return;
}
(void)store_flush_best_effort();
enabled = value;
}
void ocpp_set_server(char *value)
{
storage_init_best_effort();
ESP_LOGI(TAG, "set server %s", value ? value : "(null)");
esp_err_t e = store_set_str_best_effort(NVS_NAMESPACE, NVS_OCPP_SERVER, value ? value : "");
if (e != ESP_OK)
{
ESP_LOGE(TAG, "store_set_str_best_effort(server) failed: %s", esp_err_to_name(e));
return;
}
(void)store_flush_best_effort();
}
void ocpp_set_charge_id(char *value)
{
storage_init_best_effort();
ESP_LOGI(TAG, "set charge_id %s", value ? value : "(null)");
esp_err_t e = store_set_str_best_effort(NVS_NAMESPACE, NVS_OCPP_CHARGE_ID, value ? value : "");
if (e != ESP_OK)
{
ESP_LOGE(TAG, "store_set_str_best_effort(charge_id) failed: %s", esp_err_to_name(e));
return;
}
(void)store_flush_best_effort();
}
// -----------------------------------------------------------------------------
// Event handlers (AUTH / EVSE / METER)
// -----------------------------------------------------------------------------
static void ocpp_on_auth_verify(void *arg, esp_event_base_t base, int32_t id, void *event_data)
{
(void)arg;
(void)base;
(void)id;
const auth_tag_verify_event_t *rq = (const auth_tag_verify_event_t *)event_data;
if (!rq)
return;
char idtag[AUTH_TAG_MAX_LEN];
if (rq->tag[0] == '\0')
{
strncpy(idtag, "IDTAG", sizeof(idtag));
idtag[sizeof(idtag) - 1] = '\0';
}
else
{
strncpy(idtag, rq->tag, sizeof(idtag) - 1);
idtag[sizeof(idtag) - 1] = '\0';
}
ESP_LOGI(TAG, "AUTH_EVENT_TAG_VERIFY: tag=%s req_id=%u", idtag, (unsigned)rq->req_id);
if (!enabled || g_ocpp_conn == NULL)
{
ESP_LOGW(TAG, "OCPP not ready (enabled=%d, conn=%p) ignoring verify",
enabled, (void *)g_ocpp_conn);
return;
}
if (ocpp_isTransactionActive())
{
ESP_LOGI(TAG, "Transaction active -> ocpp_end_transaction(\"%s\")", idtag);
ocpp_endTransaction(idtag, "Local");
}
else
{
ESP_LOGI(TAG, "No active transaction -> ocpp_begin_transaction(\"%s\")", idtag);
ocpp_beginTransaction(idtag);
}
}
static void evse_event_handler(void *arg, esp_event_base_t base, int32_t id, void *data)
{
(void)arg;
if (base != EVSE_EVENTS || id != EVSE_EVENT_STATE_CHANGED || data == NULL)
return;
const evse_state_event_data_t *evt = (const evse_state_event_data_t *)data;
ESP_LOGI(TAG, "EVSE event received: state = %d", (int)evt->state);
switch (evt->state)
{
case EVSE_STATE_EVENT_IDLE:
s_ev_plugged = false;
s_ev_ready = false;
break;
case EVSE_STATE_EVENT_WAITING:
s_ev_plugged = true;
s_ev_ready = false;
break;
case EVSE_STATE_EVENT_CHARGING:
s_ev_plugged = true;
s_ev_ready = true;
break;
case EVSE_STATE_EVENT_FAULT:
default:
s_ev_ready = false;
break;
}
}
static void evse_enable_available_handler(void *arg, esp_event_base_t base, int32_t id, void *data)
{
(void)arg;
if (base != EVSE_EVENTS || data == NULL)
return;
if (id == EVSE_EVENT_ENABLE_UPDATED)
{
const evse_enable_event_data_t *e = (const evse_enable_event_data_t *)data;
s_evse_enabled = e->enabled;
ESP_LOGI(TAG, "[EVSE] ENABLE_UPDATED: enabled=%d (ts=%lld)",
(int)e->enabled, (long long)e->timestamp_us);
return;
}
if (id == EVSE_EVENT_AVAILABLE_UPDATED)
{
const evse_available_event_data_t *e = (const evse_available_event_data_t *)data;
s_evse_available = e->available;
ESP_LOGI(TAG, "[EVSE] AVAILABLE_UPDATED: available=%d (ts=%lld)",
(int)e->available, (long long)e->timestamp_us);
return;
}
}
static void on_meter_event(void *arg, esp_event_base_t base, int32_t id, void *data)
{
(void)arg;
if (base != METER_EVENT || id != METER_EVENT_DATA_READY || !data)
return;
const meter_event_data_t *evt = (const meter_event_data_t *)data;
if (!evt->source || strcmp(evt->source, "EVSE") != 0)
return;
int32_t sum_w = (int32_t)evt->watt[0] + (int32_t)evt->watt[1] + (int32_t)evt->watt[2];
float avg_v = (evt->vrms[0] + evt->vrms[1] + evt->vrms[2]) / 3.0f;
float sum_i = evt->irms[0] + evt->irms[1] + evt->irms[2];
portENTER_CRITICAL(&s_meter_mux);
memcpy(s_meter.vrms, evt->vrms, sizeof(s_meter.vrms));
memcpy(s_meter.irms, evt->irms, sizeof(s_meter.irms));
s_meter.watt[0] = evt->watt[0];
s_meter.watt[1] = evt->watt[1];
s_meter.watt[2] = evt->watt[2];
s_meter.frequency = evt->frequency;
s_meter.power_factor = evt->power_factor;
s_meter.total_energy_Wh = evt->total_energy;
s_meter.sum_watt = sum_w;
s_meter.avg_voltage = avg_v;
s_meter.sum_current = sum_i;
s_meter.have_data = true;
portEXIT_CRITICAL(&s_meter_mux);
}
// -----------------------------------------------------------------------------
// MicroOCPP Inputs/CBs
// -----------------------------------------------------------------------------
bool setConnectorPluggedInput(void)
{
return s_ev_plugged;
}
bool setEvReadyInput(void)
{
return s_ev_ready;
}
bool setEvseReadyInput(void)
{
return s_evse_enabled && s_evse_available;
}
float setPowerMeterInput(void)
{
int32_t w = 0;
bool have = false;
portENTER_CRITICAL(&s_meter_mux);
have = s_meter.have_data;
if (have)
w = s_meter.sum_watt;
portEXIT_CRITICAL(&s_meter_mux);
if (!have)
ESP_LOGW(TAG, "[METER] PowerMeterInput: no data (return 0)");
else
ESP_LOGD(TAG, "[METER] PowerMeterInput: %" PRId32 " W", w);
return (float)w;
}
float setEnergyMeterInput(void)
{
float wh = 0.0f;
bool have = false;
portENTER_CRITICAL(&s_meter_mux);
have = s_meter.have_data;
if (have)
wh = s_meter.total_energy_Wh;
portEXIT_CRITICAL(&s_meter_mux);
if (!have)
ESP_LOGW(TAG, "[METER] EnergyMeterInput: no data (return 0)");
else
ESP_LOGD(TAG, "[METER] EnergyMeterInput: (%.1f Wh)", wh);
return wh;
}
int setEnergyInput(void)
{
float wh = setEnergyMeterInput();
int wh_i = (int)lrintf((double)wh);
ESP_LOGD(TAG, "[METER] EnergyInput: %.1f Wh", wh);
return wh_i;
}
float setCurrentInput(void)
{
float a = 0.0f;
bool have = false;
portENTER_CRITICAL(&s_meter_mux);
have = s_meter.have_data;
if (have)
a = s_meter.sum_current;
portEXIT_CRITICAL(&s_meter_mux);
if (!have)
ESP_LOGW(TAG, "[METER] CurrentInput: no data (return 0)");
else
ESP_LOGD(TAG, "[METER] CurrentInput: %.2f A (total)", a);
return a;
}
float setVoltageInput(void)
{
float v = 0.0f;
bool have = false;
portENTER_CRITICAL(&s_meter_mux);
have = s_meter.have_data;
if (have)
v = s_meter.avg_voltage;
portEXIT_CRITICAL(&s_meter_mux);
if (!have)
ESP_LOGW(TAG, "[METER] VoltageInput: no data (return 0)");
else
ESP_LOGD(TAG, "[METER] VoltageInput: %.1f V (avg)", v);
return v;
}
float setPowerInput(void)
{
float w = setPowerMeterInput();
ESP_LOGD(TAG, "[METER] PowerInput: %.1f W", w);
return w;
}
float setTemperatureInput(void)
{
ESP_LOGD(TAG, "TemperatureInput");
return 16.5f;
}
void setSmartChargingCurrentOutput(float limit)
{
ESP_LOGI(TAG, "SmartChargingCurrentOutput: %.0f", limit);
}
void setSmartChargingPowerOutput(float limit)
{
ESP_LOGI(TAG, "SmartChargingPowerOutput: %.0f", limit);
}
void setSmartChargingOutput(float power, float current, int nphases)
{
ESP_LOGI(TAG, "SmartChargingOutput: P=%.0f W, I=%.0f A, phases=%d", power, current, nphases);
}
void setGetConfiguration(const char *payload, size_t len)
{
ESP_LOGI(TAG, "GetConfiguration: %.*s (%u)", (int)len, payload, (unsigned)len);
}
void setStartTransaction(const char *payload, size_t len)
{
ESP_LOGI(TAG, "StartTransaction: %.*s (%u)", (int)len, payload, (unsigned)len);
}
void setChangeConfiguration(const char *payload, size_t len)
{
ESP_LOGI(TAG, "ChangeConfiguration: %.*s (%u)", (int)len, payload, (unsigned)len);
}
void OnResetExecute(bool state)
{
ESP_LOGI(TAG, "OnResetExecute (state=%d)", state);
esp_restart();
}
bool setOccupiedInput(void)
{
ESP_LOGD(TAG, "setOccupiedInput");
return false;
}
bool setStartTxReadyInput(void)
{
ESP_LOGD(TAG, "setStartTxReadyInput");
return true;
}
bool setStopTxReadyInput(void)
{
ESP_LOGD(TAG, "setStopTxReadyInput");
return true;
}
bool setOnResetNotify(bool value)
{
ESP_LOGI(TAG, "setOnResetNotify %d", value);
return true;
}
void notificationOutput(OCPP_Transaction *transaction, enum OCPP_TxNotification txNotification)
{
(void)transaction;
ESP_LOGI(TAG, "TxNotification: %d", txNotification);
switch (txNotification)
{
case Authorized:
ESP_LOGI(TAG, "Authorized");
esp_event_post(OCPP_EVENTS, OCPP_EVENT_AUTHORIZED, NULL, 0, portMAX_DELAY);
break;
case AuthorizationRejected:
ESP_LOGI(TAG, "AuthorizationRejected");
esp_event_post(OCPP_EVENTS, OCPP_EVENT_AUTH_REJECTED, NULL, 0, portMAX_DELAY);
break;
case AuthorizationTimeout:
ESP_LOGI(TAG, "AuthorizationTimeout");
esp_event_post(OCPP_EVENTS, OCPP_EVENT_AUTH_TIMEOUT, NULL, 0, portMAX_DELAY);
break;
case ReservationConflict:
ESP_LOGI(TAG, "ReservationConflict");
break;
case ConnectionTimeout:
ESP_LOGI(TAG, "ConnectionTimeout");
break;
case DeAuthorized:
ESP_LOGI(TAG, "DeAuthorized");
break;
case RemoteStart:
ESP_LOGI(TAG, "RemoteStart");
esp_event_post(OCPP_EVENTS, OCPP_EVENT_REMOTE_START, NULL, 0, portMAX_DELAY);
break;
case RemoteStop:
ESP_LOGI(TAG, "RemoteStop");
esp_event_post(OCPP_EVENTS, OCPP_EVENT_REMOTE_STOP, NULL, 0, portMAX_DELAY);
break;
case StartTx:
ESP_LOGI(TAG, "StartTx");
esp_event_post(OCPP_EVENTS, OCPP_EVENT_START_TX, NULL, 0, portMAX_DELAY);
break;
case StopTx:
ESP_LOGI(TAG, "StopTx");
esp_event_post(OCPP_EVENTS, OCPP_EVENT_STOP_TX, NULL, 0, portMAX_DELAY);
break;
}
}
bool ocpp_is_connected(void)
{
return g_ocpp_conn != NULL;
}
const char *addErrorCodeInput(void)
{
const char *ptr = NULL;
uint32_t error = evse_get_error();
if (error & EVSE_ERR_PILOT_FAULT_BIT)
ptr = "InternalError";
else if (error & EVSE_ERR_DIODE_SHORT_BIT)
ptr = "InternalError";
else if (error & EVSE_ERR_LOCK_FAULT_BIT)
ptr = "ConnectorLockFailure";
else if (error & EVSE_ERR_UNLOCK_FAULT_BIT)
ptr = "ConnectorLockFailure";
else if (error & EVSE_ERR_RCM_TRIGGERED_BIT)
ptr = "OtherError";
else if (error & EVSE_ERR_RCM_SELFTEST_FAULT_BIT)
ptr = "OtherError";
else if (error & EVSE_ERR_TEMPERATURE_HIGH_BIT)
ptr = "HighTemperature";
else if (error & EVSE_ERR_TEMPERATURE_FAULT_BIT)
ptr = "OtherError";
return ptr;
}
// -----------------------------------------------------------------------------
// Start / Stop OCPP
// -----------------------------------------------------------------------------
void ocpp_start(void)
{
ESP_LOGI(TAG, "Starting OCPP");
if (ocpp_task != NULL)
{
ESP_LOGW(TAG, "OCPP already running");
return;
}
storage_init_best_effort();
enabled = ocpp_get_enabled();
if (!enabled)
{
ESP_LOGW(TAG, "OCPP disabled");
return;
}
char serverstr[64] = {0};
ocpp_get_server(serverstr);
if (serverstr[0] == '\0')
{
ESP_LOGW(TAG, "No OCPP server configured. Skipping connection.");
return;
}
char charge_id[64] = {0};
ocpp_get_charge_id(charge_id);
if (charge_id[0] == '\0')
{
ESP_LOGW(TAG, "No OCPP charge_id configured. Skipping connection.");
return;
}
mg_mgr_init(&mgr);
mg_log_set(MG_LL_ERROR);
struct OCPP_FilesystemOpt fsopt = {.use = true, .mount = true, .formatFsOnFail = true};
g_ocpp_conn = ocpp_makeConnection(&mgr,
serverstr,
charge_id,
"",
"",
fsopt);
if (!g_ocpp_conn)
{
ESP_LOGE(TAG, "ocpp_makeConnection failed");
mg_mgr_free(&mgr);
return;
}
ocpp_initialize(g_ocpp_conn, "EPower M1", "Plixin", fsopt, false);
ocpp_setEvReadyInput(&setEvReadyInput);
ocpp_setEvseReadyInput(&setEvseReadyInput);
ocpp_setConnectorPluggedInput(&setConnectorPluggedInput);
ocpp_setOnResetExecute(&OnResetExecute);
ocpp_setTxNotificationOutput(&notificationOutput);
ocpp_setStopTxReadyInput(&setStopTxReadyInput);
ocpp_setOnResetNotify(&setOnResetNotify);
ocpp_setEnergyMeterInput(&setEnergyInput);
ocpp_addMeterValueInputFloat(&setCurrentInput, "Current.Import", "A", NULL, NULL);
ocpp_addMeterValueInputFloat(&getCurrentOffered, "Current.Offered", "A", NULL, NULL);
ocpp_addMeterValueInputFloat(&setVoltageInput, "Voltage", "V", NULL, NULL);
ocpp_addMeterValueInputFloat(&setTemperatureInput, "Temperature", "Celsius", NULL, NULL);
ocpp_addMeterValueInputFloat(&setPowerMeterInput, "Power.Active.Import", "W", NULL, NULL);
ocpp_addMeterValueInputFloat(&setEnergyMeterInput, "Energy.Active.Import.Register", "Wh", NULL, NULL);
ocpp_addErrorCodeInput(&addErrorCodeInput);
xTaskCreate(ocpp_task_func, "ocpp_task", 5 * 1024, NULL, 3, &ocpp_task);
if (!s_auth_verify_inst)
{
ESP_ERROR_CHECK(esp_event_handler_instance_register(
AUTH_EVENTS, AUTH_EVENT_TAG_VERIFY,
&ocpp_on_auth_verify, NULL, &s_auth_verify_inst));
ESP_LOGI(TAG, "Registered AUTH_EVENT_TAG_VERIFY listener");
}
if (!s_evse_state_inst)
{
ESP_ERROR_CHECK(esp_event_handler_instance_register(
EVSE_EVENTS, EVSE_EVENT_STATE_CHANGED,
&evse_event_handler, NULL, &s_evse_state_inst));
}
if (!s_evse_enable_inst)
{
ESP_ERROR_CHECK(esp_event_handler_instance_register(
EVSE_EVENTS, EVSE_EVENT_ENABLE_UPDATED,
&evse_enable_available_handler, NULL, &s_evse_enable_inst));
}
if (!s_evse_available_inst)
{
ESP_ERROR_CHECK(esp_event_handler_instance_register(
EVSE_EVENTS, EVSE_EVENT_AVAILABLE_UPDATED,
&evse_enable_available_handler, NULL, &s_evse_available_inst));
}
if (!s_meter_inst)
{
ESP_ERROR_CHECK(esp_event_handler_instance_register(
METER_EVENT, METER_EVENT_DATA_READY,
&on_meter_event, NULL, &s_meter_inst));
ESP_LOGI(TAG, "Registered METER_EVENT_DATA_READY listener (EVSE source)");
}
}
void ocpp_stop(void)
{
ESP_LOGI(TAG, "Stopping OCPP");
if (ocpp_task)
{
vTaskDelete(ocpp_task);
ocpp_task = NULL;
}
ocpp_deinitialize();
if (g_ocpp_conn)
{
ocpp_deinitConnection(g_ocpp_conn);
g_ocpp_conn = NULL;
}
mg_mgr_free(&mgr);
if (s_auth_verify_inst)
{
ESP_ERROR_CHECK(esp_event_handler_instance_unregister(
AUTH_EVENTS, AUTH_EVENT_TAG_VERIFY, s_auth_verify_inst));
s_auth_verify_inst = NULL;
}
if (s_evse_state_inst)
{
ESP_ERROR_CHECK(esp_event_handler_instance_unregister(
EVSE_EVENTS, EVSE_EVENT_STATE_CHANGED, s_evse_state_inst));
s_evse_state_inst = NULL;
}
if (s_evse_enable_inst)
{
ESP_ERROR_CHECK(esp_event_handler_instance_unregister(
EVSE_EVENTS, EVSE_EVENT_ENABLE_UPDATED, s_evse_enable_inst));
s_evse_enable_inst = NULL;
}
if (s_evse_available_inst)
{
ESP_ERROR_CHECK(esp_event_handler_instance_unregister(
EVSE_EVENTS, EVSE_EVENT_AVAILABLE_UPDATED, s_evse_available_inst));
s_evse_available_inst = NULL;
}
if (s_meter_inst)
{
ESP_ERROR_CHECK(esp_event_handler_instance_unregister(
METER_EVENT, METER_EVENT_DATA_READY, s_meter_inst));
s_meter_inst = NULL;
}
}