From 81b28b4461936103c375df6e2c3a4a5a77792812 Mon Sep 17 00:00:00 2001 From: Timothy Yin Date: Sun, 19 Apr 2026 23:27:08 +0800 Subject: [PATCH] =?UTF-8?q?feat(firmware):=20=E6=B7=BB=E5=8A=A0=20IM1281C?= =?UTF-8?q?=20=E8=BD=AE=E8=AF=A2=E9=97=B4=E9=9A=94=E5=92=8C=E7=94=B5?= =?UTF-8?q?=E8=A1=A8=E6=95=B0=E6=8D=AE=E5=A4=84=E7=90=86=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hardware/firmware/src/main.cpp | 65 +++++++++++++++++++++++++++++++++- 1 file changed, 64 insertions(+), 1 deletion(-) diff --git a/hardware/firmware/src/main.cpp b/hardware/firmware/src/main.cpp index 5f31402..3862498 100644 --- a/hardware/firmware/src/main.cpp +++ b/hardware/firmware/src/main.cpp @@ -37,6 +37,7 @@ static volatile bool s_blink_on = false; static const unsigned long BLINK_INTERVAL = 200; // 200ms blink interval static const unsigned long CC_DEBOUNCE_MS = 30; static const unsigned long AUTH_WINDOW_MS = 30000; +static const unsigned long IM1281C_POLL_INTERVAL_MS = 5000; static bool s_cc1_plugged = false; static bool s_cc2_plugged = false; @@ -98,6 +99,25 @@ SmartLed leds(LED_WS2812B, LED_COUNT, LED_PIN, 0, DoubleBuffer); MFRC522 rfid(PIN_RC_CS, PIN_RC_RST); IM1281C im1281c; +static IM1281CAData s_meter_a; +static IM1281CBData s_meter_b; +static bool s_meter_data_ready = false; + +static int energyKwhToWh(float energyKwh) +{ + if (energyKwh <= 0.0f) + { + return 0; + } + + float energyWh = energyKwh * 1000.0f; + if (energyWh > 2147483000.0f) + { + energyWh = 2147483000.0f; + } + return static_cast(energyWh + 0.5f); +} + static bool isConnectorPlugged(unsigned int connectorId) { if (connectorId == 1) @@ -309,7 +329,7 @@ static void pollIm1281c() { static unsigned long s_last_poll_ms = 0; const unsigned long now = millis(); - if ((now - s_last_poll_ms) < 1000) + if ((now - s_last_poll_ms) < IM1281C_POLL_INTERVAL_MS) { return; } @@ -323,6 +343,10 @@ static void pollIm1281c() const IM1281CAData &a = im1281c.a(); const IM1281CBData &b = im1281c.b(); + s_meter_a = a; + s_meter_b = b; + s_meter_data_ready = true; + Serial.printf("[IM1281C] A: U=%.4fV I=%.4fA P=%.4fW E=%.4fkWh PF=%.3f CO2=%.4fkg T=%.2fC F=%.2fHz\n", a.voltage, a.current, @@ -731,6 +755,45 @@ void setup() { return s_cc2_plugged; }, 2); + // Bind IM1281C metering values to OCPP connector 1 / 2 + setEnergyMeterInput([]() + { return s_meter_data_ready ? energyKwhToWh(s_meter_a.energy) : 0; }, + 1); + setPowerMeterInput([]() + { return s_meter_data_ready ? s_meter_a.power : 0.0f; }, + 1); + addMeterValueInput([]() + { return s_meter_data_ready ? s_meter_a.voltage : 0.0f; }, + "Voltage", "V", nullptr, nullptr, 1); + addMeterValueInput([]() + { return s_meter_data_ready ? s_meter_a.current : 0.0f; }, + "Current.Import", "A", nullptr, nullptr, 1); + addMeterValueInput([]() + { return s_meter_data_ready ? s_meter_a.powerFactor : 0.0f; }, + "Power.Factor", nullptr, nullptr, nullptr, 1); + addMeterValueInput([]() + { return s_meter_data_ready ? s_meter_a.frequency : 0.0f; }, + "Frequency", "Hz", nullptr, nullptr, 1); + addMeterValueInput([]() + { return s_meter_data_ready ? s_meter_a.temperature : 0.0f; }, + "Temperature", "Celsius", nullptr, nullptr, 1); + + setEnergyMeterInput([]() + { return s_meter_data_ready ? energyKwhToWh(s_meter_b.energy) : 0; }, + 2); + setPowerMeterInput([]() + { return s_meter_data_ready ? s_meter_b.power : 0.0f; }, + 2); + addMeterValueInput([]() + { return s_meter_data_ready ? s_meter_b.voltage : 0.0f; }, + "Voltage", "V", nullptr, nullptr, 2); + addMeterValueInput([]() + { return s_meter_data_ready ? s_meter_b.current : 0.0f; }, + "Current.Import", "A", nullptr, nullptr, 2); + addMeterValueInput([]() + { return s_meter_data_ready ? s_meter_b.powerFactor : 0.0f; }, + "Power.Factor", nullptr, nullptr, nullptr, 2); + // Custom RemoteStartTransaction policy: // accept only when target connector is idle + operative + plugged. setRequestHandler(