### Load Setup Content Source: https://github.com/chargelab/openocpp/blob/main/demo-esp32/main/web/web_index.html Fetches setup content from the '/setup' endpoint and updates the 'content' div. Ensures any scripts within the loaded content are executed and updates the page title. ```javascript function loadSetup() { fetch("/setup") .then(response => response.text()) .then(text => { document.getElementById("content").innerHTML = text; executeScriptElements(document.getElementById("content")); document.title = "Charger Simulator - Setup"; }) .catch(error => { document.getElementById("content").innerHTML = error; }); } ``` -------------------------------- ### Install ESP-IDF Prerequisites on Ubuntu Source: https://github.com/chargelab/openocpp/blob/main/README.md Installs necessary packages for the ESP-IDF toolchain on an Ubuntu system. Ensure you have git, wget, and build tools installed. ```shell sudo apt-get install git wget flex bison gperf python3 python3-pip python3-venv cmake ninja-build ccache libffi-dev libssl-dev dfu-util libusb-1.0-0 ``` -------------------------------- ### Download and Set Up ESP-IDF Source: https://github.com/chargelab/openocpp/blob/main/README.md Clones the specified version of the ESP-IDF repository and sets up the necessary tools for ESP32 development. This script should be run from the desired installation directory. ```shell mkdir -p ~/esp cd ~/esp git clone -b v5.2.5 --recursive https://github.com/espressif/esp-idf.git cd ~/esp/esp-idf ./install.sh esp32 ``` -------------------------------- ### Submit setup data to server Source: https://github.com/chargelab/openocpp/blob/main/demo-esp32/main/web/web_setup.html Submits the configuration data (Wi-Fi, network URL, OCPP ID, protocol) to the server using a POST request. Updates the UI to the next step upon successful submission. ```javascript function submitData() { if (!checkFormValidation()) { return; } fetch("submitSetup", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ ssid: document.getElementById("wifi").value, password: document.getElementById("Password").value, networkUrl: document.getElementById("networkUrl").value, ocppId: document.getElementById("ocppId").value, ocppProtocol: document.getElementById("ocppProtocol").value }) }) .then(()=>{ document.getElementById("step1").style.display = "none"; document.getElementById("step2").style.display = "block"; }) .catch(error => { console.log("Submit failed with error: ", error); }); } ``` -------------------------------- ### Form validation logic Source: https://github.com/chargelab/openocpp/blob/main/demo-esp32/main/web/web_setup.html Validates the setup form, checking for password match and required fields like network URL and OCPP ID. Displays error messages if validation fails. ```javascript function checkFormValidation() { document.getElementById("networkUrlError").style.display = "none"; document.getElementById("ocppIdError").style.display = "none"; var valid = true; let password = document.getElementById("Password").value; let confirmPassword = document.getElementById("Confirmpassword").value; if (password !== "" && password !== confirmPassword) { document.getElementById("PasswordMatchError").style.display = "block"; valid = false; } else { document.getElementById("PasswordMatchError").style.display = "none"; } if (document.getElementById("networkUrl").value == "") { document.getElementById("networkUrlError").style.display = "block"; valid = false; } if (document.getElementById("ocppId").value == "") { document.getElementById("ocppIdError").style.display = "block"; valid = false; } return valid; } ``` -------------------------------- ### ESP32 CMake Project Setup Source: https://github.com/chargelab/openocpp/blob/main/demo-esp32/CMakeLists.txt Sets up the CMake build system for an ESP32 project. It defines the C++ standard, conditionally includes ESP-IDF build system components, and sets up project-specific include directories. ```cmake cmake_minimum_required(VERSION 3.5) set(CMAKE_CXX_STANDARD 17) if (ESP_PLATFORM) add_compile_definitions(JSON_NO_IO) include($ENV{IDF_PATH}/tools/cmake/project.cmake) project(TestFirmware LANGUAGES C CXX) include_directories($ENV{IDF_PATH}/components/freertos/include/esp_additions/freertos/) endif() ``` -------------------------------- ### Flash and Monitor OpenOCPP ESP32 Project Source: https://github.com/chargelab/openocpp/blob/main/README.md Flashes the built OpenOCPP project onto the ESP32 device connected to /dev/ttyUSB0 and starts monitoring the serial output. Assumes the device is connected and the ESP-IDF environment is activated. ```shell cd demo-esp32 . $HOME/esp/esp-idf/export.sh idf.py -p /dev/ttyUSB0 flash && idf.py -p /dev/ttyUSB0 monitor ``` -------------------------------- ### ESP32 Boot Log Output Source: https://github.com/chargelab/openocpp/blob/main/README.md Example output from the ESP32 bootloader, showing system information, partition table details, and compilation timestamps. This is typically seen when monitoring the device after flashing. ```text I (31) boot: ESP-IDF v5.2.3 2nd stage bootloader I (31) boot: compile time Feb 24 2025 10:14:06 I (31) boot: Multicore bootloader I (35) boot: chip revision: v3.0 I (39) boot.esp32: SPI Speed : 80MHz I (44) boot.esp32: SPI Mode : DIO I (48) boot.esp32: SPI Flash Size : 4MB I (53) boot: Enabling RNG early entropy source... I (58) boot: Partition Table: I (62) boot: ## Label Usage Type ST Offset Length I (69) boot: 0 nvs WiFi data 01 02 00009000 00003000 I (77) boot: 1 pmjournal Unknown data 01 06 0000c000 00002000 I (84) boot: 2 otadata OTA data 01 00 0000e000 00002000 I (92) boot: 3 app1 OTA app 00 11 00010000 001e0000 I (99) boot: 4 app0 OTA app 00 10 001f0000 001e0000 I (106) boot: 5 spiffs Unknown data 01 82 003d0000 0002f000 I (114) boot: 6 sernr NVS keys 01 04 003ff000 00001000 I (122) boot: End of partition table ... ``` -------------------------------- ### OCPP Firmware Update Flow and Configuration Source: https://context7.com/chargelab/openocpp/llms.txt Manages OCPP-driven OTA firmware updates, including download, verification, and installation. Configure default retry behavior for firmware updates. ```cpp // Configure update retry behavior: auto settings = platform->getSettings(); settings->FirmwareUpdateDefaultRetries.setValue(3); ``` -------------------------------- ### Utility function to get DOM element Source: https://github.com/chargelab/openocpp/blob/main/demo-esp32/main/web/web_setup.html A helper function to get an HTML element by its ID. Used for DOM manipulation. ```javascript function _el(s) { return document.getElementById(s); } ``` -------------------------------- ### Parse, Modify, and Stringify JSON with DOM API Source: https://github.com/chargelab/openocpp/blob/main/rapidjson/readme.md This example demonstrates basic usage of the DOM API. It parses a JSON string into a document, modifies a value, and then stringifies the document back into a JSON string. Error handling is omitted for brevity. ```cpp #include "rapidjson/document.h" #include "rapidjson/writer.h" #include "rapidjson/stringbuffer.h" #include using namespace rapidjson; int main() { // 1. Parse a JSON string into DOM. const char* json = "{\"project\":\"rapidjson\",\"stars\":10}"; Document d; d.Parse(json); // 2. Modify it by DOM. Value& s = d["stars"]; s.SetInt(s.GetInt() + 1); // 3. Stringify the DOM StringBuffer buffer; Writer writer(buffer); d.Accept(writer); // Output {"project":"rapidjson","stars":11} std::cout << buffer.GetString() << std::endl; return 0; } ``` -------------------------------- ### Build and Flash ESP32 Demo with ESP-IDF Source: https://context7.com/chargelab/openocpp/llms.txt Steps to set up ESP-IDF, build the demo-esp32 project, and flash it to an ESP32 device. Includes prerequisites and commands for building, flashing, and monitoring. ```shell # Prerequisites: install ESP-IDF v5.2.5 sudo apt-get install git wget flex bison gperf python3 python3-pip python3-venv \ cmake ninja-build ccache libffi-dev libssl-dev dfu-util libusb-1.0-0 mkdir -p ~/esp && cd ~/esp git clone -b v5.2.5 --recursive https://github.com/espressif/esp-idf.git cd ~/esp/esp-idf && ./install.sh esp32 # Activate the toolchain (required in every new terminal) . $HOME/esp/esp-idf/export.sh # Build the demo cd /path/to/openocpp/demo-esp32 idf.py build # Build output: demo-esp32/build/demo-esp32.bin (~1.7 MB) # Flash to ESP32 (adjust /dev/ttyUSB0 to your port) idf.py -p /dev/ttyUSB0 flash && idf.py -p /dev/ttyUSB0 monitor # Expected boot log: ``` -------------------------------- ### Initialize and Run StandardCharger on ESP32 Source: https://context7.com/chargelab/openocpp/llms.txt This snippet demonstrates the initialization of the OpenOCPP library on an ESP32 microcontroller. It sets up the platform, configures charger identity and backend settings, and creates the station hardware abstraction. The main loop continuously updates measurements and processes OCPP messages. ```cpp #include "openocpp/implementation/standard_charger.h" #include "openocpp/implementation/platform_esp.h" #include "openocpp/implementation/station_test_esp32.h" extern "C" void app_main(void) { // Set log level chargelab::logging::SetLogLevel(chargelab::logging::LogLevel::info); // Create the platform (ESP32-specific implementation of PlatformInterface) auto platform = std::make_shared(); // Configure charger identity in settings auto settings = platform->getSettings(); settings->ChargerVendor.setValue("AcmeCorp"); settings->ChargerModel.setValue("AC22kW"); settings->ChargerSerialNumber.setValue("SN-0001"); settings->ChargerFirmwareVersion.setValue("1.0.0"); // Set OCPP backend URL and protocol (OCPP 1.6 over WebSocket) settings->CentralSystemURL.setValue("wss://my-ocpp-backend.com"); settings->ChargePointId.setValue("CHARGER-001"); // Create the station hardware abstraction (test/demo implementation for ESP32) auto station = std::make_shared(platform); // Assemble the full charger stack auto charger = std::make_unique(platform, station); // Add a custom module after standard modules (e.g., a provisioning portal) // charger->addAfter(std::make_shared(...)); // Main loop: update hardware readings then drive the OCPP stack while (true) { station->updateMeasurements(); // Poll hardware sensors charger->runStep(); // Process all OCPP state machines using namespace std::chrono_literals; std::this_thread::sleep_for(100ms); } // Expected: charger sends BootNotification, receives Accepted, starts sending Heartbeats, // and is ready to handle RemoteStart/Stop and RFID tap transactions. } ``` -------------------------------- ### Initialize Connector Settings and Fetch Status Source: https://github.com/chargelab/openocpp/blob/main/demo-esp32/main/web/web_control.html Initializes connector settings and fetches the initial status of the charger. It populates the connector ID dropdown and then calls fetchAndFill to update the UI. ```javascript var simulateRfidRequest = null; var updateConnectorSettingsRequest = null; var lastStatusUpdate = null; // document.body.addEventListener('change', function(e) { // if (e.target.id === "") { // // } // if (e.target.type === "select-one") { // document.getElementById("message_result").innerHTML = ""; // return; // } // updateChanges(); // }); setTimeout(() => { fetch("getDeviceConfiguration", {signal: AbortSignal.timeout(1000)}) .then(response => response.text()) .then(text => { let obj = JSON.parse(text); let number_of_connectors = (obj || {})['numberOfConnectors'] || 0; let connector_id_select = document.getElementById("connector_id"); for (let i = 0; i < number_of_connectors; i++) { connector_id_select.options[i] = new Option(i+1, i+1); } }) .then(() => { setTimeout(fetchAndFill, 100); }) }, 100); ``` -------------------------------- ### Build OpenOCPP ESP32 Project Source: https://github.com/chargelab/openocpp/blob/main/README.md Builds the OpenOCPP project for the ESP32 target. Ensure the ESP-IDF environment is activated and navigate to the demo-esp32 directory before running. ```shell cd demo-esp32 . $HOME/esp/esp-idf/export.sh idf.py build ``` -------------------------------- ### Manage OCPP Settings Source: https://context7.com/chargelab/openocpp/llms.txt Read, write, and register custom settings. Persist changes to storage and load them on startup. Settings are backed by persistent storage and handle access policies. ```cpp #include "openocpp/common/settings.h" // Reading and writing settings auto settings = platform->getSettings(); // Standard OCPP 1.6 keys int heartbeat_interval = settings->HeartbeatInterval.getValue(); // default: 30s settings->HeartbeatInterval.setValue(60); bool allow_offline = settings->AllowOfflineTxForUnknownId.getValue(); settings->MeterValuesSampledData.setValue("Energy.Active.Import.Register,Current.Import"); settings->MeterValueSampleInterval.setValue(30); // sample every 30 seconds // Connection-transitioning settings (rolled back on failure to connect) settings->CentralSystemURL.setValue("wss://new-backend.example.com"); settings->ChargePointId.setValue("MY-CHARGER-42"); settings->BasicAuthPassword.setValue("mysecretpassword123"); // min 16 chars // Custom settings registration (for application-specific state) auto myFlag = std::make_shared( []() { return chargelab::SettingMetadata { "MyCustomFlag", chargelab::SettingConfig::rwPolicy(), std::nullopt, std::nullopt, chargelab::SettingBool::kTextFalse // default value }; }, [](auto const&) { return true; } // validator: always valid ); settings->registerCustomSetting(myFlag); myFlag->setValue(true); // Iterate all settings (e.g., for diagnostics) settings->visitSettings([](chargelab::SettingBase const& s) { // Prints: "HeartbeatInterval: 60", "AllowOfflineTxForUnknownId: true", etc. printf("%s: %s\n", s.getId().c_str(), s.getValueAsString().c_str()); }); // Persist modified settings to storage settings->saveIfModified(); // Load settings from persistent storage (call once on startup) settings->loadFromStorage(); ``` -------------------------------- ### Fetch OCPP 1.6 Parameters Source: https://github.com/chargelab/openocpp/blob/main/demo-esp32/main/web/web_config.html Retrieves a list of OCPP 1.6 configuration keys and their values from the server. Populates a map and a select dropdown with available parameters. ```javascript function fetchAndFillOcpp1_6_Parameter() { fetch("getOcppParameters") .then(response => response.json()) .then(payload => { const configKeys = payload?.rsp?.configurationKey; if (!configKeys) { console.warn("No configuration keys found in response."); return; } configKeys.forEach(item => { window.ocppParametersMap.set(item.key, { value: item.value, readonly: item.readonly }); }); const select = document.getElementById("ocpp1_6_parameter"); select.innerHTML = Array.from(window.ocppParametersMap.keys()) .map(key => ``) .join(''); onOcppParameterChanged(); }) .catch(e => { console.error(e); }); } ``` -------------------------------- ### Fetch and Fill Device Settings Source: https://github.com/chargelab/openocpp/blob/main/demo-esp32/main/web/web_config.html Fetches device configuration details like central system URL, charge point ID, and OCPP protocol version. Populates the corresponding form fields. ```javascript function fetchAndFillSettings() { fetch("getDeviceConfiguration") .then(response => response.json()) .then(payload => { document.getElementById("networkUrl").value = payload.centralSystemUrl; document.getElementById("chargePointId").value = payload.chargePointId; let normalizedOcppProtocol = null; if (payload.ocppProtocol != null) { normalizedOcppProtocol = payload.ocppProtocol.replace(/^"(.*?)"$/, "$1"); } if (normalizedOcppProtocol == null || normalizedOcppProtocol === "OCPP20") { document.getElementById("ocpp_protocol").value = "OCPP 2.0.1"; } else { document.getElementById("ocpp_protocol").value = "OCPP 1.6"; } document.getElementById("securityProfile").value = payload.securityProfile; document.getElementById("serialNumber").value = payload.serialNumber; document.getElementById("maxCurrent").value = payload.maxCurrentAmps; document.getElementById("vendor").value = payload.vendor; document.getElementById("model").value = payload.model; document.getElementById("numberOfConnectors").value = payload.numberOfConnectors; document.getElementById("myTitle").innerHTML = "Charger Configuration " + "(" + payload.firmwareVersion + ")"; }); } ``` -------------------------------- ### PlatformInterface for System Abstraction Source: https://context7.com/chargelab/openocpp/llms.txt Implement PlatformInterface for platform-specific behavior. Key methods include managing OCPP WebSocket, REST connections, persistent storage, flash partitions, certificates, and system clock/reset. ```cpp #include "openocpp/interface/platform_interface.h" // PlatformInterface is implemented per-platform (e.g., PlatformESP for ESP32). // Key methods used by the OCPP stack: // 1. OCPP WebSocket connection std::shared_ptr ws = platform->ocppConnection(); bool connected = ws->isConnected(); std::optional msg = ws->pollMessages(); // returns next received message ws->sendJson(my_ocpp_message); // sends a JSON OCPP message // 2. REST connection (used for firmware downloads) auto rest = platform->getRequest("https://firmware.example.com/v2.0.0.bin"); // rest->execute() fetches the resource; rest->getResponseCode() returns HTTP status // 3. Persistent storage (used by Settings and PendingMessagesModule) auto storage = platform->getStorage("transactions.dat"); storage->write([](auto file) { // write OCPP pending message journal to file return true; }); storage->read([](auto file) { // read previously saved pending messages return true; }); // 4. Flash partition (used for power management journal and OTA) auto partition = platform->getPartition("pmjournal"); partition->erase(); // factory reset // 5. Certificate management (OCPP 2.0.1 security profiles) platform->addCertificate(pem_string, chargelab::ocpp2_0::GetCertificateIdUseEnumType::kManufacturerRootCertificate); platform->removeCertificatesIf([](auto const& cert) { return cert.expired(); }); bool valid = platform->verifyManufacturerCertificate(pem, std::nullopt); // 6. System clock and reset platform->setSystemClock(timestamp_millis); platform->resetHard(); // full device restart platform->resetSoft(); // graceful restart ``` -------------------------------- ### Implement StationInterface for Charger Hardware Source: https://context7.com/chargelab/openocpp/llms.txt This C++ class implements the StationInterface to connect the OCPP library to specific charger hardware. It requires overriding virtual methods to provide station and EVSE metadata, poll connector status and meter values, manage charging state, read authorization tokens, and handle OTA firmware updates. ```cpp #include "openocpp/interface/station_interface.h" #include "openocpp/protocol/ocpp2_0/types/evse_type.h" class MyChargingStation : public chargelab::StationInterface { public: // Return station-level metadata (required for OCPP 2.0.1) chargelab::charger::StationMetadata getStationMetadata() override { return { .supply_phases = 3 }; } // Return per-EVSE metadata (OCPP 2.0.1 EVSE IDs, no connectorId set) std::map getEvseMetadata() override { return { { {1, std::nullopt}, { .supply_phases = 3, .power_max_watts = 22000.0 } } }; } // Return connector metadata with OCPP 1.6 connector ID mappings std::map getConnectorMetadata() override { return { { {1, 1}, { .connector_id_1_6 = 1, .connector_type = "Type2", .supply_phases = 3, .power_max_watts = 22000.0, .power_max_amps = 32.0 } } }; } // Poll real-time connector state from hardware std::optional pollConnectorStatus( chargelab::ocpp2_0::EVSEType const& evse) override { if (evse.id != 1) return std::nullopt; return chargelab::charger::ConnectorStatus { .connector_available = true, .vehicle_connected = gpio_read_pilot_pin(), // read hardware .charging_enabled = relay_is_closed(), .suspended_by_vehicle = false, .suspended_by_charger = false, .meter_watt_hours = energy_meter_read_wh() }; } // Poll OCPP 1.6 sampled values for meter reporting std::vector pollMeterValues1_6( std::optional const& evse) override { chargelab::ocpp1_6::SampledValue v; v.value = std::to_string(current_amps_); v.measurand = chargelab::ocpp1_6::Measurand::kCurrentImport; v.unit = chargelab::ocpp1_6::UnitOfMeasure::kA; return { v }; } // Poll OCPP 2.0.1 sampled values std::vector pollMeterValues2_0( std::optional const& evse) override { // Return 2.0.1 format meter values ... return {}; } // Enable or disable power delivery on a connector void setChargingEnabled(chargelab::ocpp2_0::EVSEType const& evse, bool value) override { relay_set(value); // drive hardware relay } // Read an RFID or local authorization token (OCPP 1.6) std::optional readToken1_6() override { if (rfid_available()) return chargelab::ocpp1_6::IdToken { rfid_get_tag_id() }; return std::nullopt; } // Read an RFID or local authorization token (OCPP 2.0.1) std::optional readToken2_0() override { return std::nullopt; // implement if using OCPP 2.0.1 auth } // OTA firmware update support std::string getActiveSlotId() override { return "slot-A"; } std::string getUpdateSlotId() override { return "slot-B"; } Result startUpdateProcess(std::size_t update_size) override { return ota_begin(update_size) ? Result::kSucceeded : Result::kFailed; } Result processFirmwareChunk(std::uint8_t const* block, std::size_t size) override { return ota_write(block, size) ? Result::kSucceeded : Result::kFailed; } Result finishUpdateProcess(bool succeeded) override { if (succeeded) ota_commit(); else ota_abort(); return Result::kSucceeded; } }; ``` -------------------------------- ### Load Configuration Content Source: https://github.com/chargelab/openocpp/blob/main/demo-esp32/main/web/web_index.html Fetches configuration content from the '/config' endpoint and updates the 'content' div. Ensures any scripts within the loaded content are executed and updates the page title. ```javascript function loadConfig() { fetch("/config") .then(response => response.text()) .then(text => { document.getElementById("content").innerHTML = text; executeScriptElements(document.getElementById("content")); document.title = "Charger Simulator - Configuration"; }) .catch(error => { document.getElementById("content").innerHTML = error; }); } ``` -------------------------------- ### Handle list item click for configuration Source: https://github.com/chargelab/openocpp/blob/main/demo-esp32/main/web/web_setup.html Updates configuration variables (z1) and UI elements when a list item is clicked. It parses the item's text to extract a value. ```javascript function liclk(e) { if (e && e.innerText) { var q = e.innerText.split(" "), t = e.style; if (q.length >= 3) { z1 = q[0]; var el = _el("uname"); el.value = z1; el = _el("m_si"); el.value = z; if (t) { t.backgroundColor = "#00FFBF"; if (prev_el) prev_el.backgroundColor = "#FFFFFF"; prev_el = t; } } } } ``` -------------------------------- ### Submit Device Configuration Update Source: https://github.com/chargelab/openocpp/blob/main/demo-esp32/main/web/web_config.html Collects device configuration data from form inputs and sends it to the server for updating. Handles the response to display success or failure. ```javascript function submit() { var data = new Object(); data.centralSystemUrl = document.getElementById("networkUrl").value; data.chargePointId = document.getElementById("chargePointId").value; data.ocppProtocol = document.getElementById("ocpp_protocol").value === "OCPP 2.0.1" ? "OCPP20" : "OCPP16"; data.securityProfile = parseInt(document.getElementById("securityProfile").value); data.clearCertificates = document.getElementById("clearCertificates").checked; data.serialNumber = document.getElementById("serialNumber").value; data.maxCurrentAmps = document.getElementById("maxCurrent").value; data.vendor = document.getElementById("vendor").value; data.model = document.getElementById("model").value; data.numberOfConnectors = parseInt(document.getElementById("numberOfConnectors").value, 10); data.firmwareVersion = ""; const jsonString = JSON.stringify(data); console.log(jsonString); fetch("updateDeviceConfiguration", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(data) }).then(response => response.json()) .then(json => { if (json.successful === true) document.getElementById("result").innerHTML = "Configuration updated successfully"; else document.getElementById("result").innerHTML = "Configuration update failed"; }) .catch((error) => { document.getElementById("result").innerHTML = "Configuration update failed:" + error; }); } ``` -------------------------------- ### Include Directories Configuration Source: https://github.com/chargelab/openocpp/blob/main/demo-esp32/main/CMakeLists.txt Specifies additional directories where the compiler should look for header files. This is essential for including custom libraries and modules. ```cmake include_directories(../../include) include_directories(../../rapidjson/include) include_directories(${CMAKE_BINARY_DIR}) ``` -------------------------------- ### Fetch available WiFi networks Source: https://github.com/chargelab/openocpp/blob/main/demo-esp32/main/web/web_setup.html Fetches a list of available WiFi networks from the server and populates a select dropdown with their SSIDs. Includes a default 'WiFi name' option. ```javascript sendReq("networks", function (s) { const networks = JSON.parse(s); console.log(networks); if (networks) { var select = document.getElementById('wifi'); var opt = document.createElement('option'); opt.value = ""; opt.innerHTML = "WiFi name"; select.appendChild(opt); for (let i = 0; i < networks.length; i++) { const entry = networks[i]; var opt = document.createElement('option'); opt.value = entry.ssid; opt.innerHTML = entry.ssid; select.appendChild(opt); } } }); ``` -------------------------------- ### OCPP 1.6 Transaction Lifecycle and Settings Source: https://context7.com/chargelab/openocpp/llms.txt Handles RFID tap detection, remote start/stop, authorization, and meter value sampling. Configure meter sampling intervals and offline transaction support via settings. ```cpp auto settings = platform->getSettings(); settings->PlugAndChargeId.setValue("AUTOCHARGE-TOKEN"); // Now whenever a vehicle connects, a transaction starts automatically. // Meter value sampling is controlled by settings: settings->MeterValueSampleInterval.setValue(60); // sample every 60 seconds settings->MeterValuesSampledData.setValue("Energy.Active.Import.Register,Current.Import,Voltage"); settings->ClockAlignedDataInterval.setValue(900); // clock-aligned every 15 minutes // Offline transaction support: transactions can start offline if configured settings->AllowOfflineTxForUnknownId.setValue(true); // Up to 3 offline transactions buffered; sent to CSMS on reconnect ``` -------------------------------- ### Handle OCPP Boot Notification Source: https://context7.com/chargelab/openocpp/llms.txt Manages the mandatory OCPP boot registration sequence. Sends BootNotification requests, handles responses, syncs system clock, and gates other OCPP functionality until registration is complete. ```cpp #include "openocpp/module/boot_notification_module.h" // BootNotificationModule is constructed automatically inside StandardCharger. // The module reads charger identity from Settings: auto settings = platform->getSettings(); settings->ChargerVendor.setValue("AcmeCorp"); settings->ChargerModel.setValue("AC22kW-v2"); settings->ChargerSerialNumber.setValue("SN20240001"); settings->ChargerFirmwareVersion.setValue("2.1.0"); settings->ChargerICCID.setValue("89011703278473610528"); // optional modem ICCID // After StandardCharger::runStep() is called, the module automatically sends: // OCPP 1.6: // [2,"","BootNotification",{"chargePointVendor":"AcmeCorp","chargePointModel":"AC22kW-v2", // "chargePointSerialNumber":"SN20240001","firmwareVersion":"2.1.0"}] // // OCPP 2.0.1: // [2,"","BootNotification",{"reason":"PowerUp","chargingStation": // {"serialNumber":"SN20240001","model":"AC22kW-v2","vendorName":"AcmeCorp", // "firmwareVersion":"2.1.0"}}] // // On Accepted response the system clock is set from currentTime and HeartbeatInterval updated. // Check registration status (available on the module reference from StandardCharger): auto charger = std::make_unique(platform, station); bool ready = charger->boot_notification_module->registrationComplete(); // ready == false until CSMS responds with Accepted ``` -------------------------------- ### Call Custom Gzip Function Source: https://github.com/chargelab/openocpp/blob/main/demo-esp32/main/CMakeLists.txt Invokes the custom `gzip_files` function defined earlier in the CMakeLists.txt to process and create gzipped versions of web assets. ```cmake gzip_files() ``` -------------------------------- ### Fetch and Fill Charger Status and Settings Source: https://github.com/chargelab/openocpp/blob/main/demo-esp32/main/web/web_control.html Fetches charger status and settings, or processes pending update/simulation requests. Updates the UI elements accordingly, including charging status color. ```javascript function fetchAndFill() { let future; if (updateConnectorSettingsRequest != null) { future = fetch("updateConnectorSettings", { signal: AbortSignal.timeout(1000), method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(updateConnectorSettingsRequest) }) .then(()=>{ document.getElementById("message_result").innerHTML = "The charger status was updated successfully."; }) .catch(error => { document.getElementById("message_result").innerHTML = "The charger status was not updated due to error:" + error; }); updateConnectorSettingsRequest = null; } else if (simulateRfidRequest != null) { future = fetch("simulateRfidInteraction", { signal: AbortSignal.timeout(1000), method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(simulateRfidRequest) }) .then(()=>{ document.getElementById("message_result").innerHTML = "RFID request accepted."; }) .catch(error => { document.getElementById("message_result").innerHTML = "RFID request failed with error: " + error; }); simulateRfidRequest = null; } else if (lastStatusUpdate == null || Math.abs(Date.now() - lastStatusUpdate) > 2000) { lastStatusUpdate = Date.now(); connector_id = document.getElementById("connector_id").value; if (connector_id === null) { connector_id = 1; } future = fetch("getConnectorStatus" + "?connectorId=" + connector_id, {signal: AbortSignal.timeout(1000)}) .then(response => response.text()) .then(text => { let obj = JSON.parse(text); let settings = (obj || {})['connectorSettings'] || {}; updateBoolInput("ev_connected", settings['vehicleConnected']); updateBoolInput("suspended_ev", settings['suspendedByVehicle']); updateBoolInput("suspended_charger", settings['suspendedByCharger']); let charging_status = (obj || {})['chargePointStatus1_6'] || {}; const chargingElement = document.getElementById('charging_status'); if (charging_status === "ValueNotFoundInEnum") { chargingElement.innerHTML = ""; } else { chargingElement.innerHTML = charging_status; // Set color based on charging_status switch (charging_status) { case "Charging": chargingElement.style.color = "green"; break; case "Faulted": chargingElement.style.color = "red"; break; case "Unavailable": chargingElement.style.color = "gray"; break; default: chargingElement.style.color = "blue"; // Default color break; } } }); } else { future = Promise.resolve(); } future.then(() => setTimeout(fetchAndFill, 100)) .catch(() => setTimeout(fetchAndFill, 100)); } ``` -------------------------------- ### Structured Logging with CHARGELAB_LOG_MESSAGE Source: https://context7.com/chargelab/openocpp/llms.txt Use CHARGELAB_LOG_MESSAGE for stream-style logging with different levels. Register a listener for remote log streaming. Supports structured data for richer logs. ```cpp #include "openocpp/common/logging.h" // Set global minimum log level (suppress below this level) chargelab::logging::SetLogLevel(chargelab::logging::LogLevel::info); // Stream-style log messages (zero-cost if level disabled) CHARGELAB_LOG_MESSAGE(info) << "Charger starting up, firmware: " << firmware_version; CHARGELAB_LOG_MESSAGE(warning) << "Unexpected response status: " << status_code; CHARGELAB_LOG_MESSAGE(error) << "OTA write failed at offset: " << offset; CHARGELAB_LOG_MESSAGE(debug) << "Connector status polled: connected=" << vehicle_connected; // Register a custom logging listener (e.g., forward logs to CSMS or UART) auto listener = std::make_shared( [](chargelab::logging::LogMetadata const& meta, std::string_view const& msg) { // meta.level: trace/debug/info/warning/error/fatal // meta.function: calling function name const char* level_str = (meta.level == chargelab::logging::LogLevel::error) ? "ERROR" : "INFO"; printf("[%s] (%s) %.*s\n", level_str, meta.function.data(), (int)msg.size(), msg.data()); } ); chargelab::logging::RegisterLoggingListener(listener); // Log messages with structured data (supports arithmetic types, strings, enums) int connector_id = 1; double watt_hours = 12345.6; CHARGELAB_LOG_MESSAGE(info) << "Transaction started on connector " << connector_id << " energy=" << watt_hours << "Wh"; // Unregister when done chargelab::logging::UnregisterLoggingListener(listener); ``` -------------------------------- ### Custom CMake Function to Gzip Files Source: https://github.com/chargelab/openocpp/blob/main/demo-esp32/main/CMakeLists.txt Defines a CMake function to find HTML and ICO files in the web directory, then creates gzipped versions of them. This is useful for compressing web assets before embedding them. ```cmake function(gzip_files) file(GLOB WEB_FILES "${CMAKE_CURRENT_SOURCE_DIR}/web/*.html" "${CMAKE_CURRENT_SOURCE_DIR}/web/*.ico") foreach(FILE ${WEB_FILES}) get_filename_component(FILENAME ${FILE} NAME) set(GZIPPED_FILE "${CMAKE_CURRENT_SOURCE_DIR}/web/${FILENAME}.gz") add_custom_command( OUTPUT ${GZIPPED_FILE} COMMAND ${CMAKE_COMMAND} -E echo "Gzipping ${FILENAME}" COMMAND gzip -c ${FILE} > ${GZIPPED_FILE} DEPENDS ${FILE} VERBATIM ) list(APPEND GZIPPED_FILES ${GZIPPED_FILE}) endforeach() set(GZIPPED_FILES ${GZIPPED_FILES} PARENT_SCOPE) endfunction() ``` -------------------------------- ### Target Compile Options and Definitions Source: https://github.com/chargelab/openocpp/blob/main/demo-esp32/main/CMakeLists.txt Sets specific compile options and definitions for the component. `-mtext-section-literals` is a compiler flag, and `JSON_NO_IO` is a preprocessor definition to disable JSON I/O operations. ```cmake target_compile_options(${COMPONENT_LIB} PRIVATE -mtext-section-literals) # add_compile_definitions(LOG_WITH_FILE_AND_LINE) add_compile_definitions(JSON_NO_IO) ``` -------------------------------- ### Update Charger Settings Source: https://github.com/chargelab/openocpp/blob/main/demo-esp32/main/web/web_control.html Gathers current UI settings and prepares a request to update the charger's connector settings. This function is triggered by user changes. ```javascript function updateChanges() { updateConnectorSettingsRequest = { connectorId: parseInt(document.getElementById("connector_id").value, 10), vehicleConnected: document.getElementById("ev_connected_true").checked, suspendedByVehicle: document.getElementById("suspended_ev_true").checked, suspendedByCharger: document.getElementById("suspended_charger_true").checked, allowWebsocketConnection: document.getElementById("allow_ ``` -------------------------------- ### Execute Script Elements Source: https://github.com/chargelab/openocpp/blob/main/demo-esp32/main/web/web_index.html Finds and executes script elements within a given container element. This is necessary because dynamically inserted HTML content may not execute scripts automatically. ```javascript function executeScriptElements(containerElement) { const scriptElements = containerElement.querySelectorAll("script"); Array.from(scriptElements).forEach((scriptElement) => { const clonedElement = document.createElement("script"); Array.from(scriptElement.attributes).forEach((attribute) => { clonedElement.setAttribute(attribute.name, attribute.value); }); clonedElement.text = scriptElement.text; scriptElement.parentNode.replaceChild(clonedElement, scriptElement); }); } ``` -------------------------------- ### Activate ESP-IDF Environment Source: https://github.com/chargelab/openocpp/blob/main/README.md Activates the ESP-IDF environment for the current terminal session. This command must be run every time a new terminal is opened before using idf.py commands. ```shell . $HOME/esp/esp-idf/export.sh ``` -------------------------------- ### Load Control Content Source: https://github.com/chargelab/openocpp/blob/main/demo-esp32/main/web/web_index.html Fetches control content from the '/control' endpoint and updates the 'content' div. Ensures any scripts within the loaded content are executed and updates the page title. ```javascript function loadControl() { fetch("/control") .then(response => response.text()) .then(text => { document.getElementById("content").innerHTML = text; executeScriptElements(document.getElementById("content")); document.title = "Charger Simulator - Control"; }) .catch(error => { document.getElementById("content").innerHTML = error; }); } ``` -------------------------------- ### Submit OCPP 1.6 Parameter Change Source: https://github.com/chargelab/openocpp/blob/main/demo-esp32/main/web/web_config.html Sends a request to the server to update a specific OCPP 1.6 parameter with a new value. Updates the local map and displays the server response status. ```javascript async function submitOcpp1_6_ParameterChange() { const selectedKey = document.getElementById("ocpp1_6_parameter").value; const newValue = document.getElementById("ocpp1_6_parameter_input").value; try { const response = await fetch('updateOcppParameter', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ key: selectedKey, value: newValue }) }); if (response.ok) { const payload = await response.json(); console.log(`change ocpp parameter response: ${payload}`); if (payload.status === "Accepted" || payload.status === "RebootRequired") { if (ocppParametersMap.has(selectedKey)) { window.ocppParametersMap.get(selectedKey).value = newValue; } else { console.warn(`Key ${selectedKey} not found in ocppParametersMap.`); } } document.getElementById("ocpp1_6_submit_result").innerHTML = `Get response with status: ${payload.status} for ${selectedKey} = ${newValue}`; } else { document.getElementById("ocpp1_6_submit_result").innerHTML = "Failed to update the ocpp variable value on server."; } } catch (error) { console.error("Error submitting value:", error); document.getElementById("ocpp1_6_submit_result").innerHTML = ""; } } ``` -------------------------------- ### ESP-IDF Component Registration Source: https://github.com/chargelab/openocpp/blob/main/demo-esp32/main/CMakeLists.txt Registers the main component for the ESP-IDF project. It specifies source files, include directories, required components, and files to be embedded into the firmware. This is a core part of ESP-IDF build system configuration. ```cmake list(APPEND SOURCES "main.cc") list(APPEND SOURCES "../../include/openocpp/implementation/logging_esp.cc") idf_component_register( SRCS ${SOURCES} INCLUDE_DIRS "." REQUIRES app_update esp_websocket_client esp_wifi nvs_flash spiffs driver esp_eth esp_https_server esp_http_client EMBED_TXTFILES "certs/servercert.pem" "certs/prvtkey.pem" "certs/manufacturer.pem" EMBED_FILES "web/web_favicon.ico.gz" "web/web_index.html.gz" "web/web_setup.html.gz" "web/web_config.html.gz" "web/web_control.html.gz" ) ``` -------------------------------- ### Toggle password visibility Source: https://github.com/chargelab/openocpp/blob/main/demo-esp32/main/web/web_setup.html Switches the input type for password fields between 'password' and 'text' to show or hide the entered password. Updates the eye icon accordingly. ```javascript function toggleShowPassword() { if (document.getElementById('PasswordEye').className === "eye-hide") { document.getElementById('Password').type = "text"; document.getElementById('Confirmpassword').type = "text"; document.getElementById('PasswordEye').className = "eye"; document.getElementById('ConfirmpasswordEye').className = "eye"; } else { document.getElementById('Password').type = "password"; document.getElementById('Confirmpassword').type = "password"; document.getElementById('PasswordEye').className = "eye-hide" document.getElementById('ConfirmpasswordEye').className = "eye-hide"; } } ``` -------------------------------- ### Add Active Link Event Listeners Source: https://github.com/chargelab/openocpp/blob/main/demo-esp32/main/web/web_index.html Attaches click event listeners to navigation links to manage the 'active' class for styling. Prevents default link behavior and applies the active class to the clicked link. ```javascript function addSetLinkActiveEvents() { const links = document.querySelectorAll(".mylink"); if (links.length) { links.forEach((link) => { link.addEventListener('click', (e) => { links.forEach((link) => { link.classList.remove('active'); }); e.preventDefault(); link.classList.add('active'); }); }); } } ``` -------------------------------- ### AJAX request function Source: https://github.com/chargelab/openocpp/blob/main/demo-esp32/main/web/web_setup.html A generic function to make an XMLHttpRequest to a specified URL. It can execute a callback function with the response text. ```javascript function sendReq(r, cb) { var x = new XMLHttpRequest(); x.onreadystatechange = function () { if (this.readyState == 4 && (this.status == 200 || this.status == 0)) { if (cb) cb(this.responseText); } }; x.open("GET", r, true); x.send(); } ``` -------------------------------- ### Handle OCPP Parameter Change Source: https://github.com/chargelab/openocpp/blob/main/demo-esp32/main/web/web_config.html Updates the input field and read-only status based on the selected OCPP parameter. This function is called when the user selects a different parameter from the dropdown. ```javascript function onOcppParameterChanged() { const selectedKey = document.getElementById("ocpp1_6_parameter").value; const param = window.ocppParametersMap.get(selectedKey); document.getElementById("ocpp1_6_parameter_input").value = param.value || ""; document.getElementById("ocpp-parameter-readonly-status").textContent = param.readonly ? "Yes (Read-Only)" : "No (Editable)"; } ``` -------------------------------- ### Close modal on outside click Source: https://github.com/chargelab/openocpp/blob/main/demo-esp32/main/web/web_setup.html Handles closing a modal element when the user clicks outside of it. Assumes the modal has the ID 'id01'. ```javascript window.onclick = function (event) { var el = _el('id01'); if (event.target == el) { el.style.display = "none"; } } ``` -------------------------------- ### Update Boolean Input Fields Source: https://github.com/chargelab/openocpp/blob/main/demo-esp32/main/web/web_control.html Updates a boolean input field (radio button group) based on the provided value. Ensures the correct radio button is checked. ```javascript function updateBoolInput(name, value) { if (value === true) { if (!document.getElementById(name + "_true").checked) { console.log("Setting: " + name + "_true"); document.getElementById(name + "_true").checked = true; } } else { if (!document.getElementById(name + "_false").checked) { console.log("Setting: " + name + "_false"); document.getElementById(name + "_false").checked = true; } } } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.