mirror of
https://github.com/dalathegreat/Battery-Emulator.git
synced 2025-10-03 17:59:27 +02:00
Initial version of PDM support
This commit is contained in:
parent
01a17b8c72
commit
4cd5289929
8 changed files with 357 additions and 14 deletions
|
@ -377,8 +377,12 @@ void receive_can() { // This section checks if we have a complete CAN message i
|
||||||
#ifdef SMA_CAN
|
#ifdef SMA_CAN
|
||||||
receive_can_sma(rx_frame);
|
receive_can_sma(rx_frame);
|
||||||
#endif
|
#endif
|
||||||
|
// Charger
|
||||||
#ifdef CHEVYVOLT_CHARGER
|
#ifdef CHEVYVOLT_CHARGER
|
||||||
receive_can_chevyvolt_charger(rx_frame);
|
receive_can_chevyvolt_charger(rx_frame);
|
||||||
|
#endif
|
||||||
|
#ifdef NISSANLEAF_CHARGER
|
||||||
|
receive_can_nissanleaf_charger(rx_frame);
|
||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
//printf("New extended frame");
|
//printf("New extended frame");
|
||||||
|
@ -441,6 +445,9 @@ void send_can() {
|
||||||
#ifdef CHEVYVOLT_CHARGER
|
#ifdef CHEVYVOLT_CHARGER
|
||||||
send_can_chevyvolt_charger();
|
send_can_chevyvolt_charger();
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef NISSANLEAF_CHARGER
|
||||||
|
send_can_nissanleaf_charger();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DUAL_CAN
|
#ifdef DUAL_CAN
|
||||||
|
|
|
@ -15,7 +15,7 @@ volatile uint16_t MAXCHARGEAMP =
|
||||||
volatile uint16_t MAXDISCHARGEAMP =
|
volatile uint16_t MAXDISCHARGEAMP =
|
||||||
300; //30.0A , BYD CAN specific setting, Max discharge speed in Amp (Some inverters needs to be artificially limited)
|
300; //30.0A , BYD CAN specific setting, Max discharge speed in Amp (Some inverters needs to be artificially limited)
|
||||||
|
|
||||||
/* Charger settings */
|
/* Charger settings (Optional, when generator charging) */
|
||||||
volatile float CHARGER_SET_HV = 384; // Reasonably appropriate 4.0v per cell charging of a 96s pack
|
volatile float CHARGER_SET_HV = 384; // Reasonably appropriate 4.0v per cell charging of a 96s pack
|
||||||
volatile float CHARGER_MAX_HV = 420; // Max permissible output (VDC) of charger
|
volatile float CHARGER_MAX_HV = 420; // Max permissible output (VDC) of charger
|
||||||
volatile float CHARGER_MIN_HV = 200; // Min permissible output (VDC) of charger
|
volatile float CHARGER_MIN_HV = 200; // Min permissible output (VDC) of charger
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
//#define RENAULT_ZOE_BATTERY
|
//#define RENAULT_ZOE_BATTERY
|
||||||
//#define SANTA_FE_PHEV_BATTERY
|
//#define SANTA_FE_PHEV_BATTERY
|
||||||
//#define TESLA_MODEL_3_BATTERY
|
//#define TESLA_MODEL_3_BATTERY
|
||||||
//#define TEST_FAKE_BATTERY
|
#define TEST_FAKE_BATTERY
|
||||||
|
|
||||||
/* Select inverter communication protocol. See Wiki for which to use with your inverter: https://github.com/dalathegreat/BYD-Battery-Emulator-For-Gen24/wiki */
|
/* Select inverter communication protocol. See Wiki for which to use with your inverter: https://github.com/dalathegreat/BYD-Battery-Emulator-For-Gen24/wiki */
|
||||||
//#define BYD_CAN //Enable this line to emulate a "BYD Battery-Box Premium HVS" over CAN Bus
|
//#define BYD_CAN //Enable this line to emulate a "BYD Battery-Box Premium HVS" over CAN Bus
|
||||||
|
@ -36,10 +36,11 @@
|
||||||
//#define DUAL_CAN //Enable this line to activate an isolated secondary CAN Bus using add-on MCP2515 controller (Needed for FoxESS inverters)
|
//#define DUAL_CAN //Enable this line to activate an isolated secondary CAN Bus using add-on MCP2515 controller (Needed for FoxESS inverters)
|
||||||
//#define SERIAL_LINK_RECEIVER //Enable this line to receive battery data over RS485 pins from another Lilygo (This LilyGo interfaces with inverter)
|
//#define SERIAL_LINK_RECEIVER //Enable this line to receive battery data over RS485 pins from another Lilygo (This LilyGo interfaces with inverter)
|
||||||
//#define SERIAL_LINK_TRANSMITTER //Enable this line to send battery data over RS485 pins to another Lilygo (This LilyGo interfaces with battery)
|
//#define SERIAL_LINK_TRANSMITTER //Enable this line to send battery data over RS485 pins to another Lilygo (This LilyGo interfaces with battery)
|
||||||
//#define WEBSERVER //Enable this line to enable WiFi, and to run the webserver. See USER_SETTINGS.cpp for the Wifi settings.
|
#define WEBSERVER //Enable this line to enable WiFi, and to run the webserver. See USER_SETTINGS.cpp for the Wifi settings.
|
||||||
|
|
||||||
/* Select charger used (Optional) */
|
/* Select charger used (Optional) */
|
||||||
//#define CHEVYVOLT_CHARGER //Enable this line to control a Chevrolet Volt charger connected to battery - for example, when generator charging or using an inverter without a charging function.
|
//#define CHEVYVOLT_CHARGER //Enable this line to control a Chevrolet Volt charger connected to battery - for example, when generator charging or using an inverter without a charging function.
|
||||||
|
#define NISSANLEAF_CHARGER //Enable this line to control a Nissan LEAF PDM connected to battery - for example, when generator charging
|
||||||
|
|
||||||
/* Battery limits: These are set in the USER_SETTINGS.cpp file, or later on via the Webserver */
|
/* Battery limits: These are set in the USER_SETTINGS.cpp file, or later on via the Webserver */
|
||||||
extern volatile uint16_t BATTERY_WH_MAX;
|
extern volatile uint16_t BATTERY_WH_MAX;
|
||||||
|
@ -49,7 +50,7 @@ extern volatile uint16_t MAXCHARGEAMP;
|
||||||
extern volatile uint16_t MAXDISCHARGEAMP;
|
extern volatile uint16_t MAXDISCHARGEAMP;
|
||||||
extern volatile uint8_t AccessPointEnabled;
|
extern volatile uint8_t AccessPointEnabled;
|
||||||
|
|
||||||
/* Charger limits: Set in the USER_SETTINGS.cpp or later in the webserver */
|
/* Charger limits (Optional): Set in the USER_SETTINGS.cpp or later in the webserver */
|
||||||
extern volatile float charger_setpoint_HV_VDC;
|
extern volatile float charger_setpoint_HV_VDC;
|
||||||
extern volatile float charger_setpoint_HV_IDC;
|
extern volatile float charger_setpoint_HV_IDC;
|
||||||
extern volatile float charger_setpoint_HV_IDC_END;
|
extern volatile float charger_setpoint_HV_IDC_END;
|
||||||
|
|
|
@ -25,7 +25,7 @@ void update_values_test_battery() { /* This function puts fake values onto the p
|
||||||
|
|
||||||
StateOfHealth = 9900; // 99.00%
|
StateOfHealth = 9900; // 99.00%
|
||||||
|
|
||||||
battery_voltage = 3700; // 370.0V
|
//battery_voltage = 3700; // 370.0V , value set in startup in .ino file, editable via webUI
|
||||||
|
|
||||||
battery_current = 0; // 0 A
|
battery_current = 0; // 0 A
|
||||||
|
|
||||||
|
|
|
@ -5,4 +5,8 @@
|
||||||
#include "chevyvolt.h"
|
#include "chevyvolt.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef NISSANLEAF_CHARGER
|
||||||
|
#include "nissanleaf.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
256
Software/src/charger/nissanleaf.cpp
Normal file
256
Software/src/charger/nissanleaf.cpp
Normal file
|
@ -0,0 +1,256 @@
|
||||||
|
#include "nissanleaf.h"
|
||||||
|
#include "../lib/miwagner-ESP32-Arduino-CAN/CAN_config.h"
|
||||||
|
#include "../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h"
|
||||||
|
|
||||||
|
/* This implements Nissan LEAF PDM charger support. 2013-2024 Gen2/3 PDMs are supported
|
||||||
|
*
|
||||||
|
* This code is intended to facilitate standalone battery charging,
|
||||||
|
* for instance for troubleshooting purposes or emergency generator usage
|
||||||
|
*
|
||||||
|
* Credits go to:
|
||||||
|
* Damien Maguire (evmbw.org, https://github.com/damienmaguire/Stm32-vcu)
|
||||||
|
*
|
||||||
|
* The code functions a bit differently incase a Nissan LEAF battery is used. Almost
|
||||||
|
* all CAN messages are already sent from the battery in that case, so the charger
|
||||||
|
* implementation can focus on only controlling the charger, spoofing battery messages
|
||||||
|
* is not needed.
|
||||||
|
*
|
||||||
|
* Incase another battery type is used, the code ofcourse emulates a complete Nissan LEAF
|
||||||
|
* battery onto the CAN bus.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* CAN cycles and timers */
|
||||||
|
static const uint8_t interval10ms = 10;
|
||||||
|
static const uint8_t interval100ms = 100;
|
||||||
|
static unsigned long previousMillis10ms = 0;
|
||||||
|
static unsigned long previousMillis100ms = 0;
|
||||||
|
|
||||||
|
/* LEAF charger/battery parameters */
|
||||||
|
enum OBC_MODES : uint8_t { IDLE_OR_QC = 1, FINISHED = 2, CHARGING_OR_INTERRUPTED = 4, IDLE1 = 8, IDLE2 = 9, PLUGGED_IN_WAITING_ON_TIMER };
|
||||||
|
static uint8_t mprun100 = 0; //counter 0-3
|
||||||
|
static uint8_t mprun10 = 0; //counter 0-3
|
||||||
|
static uint8_t OBC_Charge_Status = IDLE_OR_QC;
|
||||||
|
static uint8_t OBCpowerSetpoint = 0;
|
||||||
|
static uint8_t OBCpower = 0;
|
||||||
|
static bool PPStatus = false;
|
||||||
|
static bool OBCwakeup = false;
|
||||||
|
|
||||||
|
/* Voltage and current settings. Validation performed to set ceiling of 3300w vol*cur */
|
||||||
|
extern volatile float charger_setpoint_HV_VDC;
|
||||||
|
extern volatile float charger_setpoint_HV_IDC;
|
||||||
|
extern volatile float charger_setpoint_HV_IDC_END;
|
||||||
|
extern bool charger_HV_enabled;
|
||||||
|
extern bool charger_aux12V_enabled;
|
||||||
|
|
||||||
|
extern float charger_stat_HVcur;
|
||||||
|
extern float charger_stat_HVvol;
|
||||||
|
extern float charger_stat_ACcur;
|
||||||
|
extern float charger_stat_ACvol;
|
||||||
|
extern float charger_stat_LVcur;
|
||||||
|
extern float charger_stat_LVvol;
|
||||||
|
|
||||||
|
//Actual content messages
|
||||||
|
static CAN_frame_t LEAF_1DB = {.FIR = {.B =
|
||||||
|
{
|
||||||
|
.DLC = 8,
|
||||||
|
.FF = CAN_frame_std,
|
||||||
|
}},
|
||||||
|
.MsgID = 0x1DB,
|
||||||
|
.data = {0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00}};
|
||||||
|
static CAN_frame_t LEAF_1DC = {.FIR = {.B =
|
||||||
|
{
|
||||||
|
.DLC = 8,
|
||||||
|
.FF = CAN_frame_std,
|
||||||
|
}},
|
||||||
|
.MsgID = 0x1DC,
|
||||||
|
.data = {0x6E, 0x0A, 0x05, 0xD5, 0x00, 0x00, 0x00, 0x00}};
|
||||||
|
static CAN_frame_t LEAF_1F2 = {.FIR = {.B =
|
||||||
|
{
|
||||||
|
.DLC = 8,
|
||||||
|
.FF = CAN_frame_std,
|
||||||
|
}},
|
||||||
|
.MsgID = 0x1F2,
|
||||||
|
.data = {0x30, 0x00, 0x20, 0xAC, 0x00, 0x3C, 0x00, 0x8F}};
|
||||||
|
static CAN_frame_t LEAF_50B = {.FIR = {.B =
|
||||||
|
{
|
||||||
|
.DLC = 7,
|
||||||
|
.FF = CAN_frame_std,
|
||||||
|
}},
|
||||||
|
.MsgID = 0x50B,
|
||||||
|
.data = {0x00, 0x00, 0x06, 0xC0, 0x00, 0x00, 0x00}};
|
||||||
|
static CAN_frame_t LEAF_55B = {.FIR = {.B =
|
||||||
|
{
|
||||||
|
.DLC = 8,
|
||||||
|
.FF = CAN_frame_std,
|
||||||
|
}},
|
||||||
|
.MsgID = 0x55B,
|
||||||
|
.data = {0xA4, 0x40, 0xAA, 0x00, 0xDF, 0xC0, 0x10, 0x00}};
|
||||||
|
static CAN_frame_t LEAF_5BC = {.FIR = {.B =
|
||||||
|
{
|
||||||
|
.DLC = 8,
|
||||||
|
.FF = CAN_frame_std,
|
||||||
|
}},
|
||||||
|
.MsgID = 0x5BC,
|
||||||
|
.data = {0x3D, 0x80, 0xF0, 0x64, 0xB0, 0x01, 0x00, 0x32}};
|
||||||
|
|
||||||
|
static CAN_frame_t LEAF_59E = {.FIR = {.B =
|
||||||
|
{
|
||||||
|
.DLC = 8,
|
||||||
|
.FF = CAN_frame_std,
|
||||||
|
}},
|
||||||
|
.MsgID = 0x59E,
|
||||||
|
.data = {0x00, 0x00, 0x0C, 0x76, 0x18, 0x00, 0x00, 0x00}};
|
||||||
|
|
||||||
|
static uint8_t crctable[256] = {
|
||||||
|
0, 133, 143, 10, 155, 30, 20, 145, 179, 54, 60, 185, 40, 173, 167, 34, 227, 102, 108, 233, 120, 253,
|
||||||
|
247, 114, 80, 213, 223, 90, 203, 78, 68, 193, 67, 198, 204, 73, 216, 93, 87, 210, 240, 117, 127, 250,
|
||||||
|
107, 238, 228, 97, 160, 37, 47, 170, 59, 190, 180, 49, 19, 150, 156, 25, 136, 13, 7, 130, 134, 3,
|
||||||
|
9, 140, 29, 152, 146, 23, 53, 176, 186, 63, 174, 43, 33, 164, 101, 224, 234, 111, 254, 123, 113, 244,
|
||||||
|
214, 83, 89, 220, 77, 200, 194, 71, 197, 64, 74, 207, 94, 219, 209, 84, 118, 243, 249, 124, 237, 104,
|
||||||
|
98, 231, 38, 163, 169, 44, 189, 56, 50, 183, 149, 16, 26, 159, 14, 139, 129, 4, 137, 12, 6, 131,
|
||||||
|
18, 151, 157, 24, 58, 191, 181, 48, 161, 36, 46, 171, 106, 239, 229, 96, 241, 116, 126, 251, 217, 92,
|
||||||
|
86, 211, 66, 199, 205, 72, 202, 79, 69, 192, 81, 212, 222, 91, 121, 252, 246, 115, 226, 103, 109, 232,
|
||||||
|
41, 172, 166, 35, 178, 55, 61, 184, 154, 31, 21, 144, 1, 132, 142, 11, 15, 138, 128, 5, 148, 17,
|
||||||
|
27, 158, 188, 57, 51, 182, 39, 162, 168, 45, 236, 105, 99, 230, 119, 242, 248, 125, 95, 218, 208, 85,
|
||||||
|
196, 65, 75, 206, 76, 201, 195, 70, 215, 82, 88, 221, 255, 122, 112, 245, 100, 225, 235, 110, 175, 42,
|
||||||
|
32, 165, 52, 177, 187, 62, 28, 153, 147, 22, 135, 2, 8, 141};
|
||||||
|
|
||||||
|
|
||||||
|
void receive_can_nissanleaf_charger(CAN_frame_t rx_frame) {
|
||||||
|
|
||||||
|
switch (rx_frame.MsgID) {
|
||||||
|
case 0x679: // This message fires once when charging cable is plugged in
|
||||||
|
OBCwakeup = true;
|
||||||
|
charger_aux12V_enabled = true; //Not possible to turn off 12V charging
|
||||||
|
// Startout with default values, so that charging can begin when user plugs in cable
|
||||||
|
charger_HV_enabled = true;
|
||||||
|
charger_setpoint_HV_IDC = 16; // Ampere
|
||||||
|
charger_setpoint_HV_VDC = 400; // Target voltage
|
||||||
|
break;
|
||||||
|
case 0x390:
|
||||||
|
OBC_Charge_Status = ((rx_frame.data.u8[5] & 0x7E) >> 1);
|
||||||
|
if(OBC_Charge_Status == PLUGGED_IN_WAITING_ON_TIMER || CHARGING_OR_INTERRUPTED) {
|
||||||
|
PPStatus = true; //plug inserted
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
PPStatus = false; //plug not inserted
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void send_can_nissanleaf_charger() {
|
||||||
|
unsigned long currentMillis = millis();
|
||||||
|
|
||||||
|
/* Send keepalive with mode every 10ms */
|
||||||
|
if (currentMillis - previousMillis10ms >= interval10ms) {
|
||||||
|
previousMillis10ms = currentMillis;
|
||||||
|
|
||||||
|
mprun10++;
|
||||||
|
if (mprun10 >= 4)
|
||||||
|
mprun10 = 0;
|
||||||
|
|
||||||
|
/* 1DB is the main control message. If LEAF battery is used, the battery controls almost everything */
|
||||||
|
// Only send these messages if Nissan LEAF battery is not used
|
||||||
|
#ifndef NISSAN_LEAF_BATTERY
|
||||||
|
|
||||||
|
// VCM message, containing info if battery should sleep or stay awake
|
||||||
|
ESP32Can.CANWriteFrame(&LEAF_50B); // HCM_WakeUpSleepCommand == 11b == WakeUp, and CANMASK = 1
|
||||||
|
|
||||||
|
LEAF_1DB.data.u8[7] = calculate_CRC_Nissan(&LEAF_1DB);
|
||||||
|
ESP32Can.CANWriteFrame(&LEAF_1DB);
|
||||||
|
|
||||||
|
LEAF_1DC.data.u8[7] = calculate_CRC_Nissan(&LEAF_1DC);
|
||||||
|
ESP32Can.CANWriteFrame(&LEAF_1DC);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
OBCpowerSetpoint = ((charger_setpoint_HV_IDC * 4) + 0x64);
|
||||||
|
|
||||||
|
// convert power setpoint to PDM format:
|
||||||
|
// 0xA0 = 15A (60x)
|
||||||
|
// 0x70 = 3 amps ish (12x)
|
||||||
|
// 0x6a = 1.4A (6x)
|
||||||
|
// 0x66 = 0.5A (2x)
|
||||||
|
// 0x65 = 0.3A (1x)
|
||||||
|
// 0x64 = no chg
|
||||||
|
// so 0x64=100. 0xA0=160. so 60 decimal steps. 1 step=100W???
|
||||||
|
|
||||||
|
// This line controls if power should flow or not
|
||||||
|
if (PPStatus && charger_HV_enabled) { //Charging starts when cable plugged in and User has requested charging to start via WebUI
|
||||||
|
// clamp min and max values
|
||||||
|
if (OBCpowerSetpoint > 0xA0) { //15A TODO, raise once cofirmed how to map bits into frame0 and frame1
|
||||||
|
OBCpowerSetpoint = 0xA0;
|
||||||
|
}
|
||||||
|
else if(OBCpowerSetpoint <= 0x64) {
|
||||||
|
OBCpowerSetpoint = 0x64; // 100W? stuck at 100 in drive mode (no charging)
|
||||||
|
}
|
||||||
|
|
||||||
|
// if actual battery_voltage is less than setpoint got to max power set from web ui
|
||||||
|
if (battery_voltage < (CHARGER_SET_HV * 10)) { //battery_voltage = V+1, 0-500.0 (0-5000)
|
||||||
|
OBCpower = OBCpowerSetpoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
// decrement charger power if volt setpoint is reached
|
||||||
|
if (battery_voltage >= (CHARGER_SET_HV * 10)) {
|
||||||
|
OBCpower--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// set power to 0 if charge control is set to off or not in charge mode
|
||||||
|
OBCpower = 0x64;
|
||||||
|
}
|
||||||
|
|
||||||
|
LEAF_1F2.data.u8[1] = OBCpower;
|
||||||
|
LEAF_1F2.data.u8[6] = mprun10;
|
||||||
|
LEAF_1F2.data.u8[7] = calculate_checksum_nibble(&LEAF_1F2);
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
ESP32Can.CANWriteFrame(&LEAF_1F2); // Logic needed to hijack so that the LEAF code does not send the static locked variant when charger is used! This is the only collision message
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Send messages every 100ms here */
|
||||||
|
if (currentMillis - previousMillis100ms >= interval100ms) {
|
||||||
|
previousMillis100ms = currentMillis;
|
||||||
|
|
||||||
|
mprun100++;
|
||||||
|
if (mprun100 > 3) {
|
||||||
|
mprun100 = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only send these messages if Nissan LEAF battery is not used
|
||||||
|
#ifndef NISSAN_LEAF_BATTERY
|
||||||
|
|
||||||
|
LEAF_55B.data.u8[6] = ((0x1 << 4) | (mprun100));
|
||||||
|
|
||||||
|
LEAF_55B.data.u8[7] = calculate_CRC_Nissan(&LEAF_55B);
|
||||||
|
ESP32Can.CANWriteFrame(&LEAF_55B);
|
||||||
|
|
||||||
|
ESP32Can.CANWriteFrame(&LEAF_59E);
|
||||||
|
|
||||||
|
ESP32Can.CANWriteFrame(&LEAF_5BC);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t calculate_CRC_Nissan(CAN_frame_t* frame) {
|
||||||
|
uint8_t crc = 0;
|
||||||
|
for (uint8_t j = 0; j < 7; j++) {
|
||||||
|
crc = crctable[(crc ^ static_cast<uint8_t>(frame->data.u8[j])) % 256];
|
||||||
|
}
|
||||||
|
return crc;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t calculate_checksum_nibble(CAN_frame_t *frame){
|
||||||
|
uint8_t sum = 0;
|
||||||
|
for(uint8_t i = 0; i < 7; i++){
|
||||||
|
sum += frame->data.u8[i] >> 4;
|
||||||
|
sum += frame->data.u8[i] & 0xF;
|
||||||
|
}
|
||||||
|
sum = (sum + 2) & 0xF;
|
||||||
|
return sum;
|
||||||
|
}
|
15
Software/src/charger/nissanleaf.h
Normal file
15
Software/src/charger/nissanleaf.h
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
#ifndef NISSANLEAF_H
|
||||||
|
#define NISSANLEAF_H
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include "../../USER_SETTINGS.h"
|
||||||
|
#include "../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h"
|
||||||
|
|
||||||
|
extern uint16_t battery_voltage; //V+1, 0-500.0 (0-5000)
|
||||||
|
|
||||||
|
void update_values_can_nissanleaf_charger();
|
||||||
|
void send_can_nissanleaf_charger();
|
||||||
|
void receive_can_nissanleaf_charger(CAN_frame_t rx_frame);
|
||||||
|
uint8_t calculate_CRC_Nissan(CAN_frame_t* frame);
|
||||||
|
uint8_t calculate_checksum_nibble(CAN_frame_t *frame);
|
||||||
|
|
||||||
|
#endif
|
|
@ -115,7 +115,23 @@ void init_webserver() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
#ifdef CHEVYVOLT_CHARGER
|
#ifdef TEST_FAKE_BATTERY
|
||||||
|
// Route for editing FakeBatteryVoltage
|
||||||
|
server.on("/updateFakeBatteryVoltage", HTTP_GET, [](AsyncWebServerRequest* request) {
|
||||||
|
if (!request->hasParam("value")) {
|
||||||
|
request->send(400, "text/plain", "Bad Request");
|
||||||
|
}
|
||||||
|
|
||||||
|
String value = request->getParam("value")->value();
|
||||||
|
float val = value.toFloat();
|
||||||
|
|
||||||
|
battery_voltage = val*10;
|
||||||
|
|
||||||
|
request->send(200, "text/plain", "Updated successfully");
|
||||||
|
});
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined CHEVYVOLT_CHARGER || defined NISSANLEAF_CHARGER
|
||||||
// Route for editing ChargerTargetV
|
// Route for editing ChargerTargetV
|
||||||
server.on("/updateChargeSetpointV", HTTP_GET, [](AsyncWebServerRequest* request) {
|
server.on("/updateChargeSetpointV", HTTP_GET, [](AsyncWebServerRequest* request) {
|
||||||
if (!request->hasParam("value")) {
|
if (!request->hasParam("value")) {
|
||||||
|
@ -378,10 +394,13 @@ String processor(const String& var) {
|
||||||
#endif
|
#endif
|
||||||
content += "</h4>";
|
content += "</h4>";
|
||||||
|
|
||||||
#ifdef CHEVYVOLT_CHARGER
|
#if defined CHEVYVOLT_CHARGER || defined NISSANLEAF_CHARGER
|
||||||
content += "<h4 style='color: white;'>Charger protocol: ";
|
content += "<h4 style='color: white;'>Charger protocol: ";
|
||||||
#ifdef CHEVYVOLT_CHARGER
|
#ifdef CHEVYVOLT_CHARGER
|
||||||
content += "Chevy Volt Gen1 Charger";
|
content += "Chevy Volt Gen1 Charger";
|
||||||
|
#endif
|
||||||
|
#ifdef NISSANLEAF_CHARGER
|
||||||
|
content += "Nissan LEAF 2013-2024 PDM charger";
|
||||||
#endif
|
#endif
|
||||||
content += "</h4>";
|
content += "</h4>";
|
||||||
#endif
|
#endif
|
||||||
|
@ -479,7 +498,13 @@ String processor(const String& var) {
|
||||||
content += "<span style='color: red;'>✕</span></h4>";
|
content += "<span style='color: red;'>✕</span></h4>";
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CHEVYVOLT_CHARGER
|
// Close the block
|
||||||
|
content += "</div>";
|
||||||
|
|
||||||
|
#if defined CHEVYVOLT_CHARGER || defined NISSANLEAF_CHARGER
|
||||||
|
// Start a new block with orange background color
|
||||||
|
content += "<div style='background-color: #FF6E00; padding: 10px; margin-bottom: 10px;border-radius: 50px'>";
|
||||||
|
|
||||||
content += "<h4>Charger HV Enabled: ";
|
content += "<h4>Charger HV Enabled: ";
|
||||||
if (charger_HV_enabled) {
|
if (charger_HV_enabled) {
|
||||||
content += "<span>✓</span>";
|
content += "<span>✓</span>";
|
||||||
|
@ -513,10 +538,12 @@ String processor(const String& var) {
|
||||||
content += "<h4 style='color: white;'>Charger LVDC Output V: " + String(LVvol, 2) + "</h4>";
|
content += "<h4 style='color: white;'>Charger LVDC Output V: " + String(LVvol, 2) + "</h4>";
|
||||||
content += "<h4 style='color: white;'>Charger AC Input V: " + String(ACvol, 2) + "VAC</h4>";
|
content += "<h4 style='color: white;'>Charger AC Input V: " + String(ACvol, 2) + "VAC</h4>";
|
||||||
content += "<h4 style='color: white;'>Charger AC Input I: " + String(ACvol, 2) + "VAC</h4>";
|
content += "<h4 style='color: white;'>Charger AC Input I: " + String(ACvol, 2) + "VAC</h4>";
|
||||||
#endif
|
|
||||||
|
|
||||||
// Close the block
|
// Close the block
|
||||||
content += "</div>";
|
content += "</div>";
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
content += "<button onclick='goToUpdatePage()'>Perform OTA update</button>";
|
content += "<button onclick='goToUpdatePage()'>Perform OTA update</button>";
|
||||||
content += " ";
|
content += " ";
|
||||||
|
@ -569,7 +596,25 @@ String settings_processor(const String& var) {
|
||||||
" A </span> <button onclick='editMaxChargeA()'>Edit</button></h4>";
|
" A </span> <button onclick='editMaxChargeA()'>Edit</button></h4>";
|
||||||
content += "<h4 style='color: white;'>Max discharge speed: " + String(MAXDISCHARGEAMP / 10.0, 1) +
|
content += "<h4 style='color: white;'>Max discharge speed: " + String(MAXDISCHARGEAMP / 10.0, 1) +
|
||||||
" A </span> <button onclick='editMaxDischargeA()'>Edit</button></h4>";
|
" A </span> <button onclick='editMaxDischargeA()'>Edit</button></h4>";
|
||||||
#ifdef CHEVYVOLT_CHARGER
|
// Close the block
|
||||||
|
content += "</div>";
|
||||||
|
|
||||||
|
#ifdef TEST_FAKE_BATTERY
|
||||||
|
// Start a new block with blue background color
|
||||||
|
content += "<div style='background-color: #2E37AD; padding: 10px; margin-bottom: 10px;border-radius: 50px'>";
|
||||||
|
float voltageFloat = static_cast<float>(battery_voltage) / 10.0; // Convert to float and divide by 10
|
||||||
|
content += "<h4 style='color: white;'>Fake battery voltage: " + String(voltageFloat, 1) +
|
||||||
|
" V </span> <button onclick='editFakeBatteryVoltage()'>Edit</button></h4>";
|
||||||
|
|
||||||
|
// Close the block
|
||||||
|
content += "</div>";
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined CHEVYVOLT_CHARGER || defined NISSANLEAF_CHARGER
|
||||||
|
|
||||||
|
// Start a new block with orange background color
|
||||||
|
content += "<div style='background-color: #FF6E00; padding: 10px; margin-bottom: 10px;border-radius: 50px'>";
|
||||||
|
|
||||||
content += "<h4 style='color: white;'>Charger HVDC Enabled: ";
|
content += "<h4 style='color: white;'>Charger HVDC Enabled: ";
|
||||||
if (charger_HV_enabled) {
|
if (charger_HV_enabled) {
|
||||||
content += "<span>✓</span>";
|
content += "<span>✓</span>";
|
||||||
|
@ -590,6 +635,9 @@ String settings_processor(const String& var) {
|
||||||
" V </span> <button onclick='editChargerSetpointVDC()'>Edit</button></h4>";
|
" V </span> <button onclick='editChargerSetpointVDC()'>Edit</button></h4>";
|
||||||
content += "<h4 style='color: white;'>Charger Current Setpoint: " + String(charger_setpoint_HV_IDC, 1) +
|
content += "<h4 style='color: white;'>Charger Current Setpoint: " + String(charger_setpoint_HV_IDC, 1) +
|
||||||
" A </span> <button onclick='editChargerSetpointIDC()'>Edit</button></h4>";
|
" A </span> <button onclick='editChargerSetpointIDC()'>Edit</button></h4>";
|
||||||
|
|
||||||
|
// Close the block
|
||||||
|
content += "</div>";
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
content += "<script>";
|
content += "<script>";
|
||||||
|
@ -662,7 +710,22 @@ String settings_processor(const String& var) {
|
||||||
content += "}";
|
content += "}";
|
||||||
content += "}";
|
content += "}";
|
||||||
|
|
||||||
#ifdef CHEVYVOLT_CHARGER
|
#ifdef TEST_FAKE_BATTERY
|
||||||
|
content += "function editFakeBatteryVoltage() {";
|
||||||
|
content += " var value = prompt('Enter new fake battery voltage');";
|
||||||
|
content += "if (value !== null) {";
|
||||||
|
content += " if (value >= 0 && value <= 5000) {";
|
||||||
|
content += " var xhr = new XMLHttpRequest();";
|
||||||
|
content += " xhr.open('GET', '/updateFakeBatteryVoltage?value=' + value, true);";
|
||||||
|
content += " xhr.send();";
|
||||||
|
content += " } else {";
|
||||||
|
content += " alert('Invalid value. Please enter a value between 0 and 1000');";
|
||||||
|
content += " }";
|
||||||
|
content += "}";
|
||||||
|
content += "}";
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined CHEVYVOLT_CHARGER || defined NISSANLEAF_CHARGER
|
||||||
content += "function editChargerHVDCEnabled() {";
|
content += "function editChargerHVDCEnabled() {";
|
||||||
content += " var value = prompt('Enable or disable HV DC output. Enter 1 for enabled, 0 for disabled');";
|
content += " var value = prompt('Enable or disable HV DC output. Enter 1 for enabled, 0 for disabled');";
|
||||||
content += " if (value !== null) {";
|
content += " if (value !== null) {";
|
||||||
|
@ -738,9 +801,6 @@ String settings_processor(const String& var) {
|
||||||
#endif
|
#endif
|
||||||
content += "</script>";
|
content += "</script>";
|
||||||
|
|
||||||
// Close the block
|
|
||||||
content += "</div>";
|
|
||||||
|
|
||||||
content += "<button onclick='goToMainPage()'>Back to main page</button>";
|
content += "<button onclick='goToMainPage()'>Back to main page</button>";
|
||||||
content += "<script>";
|
content += "<script>";
|
||||||
content += "function goToMainPage() { window.location.href = '/'; }";
|
content += "function goToMainPage() { window.location.href = '/'; }";
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue