#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 #include //C-facade of MicroOcpp #include //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("AO_FreeVendActive", true, CONFIGURATION_FN, true, true, true, true); freevendIdTag = ArduinoOcpp::declareConfiguration("AO_FreeVendIdTag", "DefaultIdTag", CONFIGURATION_FN, true, true, true, true); */ // allowOfflineTxForUnknownId = ArduinoOcpp::declareConfiguration("AllowOfflineTxForUnknownId", true, CONFIGURATION_FN, true, true, true, true); // silentOfflineTx = ArduinoOcpp::declareConfiguration("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(¬ificationOutput); // 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, 5, &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); }