Files
chargeflow/components/ocpp/src/ocpp.c
2025-06-14 11:46:10 +01:00

551 lines
14 KiB
C
Executable File

#include "esp_log.h"
#include "ocpp.h"
#include "evse_api.h"
#include "evse_error.h"
#include "evse_state.h"
#include "esp_wifi.h"
#include "nvs.h"
/* MicroOcpp includes */
#include <mongoose.h>
#include <MicroOcpp_c.h> //C-facade of MicroOcpp
#include <MicroOcppMongooseClient_c.h> //WebSocket integration for ESP-IDF
#define NVS_NAMESPACE "ocpp"
#define NVS_OCPP_AUTHORIZATION "authorization"
#define NVS_OCPP_ENABLED "enabled"
#define NVS_OCPP_SERVER "ocpp_server"
#define NVS_OCPP_RFID "ocpp_rfid"
#define AP_SSID "PLX-%02x%02x%02x"
static nvs_handle nvs;
static const char *TAG = "ocpp";
static bool enabled = true;
static bool authorization = false;
// static bool connector_plugged = false;
// static bool is_charging = false;
static TaskHandle_t ocpp_task = NULL;
static struct mg_mgr mgr; // Event manager
static void ocpp_task_func(void *param)
{
while (true)
{
// if (enabled)
{
mg_mgr_poll(&mgr, 10);
ocpp_loop();
if (evse_is_enabled() != ocpp_isOperative())
{
printf("ocpp_isOperative()");
evse_set_enabled(ocpp_isOperative());
}
}
vTaskDelay(pdMS_TO_TICKS(500));
}
}
bool ocpp_get_enabled(void)
{
uint8_t value = false;
nvs_get_u8(nvs, NVS_OCPP_ENABLED, &value);
ESP_LOGI(TAG, "Ocpp get enabled %d", value);
return value;
}
bool ocpp_get_authorization(void)
{
uint8_t value = false;
nvs_get_u8(nvs, NVS_OCPP_AUTHORIZATION, &value);
ESP_LOGI(TAG, "Ocpp get authorization %d", value);
return value;
}
void ocpp_get_server(char *value)
{
size_t len = 64;
value[0] = '\0';
nvs_get_str(nvs, NVS_OCPP_SERVER, value, &len);
ESP_LOGI(TAG, "Ocpp get server %s", value);
}
void ocpp_get_rfid(char *value)
{
size_t len = 64;
value[0] = '\0';
nvs_get_str(nvs, NVS_OCPP_RFID, value, &len);
ESP_LOGI(TAG, "Ocpp get rfid %s", value);
}
void ocpp_set_authorization(bool value)
{
ESP_LOGI(TAG, "Ocpp set authorization %d", value);
nvs_set_u8(nvs, NVS_OCPP_ENABLED, value);
nvs_commit(nvs);
authorization = value;
}
void ocpp_set_enabled(bool value)
{
ESP_LOGI(TAG, "Ocpp set enabled %d", value);
nvs_set_u8(nvs, NVS_OCPP_ENABLED, value);
nvs_commit(nvs);
enabled = value;
}
void ocpp_set_server(char *value)
{
ESP_LOGI(TAG, "Ocpp set server %s", value);
nvs_set_str(nvs, NVS_OCPP_SERVER, value);
nvs_commit(nvs);
}
void ocpp_set_rfid(char *value)
{
ESP_LOGI(TAG, "Ocpp set rfid %s", value);
nvs_set_str(nvs, NVS_OCPP_RFID, value);
nvs_commit(nvs);
}
bool setConnectorPluggedInput()
{
// ESP_LOGI(TAG, "setConnectorPluggedInput");
return evse_is_connector_plugged(evse_get_state());
// return true;
}
bool setEvReadyInput()
{
// ESP_LOGI(TAG, "EvReadyInput");
return evse_state_is_charging(evse_get_state());
// return is_charging;
}
bool setEvseReadyInput()
{
// ESP_LOGI(TAG, "EvseReadyInput");
return evse_is_enabled();
// return false;
}
float setPowerMeterInput()
{
ESP_LOGI(TAG, "PowerMeterInput");
//MeterData data = meter_getData();
//return data.wattA + data.wattB + data.wattC;
return 0.0f;
}
float setEnergyMeterInput()
{
ESP_LOGI(TAG, "EnergyMeterInput");
// Exemplo com valor fixo (pode ser substituído depois)
return 3600.0f;
}
int setEnergyInput()
{
ESP_LOGI(TAG, "EnergyInput");
// Exemplo com valor fixo
return 3600;
}
float setCurrentInput()
{
ESP_LOGI(TAG, "CurrentInput");
/*
if (!meter_is_running()) {
ESP_LOGW(TAG, "Meter not running, returning fallback.");
return 0.0f;
}
MeterData data = meter_getData();
return data.irmsA;
*/
return 0;
}
float setVoltageInput()
{
ESP_LOGI(TAG, "VoltageInput");
/*
if (!meter_is_running()) {
ESP_LOGW(TAG, "Meter not running, returning fallback.");
return 0.0f;
}
MeterData data = meter_getData();
return data.vrmsA;
*/
return 0.0f;
}
float setTemperatureInput()
{
ESP_LOGI(TAG, "TemperatureInput");
return 16.5f;
}
float setPowerInput()
{
ESP_LOGI(TAG, "PowerInput");
// return (float)orno_modbus_get_meter_state().activepower;
//return meter_getData().wattA + meter_getData().wattB + meter_getData().wattC;
return 0;
}
void setSmartChargingCurrentOutput(float limit)
{
ESP_LOGI(TAG, "SmartChargingCurrentOutput: %.0f\n", limit);
};
void setSmartChargingPowerOutput(float limit)
{
ESP_LOGI(TAG, "SmartChargingPowerOutput: %.0f\n", limit);
};
void setSmartChargingOutput(float power, float current, int nphases)
{
ESP_LOGI(TAG, " SmartChargingOutput: %.0f %.0f \n", power, current);
};
void setGetConfiguration(const char *payload, size_t len)
{
ESP_LOGI(TAG, " setGetConfiguration: %s %d \n", payload, len);
}
void setStartTransaction(const char *payload, size_t len)
{
ESP_LOGI(TAG, " setStartTransaction: %s %d \n", payload, len);
}
void setChangeConfiguration(const char *payload, size_t len)
{
ESP_LOGI(TAG, " setChangeConfiguration: %s %d \n", payload, len);
}
void OnResetExecute(bool state)
{
ESP_LOGI(TAG, "#### OnResetExecute");
//esp_restart();
}
bool setOccupiedInput()
{
ESP_LOGI(TAG, "setOccupiedInput");
return false;
}
bool setStartTxReadyInput()
{
ESP_LOGI(TAG, "!!!!!! StartTxReadyInput");
return false;
}
bool setStopTxReadyInput()
{
ESP_LOGI(TAG, "===== StopTxReadyInput");
return true;
}
/*
enum OptionalBool setOnUnlockConnectorInOut()
{
ESP_LOGI(TAG, "***** OnUnlockConnectorInOut");
return OptionalTrue;
}*/
bool setOnResetNotify(bool value)
{
ESP_LOGI(TAG, "!!!!!! setOnResetNotify %d", value);
return true;
}
void notificationOutput(OCPP_Transaction *transaction, enum OCPP_TxNotification txNotification)
{
ESP_LOGI(TAG, "Set notificationOutput ----> %d", txNotification);
switch (txNotification)
{
// Authorization events
case Authorized:
ESP_LOGI(TAG, "<----------- Authorized ---------->");
//evse_authorize();
// is_charging = true;
break; // success
case AuthorizationRejected:
ESP_LOGI(TAG, "AuthorizationRejected ---->");
break; // IdTag not authorized
case AuthorizationTimeout:
ESP_LOGI(TAG, "AuthorizationTimeout ---->");
break; // authorization failed - offline
case ReservationConflict:
ESP_LOGI(TAG, "ReservationConflict ---->");
break; // connector reserved for other IdTag
case ConnectionTimeout:
ESP_LOGI(TAG, "ConnectionTimeout ---->");
break; // user took to long to plug vehicle after the authorization
case DeAuthorized:
ESP_LOGI(TAG, "DeAuthorized ---->");
//evse_set_authorized(false);
//evse_set_limit_reached(2);
// ocpp_set_charging(false);
break; // server rejected StartTx
case RemoteStart:
ESP_LOGI(TAG, "RemoteStart ---->");
break; // authorized via RemoteStartTransaction
case RemoteStop:
ESP_LOGI(TAG, "RemoteStop ---->");
break; // stopped via RemoteStopTransaction
// Tx lifecycle events
case StartTx:
ESP_LOGI(TAG, "StartTx ---->");
break;
case StopTx:
// is_charging = false;
ESP_LOGI(TAG, "StopTx ---->");
//evse_set_authorized(false);
//evse_set_limit_reached(2);
break;
};
}
const char *addErrorCodeInput()
{
// ESP_LOGI(TAG, "AddErrorCodeInput");
char *ptr = NULL;
uint32_t error = 0; // evse_get_error();
// ESP_LOGI(TAG, "AddErrorCodeInput %" PRIu32 "", 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;
}
void ocpp_begin_transaction(char *value)
{
ocpp_beginTransaction(value);
}
void ocpp_end_transaction(char *value)
{
ocpp_endTransaction(value, "Local");
}
void ocpp_begin_transaction_authorized(char *value)
{
ocpp_beginTransaction_authorized(value, NULL);
}
void ocpp_end_transaction_authorized(char *value)
{
ocpp_endTransaction_authorized(value, "Local");
}
bool ocpp_is_TransactionActive()
{
return ocpp_isTransactionActive();
}
void ocpp_start()
{
ESP_LOGI(TAG, "Starting ocpp");
ESP_ERROR_CHECK(nvs_open(NVS_NAMESPACE, NVS_READWRITE, &nvs));
// enabled = ocpp_get_enabled();
authorization = ocpp_get_authorization();
char serverstr[64];
ocpp_get_server(serverstr);
char rfidstr[64];
ocpp_get_rfid(rfidstr);
/* Initialize Mongoose (necessary for MicroOcpp)*/
// struct mg_mgr mgr; // Event manager
mg_mgr_init(&mgr); // Initialise event manager
mg_log_set(MG_LL_ERROR); // Set log level
/* Initialize MicroOcpp */
struct OCPP_FilesystemOpt fsopt = {.use = true, .mount = true, .formatFsOnFail = true};
char chargeid[12];
uint8_t mac[6];
esp_wifi_get_mac(ESP_IF_WIFI_AP, mac);
sprintf((char *)chargeid, AP_SSID, mac[3], mac[4], mac[5]);
char *urlid = (char *)malloc(62 * sizeof(char));
sprintf(urlid, "%s", strupr(chargeid));
//"ws://192.168.1.164:3000",
// ws://192.168.1.115:8010/OCPP16/5c866e81a2d9593de43efdb4/6750f0235b1b277aa16caf19
OCPP_Connection *osock = ocpp_makeConnection(&mgr,
"ws://192.168.2.217:8010/OCPP16/5c866e81a2d9593de43efdb4/6750f0235b1b277aa16caf19/",
"Plx_00AA1",
"",
"", fsopt);
ocpp_initialize(osock, "EPower M1", "Plixin", fsopt, false);
// ocpp_authorize()
// ocpp_authorize(rfidstr,NULL,NULL,NULL,NULL,NULL);
// ocpp_authorize("2D3CF08E", NULL, NULL, NULL, NULL, NULL);
// 2D3CF08E
/*
* Load OCPP configs. Default values will be overwritten by OpenEVSE configs. Mark configs
* to require reboot if changed via OCPP server
freevendActive = ArduinoOcpp::declareConfiguration<bool>("AO_FreeVendActive", true, CONFIGURATION_FN, true, true, true, true);
freevendIdTag = ArduinoOcpp::declareConfiguration<const char*>("AO_FreeVendIdTag", "DefaultIdTag", CONFIGURATION_FN, true, true, true, true);
*/
// allowOfflineTxForUnknownId = ArduinoOcpp::declareConfiguration<bool>("AllowOfflineTxForUnknownId", true, CONFIGURATION_FN, true, true, true, true);
// silentOfflineTx = ArduinoOcpp::declareConfiguration<bool>("AO_SilentOfflineTransactions", true, CONFIGURATION_FN, true, true, true, true);
/*
//when the OCPP server updates the configs, the following callback will apply them to the OpenEVSE configs
setOnReceiveRequest("ChangeConfiguration", [this] (JsonObject) {
config_set("ocpp_auth_auto", (uint32_t) (*freevendActive ? 1 : 0));
config_set("ocpp_idtag", String((const char*) *freevendIdTag));
config_set("ocpp_auth_offline", (uint32_t) (*allowOfflineTxForUnknownId ? 1 : 0));
config_commit();
});
*/
// ocpp_set_authorization
// ocpp_setEnergyMeterInput(&setEnergyInput);
// ocpp_setPowerMeterInput(&setPowerMeterInput);
ocpp_setEvReadyInput(&setEvReadyInput);
ocpp_setEvseReadyInput(&setEvseReadyInput);
ocpp_setSmartChargingCurrentOutput(&setSmartChargingCurrentOutput);
ocpp_setSmartChargingPowerOutput(&setSmartChargingPowerOutput);
ocpp_setSmartChargingOutput(&setSmartChargingOutput);
ocpp_setConnectorPluggedInput(&setConnectorPluggedInput);
ocpp_setOnResetExecute(&OnResetExecute);
ocpp_setTxNotificationOutput(&notificationOutput);
// ocpp_setStartTxReadyInput(&setStartTxReadyInput);
ocpp_setStopTxReadyInput(&setStopTxReadyInput);
// ocpp_setOnUnlockConnectorInOut(&setOnUnlockConnectorInOut);
// ocpp_setOccupiedInput(&setOccupiedInput);
ocpp_addMeterValueInputFloat(&setCurrentInput, "Current.Import", "A", NULL, NULL);
ocpp_addMeterValueInputFloat(&setCurrentInput, "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", "W", NULL, NULL);
ocpp_addErrorCodeInput(&addErrorCodeInput);
ocpp_setOnResetNotify(&setOnResetNotify);
// ocpp_setOnResetExecute(void (*onResetExecute)(bool));
// ocpp_setOnReceiveRequest(const char *operationType, OnMessage onRequest);
// ocpp_setOnSendConf(const char *operationType, OnMessage onConfirmation);
// when the OCPP server updates the configs, the following callback will apply them to the OpenEVSE configs
// ocpp_setOnReceiveRequest("ChangeConfiguration", &setChangeConfiguration);
// ocpp_setOnReceiveRequest("GetConfiguration", &setGetConfiguration);
// ocpp_setOnReceiveRequest("StartTransaction", &setStartTransaction);
xTaskCreate(ocpp_task_func, "ocpp_task", 5 * 1024, NULL, 4, &ocpp_task);
}
void ocpp_stop(void)
{
ESP_LOGI(TAG, "Stopping");
if (ocpp_task)
{
vTaskDelete(ocpp_task);
ocpp_task = NULL;
}
/* Deallocate ressources */
ocpp_deinitialize();
// ocpp_deinitConnection(osock);
mg_mgr_free(&mgr);
}