300 lines
6.7 KiB
C++
300 lines
6.7 KiB
C++
#include <Arduino.h>
|
|
#include <WiFiManager.h>
|
|
#include <string.h>
|
|
|
|
#include <MicroOcpp.h>
|
|
#include <MicroOcppMongooseClient.h>
|
|
#include <MicroOcpp/Core/Context.h>
|
|
|
|
#include <SmartLeds.h>
|
|
#include <MFRC522.h>
|
|
|
|
#include "esp_system.h"
|
|
#include "config.h"
|
|
|
|
/* LED State Enum */
|
|
enum LEDState
|
|
{
|
|
LED_INITIALIZING, // Blue blinking - Initialization and WiFi connecting
|
|
LED_WIFI_CONNECTED, // Blue solid - WiFi connected, connecting to OCPP server
|
|
LED_OCPP_CONNECTED, // Green solid - Successfully connected to OCPP server
|
|
LED_ERROR // Red - Error state
|
|
};
|
|
|
|
static int s_retry_num = 0;
|
|
static volatile bool s_ocpp_connected = false;
|
|
static volatile LEDState s_led_state = LED_INITIALIZING;
|
|
static volatile unsigned long s_blink_last_time = 0;
|
|
static volatile bool s_blink_on = false;
|
|
static const unsigned long BLINK_INTERVAL = 200; // 200ms blink interval
|
|
|
|
uint8_t mac[6];
|
|
char cpSerial[13];
|
|
|
|
struct mg_mgr mgr;
|
|
|
|
/**
|
|
* WS2812B LED Pin
|
|
* - GPIO 17 - RYMCU ESP32-DevKitC
|
|
* - GPIO 16 - YD-ESP32-A
|
|
*/
|
|
#define LED_PIN 17
|
|
#define LED_COUNT 1
|
|
|
|
SmartLed leds(LED_WS2812B, LED_COUNT, LED_PIN, 0, DoubleBuffer);
|
|
|
|
/* LED Control Functions */
|
|
void updateLED()
|
|
{
|
|
unsigned long current_time = millis();
|
|
|
|
switch (s_led_state)
|
|
{
|
|
case LED_INITIALIZING:
|
|
// Blue blinking during initialization
|
|
if (current_time - s_blink_last_time >= BLINK_INTERVAL)
|
|
{
|
|
s_blink_last_time = current_time;
|
|
s_blink_on = !s_blink_on;
|
|
|
|
if (s_blink_on)
|
|
{
|
|
leds[0] = Rgb{0, 0, 255}; // Blue on
|
|
}
|
|
else
|
|
{
|
|
leds[0] = Rgb{0, 0, 0}; // Off
|
|
}
|
|
leds.show();
|
|
}
|
|
break;
|
|
|
|
case LED_WIFI_CONNECTED:
|
|
// Blue solid - WiFi connected, OCPP connecting
|
|
leds[0] = Rgb{0, 0, 255}; // Blue solid
|
|
leds.show();
|
|
break;
|
|
|
|
case LED_OCPP_CONNECTED:
|
|
// Green solid - OCPP connected
|
|
leds[0] = Rgb{0, 255, 0}; // Green solid
|
|
leds.show();
|
|
break;
|
|
|
|
case LED_ERROR:
|
|
// Red solid - Error state
|
|
leds[0] = Rgb{255, 0, 0}; // Red solid
|
|
leds.show();
|
|
break;
|
|
}
|
|
}
|
|
|
|
void setup()
|
|
{
|
|
// Get MAC address and set as Charge Point Serial Number
|
|
esp_efuse_mac_get_default(mac);
|
|
snprintf(cpSerial, sizeof(cpSerial),
|
|
"%02X%02X%02X%02X%02X%02X",
|
|
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
|
|
// reset LED
|
|
leds[0] = Rgb{0, 0, 0};
|
|
leds.show();
|
|
// initialize Serial
|
|
Serial.begin(115200);
|
|
delay(1000);
|
|
Serial.printf("\n\n%s(%s) made by %s\n", CFG_CP_MODAL, cpSerial, CFG_CP_VENDOR);
|
|
Serial.println("Initializing firmware...\n");
|
|
|
|
// Initialize LED
|
|
s_led_state = LED_INITIALIZING;
|
|
s_blink_last_time = 0;
|
|
s_blink_on = false;
|
|
|
|
leds[0] = Rgb{255, 255, 0};
|
|
leds.show();
|
|
|
|
WiFiManager wm;
|
|
const char *customHeadElement = R"rawliteral(
|
|
<style>
|
|
:root {
|
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
|
color: #1f2a37;
|
|
--primarycolor: #2563eb;
|
|
}
|
|
|
|
body,
|
|
body.invert {
|
|
margin: 0;
|
|
background: #f4f6fb;
|
|
min-height: 100vh;
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
padding: 16px;
|
|
color: #1f2a37;
|
|
}
|
|
|
|
.wrap {
|
|
width: min(360px, 100%);
|
|
background: #fff;
|
|
border-radius: 16px;
|
|
padding: 24px;
|
|
box-shadow: 0 8px 24px rgba(15, 23, 42, 0.12);
|
|
text-align: left;
|
|
}
|
|
|
|
h1,
|
|
h2,
|
|
h3,
|
|
h4 {
|
|
color: #111827;
|
|
margin-top: 0;
|
|
text-align: center;
|
|
}
|
|
|
|
label {
|
|
display: block;
|
|
margin-bottom: 6px;
|
|
font-weight: 600;
|
|
}
|
|
|
|
input,
|
|
select,
|
|
button {
|
|
border-radius: 10px;
|
|
width: 100%;
|
|
font-size: 1rem;
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
input[type="text"],
|
|
input[type="password"],
|
|
input[type="number"],
|
|
input[type="email"],
|
|
select {
|
|
padding: 12px;
|
|
margin: 0 0 16px 0;
|
|
border: 1px solid #d0d7e2;
|
|
background: #f9fafc;
|
|
transition: border 0.2s, box-shadow 0.2s, background 0.2s;
|
|
}
|
|
|
|
input:focus,
|
|
select:focus {
|
|
outline: none;
|
|
border-color: #2563eb;
|
|
background: #fff;
|
|
box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.15);
|
|
}
|
|
|
|
button,
|
|
input[type="submit"],
|
|
button.D {
|
|
padding: 12px;
|
|
border: none;
|
|
background: #2563eb;
|
|
color: #fff;
|
|
font-weight: 600;
|
|
cursor: pointer;
|
|
transition: background 0.2s, transform 0.1s;
|
|
}
|
|
|
|
button.D {
|
|
background: #dc2626;
|
|
}
|
|
|
|
button:hover,
|
|
input[type="submit"]:hover {
|
|
background: #1d4ed8;
|
|
}
|
|
|
|
button:active,
|
|
input[type="submit"]:active {
|
|
transform: scale(0.99);
|
|
}
|
|
|
|
.msg {
|
|
border-radius: 12px;
|
|
border: 1px solid #e5e7eb;
|
|
background: #f9fafb;
|
|
padding: 16px;
|
|
color: #374151;
|
|
}
|
|
|
|
.msg.P {
|
|
border-color: #2563eb;
|
|
background: rgba(37, 99, 235, 0.08);
|
|
color: #1f2a37;
|
|
}
|
|
|
|
.msg.S {
|
|
border-color: #16a34a;
|
|
background: rgba(22, 163, 74, 0.08);
|
|
}
|
|
|
|
.msg.D {
|
|
border-color: #dc2626;
|
|
background: rgba(220, 38, 38, 0.08);
|
|
}
|
|
|
|
.q {
|
|
display: none;
|
|
}
|
|
|
|
a {
|
|
color: #2563eb;
|
|
font-weight: 600;
|
|
}
|
|
|
|
hr {
|
|
border: none;
|
|
height: 1px;
|
|
background: #e5e7eb;
|
|
margin: 24px 0;
|
|
}
|
|
</style>
|
|
)rawliteral";
|
|
wm.setCustomHeadElement(customHeadElement);
|
|
bool autoConnectRet = wm.autoConnect((String("HLCP_") + String(cpSerial).substring(String(cpSerial).length() - 6)).c_str(), cpSerial);
|
|
if (!autoConnectRet)
|
|
{
|
|
Serial.println("Failed to connect and hit timeout");
|
|
s_led_state = LED_ERROR;
|
|
}
|
|
else
|
|
{
|
|
Serial.println("WiFi connected successfully");
|
|
s_led_state = LED_WIFI_CONNECTED;
|
|
|
|
mg_mgr_init(&mgr);
|
|
MicroOcpp::MOcppMongooseClient *client = new MicroOcpp::MOcppMongooseClient(&mgr, CFG_OCPP_BACKEND, CFG_CP_IDENTIFIER, CFG_AUTHORIZATIONKEY, "", MicroOcpp::makeDefaultFilesystemAdapter(MicroOcpp::FilesystemOpt::Use_Mount_FormatOnFail), MicroOcpp::ProtocolVersion(1, 6));
|
|
mocpp_initialize(*client, ChargerCredentials(CFG_CP_MODAL, CFG_CP_VENDOR, CFG_CP_FW_VERSION, cpSerial, nullptr, nullptr, CFG_CB_SERIAL, nullptr, nullptr), MicroOcpp::makeDefaultFilesystemAdapter(MicroOcpp::FilesystemOpt::Use_Mount_FormatOnFail));
|
|
}
|
|
}
|
|
|
|
void loop()
|
|
{
|
|
mg_mgr_poll(&mgr, 10);
|
|
mocpp_loop();
|
|
|
|
auto ctx = getOcppContext();
|
|
if (ctx && ctx->getConnection().isConnected())
|
|
{
|
|
if (s_led_state != LED_OCPP_CONNECTED)
|
|
{
|
|
s_led_state = LED_OCPP_CONNECTED;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (s_led_state != LED_WIFI_CONNECTED)
|
|
{
|
|
s_led_state = LED_WIFI_CONNECTED;
|
|
}
|
|
}
|
|
|
|
updateLED();
|
|
|
|
delay(10);
|
|
}
|