Add more battery info page for Chademo

This commit is contained in:
Daniel Öster 2025-06-26 22:20:32 +03:00
parent 92daa175d3
commit 6936681366
6 changed files with 144 additions and 38 deletions

View file

@ -32,6 +32,8 @@ class Battery {
virtual bool supports_real_BMS_status() { return false; } virtual bool supports_real_BMS_status() { return false; }
virtual bool supports_toggle_SOC_method() { return false; } virtual bool supports_toggle_SOC_method() { return false; }
virtual bool supports_factory_mode_method() { return false; } virtual bool supports_factory_mode_method() { return false; }
virtual bool supports_chademo_restart() { return false; }
virtual bool supports_chademo_stop() { return false; }
virtual void clear_isolation() {} virtual void clear_isolation() {}
virtual void reset_BMS() {} virtual void reset_BMS() {}
@ -46,6 +48,8 @@ class Battery {
virtual void request_close_contactors() {} virtual void request_close_contactors() {}
virtual void toggle_SOC_method() {} virtual void toggle_SOC_method() {}
virtual void set_factory_mode() {} virtual void set_factory_mode() {}
virtual void chademo_restart() {}
virtual void chademo_stop() {}
virtual void set_fake_voltage(float v) {} virtual void set_fake_voltage(float v) {}
virtual float get_voltage() { return static_cast<float>(datalayer.battery.status.voltage_dV) / 10.0; } virtual float get_voltage() { return static_cast<float>(datalayer.battery.status.voltage_dV) / 10.0; }

View file

@ -0,0 +1,72 @@
#ifndef _CHADEMO_BATTERY_HTML_H
#define _CHADEMO_BATTERY_HTML_H
#include "../datalayer/datalayer.h"
#include "../datalayer/datalayer_extended.h"
#include "src/devboard/webserver/BatteryHtmlRenderer.h"
class ChademoBatteryHtmlRenderer : public BatteryHtmlRenderer {
public:
String get_status_html() {
String content;
content += "<h4>Chademo state: ";
switch (datalayer_extended.chademo.CHADEMO_Status) {
case 0:
content += String("FAULT</h4>");
break;
case 1:
content += String("STOP</h4>");
break;
case 2:
content += String("IDLE</h4>");
break;
case 3:
content += String("CONNECTED</h4>");
break;
case 4:
content += String("INIT</h4>");
break;
case 5:
content += String("NEGOTIATE</h4>");
break;
case 6:
content += String("EV ALLOWED</h4>");
break;
case 7:
content += String("EVSE PREPARE</h4>");
break;
case 8:
content += String("EVSE START</h4>");
break;
case 9:
content += String("EVSE CONTACTORS ENABLED</h4>");
break;
case 10:
content += String("POWERFLOW</h4>");
break;
default:
content += String("Unknown</h4>");
break;
}
if (datalayer_extended.chademo.FaultBatteryCurrentDeviation) {
content += "<h4>FAULT: Battery Current Deviation</h4>";
}
if (datalayer_extended.chademo.FaultBatteryOverVoltage) {
content += "<h4>FAULT: Battery Overvoltage</h4>";
}
if (datalayer_extended.chademo.FaultBatteryUnderVoltage) {
content += "<h4>FAULT: Battery Undervoltage</h4>";
}
if (datalayer_extended.chademo.FaultBatteryVoltageDeviation) {
content += "<h4>FAULT: Battery Voltage Deviation</h4>";
}
if (datalayer_extended.chademo.FaultHighBatteryTemperature) {
content += "<h4>FAULT: Battery Temperature</h4>";
}
content += "<h4>Protocol: " + String(datalayer_extended.chademo.ControlProtocolNumberEV) + "</h4>";
return content;
}
};
#endif

View file

@ -5,17 +5,24 @@
#include "CHADEMO-BATTERY.h" #include "CHADEMO-BATTERY.h"
#include "CHADEMO-SHUNTS.h" #include "CHADEMO-SHUNTS.h"
/* CHADEMO handling runs at 6.25 times the rate of most other code, so, rather than the
* default value of 12 (for 12 iterations of the 5s value update loop) * 5 for a 60s timeout,
* instead use 75 for 75*0.8s = 60s
*/
#undef CAN_STILL_ALIVE
#define CAN_STILL_ALIVE 75
//#define CH_CAN_DEBUG
//This function maps all the values fetched via CAN to the correct parameters used for the inverter //This function maps all the values fetched via CAN to the correct parameters used for the inverter
void ChademoBattery::update_values() { void ChademoBattery::update_values() {
datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE;
//On this integration, we don't care if no CAN messages flow (normal before user plugs in)
//Always write the CAN as alive!
//Check if user is requesting an action, if so, have statemachine jump there
if (datalayer_extended.chademo.UserRequestStop) {
CHADEMO_Status = CHADEMO_STOP;
datalayer_extended.chademo.UserRequestStop = false;
}
if (datalayer_extended.chademo.UserRequestRestart) {
CHADEMO_Status = CHADEMO_IDLE;
datalayer_extended.chademo.UserRequestRestart = false;
}
datalayer.battery.status.real_soc = x102_chg_session.StateOfCharge * 100; //Convert % to pptt datalayer.battery.status.real_soc = x102_chg_session.StateOfCharge * 100; //Convert % to pptt
datalayer.battery.status.max_discharge_power_W = datalayer.battery.status.max_discharge_power_W =
@ -48,6 +55,15 @@ void ChademoBattery::update_values() {
chargingrate = x102_chg_session.StateOfCharge / x100_chg_lim.ConstantOfChargingRateIndication * 100; chargingrate = x102_chg_session.StateOfCharge / x100_chg_lim.ConstantOfChargingRateIndication * 100;
} }
} }
//Update extended datalayer for easier visualization of what's going on
datalayer_extended.chademo.CHADEMO_Status = CHADEMO_Status;
datalayer_extended.chademo.ControlProtocolNumberEV = x102_chg_session.ControlProtocolNumberEV;
datalayer_extended.chademo.FaultBatteryVoltageDeviation = x102_chg_session.f.fault.FaultBatteryVoltageDeviation;
datalayer_extended.chademo.FaultHighBatteryTemperature = x102_chg_session.f.fault.FaultHighBatteryTemperature;
datalayer_extended.chademo.FaultBatteryCurrentDeviation = x102_chg_session.f.fault.FaultBatteryCurrentDeviation;
datalayer_extended.chademo.FaultBatteryUnderVoltage = x102_chg_session.f.fault.FaultBatteryUnderVoltage;
datalayer_extended.chademo.FaultBatteryOverVoltage = x102_chg_session.f.fault.FaultBatteryOverVoltage;
} }
//TODO simplified start/stop helper functions //TODO simplified start/stop helper functions
@ -277,19 +293,6 @@ void ChademoBattery::process_vehicle_vendor_ID(CAN_frame rx_frame) {
} }
void ChademoBattery::handle_incoming_can_frame(CAN_frame rx_frame) { void ChademoBattery::handle_incoming_can_frame(CAN_frame rx_frame) {
#ifdef CH_CAN_DEBUG
logging.print(millis()); // Example printout, time, ID, length, data: 7553 1DB 8 FF C0 B9 EA 0 0 2 5D
logging.print(" ");
logging.print(rx_frame.ID, HEX);
logging.print(" ");
logging.print(rx_frame.DLC);
logging.print(" ");
for (int i = 0; i < rx_frame.DLC; ++i) {
logging.print(rx_frame.data.u8[i], HEX);
logging.print(" ");
}
logging.println("");
#endif
// CHADEMO coexists with a CAN-based shunt. Only process CHADEMO-specific IDs // CHADEMO coexists with a CAN-based shunt. Only process CHADEMO-specific IDs
// 202 is unknown // 202 is unknown
@ -303,9 +306,6 @@ void ChademoBattery::handle_incoming_can_frame(CAN_frame rx_frame) {
* has not yet been receied from a vehicle * has not yet been receied from a vehicle
*/ */
datalayer.battery.status.CAN_battery_still_alive =
CAN_STILL_ALIVE; //We are getting CAN messages from the vehicle, inform the watchdog
switch (rx_frame.ID) { switch (rx_frame.ID) {
case 0x100: case 0x100:
process_vehicle_charging_minimums(rx_frame); process_vehicle_charging_minimums(rx_frame);

View file

@ -1,7 +1,10 @@
#ifndef CHADEMO_BATTERY_H #ifndef CHADEMO_BATTERY_H
#define CHADEMO_BATTERY_H #define CHADEMO_BATTERY_H
#include <Arduino.h> #include <Arduino.h>
#include "../datalayer/datalayer.h"
#include "../datalayer/datalayer_extended.h"
#include "../include.h" #include "../include.h"
#include "CHADEMO-BATTERY-HTML.h"
#include "CanBattery.h" #include "CanBattery.h"
//Contactor control is required for CHADEMO support //Contactor control is required for CHADEMO support
@ -21,6 +24,12 @@ class ChademoBattery : public CanBattery {
virtual void update_values(); virtual void update_values();
virtual void transmit_can(unsigned long currentMillis); virtual void transmit_can(unsigned long currentMillis);
bool supports_chademo_restart() { return true; }
bool supports_chademo_stop() { return true; }
void chademo_restart() { datalayer_extended.chademo.UserRequestRestart = true; }
void chademo_stop() { datalayer_extended.chademo.UserRequestStop = true; }
private: private:
void process_vehicle_charging_minimums(CAN_frame rx_frame); void process_vehicle_charging_minimums(CAN_frame rx_frame);
void process_vehicle_charging_maximums(CAN_frame rx_frame); void process_vehicle_charging_maximums(CAN_frame rx_frame);
@ -40,19 +49,17 @@ class ChademoBattery : public CanBattery {
static const int MAX_EVSE_OUTPUT_VOLTAGE = 410; static const int MAX_EVSE_OUTPUT_VOLTAGE = 410;
static const int MAX_EVSE_OUTPUT_CURRENT = 11; static const int MAX_EVSE_OUTPUT_CURRENT = 11;
enum CHADEMO_STATE { #define CHADEMO_FAULT 0
CHADEMO_FAULT, #define CHADEMO_STOP 1
CHADEMO_STOP, #define CHADEMO_IDLE 2
CHADEMO_IDLE, #define CHADEMO_CONNECTED 3
CHADEMO_CONNECTED, #define CHADEMO_INIT 4 // intermediate state indicating CAN from Vehicle not yet received after connection
CHADEMO_INIT, // intermediate state indicating CAN from Vehicle not yet received after connection #define CHADEMO_NEGOTIATE 5
CHADEMO_NEGOTIATE, #define CHADEMO_EV_ALLOWED 6
CHADEMO_EV_ALLOWED, #define CHADEMO_EVSE_PREPARE 7
CHADEMO_EVSE_PREPARE, #define CHADEMO_EVSE_START 8
CHADEMO_EVSE_START, #define CHADEMO_EVSE_CONTACTORS_ENABLED 9
CHADEMO_EVSE_CONTACTORS_ENABLED, #define CHADEMO_POWERFLOW 10
CHADEMO_POWERFLOW,
};
enum Mode { CHADEMO_CHARGE, CHADEMO_DISCHARGE, CHADEMO_BIDIRECTIONAL }; enum Mode { CHADEMO_CHARGE, CHADEMO_DISCHARGE, CHADEMO_BIDIRECTIONAL };
@ -291,7 +298,7 @@ should determine that the other is the EVSE or the vehicle of the model before t
// permissible rate of change is -20A/s to 20A/s relative to 102.3 // permissible rate of change is -20A/s to 20A/s relative to 102.3
Mode EVSE_mode = CHADEMO_DISCHARGE; Mode EVSE_mode = CHADEMO_DISCHARGE;
CHADEMO_STATE CHADEMO_Status = CHADEMO_IDLE; uint8_t CHADEMO_Status = CHADEMO_IDLE;
/* Charge/discharge sequence, indicating applicable V2H guideline /* Charge/discharge sequence, indicating applicable V2H guideline
* If sequence number is not agreed upon via H201/H209 between EVSE and Vehicle, * If sequence number is not agreed upon via H201/H209 between EVSE and Vehicle,

View file

@ -274,6 +274,19 @@ typedef struct {
bool warning_Charger_not_responding = false; bool warning_Charger_not_responding = false;
} DATALAYER_INFO_CELLPOWER; } DATALAYER_INFO_CELLPOWER;
typedef struct {
bool UserRequestRestart = false;
bool UserRequestStop = false;
bool FaultBatteryVoltageDeviation = false;
bool FaultHighBatteryTemperature = false;
bool FaultBatteryCurrentDeviation = false;
bool FaultBatteryUnderVoltage = false;
bool FaultBatteryOverVoltage = false;
uint8_t CHADEMO_Status = 0;
uint8_t ControlProtocolNumberEV = 0;
} DATALAYER_INFO_CHADEMO;
typedef struct { typedef struct {
uint16_t soc_z = 0; uint16_t soc_z = 0;
uint16_t soc_u = 0; uint16_t soc_u = 0;
@ -885,6 +898,7 @@ class DataLayerExtended {
DATALAYER_INFO_BMWI3 bmwi3; DATALAYER_INFO_BMWI3 bmwi3;
DATALAYER_INFO_BYDATTO3 bydAtto3; DATALAYER_INFO_BYDATTO3 bydAtto3;
DATALAYER_INFO_CELLPOWER cellpower; DATALAYER_INFO_CELLPOWER cellpower;
DATALAYER_INFO_CHADEMO chademo;
DATALAYER_INFO_CMFAEV CMFAEV; DATALAYER_INFO_CMFAEV CMFAEV;
DATALAYER_INFO_ECMP stellantisECMP; DATALAYER_INFO_ECMP stellantisECMP;
DATALAYER_INFO_GEELY_GEOMETRY_C geometryC; DATALAYER_INFO_GEELY_GEOMETRY_C geometryC;

View file

@ -12,6 +12,15 @@ std::vector<BatteryCommand> battery_commands = {
[](Battery* b) { [](Battery* b) {
b->clear_isolation(); b->clear_isolation();
}}, }},
{"chademoRestart", "Restart", "restart the V2X session?",
[](Battery* b) { return b && b->supports_chademo_restart(); },
[](Battery* b) {
b->chademo_restart();
}},
{"chademoStop", "Stop", "stop V2X?", [](Battery* b) { return b && b->supports_chademo_restart(); },
[](Battery* b) {
b->chademo_restart();
}},
{"resetBMS", "BMS reset", "reset the BMS?", [](Battery* b) { return b && b->supports_reset_BMS(); }, {"resetBMS", "BMS reset", "reset the BMS?", [](Battery* b) { return b && b->supports_reset_BMS(); },
[](Battery* b) { [](Battery* b) {
b->reset_BMS(); b->reset_BMS();