mirror of
https://github.com/dalathegreat/Battery-Emulator.git
synced 2025-10-03 17:59:27 +02:00
Merge branch 'main' into feature/tesla-balancing
This commit is contained in:
commit
54db0a2216
28 changed files with 432 additions and 109 deletions
|
@ -51,7 +51,7 @@
|
||||||
#endif // WIFI
|
#endif // WIFI
|
||||||
|
|
||||||
// The current software version, shown on webserver
|
// The current software version, shown on webserver
|
||||||
const char* version_number = "8.0.dev";
|
const char* version_number = "8.1.dev";
|
||||||
|
|
||||||
// Interval settings
|
// Interval settings
|
||||||
uint16_t intervalUpdateValues = INTERVAL_1_S; // Interval at which to update inverter values / Modbus registers
|
uint16_t intervalUpdateValues = INTERVAL_1_S; // Interval at which to update inverter values / Modbus registers
|
||||||
|
@ -124,6 +124,9 @@ void setup() {
|
||||||
setup_battery();
|
setup_battery();
|
||||||
#ifdef EQUIPMENT_STOP_BUTTON
|
#ifdef EQUIPMENT_STOP_BUTTON
|
||||||
init_equipment_stop_button();
|
init_equipment_stop_button();
|
||||||
|
#endif
|
||||||
|
#ifdef CAN_SHUNT_SELECTED
|
||||||
|
setup_can_shunt();
|
||||||
#endif
|
#endif
|
||||||
// BOOT button at runtime is used as an input for various things
|
// BOOT button at runtime is used as an input for various things
|
||||||
pinMode(0, INPUT_PULLUP);
|
pinMode(0, INPUT_PULLUP);
|
||||||
|
|
|
@ -17,7 +17,8 @@ volatile CAN_Configuration can_config = {
|
||||||
.battery = CAN_NATIVE, // Which CAN is your battery connected to?
|
.battery = CAN_NATIVE, // Which CAN is your battery connected to?
|
||||||
.inverter = CAN_NATIVE, // Which CAN is your inverter connected to? (No need to configure incase you use RS485)
|
.inverter = CAN_NATIVE, // Which CAN is your inverter connected to? (No need to configure incase you use RS485)
|
||||||
.battery_double = CAN_ADDON_MCP2515, // (OPTIONAL) Which CAN is your second battery connected to?
|
.battery_double = CAN_ADDON_MCP2515, // (OPTIONAL) Which CAN is your second battery connected to?
|
||||||
.charger = CAN_NATIVE // (OPTIONAL) Which CAN is your charger connected to?
|
.charger = CAN_NATIVE, // (OPTIONAL) Which CAN is your charger connected to?
|
||||||
|
.shunt = CAN_NATIVE // (OPTIONAL) Which CAN is your shunt connected to?
|
||||||
};
|
};
|
||||||
|
|
||||||
std::string ssid = WIFI_SSID; // Set in USER_SECRETS.h
|
std::string ssid = WIFI_SSID; // Set in USER_SECRETS.h
|
||||||
|
|
|
@ -67,6 +67,9 @@
|
||||||
//#define PWM_CONTACTOR_CONTROL //Enable this line to use PWM for CONTACTOR_CONTROL, which lowers power consumption and heat generation. CONTACTOR_CONTROL must be enabled.
|
//#define PWM_CONTACTOR_CONTROL //Enable this line to use PWM for CONTACTOR_CONTROL, which lowers power consumption and heat generation. CONTACTOR_CONTROL must be enabled.
|
||||||
//#define NC_CONTACTORS //Enable this line to control normally closed contactors. CONTACTOR_CONTROL must be enabled for this option. Extremely rare setting!
|
//#define NC_CONTACTORS //Enable this line to control normally closed contactors. CONTACTOR_CONTROL must be enabled for this option. Extremely rare setting!
|
||||||
|
|
||||||
|
/* Shunt/Contactor settings */
|
||||||
|
//#define BMW_SBOX // SBOX relay control & battery current/voltage measurement
|
||||||
|
|
||||||
/* Other options */
|
/* Other options */
|
||||||
//#define DEBUG_VIA_USB //Enable this line to have the USB port output serial diagnostic data while program runs (WARNING, raises CPU load, do not use for production)
|
//#define DEBUG_VIA_USB //Enable this line to have the USB port output serial diagnostic data while program runs (WARNING, raises CPU load, do not use for production)
|
||||||
//#define DEBUG_VIA_WEB //Enable this line to log diagnostic data while program runs, which can be viewed via webpage (WARNING, slightly raises CPU load, do not use for production)
|
//#define DEBUG_VIA_WEB //Enable this line to log diagnostic data while program runs, which can be viewed via webpage (WARNING, slightly raises CPU load, do not use for production)
|
||||||
|
@ -143,6 +146,7 @@ typedef struct {
|
||||||
CAN_Interface inverter;
|
CAN_Interface inverter;
|
||||||
CAN_Interface battery_double;
|
CAN_Interface battery_double;
|
||||||
CAN_Interface charger;
|
CAN_Interface charger;
|
||||||
|
CAN_Interface shunt;
|
||||||
} CAN_Configuration;
|
} CAN_Configuration;
|
||||||
extern volatile CAN_Configuration can_config;
|
extern volatile CAN_Configuration can_config;
|
||||||
extern volatile uint8_t AccessPointEnabled;
|
extern volatile uint8_t AccessPointEnabled;
|
||||||
|
|
|
@ -2,6 +2,13 @@
|
||||||
#define BATTERIES_H
|
#define BATTERIES_H
|
||||||
#include "../../USER_SETTINGS.h"
|
#include "../../USER_SETTINGS.h"
|
||||||
|
|
||||||
|
#ifdef BMW_SBOX
|
||||||
|
#include "BMW-SBOX.h"
|
||||||
|
void handle_incoming_can_frame_shunt(CAN_frame rx_frame);
|
||||||
|
void transmit_can_shunt();
|
||||||
|
void setup_can_shunt();
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef BMW_I3_BATTERY
|
#ifdef BMW_I3_BATTERY
|
||||||
#include "BMW-I3-BATTERY.h"
|
#include "BMW-I3-BATTERY.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
218
Software/src/battery/BMW-SBOX.cpp
Normal file
218
Software/src/battery/BMW-SBOX.cpp
Normal file
|
@ -0,0 +1,218 @@
|
||||||
|
#include "../include.h"
|
||||||
|
#ifdef BMW_SBOX
|
||||||
|
#include "../datalayer/datalayer.h"
|
||||||
|
#include "BMW-SBOX.h"
|
||||||
|
|
||||||
|
#define MAX_ALLOWED_FAULT_TICKS 1000
|
||||||
|
|
||||||
|
enum SboxState { DISCONNECTED, PRECHARGE, NEGATIVE, POSITIVE, PRECHARGE_OFF, COMPLETED, SHUTDOWN_REQUESTED };
|
||||||
|
SboxState contactorStatus = DISCONNECTED;
|
||||||
|
|
||||||
|
unsigned long prechargeStartTime = 0;
|
||||||
|
unsigned long negativeStartTime = 0;
|
||||||
|
unsigned long positiveStartTime = 0;
|
||||||
|
unsigned long timeSpentInFaultedMode = 0;
|
||||||
|
unsigned long LastMsgTime = 0; // will store last time a 20ms CAN Message was send
|
||||||
|
unsigned long LastAvgTime = 0; // Last current storage time
|
||||||
|
unsigned long ShuntLastSeen = 0;
|
||||||
|
|
||||||
|
uint32_t avg_mA_array[10];
|
||||||
|
uint32_t avg_sum;
|
||||||
|
|
||||||
|
uint8_t k; //avg array pointer
|
||||||
|
|
||||||
|
uint8_t CAN100_cnt = 0;
|
||||||
|
|
||||||
|
CAN_frame SBOX_100 = {.FD = false,
|
||||||
|
.ext_ID = false,
|
||||||
|
.DLC = 4,
|
||||||
|
.ID = 0x100,
|
||||||
|
.data = {0x55, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00}}; // Byte 0: relay control, Byte 1: counter 0-E, Byte 4: CRC
|
||||||
|
|
||||||
|
CAN_frame SBOX_300 = {.FD = false,
|
||||||
|
.ext_ID = false,
|
||||||
|
.DLC = 4,
|
||||||
|
.ID = 0x300,
|
||||||
|
.data = {0xFF, 0xFE, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00}}; // Static frame
|
||||||
|
|
||||||
|
uint8_t reverse_bits(uint8_t byte) {
|
||||||
|
uint8_t reversed = 0;
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
|
reversed = (reversed << 1) | (byte & 1);
|
||||||
|
byte >>= 1;
|
||||||
|
}
|
||||||
|
return reversed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** CRC8, both inverted, poly 0x31 **/
|
||||||
|
uint8_t calculateCRC(CAN_frame CAN) {
|
||||||
|
uint8_t crc = 0;
|
||||||
|
for (size_t i = 0; i < CAN.DLC; i++) {
|
||||||
|
uint8_t reversed_byte = reverse_bits(CAN.data.u8[i]);
|
||||||
|
crc ^= reversed_byte;
|
||||||
|
for (int j = 0; j < 8; j++) {
|
||||||
|
if (crc & 0x80) {
|
||||||
|
crc = (crc << 1) ^ 0x31;
|
||||||
|
} else {
|
||||||
|
crc <<= 1;
|
||||||
|
}
|
||||||
|
crc &= 0xFF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
crc = reverse_bits(crc);
|
||||||
|
return crc;
|
||||||
|
}
|
||||||
|
|
||||||
|
void handle_incoming_can_frame_shunt(CAN_frame rx_frame) {
|
||||||
|
unsigned long currentTime = millis();
|
||||||
|
if (rx_frame.ID == 0x200) {
|
||||||
|
ShuntLastSeen = currentTime;
|
||||||
|
datalayer.shunt.measured_amperage_mA =
|
||||||
|
((rx_frame.data.u8[2] << 24) | (rx_frame.data.u8[1] << 16) | (rx_frame.data.u8[0] << 8)) / 256;
|
||||||
|
datalayer.shunt.measured_amperage_dA = datalayer.shunt.measured_amperage_mA / 100;
|
||||||
|
|
||||||
|
/** Calculate 1S avg current **/
|
||||||
|
if (LastAvgTime + 100 < currentTime) {
|
||||||
|
LastAvgTime = currentTime;
|
||||||
|
if (k > 9) {
|
||||||
|
k = 0;
|
||||||
|
}
|
||||||
|
avg_mA_array[k] = datalayer.shunt.measured_amperage_mA;
|
||||||
|
k++;
|
||||||
|
avg_sum = 0;
|
||||||
|
for (uint8_t i = 0; i < 10; i++) {
|
||||||
|
avg_sum = avg_sum + avg_mA_array[i];
|
||||||
|
}
|
||||||
|
datalayer.shunt.measured_avg1S_amperage_mA = avg_sum / 10;
|
||||||
|
}
|
||||||
|
} else if (rx_frame.ID == 0x210) //SBOX input (battery side) voltage
|
||||||
|
{
|
||||||
|
ShuntLastSeen = currentTime;
|
||||||
|
datalayer.shunt.measured_voltage_mV =
|
||||||
|
((rx_frame.data.u8[2] << 16) | (rx_frame.data.u8[1] << 8) | (rx_frame.data.u8[0]));
|
||||||
|
} else if (rx_frame.ID == 0x220) //SBOX output voltage
|
||||||
|
{
|
||||||
|
ShuntLastSeen = currentTime;
|
||||||
|
datalayer.shunt.measured_outvoltage_mV =
|
||||||
|
((rx_frame.data.u8[2] << 16) | (rx_frame.data.u8[1] << 8) | (rx_frame.data.u8[0]));
|
||||||
|
datalayer.shunt.available = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void transmit_can_shunt() {
|
||||||
|
unsigned long currentTime = millis();
|
||||||
|
|
||||||
|
/** Shunt can frames seen? **/
|
||||||
|
if (ShuntLastSeen + 1000 < currentTime) {
|
||||||
|
datalayer.shunt.available = false;
|
||||||
|
} else {
|
||||||
|
datalayer.shunt.available = true;
|
||||||
|
}
|
||||||
|
// Send 20ms CAN Message
|
||||||
|
if (currentTime - LastMsgTime >= INTERVAL_20_MS) {
|
||||||
|
LastMsgTime = currentTime;
|
||||||
|
// First check if we have any active errors, incase we do, turn off the battery
|
||||||
|
if (datalayer.battery.status.bms_status == FAULT) {
|
||||||
|
timeSpentInFaultedMode++;
|
||||||
|
} else {
|
||||||
|
timeSpentInFaultedMode = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//handle contactor control SHUTDOWN_REQUESTED
|
||||||
|
if (timeSpentInFaultedMode > MAX_ALLOWED_FAULT_TICKS) {
|
||||||
|
contactorStatus = SHUTDOWN_REQUESTED;
|
||||||
|
SBOX_100.data.u8[0] = 0x55; // All open
|
||||||
|
}
|
||||||
|
|
||||||
|
if (contactorStatus == SHUTDOWN_REQUESTED) {
|
||||||
|
datalayer.shunt.contactors_engaged = false;
|
||||||
|
return; // A fault scenario latches the contactor control. It is not possible to recover without a powercycle (and investigation why fault occured)
|
||||||
|
}
|
||||||
|
|
||||||
|
// After that, check if we are OK to start turning on the contactors
|
||||||
|
if (contactorStatus == DISCONNECTED) {
|
||||||
|
datalayer.shunt.contactors_engaged = false;
|
||||||
|
SBOX_100.data.u8[0] = 0x55; // All open
|
||||||
|
|
||||||
|
if (datalayer.system.status.battery_allows_contactor_closing &&
|
||||||
|
datalayer.system.status.inverter_allows_contactor_closing &&
|
||||||
|
!datalayer.system.settings.equipment_stop_active &&
|
||||||
|
(datalayer.shunt.measured_voltage_mV > MINIMUM_INPUT_VOLTAGE * 1000)) {
|
||||||
|
contactorStatus = PRECHARGE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// In case the inverter requests contactors to open, set the state accordingly
|
||||||
|
if (contactorStatus == COMPLETED) {
|
||||||
|
//Incase inverter (or estop) requests contactors to open, make state machine jump to Disconnected state (recoverable)
|
||||||
|
if (!datalayer.system.status.inverter_allows_contactor_closing ||
|
||||||
|
datalayer.system.settings.equipment_stop_active) {
|
||||||
|
contactorStatus = DISCONNECTED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Handle actual state machine. This first turns on Precharge, then Negative, then Positive, and finally turns OFF precharge
|
||||||
|
switch (contactorStatus) {
|
||||||
|
case PRECHARGE:
|
||||||
|
SBOX_100.data.u8[0] = 0x86; // Precharge relay only
|
||||||
|
prechargeStartTime = currentTime;
|
||||||
|
contactorStatus = NEGATIVE;
|
||||||
|
#ifdef DEBUG_VIA_USB
|
||||||
|
Serial.println("S-BOX Precharge relay engaged");
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
case NEGATIVE:
|
||||||
|
if (currentTime - prechargeStartTime >= CONTACTOR_CONTROL_T1) {
|
||||||
|
SBOX_100.data.u8[0] = 0xA6; // Precharge + Negative
|
||||||
|
negativeStartTime = currentTime;
|
||||||
|
contactorStatus = POSITIVE;
|
||||||
|
datalayer.shunt.precharging = true;
|
||||||
|
#ifdef DEBUG_VIA_USB
|
||||||
|
Serial.println("S-BOX Negative relay engaged");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case POSITIVE:
|
||||||
|
if (currentTime - negativeStartTime >= CONTACTOR_CONTROL_T2 &&
|
||||||
|
(datalayer.shunt.measured_voltage_mV * MAX_PRECHARGE_RESISTOR_VOLTAGE_PERCENT <
|
||||||
|
datalayer.shunt.measured_outvoltage_mV)) {
|
||||||
|
SBOX_100.data.u8[0] = 0xAA; // Precharge + Negative + Positive
|
||||||
|
positiveStartTime = currentTime;
|
||||||
|
contactorStatus = PRECHARGE_OFF;
|
||||||
|
datalayer.shunt.precharging = false;
|
||||||
|
#ifdef DEBUG_VIA_USB
|
||||||
|
Serial.println("S-BOX Positive relay engaged");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case PRECHARGE_OFF:
|
||||||
|
if (currentTime - positiveStartTime >= CONTACTOR_CONTROL_T3) {
|
||||||
|
SBOX_100.data.u8[0] = 0x6A; // Negative + Positive
|
||||||
|
contactorStatus = COMPLETED;
|
||||||
|
#ifdef DEBUG_VIA_USB
|
||||||
|
Serial.println("S-BOX Precharge relay released");
|
||||||
|
#endif
|
||||||
|
datalayer.shunt.contactors_engaged = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case COMPLETED:
|
||||||
|
SBOX_100.data.u8[0] = 0x6A; // Negative + Positive
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
CAN100_cnt++;
|
||||||
|
if (CAN100_cnt > 0x0E) {
|
||||||
|
CAN100_cnt = 0;
|
||||||
|
}
|
||||||
|
SBOX_100.data.u8[1] = CAN100_cnt << 4 | 0x01;
|
||||||
|
SBOX_100.data.u8[3] = 0x00;
|
||||||
|
SBOX_100.data.u8[3] = calculateCRC(SBOX_100);
|
||||||
|
transmit_can_frame(&SBOX_100, can_config.shunt);
|
||||||
|
transmit_can_frame(&SBOX_300, can_config.shunt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_can_shunt() {
|
||||||
|
strncpy(datalayer.system.info.shunt_protocol, "BMW SBOX", 63);
|
||||||
|
datalayer.system.info.shunt_protocol[63] = '\0';
|
||||||
|
}
|
||||||
|
#endif
|
22
Software/src/battery/BMW-SBOX.h
Normal file
22
Software/src/battery/BMW-SBOX.h
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
#ifndef BMW_SBOX_CONTROL_H
|
||||||
|
#define BMW_SBOX_CONTROL_H
|
||||||
|
#include "../include.h"
|
||||||
|
#define CAN_SHUNT_SELECTED
|
||||||
|
void transmit_can(CAN_frame* tx_frame, int interface);
|
||||||
|
|
||||||
|
/** Minimum input voltage required to enable relay control **/
|
||||||
|
#define MINIMUM_INPUT_VOLTAGE 250
|
||||||
|
|
||||||
|
/** Minimum required percentage of input voltage at the output port to engage the positive relay. **/
|
||||||
|
/** Prevents engagement of the positive contactor if the precharge resistor is faulty. **/
|
||||||
|
#define MAX_PRECHARGE_RESISTOR_VOLTAGE_PERCENT 0.99
|
||||||
|
|
||||||
|
/* NOTE: modify the T2 time constant below to account for the resistance and capacitance of the target system.
|
||||||
|
* t=3RC at minimum, t=5RC ideally
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define CONTACTOR_CONTROL_T1 5000 // Time before negative contactor engages and precharging starts
|
||||||
|
#define CONTACTOR_CONTROL_T2 5000 // Precharge time before precharge resistor is bypassed by positive contactor
|
||||||
|
#define CONTACTOR_CONTROL_T3 2000 // Precharge relay lead time after positive contactor has been engaged
|
||||||
|
|
||||||
|
#endif
|
|
@ -106,8 +106,8 @@ void update_values_battery() {
|
||||||
/*Finally print out values to serial if configured to do so*/
|
/*Finally print out values to serial if configured to do so*/
|
||||||
#ifdef DEBUG_LOG
|
#ifdef DEBUG_LOG
|
||||||
logging.println("Values going to inverter");
|
logging.println("Values going to inverter");
|
||||||
print_units("SOH: ", (datalayer.battery.status.soh_pptt * 0.01), "pct ");
|
print_units("SOH%: ", (datalayer.battery.status.soh_pptt * 0.01), "% ");
|
||||||
print_units(", SOC: ", (datalayer.battery.status.reported_soc * 0.01), "pct ");
|
print_units(", SOC%: ", (datalayer.battery.status.reported_soc * 0.01), "% ");
|
||||||
print_units(", Voltage: ", (datalayer.battery.status.voltage_dV * 0.1), "V ");
|
print_units(", Voltage: ", (datalayer.battery.status.voltage_dV * 0.1), "V ");
|
||||||
print_units(", Max discharge power: ", datalayer.battery.status.max_discharge_power_W, "W ");
|
print_units(", Max discharge power: ", datalayer.battery.status.max_discharge_power_W, "W ");
|
||||||
print_units(", Max charge power: ", datalayer.battery.status.max_charge_power_W, "W ");
|
print_units(", Max charge power: ", datalayer.battery.status.max_charge_power_W, "W ");
|
||||||
|
|
|
@ -695,11 +695,11 @@ void update_values_battery() { //This function maps all the values fetched via
|
||||||
logging.println("Values from battery: ");
|
logging.println("Values from battery: ");
|
||||||
logging.print("SOC BMS: ");
|
logging.print("SOC BMS: ");
|
||||||
logging.print((uint16_t)SOC_BMS / 10.0, 1);
|
logging.print((uint16_t)SOC_BMS / 10.0, 1);
|
||||||
logging.print("pct | SOC Display: ");
|
logging.print("% | SOC Display: ");
|
||||||
logging.print((uint16_t)SOC_Display / 10.0, 1);
|
logging.print((uint16_t)SOC_Display / 10.0, 1);
|
||||||
logging.print("pct | SOH ");
|
logging.print("% | SOH ");
|
||||||
logging.print((uint16_t)batterySOH / 10.0, 1);
|
logging.print((uint16_t)batterySOH / 10.0, 1);
|
||||||
logging.println("pct");
|
logging.println("%");
|
||||||
logging.print((int16_t)batteryAmps / 10.0, 1);
|
logging.print((int16_t)batteryAmps / 10.0, 1);
|
||||||
logging.print(" Amps | ");
|
logging.print(" Amps | ");
|
||||||
logging.print((uint16_t)batteryVoltage / 10.0, 1);
|
logging.print((uint16_t)batteryVoltage / 10.0, 1);
|
||||||
|
|
|
@ -147,11 +147,11 @@ void update_values_battery() { //This function maps all the values fetched via
|
||||||
logging.println("Values from battery: ");
|
logging.println("Values from battery: ");
|
||||||
logging.print("SOC BMS: ");
|
logging.print("SOC BMS: ");
|
||||||
logging.print((uint16_t)SOC_BMS / 10.0, 1);
|
logging.print((uint16_t)SOC_BMS / 10.0, 1);
|
||||||
logging.print("pct | SOC Display: ");
|
logging.print("% | SOC Display: ");
|
||||||
logging.print((uint16_t)SOC_Display / 10.0, 1);
|
logging.print((uint16_t)SOC_Display / 10.0, 1);
|
||||||
logging.print("pct | SOH ");
|
logging.print("% | SOH ");
|
||||||
logging.print((uint16_t)batterySOH / 10.0, 1);
|
logging.print((uint16_t)batterySOH / 10.0, 1);
|
||||||
logging.println("pct");
|
logging.println("%");
|
||||||
logging.print((int16_t)batteryAmps / 10.0, 1);
|
logging.print((int16_t)batteryAmps / 10.0, 1);
|
||||||
logging.print(" Amps | ");
|
logging.print(" Amps | ");
|
||||||
logging.print((uint16_t)batteryVoltage / 10.0, 1);
|
logging.print((uint16_t)batteryVoltage / 10.0, 1);
|
||||||
|
|
|
@ -44,7 +44,7 @@ CAN_frame LEAF_GROUP_REQUEST = {.FD = false,
|
||||||
.ext_ID = false,
|
.ext_ID = false,
|
||||||
.DLC = 8,
|
.DLC = 8,
|
||||||
.ID = 0x79B,
|
.ID = 0x79B,
|
||||||
.data = {0x02, 0x21, PIDgroups[0], 0, 0, 0, 0, 0}};
|
.data = {2, 0x21, 1, 0, 0, 0, 0, 0}};
|
||||||
CAN_frame LEAF_NEXT_LINE_REQUEST = {.FD = false,
|
CAN_frame LEAF_NEXT_LINE_REQUEST = {.FD = false,
|
||||||
.ext_ID = false,
|
.ext_ID = false,
|
||||||
.DLC = 8,
|
.DLC = 8,
|
||||||
|
@ -110,7 +110,7 @@ static bool battery_Batt_Heater_Mail_Send_Request = false; //Stores info when a
|
||||||
static uint8_t battery_request_idx = 0;
|
static uint8_t battery_request_idx = 0;
|
||||||
static uint8_t group_7bb = 0;
|
static uint8_t group_7bb = 0;
|
||||||
static bool stop_battery_query = true;
|
static bool stop_battery_query = true;
|
||||||
static uint8_t hold_off_with_polling_10seconds = 10;
|
static uint8_t hold_off_with_polling_10seconds = 2; //Paused for 20 seconds on startup
|
||||||
static uint16_t battery_cell_voltages[97]; //array with all the cellvoltages
|
static uint16_t battery_cell_voltages[97]; //array with all the cellvoltages
|
||||||
static uint8_t battery_cellcounter = 0;
|
static uint8_t battery_cellcounter = 0;
|
||||||
static uint16_t battery_min_max_voltage[2]; //contains cell min[0] and max[1] values in mV
|
static uint16_t battery_min_max_voltage[2]; //contains cell min[0] and max[1] values in mV
|
||||||
|
@ -612,10 +612,11 @@ void handle_incoming_can_frame_battery2(CAN_frame rx_frame) {
|
||||||
//First check which group data we are getting
|
//First check which group data we are getting
|
||||||
if (rx_frame.data.u8[0] == 0x10) { //First message of a group
|
if (rx_frame.data.u8[0] == 0x10) { //First message of a group
|
||||||
battery2_group_7bb = rx_frame.data.u8[3];
|
battery2_group_7bb = rx_frame.data.u8[3];
|
||||||
transmit_can_frame(&LEAF_NEXT_LINE_REQUEST, can_config.battery_double);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (battery2_group_7bb == 1) //High precision SOC, Current, voltages etc.
|
transmit_can_frame(&LEAF_NEXT_LINE_REQUEST, can_config.battery_double);
|
||||||
|
|
||||||
|
if (battery2_group_7bb == 0x01) //High precision SOC, Current, voltages etc.
|
||||||
{
|
{
|
||||||
if (rx_frame.data.u8[0] == 0x10) { //First frame
|
if (rx_frame.data.u8[0] == 0x10) { //First frame
|
||||||
//High precision battery2_current_1 resides here, but has been deemed unusable by 62kWh owners
|
//High precision battery2_current_1 resides here, but has been deemed unusable by 62kWh owners
|
||||||
|
@ -633,7 +634,7 @@ void handle_incoming_can_frame_battery2(CAN_frame rx_frame) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (battery2_group_7bb == 2) //Cell Voltages
|
if (battery2_group_7bb == 0x02) //Cell Voltages
|
||||||
{
|
{
|
||||||
if (rx_frame.data.u8[0] == 0x10) { //first frame is anomalous
|
if (rx_frame.data.u8[0] == 0x10) { //first frame is anomalous
|
||||||
battery2_request_idx = 0;
|
battery2_request_idx = 0;
|
||||||
|
@ -676,7 +677,7 @@ void handle_incoming_can_frame_battery2(CAN_frame rx_frame) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (battery2_group_7bb == 4) { //Temperatures
|
if (battery2_group_7bb == 0x04) { //Temperatures
|
||||||
if (rx_frame.data.u8[0] == 0x10) { //First message
|
if (rx_frame.data.u8[0] == 0x10) { //First message
|
||||||
battery2_temp_raw_1 = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5];
|
battery2_temp_raw_1 = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5];
|
||||||
battery2_temp_raw_2_highnibble = rx_frame.data.u8[7];
|
battery2_temp_raw_2_highnibble = rx_frame.data.u8[7];
|
||||||
|
@ -869,11 +870,11 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) {
|
||||||
//First check which group data we are getting
|
//First check which group data we are getting
|
||||||
if (rx_frame.data.u8[0] == 0x10) { //First message of a group
|
if (rx_frame.data.u8[0] == 0x10) { //First message of a group
|
||||||
group_7bb = rx_frame.data.u8[3];
|
group_7bb = rx_frame.data.u8[3];
|
||||||
|
|
||||||
transmit_can_frame(&LEAF_NEXT_LINE_REQUEST, can_config.battery); //Request the next frame for the group
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (group_7bb == 1) //High precision SOC, Current, voltages etc.
|
transmit_can_frame(&LEAF_NEXT_LINE_REQUEST, can_config.battery); //Request the next frame for the group
|
||||||
|
|
||||||
|
if (group_7bb == 0x01) //High precision SOC, Current, voltages etc.
|
||||||
{
|
{
|
||||||
if (rx_frame.data.u8[0] == 0x10) { //First frame
|
if (rx_frame.data.u8[0] == 0x10) { //First frame
|
||||||
//High precision Battery_current_1 resides here, but has been deemed unusable by 62kWh owners
|
//High precision Battery_current_1 resides here, but has been deemed unusable by 62kWh owners
|
||||||
|
@ -891,7 +892,7 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (group_7bb == 2) //Cell Voltages
|
if (group_7bb == 0x02) //Cell Voltages
|
||||||
{
|
{
|
||||||
if (rx_frame.data.u8[0] == 0x10) { //first frame is anomalous
|
if (rx_frame.data.u8[0] == 0x10) { //first frame is anomalous
|
||||||
battery_request_idx = 0;
|
battery_request_idx = 0;
|
||||||
|
@ -934,7 +935,7 @@ void handle_incoming_can_frame_battery(CAN_frame rx_frame) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (group_7bb == 4) { //Temperatures
|
if (group_7bb == 0x04) { //Temperatures
|
||||||
if (rx_frame.data.u8[0] == 0x10) { //First message
|
if (rx_frame.data.u8[0] == 0x10) { //First message
|
||||||
battery_temp_raw_1 = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5];
|
battery_temp_raw_1 = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5];
|
||||||
battery_temp_raw_2_highnibble = rx_frame.data.u8[7];
|
battery_temp_raw_2_highnibble = rx_frame.data.u8[7];
|
||||||
|
|
|
@ -105,9 +105,9 @@ void update_values_battery() { //This function maps all the values fetched via
|
||||||
|
|
||||||
#ifdef DEBUG_LOG
|
#ifdef DEBUG_LOG
|
||||||
logging.println("Values going to inverter:");
|
logging.println("Values going to inverter:");
|
||||||
logging.print("SOH: ");
|
logging.print("SOH%: ");
|
||||||
logging.print(datalayer.battery.status.soh_pptt);
|
logging.print(datalayer.battery.status.soh_pptt);
|
||||||
logging.print(", SOC scaled: ");
|
logging.print(", SOC% scaled: ");
|
||||||
logging.print(datalayer.battery.status.reported_soc);
|
logging.print(datalayer.battery.status.reported_soc);
|
||||||
logging.print(", Voltage: ");
|
logging.print(", Voltage: ");
|
||||||
logging.print(datalayer.battery.status.voltage_dV);
|
logging.print(datalayer.battery.status.voltage_dV);
|
||||||
|
|
|
@ -2723,7 +2723,7 @@ void print_SOC(char* header, int SOC) {
|
||||||
if (hundredth < 10)
|
if (hundredth < 10)
|
||||||
logging.print(0);
|
logging.print(0);
|
||||||
logging.print(hundredth);
|
logging.print(hundredth);
|
||||||
logging.println("pct");
|
logging.println("%");
|
||||||
}
|
}
|
||||||
|
|
||||||
void printFaultCodesIfActive() {
|
void printFaultCodesIfActive() {
|
||||||
|
|
|
@ -56,8 +56,8 @@ void update_values_battery() { /* This function puts fake values onto the parame
|
||||||
/*Finally print out values to serial if configured to do so*/
|
/*Finally print out values to serial if configured to do so*/
|
||||||
#ifdef DEBUG_LOG
|
#ifdef DEBUG_LOG
|
||||||
logging.println("FAKE Values going to inverter");
|
logging.println("FAKE Values going to inverter");
|
||||||
print_units("SOH: ", (datalayer.battery.status.soh_pptt * 0.01), "pct ");
|
print_units("SOH%: ", (datalayer.battery.status.soh_pptt * 0.01), "% ");
|
||||||
print_units(", SOC: ", (datalayer.battery.status.reported_soc * 0.01), "pct ");
|
print_units(", SOC%: ", (datalayer.battery.status.reported_soc * 0.01), "% ");
|
||||||
print_units(", Voltage: ", (datalayer.battery.status.voltage_dV * 0.1), "V ");
|
print_units(", Voltage: ", (datalayer.battery.status.voltage_dV * 0.1), "V ");
|
||||||
print_units(", Max discharge power: ", datalayer.battery.status.max_discharge_power_W, "W ");
|
print_units(", Max discharge power: ", datalayer.battery.status.max_discharge_power_W, "W ");
|
||||||
print_units(", Max charge power: ", datalayer.battery.status.max_charge_power_W, "W ");
|
print_units(", Max charge power: ", datalayer.battery.status.max_charge_power_W, "W ");
|
||||||
|
@ -109,8 +109,8 @@ void update_values_battery2() { // Handle the values coming in from battery #2
|
||||||
/*Finally print out values to serial if configured to do so*/
|
/*Finally print out values to serial if configured to do so*/
|
||||||
#ifdef DEBUG_LOG
|
#ifdef DEBUG_LOG
|
||||||
logging.println("FAKE Values battery 2 going to inverter");
|
logging.println("FAKE Values battery 2 going to inverter");
|
||||||
print_units("SOH 2: ", (datalayer.battery2.status.soh_pptt * 0.01), "pct ");
|
print_units("SOH 2 %: ", (datalayer.battery2.status.soh_pptt * 0.01), "% ");
|
||||||
print_units(", SOC 2: ", (datalayer.battery2.status.reported_soc * 0.01), "pct ");
|
print_units(", SOC 2 %: ", (datalayer.battery2.status.reported_soc * 0.01), "% ");
|
||||||
print_units(", Voltage 2: ", (datalayer.battery2.status.voltage_dV * 0.1), "V ");
|
print_units(", Voltage 2: ", (datalayer.battery2.status.voltage_dV * 0.1), "V ");
|
||||||
print_units(", Max discharge power 2: ", datalayer.battery2.status.max_discharge_power_W, "W ");
|
print_units(", Max discharge power 2: ", datalayer.battery2.status.max_discharge_power_W, "W ");
|
||||||
print_units(", Max charge power 2: ", datalayer.battery2.status.max_charge_power_W, "W ");
|
print_units(", Max charge power 2: ", datalayer.battery2.status.max_charge_power_W, "W ");
|
||||||
|
|
|
@ -95,11 +95,11 @@ void update_values_battery() { //This function maps all the values fetched via
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DEBUG_LOG
|
#ifdef DEBUG_LOG
|
||||||
logging.print("BMS reported SOC: ");
|
logging.print("BMS reported SOC%: ");
|
||||||
logging.println(SOC_BMS);
|
logging.println(SOC_BMS);
|
||||||
logging.print("Calculated SOC: ");
|
logging.print("Calculated SOC%: ");
|
||||||
logging.println(SOC_CALC);
|
logging.println(SOC_CALC);
|
||||||
logging.print("Rescaled SOC: ");
|
logging.print("Rescaled SOC%: ");
|
||||||
logging.println(datalayer.battery.status.reported_soc / 100);
|
logging.println(datalayer.battery.status.reported_soc / 100);
|
||||||
logging.print("Battery current: ");
|
logging.print("Battery current: ");
|
||||||
logging.println(BATT_I);
|
logging.println(BATT_I);
|
||||||
|
|
|
@ -101,6 +101,9 @@ void map_can_frame_to_variable_charger(CAN_frame rx_frame) {
|
||||||
case 0x308:
|
case 0x308:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
#ifdef DEBUG_LOG
|
||||||
|
logging.printf("CAN Rcv unknown frame MsgID=%x\n", rx_frame.MsgID);
|
||||||
|
#endif
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -90,7 +90,7 @@ void init_CAN() {
|
||||||
logging.println(settings2517.exactArbitrationBitRate() ? "yes)" : "no)");
|
logging.println(settings2517.exactArbitrationBitRate() ? "yes)" : "no)");
|
||||||
logging.print("Arbitration Sample point: ");
|
logging.print("Arbitration Sample point: ");
|
||||||
logging.print(settings2517.arbitrationSamplePointFromBitStart());
|
logging.print(settings2517.arbitrationSamplePointFromBitStart());
|
||||||
logging.println("pct");
|
logging.println("%");
|
||||||
#endif // DEBUG_LOG
|
#endif // DEBUG_LOG
|
||||||
} else {
|
} else {
|
||||||
#ifdef DEBUG_LOG
|
#ifdef DEBUG_LOG
|
||||||
|
@ -116,6 +116,10 @@ void transmit_can() {
|
||||||
#ifdef CHARGER_SELECTED
|
#ifdef CHARGER_SELECTED
|
||||||
transmit_can_charger();
|
transmit_can_charger();
|
||||||
#endif // CHARGER_SELECTED
|
#endif // CHARGER_SELECTED
|
||||||
|
|
||||||
|
#ifdef CAN_SHUNT_SELECTED
|
||||||
|
transmit_can_shunt();
|
||||||
|
#endif // CAN_SHUNT_SELECTED
|
||||||
}
|
}
|
||||||
|
|
||||||
void transmit_can_frame(CAN_frame* tx_frame, int interface) {
|
void transmit_can_frame(CAN_frame* tx_frame, int interface) {
|
||||||
|
@ -339,6 +343,11 @@ void map_can_frame_to_variable(CAN_frame* rx_frame, int interface) {
|
||||||
if (interface == can_config.charger) {
|
if (interface == can_config.charger) {
|
||||||
#ifdef CHARGER_SELECTED
|
#ifdef CHARGER_SELECTED
|
||||||
map_can_frame_to_variable_charger(*rx_frame);
|
map_can_frame_to_variable_charger(*rx_frame);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
if (interface == can_config.shunt) {
|
||||||
|
#ifdef CAN_SHUNT_SELECTED
|
||||||
|
handle_incoming_can_frame_shunt(*rx_frame);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -149,6 +149,20 @@ typedef struct {
|
||||||
uint16_t measured_voltage_dV = 0;
|
uint16_t measured_voltage_dV = 0;
|
||||||
/** measured amperage in deciAmperes. 300 = 30.0 A */
|
/** measured amperage in deciAmperes. 300 = 30.0 A */
|
||||||
uint16_t measured_amperage_dA = 0;
|
uint16_t measured_amperage_dA = 0;
|
||||||
|
/** measured battery voltage in mV (S-BOX) **/
|
||||||
|
uint32_t measured_voltage_mV = 0;
|
||||||
|
/** measured output voltage in mV (eg. S-BOX) **/
|
||||||
|
uint32_t measured_outvoltage_mV = 0;
|
||||||
|
/** measured amperage in mA (eg. S-BOX) **/
|
||||||
|
int32_t measured_amperage_mA = 0;
|
||||||
|
/** Average current from last 1s **/
|
||||||
|
int32_t measured_avg1S_amperage_mA = 0;
|
||||||
|
/** True if contactors are precharging state */
|
||||||
|
bool precharging = false;
|
||||||
|
/** True if the contactor controlled by battery-emulator is closed */
|
||||||
|
bool contactors_engaged = false;
|
||||||
|
/** True if shunt communication ok **/
|
||||||
|
bool available = false;
|
||||||
} DATALAYER_SHUNT_TYPE;
|
} DATALAYER_SHUNT_TYPE;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@ -156,6 +170,8 @@ typedef struct {
|
||||||
char battery_protocol[64] = {0};
|
char battery_protocol[64] = {0};
|
||||||
/** array with type of inverter used, for displaying on webserver */
|
/** array with type of inverter used, for displaying on webserver */
|
||||||
char inverter_protocol[64] = {0};
|
char inverter_protocol[64] = {0};
|
||||||
|
/** array with type of battery used, for displaying on webserver */
|
||||||
|
char shunt_protocol[64] = {0};
|
||||||
/** array with incoming CAN messages, for displaying on webserver */
|
/** array with incoming CAN messages, for displaying on webserver */
|
||||||
char logged_can_messages[15000] = {0};
|
char logged_can_messages[15000] = {0};
|
||||||
size_t logged_can_messages_offset = 0;
|
size_t logged_can_messages_offset = 0;
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
#include "can_logging_html.h"
|
#include "can_logging_html.h"
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include "../../datalayer/datalayer.h"
|
#include "../../datalayer/datalayer.h"
|
||||||
|
#include "index_html.h"
|
||||||
|
|
||||||
String can_logger_processor(const String& var) {
|
String can_logger_processor(void) {
|
||||||
if (var == "X") {
|
|
||||||
if (!datalayer.system.info.can_logging_active) {
|
if (!datalayer.system.info.can_logging_active) {
|
||||||
datalayer.system.info.logged_can_messages_offset = 0;
|
datalayer.system.info.logged_can_messages_offset = 0;
|
||||||
datalayer.system.info.logged_can_messages[0] = '\0';
|
datalayer.system.info.logged_can_messages[0] = '\0';
|
||||||
}
|
}
|
||||||
datalayer.system.info.can_logging_active =
|
datalayer.system.info.can_logging_active =
|
||||||
true; // Signal to main loop that we should log messages. Disabled by default for performance reasons
|
true; // Signal to main loop that we should log messages. Disabled by default for performance reasons
|
||||||
String content = "";
|
String content = index_html_header;
|
||||||
// Page format
|
// Page format
|
||||||
content += "<style>";
|
content += "<style>";
|
||||||
content += "body { background-color: black; color: white; font-family: Arial, sans-serif; }";
|
content += "body { background-color: black; color: white; font-family: Arial, sans-serif; }";
|
||||||
|
@ -27,7 +27,7 @@ String can_logger_processor(const String& var) {
|
||||||
#ifdef LOG_CAN_TO_SD
|
#ifdef LOG_CAN_TO_SD
|
||||||
content += "<button onclick='deleteLogFile()'>Delete log file</button> ";
|
content += "<button onclick='deleteLogFile()'>Delete log file</button> ";
|
||||||
#endif
|
#endif
|
||||||
content += "<button onclick='stopLoggingAndGoToMainPage()'>Back to main page</button>";
|
content += "<button onclick='stopLoggingAndGoToMainPage()'>Stop & Back to main page</button>";
|
||||||
|
|
||||||
// Start a new block for the CAN messages
|
// Start a new block for the CAN messages
|
||||||
content += "<div style='background-color: #303E47; padding: 20px; border-radius: 15px'>";
|
content += "<div style='background-color: #303E47; padding: 20px; border-radius: 15px'>";
|
||||||
|
@ -62,7 +62,6 @@ String can_logger_processor(const String& var) {
|
||||||
content += " fetch('/stop_can_logging').then(() => window.location.href = '/');";
|
content += " fetch('/stop_can_logging').then(() => window.location.href = '/');";
|
||||||
content += "}";
|
content += "}";
|
||||||
content += "</script>";
|
content += "</script>";
|
||||||
|
content += index_html_footer;
|
||||||
return content;
|
return content;
|
||||||
}
|
|
||||||
return String();
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,6 @@
|
||||||
*
|
*
|
||||||
* @return String
|
* @return String
|
||||||
*/
|
*/
|
||||||
String can_logger_processor(const String& var);
|
String can_logger_processor(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
#include "debug_logging_html.h"
|
#include "debug_logging_html.h"
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include "../../datalayer/datalayer.h"
|
#include "../../datalayer/datalayer.h"
|
||||||
|
#include "index_html.h"
|
||||||
|
|
||||||
#ifdef DEBUG_VIA_WEB
|
#ifdef DEBUG_VIA_WEB
|
||||||
String debug_logger_processor(const String& var) {
|
String debug_logger_processor(void) {
|
||||||
String content = "";
|
String content = String(index_html_header);
|
||||||
// Page format
|
// Page format
|
||||||
content += "<style>";
|
content += "<style>";
|
||||||
content += "body { background-color: black; color: white; font-family: Arial, sans-serif; }";
|
content += "body { background-color: black; color: white; font-family: Arial, sans-serif; }";
|
||||||
|
@ -31,6 +32,7 @@ String debug_logger_processor(const String& var) {
|
||||||
content += "function exportLog() { window.location.href = '/export_log'; }";
|
content += "function exportLog() { window.location.href = '/export_log'; }";
|
||||||
content += "function goToMainPage() { window.location.href = '/'; }";
|
content += "function goToMainPage() { window.location.href = '/'; }";
|
||||||
content += "</script>";
|
content += "</script>";
|
||||||
|
content += index_html_footer;
|
||||||
return content;
|
return content;
|
||||||
}
|
}
|
||||||
#endif // DEBUG_VIA_WEB
|
#endif // DEBUG_VIA_WEB
|
||||||
|
|
|
@ -11,6 +11,6 @@
|
||||||
*
|
*
|
||||||
* @return String
|
* @return String
|
||||||
*/
|
*/
|
||||||
String debug_logger_processor(const String& var);
|
String debug_logger_processor(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,6 +1,12 @@
|
||||||
const char index_html[] = R"rawliteral(
|
#include "index_html.h"
|
||||||
<!doctypehtml><title>Battery Emulator</title><meta content="width=device-width"name=viewport><style>html{font-family:Arial;display:inline-block;text-align:center}h2{font-size:3rem}body{max-width:800px;margin:0 auto}</style>%X%
|
|
||||||
)rawliteral";
|
#define INDEX_HTML_HEADER \
|
||||||
|
R"rawliteral(<!doctype html><html><head><title>Battery Emulator</title><meta content="width=device-width"name=viewport><style>html{font-family:Arial;display:inline-block;text-align:center}h2{font-size:3rem}body{max-width:800px;margin:0 auto}</style><body>)rawliteral"
|
||||||
|
#define INDEX_HTML_FOOTER R"rawliteral(</body></html>)rawliteral";
|
||||||
|
|
||||||
|
const char index_html[] = INDEX_HTML_HEADER "%X%" INDEX_HTML_FOOTER;
|
||||||
|
const char index_html_header[] = INDEX_HTML_HEADER;
|
||||||
|
const char index_html_footer[] = INDEX_HTML_FOOTER;
|
||||||
|
|
||||||
/* The above code is minified (https://kangax.github.io/html-minifier/) to increase performance. Here is the full HTML function:
|
/* The above code is minified (https://kangax.github.io/html-minifier/) to increase performance. Here is the full HTML function:
|
||||||
<!DOCTYPE HTML><html>
|
<!DOCTYPE HTML><html>
|
||||||
|
|
8
Software/src/devboard/webserver/index_html.h
Normal file
8
Software/src/devboard/webserver/index_html.h
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
#ifndef INDEX_HTML_H
|
||||||
|
#define INDEX_HTML_H
|
||||||
|
|
||||||
|
extern const char index_html[];
|
||||||
|
extern const char index_html_header[];
|
||||||
|
extern const char index_html_footer[];
|
||||||
|
|
||||||
|
#endif // INDEX_HTML_H
|
|
@ -41,6 +41,11 @@ String settings_processor(const String& var) {
|
||||||
content += "<h4 style='color: white;'>Inverter interface: RS485<span id='Inverter'></span></h4>";
|
content += "<h4 style='color: white;'>Inverter interface: RS485<span id='Inverter'></span></h4>";
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef CAN_SHUNT_SELECTED
|
||||||
|
content += "<h4 style='color: white;'>Shunt Interface: <span id='Shunt'>" +
|
||||||
|
String(getCANInterfaceName(can_config.shunt)) + "</span></h4>";
|
||||||
|
#endif //CAN_SHUNT_SELECTED
|
||||||
|
|
||||||
// Close the block
|
// Close the block
|
||||||
content += "</div>";
|
content += "</div>";
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@ unsigned long ota_progress_millis = 0;
|
||||||
#include "cellmonitor_html.h"
|
#include "cellmonitor_html.h"
|
||||||
#include "debug_logging_html.h"
|
#include "debug_logging_html.h"
|
||||||
#include "events_html.h"
|
#include "events_html.h"
|
||||||
#include "index_html.cpp"
|
#include "index_html.h"
|
||||||
#include "settings_html.h"
|
#include "settings_html.h"
|
||||||
|
|
||||||
MyTimer ota_timeout_timer = MyTimer(15000);
|
MyTimer ota_timeout_timer = MyTimer(15000);
|
||||||
|
@ -31,8 +31,6 @@ const char get_firmware_info_html[] = R"rawliteral(%X%)rawliteral";
|
||||||
|
|
||||||
void init_webserver() {
|
void init_webserver() {
|
||||||
|
|
||||||
String content = index_html;
|
|
||||||
|
|
||||||
server.on("/logout", HTTP_GET, [](AsyncWebServerRequest* request) { request->send(401); });
|
server.on("/logout", HTTP_GET, [](AsyncWebServerRequest* request) { request->send(401); });
|
||||||
|
|
||||||
// Route for firmware info from ota update page
|
// Route for firmware info from ota update page
|
||||||
|
@ -63,13 +61,15 @@ void init_webserver() {
|
||||||
|
|
||||||
// Route for going to CAN logging web page
|
// Route for going to CAN logging web page
|
||||||
server.on("/canlog", HTTP_GET, [](AsyncWebServerRequest* request) {
|
server.on("/canlog", HTTP_GET, [](AsyncWebServerRequest* request) {
|
||||||
request->send_P(200, "text/html", index_html, can_logger_processor);
|
AsyncWebServerResponse* response = request->beginResponse(200, "text/html", can_logger_processor());
|
||||||
|
request->send(response);
|
||||||
});
|
});
|
||||||
|
|
||||||
#ifdef DEBUG_VIA_WEB
|
#ifdef DEBUG_VIA_WEB
|
||||||
// Route for going to debug logging web page
|
// Route for going to debug logging web page
|
||||||
server.on("/log", HTTP_GET, [](AsyncWebServerRequest* request) {
|
server.on("/log", HTTP_GET, [](AsyncWebServerRequest* request) {
|
||||||
request->send_P(200, "text/html", index_html, debug_logger_processor);
|
AsyncWebServerResponse* response = request->beginResponse(200, "text/html", debug_logger_processor());
|
||||||
|
request->send(response);
|
||||||
});
|
});
|
||||||
#endif // DEBUG_VIA_WEB
|
#endif // DEBUG_VIA_WEB
|
||||||
|
|
||||||
|
@ -742,6 +742,12 @@ String processor(const String& var) {
|
||||||
}
|
}
|
||||||
content += "</h4>";
|
content += "</h4>";
|
||||||
|
|
||||||
|
#ifdef CAN_SHUNT_SELECTED
|
||||||
|
content += "<h4 style='color: white;'>Shunt protocol: ";
|
||||||
|
content += datalayer.system.info.shunt_protocol;
|
||||||
|
content += "</h4>";
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined CHEVYVOLT_CHARGER || defined NISSANLEAF_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
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
//----------------------------------------------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
#include "ACAN2517FD.h"
|
#include "ACAN2517FD.h"
|
||||||
|
#include "../../system_settings.h" //Contains task priority
|
||||||
|
|
||||||
//----------------------------------------------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@ -506,7 +507,7 @@ uint32_t ACAN2517FD::begin (const ACAN2517FDSettings & inSettings,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#ifdef ARDUINO_ARCH_ESP32
|
#ifdef ARDUINO_ARCH_ESP32
|
||||||
xTaskCreate (myESP32Task, "ACAN2517Handler", 1024, this, 256, &mESP32TaskHandle) ;
|
xTaskCreate (myESP32Task, "ACAN2517Handler", 1024, this, TASK_ACAN2517FD_PRIORITY, &mESP32TaskHandle) ;
|
||||||
#endif
|
#endif
|
||||||
if (mINT != 255) { // 255 means interrupt is not used
|
if (mINT != 255) { // 255 means interrupt is not used
|
||||||
#ifdef ARDUINO_ARCH_ESP32
|
#ifdef ARDUINO_ARCH_ESP32
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
//··································································································
|
//··································································································
|
||||||
|
|
||||||
#include "ACAN2515.h"
|
#include "ACAN2515.h"
|
||||||
|
#include "../../system_settings.h" //Contains task priority
|
||||||
|
|
||||||
//··································································································
|
//··································································································
|
||||||
// MCP2515 COMMANDS
|
// MCP2515 COMMANDS
|
||||||
|
@ -225,7 +226,7 @@ uint16_t ACAN2515::beginWithoutFilterCheck (const ACAN2515Settings & inSettings,
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#ifdef ARDUINO_ARCH_ESP32
|
#ifdef ARDUINO_ARCH_ESP32
|
||||||
xTaskCreate (myESP32Task, "ACAN2515Handler", 1024, this, 256, NULL) ;
|
xTaskCreate (myESP32Task, "ACAN2515Handler", 1024, this, TASK_ACAN2515_PRIORITY, NULL) ;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
//----------------------------------- Return
|
//----------------------------------- Return
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#ifndef SYSTEM_SETTINGS_H_
|
#ifndef SYSTEM_SETTINGS_H_
|
||||||
#define SYSTEM_SETTINGS_H_
|
#define SYSTEM_SETTINGS_H_
|
||||||
/** TASKS
|
/** TASKS
|
||||||
|
* Higher number equals higher priority. Max 25 per core
|
||||||
*
|
*
|
||||||
* Parameter: TASK_CORE_PRIO
|
* Parameter: TASK_CORE_PRIO
|
||||||
* Description:
|
* Description:
|
||||||
|
@ -13,10 +14,20 @@
|
||||||
* Parameter: TASK_MODBUS_PRIO
|
* Parameter: TASK_MODBUS_PRIO
|
||||||
* Description:
|
* Description:
|
||||||
* Defines the priority of MODBUS handling
|
* Defines the priority of MODBUS handling
|
||||||
|
*
|
||||||
|
* Parameter: TASK_ACAN2515_PRIORITY
|
||||||
|
* Description:
|
||||||
|
* Defines the priority of ACAN2515 CAN handling
|
||||||
|
*
|
||||||
|
* Parameter: TASK_ACAN2515_PRIORITY
|
||||||
|
* Description:
|
||||||
|
* Defines the priority of ACAN2517FD CAN-FD handling
|
||||||
*/
|
*/
|
||||||
#define TASK_CORE_PRIO 4
|
#define TASK_CORE_PRIO 4
|
||||||
#define TASK_CONNECTIVITY_PRIO 3
|
#define TASK_CONNECTIVITY_PRIO 3
|
||||||
#define TASK_MODBUS_PRIO 8
|
#define TASK_MODBUS_PRIO 8
|
||||||
|
#define TASK_ACAN2515_PRIORITY 10
|
||||||
|
#define TASK_ACAN2517FD_PRIORITY 10
|
||||||
|
|
||||||
/** MAX AMOUNT OF CELLS
|
/** MAX AMOUNT OF CELLS
|
||||||
*
|
*
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue