mirror of
https://github.com/dalathegreat/Battery-Emulator.git
synced 2025-10-04 10:19:29 +02:00
All chargers compiled
This commit is contained in:
parent
1d733fa78f
commit
517731c4c3
14 changed files with 316 additions and 274 deletions
|
@ -101,9 +101,7 @@ void setup() {
|
||||||
init_precharge_control();
|
init_precharge_control();
|
||||||
#endif // PRECHARGE_CONTROL
|
#endif // PRECHARGE_CONTROL
|
||||||
|
|
||||||
#if defined(CHARGER_SELECTED)
|
|
||||||
setup_charger();
|
setup_charger();
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(CAN_INVERTER_SELECTED) || defined(MODBUS_INVERTER_SELECTED) || defined(RS485_INVERTER_SELECTED)
|
#if defined(CAN_INVERTER_SELECTED) || defined(MODBUS_INVERTER_SELECTED) || defined(RS485_INVERTER_SELECTED)
|
||||||
setup_inverter();
|
setup_inverter();
|
||||||
|
|
|
@ -8,6 +8,8 @@
|
||||||
#include "../datalayer/datalayer_extended.h" //For "More battery info" webpage
|
#include "../datalayer/datalayer_extended.h" //For "More battery info" webpage
|
||||||
#include "../devboard/utils/events.h"
|
#include "../devboard/utils/events.h"
|
||||||
|
|
||||||
|
#include "../charger/CanCharger.h"
|
||||||
|
|
||||||
/* Do not change code below unless you are sure what you are doing */
|
/* Do not change code below unless you are sure what you are doing */
|
||||||
static unsigned long previousMillis10 = 0; // will store last time a 10ms CAN Message was send
|
static unsigned long previousMillis10 = 0; // will store last time a 10ms CAN Message was send
|
||||||
static unsigned long previousMillis100 = 0; // will store last time a 100ms CAN Message was send
|
static unsigned long previousMillis100 = 0; // will store last time a 100ms CAN Message was send
|
||||||
|
@ -1199,13 +1201,14 @@ void transmit_can_battery(unsigned long currentMillis) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Only send this message when NISSANLEAF_CHARGER is not defined (otherwise it will collide!)
|
//Only send this message when NISSANLEAF_CHARGER is not defined (otherwise it will collide!)
|
||||||
#ifndef NISSANLEAF_CHARGER
|
|
||||||
transmit_can_frame(&LEAF_1F2, can_config.battery);
|
if (!charger || charger->type() != ChargerType::NissanLeaf) {
|
||||||
|
transmit_can_frame(&LEAF_1F2, can_config.battery);
|
||||||
#ifdef DOUBLE_BATTERY
|
#ifdef DOUBLE_BATTERY
|
||||||
transmit_can_frame(&LEAF_1F2, can_config.battery_double);
|
transmit_can_frame(&LEAF_1F2, can_config.battery_double);
|
||||||
#endif // DOUBLE_BATTERY
|
#endif // DOUBLE_BATTERY
|
||||||
#endif
|
}
|
||||||
|
|
||||||
mprun10r = (mprun10r + 1) % 20; // 0x1F2 patter repeats after 20 messages. 0-1..19-0
|
mprun10r = (mprun10r + 1) % 20; // 0x1F2 patter repeats after 20 messages. 0-1..19-0
|
||||||
|
|
||||||
|
|
|
@ -1,19 +1,9 @@
|
||||||
#include "../include.h"
|
#include "../include.h"
|
||||||
|
|
||||||
#ifdef SELECTED_CHARGER_CLASS
|
CanCharger* charger = nullptr;
|
||||||
|
|
||||||
static CanCharger* charger;
|
|
||||||
|
|
||||||
void map_can_frame_to_variable_charger(CAN_frame rx_frame) {
|
|
||||||
charger->map_can_frame_to_variable(rx_frame);
|
|
||||||
}
|
|
||||||
|
|
||||||
void transmit_can_charger(unsigned long currentMillis) {
|
|
||||||
charger->transmit_can(currentMillis);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setup_charger() {
|
void setup_charger() {
|
||||||
|
#ifdef SELECTED_CHARGER_CLASS
|
||||||
charger = new SELECTED_CHARGER_CLASS();
|
charger = new SELECTED_CHARGER_CLASS();
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
|
|
@ -2,16 +2,14 @@
|
||||||
#define CHARGERS_H
|
#define CHARGERS_H
|
||||||
#include "../../USER_SETTINGS.h"
|
#include "../../USER_SETTINGS.h"
|
||||||
|
|
||||||
#ifdef CHEVYVOLT_CHARGER
|
|
||||||
#include "CHEVY-VOLT-CHARGER.h"
|
#include "CHEVY-VOLT-CHARGER.h"
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef NISSANLEAF_CHARGER
|
|
||||||
#include "NISSAN-LEAF-CHARGER.h"
|
#include "NISSAN-LEAF-CHARGER.h"
|
||||||
#endif
|
|
||||||
|
|
||||||
void map_can_frame_to_variable_charger(CAN_frame rx_frame);
|
// Constructs the global charger object based on build-time selection of charger type.
|
||||||
void transmit_can_charger(unsigned long currentMillis);
|
// Safe to call even though no charger is selected.
|
||||||
void setup_charger();
|
void setup_charger();
|
||||||
|
|
||||||
|
// The selected charger or null if no charger in use.
|
||||||
|
extern CanCharger* charger;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
#include "../include.h"
|
|
||||||
#ifdef CHEVYVOLT_CHARGER
|
|
||||||
#include "../datalayer/datalayer.h"
|
|
||||||
#include "CHEVY-VOLT-CHARGER.h"
|
#include "CHEVY-VOLT-CHARGER.h"
|
||||||
|
#include "../datalayer/datalayer.h"
|
||||||
|
#include "../include.h"
|
||||||
|
|
||||||
/* This implements Chevy Volt / Ampera charger support (2011-2015 model years).
|
/* This implements Chevy Volt / Ampera charger support (2011-2015 model years).
|
||||||
*
|
*
|
||||||
|
@ -157,4 +156,3 @@ void ChevyVoltCharger::transmit_can(unsigned long currentMillis) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
|
@ -1,29 +1,43 @@
|
||||||
#ifndef CHEVYVOLT_CHARGER_H
|
#ifndef CHEVYVOLT_CHARGER_H
|
||||||
#define CHEVYVOLT_CHARGER_H
|
#define CHEVYVOLT_CHARGER_H
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
|
#include "../datalayer/datalayer.h"
|
||||||
#include "../include.h"
|
#include "../include.h"
|
||||||
|
|
||||||
#include "CanCharger.h"
|
#include "CanCharger.h"
|
||||||
|
|
||||||
#define CHARGER_SELECTED
|
#ifdef CHEVYVOLT_CHARGER
|
||||||
#define SELECTED_CHARGER_CLASS ChevyVoltCharger
|
#define SELECTED_CHARGER_CLASS ChevyVoltCharger
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Charger hardware limits
|
class ChevyVoltCharger : public CanCharger {
|
||||||
|
public:
|
||||||
|
ChevyVoltCharger() : CanCharger(ChargerType::ChevyVolt) {}
|
||||||
|
|
||||||
|
const char* name() { return "Chevy Volt Gen1 Charger"; }
|
||||||
|
|
||||||
|
void map_can_frame_to_variable(CAN_frame rx_frame);
|
||||||
|
void transmit_can(unsigned long currentMillis);
|
||||||
|
|
||||||
|
float outputPowerDC() {
|
||||||
|
return static_cast<float>(datalayer.charger.charger_stat_HVcur * datalayer.charger.charger_stat_HVvol);
|
||||||
|
}
|
||||||
|
bool efficiencySupported() { return true; }
|
||||||
|
float efficiency() {
|
||||||
|
float chgPwrAC = static_cast<float>(datalayer.charger.charger_stat_ACcur * datalayer.charger.charger_stat_ACvol);
|
||||||
|
return outputPowerDC() / chgPwrAC * 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
/* Charger hardware limits
|
||||||
*
|
*
|
||||||
* Relative to runtime settings, expectations are:
|
* Relative to runtime settings, expectations are:
|
||||||
* hw minimum <= setting minimum <= setting maximum <= hw max
|
* hw minimum <= setting minimum <= setting maximum <= hw max
|
||||||
*/
|
*/
|
||||||
#define CHEVYVOLT_MAX_HVDC 420.0
|
const float CHEVYVOLT_MAX_HVDC = 420.0;
|
||||||
#define CHEVYVOLT_MIN_HVDC 200.0
|
const float CHEVYVOLT_MIN_HVDC = 200.0;
|
||||||
#define CHEVYVOLT_MAX_AMP 11.5
|
const float CHEVYVOLT_MAX_AMP = 11.5;
|
||||||
#define CHEVYVOLT_MAX_POWER 3300
|
const float CHEVYVOLT_MAX_POWER = 3300;
|
||||||
|
|
||||||
class ChevyVoltCharger : public CanCharger {
|
|
||||||
public:
|
|
||||||
void map_can_frame_to_variable(CAN_frame rx_frame);
|
|
||||||
void transmit_can(unsigned long currentMillis);
|
|
||||||
|
|
||||||
private:
|
|
||||||
/* CAN cycles and timers */
|
/* CAN cycles and timers */
|
||||||
unsigned long previousMillis30ms = 0; // 30ms cycle for keepalive frames
|
unsigned long previousMillis30ms = 0; // 30ms cycle for keepalive frames
|
||||||
unsigned long previousMillis200ms = 0; // 200ms cycle for commanding I/V targets
|
unsigned long previousMillis200ms = 0; // 200ms cycle for commanding I/V targets
|
||||||
|
|
|
@ -3,10 +3,46 @@
|
||||||
|
|
||||||
#include "src/devboard/utils/types.h"
|
#include "src/devboard/utils/types.h"
|
||||||
|
|
||||||
class CanCharger {
|
#include "../datalayer/datalayer.h"
|
||||||
|
|
||||||
|
enum class ChargerType { NissanLeaf, ChevyVolt };
|
||||||
|
|
||||||
|
// Generic base class for all chargers
|
||||||
|
class Charger {
|
||||||
|
public:
|
||||||
|
ChargerType type() { return m_type; }
|
||||||
|
|
||||||
|
virtual const char* name() = 0;
|
||||||
|
|
||||||
|
virtual float outputPowerDC() = 0;
|
||||||
|
|
||||||
|
virtual float HVDC_output_voltage() { return datalayer.charger.charger_stat_HVvol; }
|
||||||
|
virtual float HVDC_output_current() { return datalayer.charger.charger_stat_HVcur; }
|
||||||
|
|
||||||
|
virtual float LVDC_output_voltage() { return datalayer.charger.charger_stat_LVvol; }
|
||||||
|
virtual float LVDC_output_current() { return datalayer.charger.charger_stat_LVcur; }
|
||||||
|
|
||||||
|
virtual float AC_input_voltage() { return datalayer.charger.charger_stat_ACvol; }
|
||||||
|
virtual float AC_input_current() { return datalayer.charger.charger_stat_ACcur; }
|
||||||
|
|
||||||
|
virtual bool efficiencySupported() { return false; }
|
||||||
|
virtual float efficiency() { return 0; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Charger(ChargerType type) : m_type(type) {}
|
||||||
|
|
||||||
|
private:
|
||||||
|
ChargerType m_type;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Base class for chargers on a CAN bus
|
||||||
|
class CanCharger : public Charger {
|
||||||
public:
|
public:
|
||||||
virtual void map_can_frame_to_variable(CAN_frame rx_frame) = 0;
|
virtual void map_can_frame_to_variable(CAN_frame rx_frame) = 0;
|
||||||
virtual void transmit_can(unsigned long currentMillis) = 0;
|
virtual void transmit_can(unsigned long currentMillis) = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
CanCharger(ChargerType type) : Charger(type) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
#include "../include.h"
|
|
||||||
#ifdef NISSANLEAF_CHARGER
|
|
||||||
#include "../datalayer/datalayer.h"
|
|
||||||
#include "NISSAN-LEAF-CHARGER.h"
|
#include "NISSAN-LEAF-CHARGER.h"
|
||||||
|
#include "../datalayer/datalayer.h"
|
||||||
|
#include "../include.h"
|
||||||
|
|
||||||
/* This implements Nissan LEAF PDM charger support. 2013-2024 Gen2/3 PDMs are supported
|
/* This implements Nissan LEAF PDM charger support. 2013-2024 Gen2/3 PDMs are supported
|
||||||
*
|
*
|
||||||
|
@ -184,4 +183,3 @@ void NissanLeafCharger::transmit_can(unsigned long currentMillis) {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
|
@ -4,14 +4,31 @@
|
||||||
#include "../include.h"
|
#include "../include.h"
|
||||||
|
|
||||||
#include "CanCharger.h"
|
#include "CanCharger.h"
|
||||||
#define CHARGER_SELECTED
|
|
||||||
|
#ifdef NISSANLEAF_CHARGER
|
||||||
#define SELECTED_CHARGER_CLASS NissanLeafCharger
|
#define SELECTED_CHARGER_CLASS NissanLeafCharger
|
||||||
|
#endif
|
||||||
|
|
||||||
class NissanLeafCharger : public CanCharger {
|
class NissanLeafCharger : public CanCharger {
|
||||||
public:
|
public:
|
||||||
|
NissanLeafCharger() : CanCharger(ChargerType::NissanLeaf) {}
|
||||||
|
|
||||||
|
const char* name() { return "Nissan LEAF 2013-2024 PDM charger"; }
|
||||||
void map_can_frame_to_variable(CAN_frame rx_frame);
|
void map_can_frame_to_variable(CAN_frame rx_frame);
|
||||||
void transmit_can(unsigned long currentMillis);
|
void transmit_can(unsigned long currentMillis);
|
||||||
|
|
||||||
|
float outputPowerDC() { return static_cast<float>(datalayer.charger.charger_stat_HVcur * 100); }
|
||||||
|
|
||||||
|
float HVDC_output_current() {
|
||||||
|
// P/U=I
|
||||||
|
if (datalayer.battery.status.voltage_dV > 0) {
|
||||||
|
return outputPowerDC() / (datalayer.battery.status.voltage_dV / 10);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
float HVDC_output_voltage() { return static_cast<float>(datalayer.battery.status.voltage_dV / 10); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/* CAN cycles and timers */
|
/* CAN cycles and timers */
|
||||||
unsigned long previousMillis10ms = 0;
|
unsigned long previousMillis10ms = 0;
|
||||||
|
|
|
@ -119,9 +119,9 @@ void transmit_can(unsigned long currentMillis) {
|
||||||
transmit_can_inverter(currentMillis);
|
transmit_can_inverter(currentMillis);
|
||||||
#endif // CAN_INVERTER_SELECTED
|
#endif // CAN_INVERTER_SELECTED
|
||||||
|
|
||||||
#ifdef CHARGER_SELECTED
|
if (charger) {
|
||||||
transmit_can_charger(currentMillis);
|
charger->transmit_can(currentMillis);
|
||||||
#endif // CHARGER_SELECTED
|
}
|
||||||
|
|
||||||
#ifdef CAN_SHUNT_SELECTED
|
#ifdef CAN_SHUNT_SELECTED
|
||||||
transmit_can_shunt(currentMillis);
|
transmit_can_shunt(currentMillis);
|
||||||
|
@ -330,10 +330,8 @@ void map_can_frame_to_variable(CAN_frame* rx_frame, int interface) {
|
||||||
handle_incoming_can_frame_battery2(*rx_frame);
|
handle_incoming_can_frame_battery2(*rx_frame);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
if (interface == can_config.charger) {
|
if (interface == can_config.charger && charger) {
|
||||||
#ifdef CHARGER_SELECTED
|
charger->map_can_frame_to_variable(*rx_frame);
|
||||||
map_can_frame_to_variable_charger(*rx_frame);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
if (interface == can_config.shunt) {
|
if (interface == can_config.shunt) {
|
||||||
#ifdef CAN_SHUNT_SELECTED
|
#ifdef CAN_SHUNT_SELECTED
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
#ifndef _DATALAYER_H_
|
#ifndef _DATALAYER_H_
|
||||||
#define _DATALAYER_H_
|
#define _DATALAYER_H_
|
||||||
|
|
||||||
#include "../include.h"
|
#include "../../USER_SETTINGS.h"
|
||||||
|
#include "../devboard/utils/types.h"
|
||||||
|
#include "../system_settings.h"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
/** uint32_t */
|
/** uint32_t */
|
||||||
|
|
|
@ -231,15 +231,15 @@ void update_machineryprotection() {
|
||||||
}
|
}
|
||||||
#endif //CAN_INVERTER_SELECTED
|
#endif //CAN_INVERTER_SELECTED
|
||||||
|
|
||||||
#ifdef CHARGER_SELECTED
|
if (charger) {
|
||||||
// Check if the charger is still sending CAN messages. If we go 60s without messages we raise a warning
|
// Check if the charger is still sending CAN messages. If we go 60s without messages we raise a warning
|
||||||
if (!datalayer.charger.CAN_charger_still_alive) {
|
if (!datalayer.charger.CAN_charger_still_alive) {
|
||||||
set_event(EVENT_CAN_CHARGER_MISSING, can_config.charger);
|
set_event(EVENT_CAN_CHARGER_MISSING, can_config.charger);
|
||||||
} else {
|
} else {
|
||||||
datalayer.charger.CAN_charger_still_alive--;
|
datalayer.charger.CAN_charger_still_alive--;
|
||||||
clear_event(EVENT_CAN_CHARGER_MISSING);
|
clear_event(EVENT_CAN_CHARGER_MISSING);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif //CHARGER_SELECTED
|
|
||||||
|
|
||||||
#ifdef DOUBLE_BATTERY // Additional Double-Battery safeties are checked here
|
#ifdef DOUBLE_BATTERY // Additional Double-Battery safeties are checked here
|
||||||
// Check if the Battery 2 BMS is still sending CAN messages. If we go 60s without messages we raise a warning
|
// Check if the Battery 2 BMS is still sending CAN messages. If we go 60s without messages we raise a warning
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include "settings_html.h"
|
#include "settings_html.h"
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
|
#include "../../charger/CHARGERS.h"
|
||||||
#include "../../datalayer/datalayer.h"
|
#include "../../datalayer/datalayer.h"
|
||||||
|
|
||||||
String settings_processor(const String& var) {
|
String settings_processor(const String& var) {
|
||||||
|
@ -143,37 +144,36 @@ String settings_processor(const String& var) {
|
||||||
content += "</div>";
|
content += "</div>";
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined CHEVYVOLT_CHARGER || defined NISSANLEAF_CHARGER
|
if (charger) {
|
||||||
|
// Start a new block with orange background color
|
||||||
|
content += "<div style='background-color: #FF6E00; padding: 10px; margin-bottom: 10px;border-radius: 50px'>";
|
||||||
|
|
||||||
// Start a new block with orange background color
|
content += "<h4 style='color: white;'>Charger HVDC Enabled: ";
|
||||||
content += "<div style='background-color: #FF6E00; padding: 10px; margin-bottom: 10px;border-radius: 50px'>";
|
if (datalayer.charger.charger_HV_enabled) {
|
||||||
|
content += "<span>✓</span>";
|
||||||
|
} else {
|
||||||
|
content += "<span style='color: red;'>✕</span>";
|
||||||
|
}
|
||||||
|
content += " <button onclick='editChargerHVDCEnabled()'>Edit</button></h4>";
|
||||||
|
|
||||||
content += "<h4 style='color: white;'>Charger HVDC Enabled: ";
|
content += "<h4 style='color: white;'>Charger Aux12VDC Enabled: ";
|
||||||
if (datalayer.charger.charger_HV_enabled) {
|
if (datalayer.charger.charger_aux12V_enabled) {
|
||||||
content += "<span>✓</span>";
|
content += "<span>✓</span>";
|
||||||
} else {
|
} else {
|
||||||
content += "<span style='color: red;'>✕</span>";
|
content += "<span style='color: red;'>✕</span>";
|
||||||
|
}
|
||||||
|
content += " <button onclick='editChargerAux12vEnabled()'>Edit</button></h4>";
|
||||||
|
|
||||||
|
content += "<h4 style='color: white;'>Charger Voltage Setpoint: " +
|
||||||
|
String(datalayer.charger.charger_setpoint_HV_VDC, 1) +
|
||||||
|
" V </span> <button onclick='editChargerSetpointVDC()'>Edit</button></h4>";
|
||||||
|
content += "<h4 style='color: white;'>Charger Current Setpoint: " +
|
||||||
|
String(datalayer.charger.charger_setpoint_HV_IDC, 1) +
|
||||||
|
" A </span> <button onclick='editChargerSetpointIDC()'>Edit</button></h4>";
|
||||||
|
|
||||||
|
// Close the block
|
||||||
|
content += "</div>";
|
||||||
}
|
}
|
||||||
content += " <button onclick='editChargerHVDCEnabled()'>Edit</button></h4>";
|
|
||||||
|
|
||||||
content += "<h4 style='color: white;'>Charger Aux12VDC Enabled: ";
|
|
||||||
if (datalayer.charger.charger_aux12V_enabled) {
|
|
||||||
content += "<span>✓</span>";
|
|
||||||
} else {
|
|
||||||
content += "<span style='color: red;'>✕</span>";
|
|
||||||
}
|
|
||||||
content += " <button onclick='editChargerAux12vEnabled()'>Edit</button></h4>";
|
|
||||||
|
|
||||||
content +=
|
|
||||||
"<h4 style='color: white;'>Charger Voltage Setpoint: " + String(datalayer.charger.charger_setpoint_HV_VDC, 1) +
|
|
||||||
" V </span> <button onclick='editChargerSetpointVDC()'>Edit</button></h4>";
|
|
||||||
content +=
|
|
||||||
"<h4 style='color: white;'>Charger Current Setpoint: " + String(datalayer.charger.charger_setpoint_HV_IDC, 1) +
|
|
||||||
" A </span> <button onclick='editChargerSetpointIDC()'>Edit</button></h4>";
|
|
||||||
|
|
||||||
// Close the block
|
|
||||||
content += "</div>";
|
|
||||||
#endif
|
|
||||||
|
|
||||||
content += "<script>"; // Note, this section is minified to improve performance
|
content += "<script>"; // Note, this section is minified to improve performance
|
||||||
content += "function editComplete(){if(this.status==200){window.location.reload();}}";
|
content += "function editComplete(){if(this.status==200){window.location.reload();}}";
|
||||||
|
@ -305,40 +305,44 @@ String settings_processor(const String& var) {
|
||||||
"between 0 and 1000');}}}";
|
"between 0 and 1000');}}}";
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined CHEVYVOLT_CHARGER || defined NISSANLEAF_CHARGER
|
if (charger) {
|
||||||
content +=
|
content +=
|
||||||
"function editChargerHVDCEnabled(){var value=prompt('Enable or disable HV DC output. Enter 1 for enabled, 0 "
|
"function editChargerHVDCEnabled(){var value=prompt('Enable or disable HV DC output. Enter 1 for enabled, 0 "
|
||||||
"for disabled');if(value!==null){if(value==0||value==1){var xhr=new "
|
"for disabled');if(value!==null){if(value==0||value==1){var xhr=new "
|
||||||
"XMLHttpRequest();xhr.onload=editComplete;xhr.onerror=editError;xhr.open('GET','/"
|
"XMLHttpRequest();xhr.onload=editComplete;xhr.onerror=editError;xhr.open('GET','/"
|
||||||
"updateChargerHvEnabled?value='+value,true);xhr.send();}}else{alert('Invalid value. Please enter 1 or 0');}}";
|
"updateChargerHvEnabled?value='+value,true);xhr.send();}}else{alert('Invalid value. Please enter 1 or 0');}}";
|
||||||
content +=
|
content +=
|
||||||
"function editChargerAux12vEnabled(){var value=prompt('Enable or disable low voltage 12v auxiliary DC output. "
|
"function editChargerAux12vEnabled(){var value=prompt('Enable or disable low voltage 12v auxiliary DC "
|
||||||
"Enter 1 for enabled, 0 for disabled');if(value!==null){if(value==0||value==1){var xhr=new "
|
"output. "
|
||||||
"XMLHttpRequest();xhr.onload=editComplete;xhr.onerror=editError;xhr.open('GET','/"
|
"Enter 1 for enabled, 0 for disabled');if(value!==null){if(value==0||value==1){var xhr=new "
|
||||||
"updateChargerAux12vEnabled?value='+value,true);xhr.send();}else{alert('Invalid value. Please enter 1 or "
|
"XMLHttpRequest();xhr.onload=editComplete;xhr.onerror=editError;xhr.open('GET','/"
|
||||||
"0');}}}";
|
"updateChargerAux12vEnabled?value='+value,true);xhr.send();}else{alert('Invalid value. Please enter 1 or "
|
||||||
content +=
|
"0');}}}";
|
||||||
"function editChargerSetpointVDC(){var value=prompt('Set charging voltage. Input will be validated against "
|
content +=
|
||||||
"inverter and/or charger configuration parameters, but use sensible values like 200 to "
|
"function editChargerSetpointVDC(){var value=prompt('Set charging voltage. Input will be validated against "
|
||||||
"420.');if(value!==null){if(value>=0&&value<=1000){var xhr=new "
|
"inverter and/or charger configuration parameters, but use sensible values like 200 to "
|
||||||
"XMLHttpRequest();xhr.onload=editComplete;xhr.onerror=editError;xhr.open('GET','/"
|
"420.');if(value!==null){if(value>=0&&value<=1000){var xhr=new "
|
||||||
"updateChargeSetpointV?value='+value,true);xhr.send();}else{alert('Invalid value. Please enter a value between "
|
"XMLHttpRequest();xhr.onload=editComplete;xhr.onerror=editError;xhr.open('GET','/"
|
||||||
"0 and 1000');}}}";
|
"updateChargeSetpointV?value='+value,true);xhr.send();}else{alert('Invalid value. Please enter a value "
|
||||||
content +=
|
"between "
|
||||||
"function editChargerSetpointIDC(){var value=prompt('Set charging amperage. Input will be validated against "
|
"0 and 1000');}}}";
|
||||||
"inverter and/or charger configuration parameters, but use sensible values like 6 to "
|
content +=
|
||||||
"48.');if(value!==null){if(value>=0&&value<=1000){var xhr=new "
|
"function editChargerSetpointIDC(){var value=prompt('Set charging amperage. Input will be validated against "
|
||||||
"XMLHttpRequest();xhr.onload=editComplete;xhr.onerror=editError;xhr.open('GET','/"
|
"inverter and/or charger configuration parameters, but use sensible values like 6 to "
|
||||||
"updateChargeSetpointA?value='+value,true);xhr.send();}else{alert('Invalid value. Please enter a value between "
|
"48.');if(value!==null){if(value>=0&&value<=1000){var xhr=new "
|
||||||
"0 and 100');}}}";
|
"XMLHttpRequest();xhr.onload=editComplete;xhr.onerror=editError;xhr.open('GET','/"
|
||||||
content +=
|
"updateChargeSetpointA?value='+value,true);xhr.send();}else{alert('Invalid value. Please enter a value "
|
||||||
"function editChargerSetpointEndI(){var value=prompt('Set amperage that terminates charge as being "
|
"between "
|
||||||
"sufficiently complete. Input will be validated against inverter and/or charger configuration parameters, but "
|
"0 and 100');}}}";
|
||||||
"use sensible values like 1-5.');if(value!==null){if(value>=0&&value<=1000){var xhr=new "
|
content +=
|
||||||
"XMLHttpRequest();xhr.onload=editComplete;xhr.onerror=editError;xhr.open('GET','/"
|
"function editChargerSetpointEndI(){var value=prompt('Set amperage that terminates charge as being "
|
||||||
"updateChargeEndA?value='+value,true);xhr.send();}else{alert('Invalid value. Please enter a value between 0 "
|
"sufficiently complete. Input will be validated against inverter and/or charger configuration parameters, "
|
||||||
"and 100');}}}";
|
"but "
|
||||||
#endif
|
"use sensible values like 1-5.');if(value!==null){if(value>=0&&value<=1000){var xhr=new "
|
||||||
|
"XMLHttpRequest();xhr.onload=editComplete;xhr.onerror=editError;xhr.open('GET','/"
|
||||||
|
"updateChargeEndA?value='+value,true);xhr.send();}else{alert('Invalid value. Please enter a value between 0 "
|
||||||
|
"and 100');}}}";
|
||||||
|
}
|
||||||
content += "</script>";
|
content += "</script>";
|
||||||
|
|
||||||
content += "<script>";
|
content += "<script>";
|
||||||
|
|
|
@ -752,94 +752,94 @@ void init_webserver() {
|
||||||
});
|
});
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined CHEVYVOLT_CHARGER || defined NISSANLEAF_CHARGER
|
if (charger) {
|
||||||
// Route for editing ChargerTargetV
|
// Route for editing ChargerTargetV
|
||||||
server.on("/updateChargeSetpointV", HTTP_GET, [](AsyncWebServerRequest* request) {
|
server.on("/updateChargeSetpointV", HTTP_GET, [](AsyncWebServerRequest* request) {
|
||||||
if (WEBSERVER_AUTH_REQUIRED && !request->authenticate(http_username, http_password))
|
if (WEBSERVER_AUTH_REQUIRED && !request->authenticate(http_username, http_password))
|
||||||
return request->requestAuthentication();
|
return request->requestAuthentication();
|
||||||
if (!request->hasParam("value")) {
|
if (!request->hasParam("value")) {
|
||||||
request->send(400, "text/plain", "Bad Request");
|
request->send(400, "text/plain", "Bad Request");
|
||||||
}
|
}
|
||||||
|
|
||||||
String value = request->getParam("value")->value();
|
|
||||||
float val = value.toFloat();
|
|
||||||
|
|
||||||
if (!(val <= CHARGER_MAX_HV && val >= CHARGER_MIN_HV)) {
|
|
||||||
request->send(400, "text/plain", "Bad Request");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(val * datalayer.charger.charger_setpoint_HV_IDC <= CHARGER_MAX_POWER)) {
|
|
||||||
request->send(400, "text/plain", "Bad Request");
|
|
||||||
}
|
|
||||||
|
|
||||||
datalayer.charger.charger_setpoint_HV_VDC = val;
|
|
||||||
|
|
||||||
request->send(200, "text/plain", "Updated successfully");
|
|
||||||
});
|
|
||||||
|
|
||||||
// Route for editing ChargerTargetA
|
|
||||||
server.on("/updateChargeSetpointA", HTTP_GET, [](AsyncWebServerRequest* request) {
|
|
||||||
if (WEBSERVER_AUTH_REQUIRED && !request->authenticate(http_username, http_password))
|
|
||||||
return request->requestAuthentication();
|
|
||||||
if (!request->hasParam("value")) {
|
|
||||||
request->send(400, "text/plain", "Bad Request");
|
|
||||||
}
|
|
||||||
|
|
||||||
String value = request->getParam("value")->value();
|
|
||||||
float val = value.toFloat();
|
|
||||||
|
|
||||||
if (!(val <= datalayer.battery.settings.max_user_set_charge_dA && val <= CHARGER_MAX_A)) {
|
|
||||||
request->send(400, "text/plain", "Bad Request");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(val * datalayer.charger.charger_setpoint_HV_VDC <= CHARGER_MAX_POWER)) {
|
|
||||||
request->send(400, "text/plain", "Bad Request");
|
|
||||||
}
|
|
||||||
|
|
||||||
datalayer.charger.charger_setpoint_HV_IDC = value.toFloat();
|
|
||||||
|
|
||||||
request->send(200, "text/plain", "Updated successfully");
|
|
||||||
});
|
|
||||||
|
|
||||||
// Route for editing ChargerEndA
|
|
||||||
server.on("/updateChargeEndA", HTTP_GET, [](AsyncWebServerRequest* request) {
|
|
||||||
if (WEBSERVER_AUTH_REQUIRED && !request->authenticate(http_username, http_password))
|
|
||||||
return request->requestAuthentication();
|
|
||||||
if (request->hasParam("value")) {
|
|
||||||
String value = request->getParam("value")->value();
|
String value = request->getParam("value")->value();
|
||||||
datalayer.charger.charger_setpoint_HV_IDC_END = value.toFloat();
|
float val = value.toFloat();
|
||||||
request->send(200, "text/plain", "Updated successfully");
|
|
||||||
} else {
|
|
||||||
request->send(400, "text/plain", "Bad Request");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Route for enabling/disabling HV charger
|
if (!(val <= CHARGER_MAX_HV && val >= CHARGER_MIN_HV)) {
|
||||||
server.on("/updateChargerHvEnabled", HTTP_GET, [](AsyncWebServerRequest* request) {
|
request->send(400, "text/plain", "Bad Request");
|
||||||
if (WEBSERVER_AUTH_REQUIRED && !request->authenticate(http_username, http_password))
|
}
|
||||||
return request->requestAuthentication();
|
|
||||||
if (request->hasParam("value")) {
|
if (!(val * datalayer.charger.charger_setpoint_HV_IDC <= CHARGER_MAX_POWER)) {
|
||||||
String value = request->getParam("value")->value();
|
request->send(400, "text/plain", "Bad Request");
|
||||||
datalayer.charger.charger_HV_enabled = (bool)value.toInt();
|
}
|
||||||
request->send(200, "text/plain", "Updated successfully");
|
|
||||||
} else {
|
datalayer.charger.charger_setpoint_HV_VDC = val;
|
||||||
request->send(400, "text/plain", "Bad Request");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Route for enabling/disabling aux12v charger
|
|
||||||
server.on("/updateChargerAux12vEnabled", HTTP_GET, [](AsyncWebServerRequest* request) {
|
|
||||||
if (WEBSERVER_AUTH_REQUIRED && !request->authenticate(http_username, http_password))
|
|
||||||
return request->requestAuthentication();
|
|
||||||
if (request->hasParam("value")) {
|
|
||||||
String value = request->getParam("value")->value();
|
|
||||||
datalayer.charger.charger_aux12V_enabled = (bool)value.toInt();
|
|
||||||
request->send(200, "text/plain", "Updated successfully");
|
request->send(200, "text/plain", "Updated successfully");
|
||||||
} else {
|
});
|
||||||
request->send(400, "text/plain", "Bad Request");
|
|
||||||
}
|
// Route for editing ChargerTargetA
|
||||||
});
|
server.on("/updateChargeSetpointA", HTTP_GET, [](AsyncWebServerRequest* request) {
|
||||||
#endif // defined CHEVYVOLT_CHARGER || defined NISSANLEAF_CHARGER
|
if (WEBSERVER_AUTH_REQUIRED && !request->authenticate(http_username, http_password))
|
||||||
|
return request->requestAuthentication();
|
||||||
|
if (!request->hasParam("value")) {
|
||||||
|
request->send(400, "text/plain", "Bad Request");
|
||||||
|
}
|
||||||
|
|
||||||
|
String value = request->getParam("value")->value();
|
||||||
|
float val = value.toFloat();
|
||||||
|
|
||||||
|
if (!(val <= datalayer.battery.settings.max_user_set_charge_dA && val <= CHARGER_MAX_A)) {
|
||||||
|
request->send(400, "text/plain", "Bad Request");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(val * datalayer.charger.charger_setpoint_HV_VDC <= CHARGER_MAX_POWER)) {
|
||||||
|
request->send(400, "text/plain", "Bad Request");
|
||||||
|
}
|
||||||
|
|
||||||
|
datalayer.charger.charger_setpoint_HV_IDC = value.toFloat();
|
||||||
|
|
||||||
|
request->send(200, "text/plain", "Updated successfully");
|
||||||
|
});
|
||||||
|
|
||||||
|
// Route for editing ChargerEndA
|
||||||
|
server.on("/updateChargeEndA", HTTP_GET, [](AsyncWebServerRequest* request) {
|
||||||
|
if (WEBSERVER_AUTH_REQUIRED && !request->authenticate(http_username, http_password))
|
||||||
|
return request->requestAuthentication();
|
||||||
|
if (request->hasParam("value")) {
|
||||||
|
String value = request->getParam("value")->value();
|
||||||
|
datalayer.charger.charger_setpoint_HV_IDC_END = value.toFloat();
|
||||||
|
request->send(200, "text/plain", "Updated successfully");
|
||||||
|
} else {
|
||||||
|
request->send(400, "text/plain", "Bad Request");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Route for enabling/disabling HV charger
|
||||||
|
server.on("/updateChargerHvEnabled", HTTP_GET, [](AsyncWebServerRequest* request) {
|
||||||
|
if (WEBSERVER_AUTH_REQUIRED && !request->authenticate(http_username, http_password))
|
||||||
|
return request->requestAuthentication();
|
||||||
|
if (request->hasParam("value")) {
|
||||||
|
String value = request->getParam("value")->value();
|
||||||
|
datalayer.charger.charger_HV_enabled = (bool)value.toInt();
|
||||||
|
request->send(200, "text/plain", "Updated successfully");
|
||||||
|
} else {
|
||||||
|
request->send(400, "text/plain", "Bad Request");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Route for enabling/disabling aux12v charger
|
||||||
|
server.on("/updateChargerAux12vEnabled", HTTP_GET, [](AsyncWebServerRequest* request) {
|
||||||
|
if (WEBSERVER_AUTH_REQUIRED && !request->authenticate(http_username, http_password))
|
||||||
|
return request->requestAuthentication();
|
||||||
|
if (request->hasParam("value")) {
|
||||||
|
String value = request->getParam("value")->value();
|
||||||
|
datalayer.charger.charger_aux12V_enabled = (bool)value.toInt();
|
||||||
|
request->send(200, "text/plain", "Updated successfully");
|
||||||
|
} else {
|
||||||
|
request->send(400, "text/plain", "Bad Request");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Send a GET request to <ESP_IP>/update
|
// Send a GET request to <ESP_IP>/update
|
||||||
server.on("/debug", HTTP_GET, [](AsyncWebServerRequest* request) {
|
server.on("/debug", HTTP_GET, [](AsyncWebServerRequest* request) {
|
||||||
|
@ -1018,16 +1018,11 @@ String processor(const String& var) {
|
||||||
content += "</h4>";
|
content += "</h4>";
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined CHEVYVOLT_CHARGER || defined NISSANLEAF_CHARGER
|
if (charger) {
|
||||||
content += "<h4 style='color: white;'>Charger protocol: ";
|
content += "<h4 style='color: white;'>Charger protocol: ";
|
||||||
#ifdef CHEVYVOLT_CHARGER
|
content += charger->name();
|
||||||
content += "Chevy Volt Gen1 Charger";
|
content += "</h4>";
|
||||||
#endif // CHEVYVOLT_CHARGER
|
}
|
||||||
#ifdef NISSANLEAF_CHARGER
|
|
||||||
content += "Nissan LEAF 2013-2024 PDM charger";
|
|
||||||
#endif // NISSANLEAF_CHARGER
|
|
||||||
content += "</h4>";
|
|
||||||
#endif // defined CHEVYVOLT_CHARGER || defined NISSANLEAF_CHARGER
|
|
||||||
|
|
||||||
// Close the block
|
// Close the block
|
||||||
content += "</div>";
|
content += "</div>";
|
||||||
|
@ -1428,61 +1423,52 @@ String processor(const String& var) {
|
||||||
content += "</div>";
|
content += "</div>";
|
||||||
#endif // DOUBLE_BATTERY
|
#endif // DOUBLE_BATTERY
|
||||||
|
|
||||||
#if defined CHEVYVOLT_CHARGER || defined NISSANLEAF_CHARGER
|
if (charger) {
|
||||||
// Start a new block with orange background color
|
// Start a new block with orange background color
|
||||||
content += "<div style='background-color: #FF6E00; padding: 10px; margin-bottom: 10px;border-radius: 50px'>";
|
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 (datalayer.charger.charger_HV_enabled) {
|
if (datalayer.charger.charger_HV_enabled) {
|
||||||
content += "<span>✓</span>";
|
content += "<span>✓</span>";
|
||||||
} else {
|
} else {
|
||||||
content += "<span style='color: red;'>✕</span>";
|
content += "<span style='color: red;'>✕</span>";
|
||||||
|
}
|
||||||
|
content += "</h4>";
|
||||||
|
|
||||||
|
content += "<h4>Charger Aux12v Enabled: ";
|
||||||
|
if (datalayer.charger.charger_aux12V_enabled) {
|
||||||
|
content += "<span>✓</span>";
|
||||||
|
} else {
|
||||||
|
content += "<span style='color: red;'>✕</span>";
|
||||||
|
}
|
||||||
|
content += "</h4>";
|
||||||
|
|
||||||
|
auto chgPwrDC = charger->outputPowerDC();
|
||||||
|
auto chgEff = charger->efficiency();
|
||||||
|
|
||||||
|
content += formatPowerValue("Charger Output Power", chgPwrDC, "", 1);
|
||||||
|
if (charger->efficiencySupported()) {
|
||||||
|
content += "<h4 style='color: white;'>Charger Efficiency: " + String(chgEff) + "%</h4>";
|
||||||
|
}
|
||||||
|
|
||||||
|
float HVvol = charger->HVDC_output_voltage();
|
||||||
|
float HVcur = charger->HVDC_output_current();
|
||||||
|
float LVvol = charger->LVDC_output_voltage();
|
||||||
|
float LVcur = charger->LVDC_output_current();
|
||||||
|
|
||||||
|
content += "<h4 style='color: white;'>Charger HVDC Output V: " + String(HVvol, 2) + " V</h4>";
|
||||||
|
content += "<h4 style='color: white;'>Charger HVDC Output I: " + String(HVcur, 2) + " A</h4>";
|
||||||
|
content += "<h4 style='color: white;'>Charger LVDC Output I: " + String(LVcur, 2) + "</h4>";
|
||||||
|
content += "<h4 style='color: white;'>Charger LVDC Output V: " + String(LVvol, 2) + "</h4>";
|
||||||
|
|
||||||
|
float ACcur = charger->AC_input_current();
|
||||||
|
float ACvol = charger->AC_input_voltage();
|
||||||
|
|
||||||
|
content += "<h4 style='color: white;'>Charger AC Input V: " + String(ACvol, 2) + " VAC</h4>";
|
||||||
|
content += "<h4 style='color: white;'>Charger AC Input I: " + String(ACcur, 2) + " A</h4>";
|
||||||
|
|
||||||
|
content += "</div>";
|
||||||
}
|
}
|
||||||
content += "</h4>";
|
|
||||||
|
|
||||||
content += "<h4>Charger Aux12v Enabled: ";
|
|
||||||
if (datalayer.charger.charger_aux12V_enabled) {
|
|
||||||
content += "<span>✓</span>";
|
|
||||||
} else {
|
|
||||||
content += "<span style='color: red;'>✕</span>";
|
|
||||||
}
|
|
||||||
content += "</h4>";
|
|
||||||
#ifdef CHEVYVOLT_CHARGER
|
|
||||||
float chgPwrDC = static_cast<float>(datalayer.charger.charger_stat_HVcur * datalayer.charger.charger_stat_HVvol);
|
|
||||||
float chgPwrAC = static_cast<float>(datalayer.charger.charger_stat_ACcur * datalayer.charger.charger_stat_ACvol);
|
|
||||||
float chgEff = chgPwrDC / chgPwrAC * 100;
|
|
||||||
float ACcur = datalayer.charger.charger_stat_ACcur;
|
|
||||||
float ACvol = datalayer.charger.charger_stat_ACvol;
|
|
||||||
float HVvol = datalayer.charger.charger_stat_HVvol;
|
|
||||||
float HVcur = datalayer.charger.charger_stat_HVcur;
|
|
||||||
float LVvol = datalayer.charger.charger_stat_LVvol;
|
|
||||||
float LVcur = datalayer.charger.charger_stat_LVcur;
|
|
||||||
|
|
||||||
content += formatPowerValue("Charger Output Power", chgPwrDC, "", 1);
|
|
||||||
content += "<h4 style='color: white;'>Charger Efficiency: " + String(chgEff) + "%</h4>";
|
|
||||||
content += "<h4 style='color: white;'>Charger HVDC Output V: " + String(HVvol, 2) + " V</h4>";
|
|
||||||
content += "<h4 style='color: white;'>Charger HVDC Output I: " + String(HVcur, 2) + " A</h4>";
|
|
||||||
content += "<h4 style='color: white;'>Charger LVDC Output I: " + String(LVcur, 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 I: " + String(ACcur, 2) + " A</h4>";
|
|
||||||
#endif // CHEVYVOLT_CHARGER
|
|
||||||
#ifdef NISSANLEAF_CHARGER
|
|
||||||
float chgPwrDC = static_cast<float>(datalayer.charger.charger_stat_HVcur * 100);
|
|
||||||
datalayer.charger.charger_stat_HVcur = chgPwrDC / (datalayer.battery.status.voltage_dV / 10); // P/U=I
|
|
||||||
datalayer.charger.charger_stat_HVvol = static_cast<float>(datalayer.battery.status.voltage_dV / 10);
|
|
||||||
float ACvol = datalayer.charger.charger_stat_ACvol;
|
|
||||||
float HVvol = datalayer.charger.charger_stat_HVvol;
|
|
||||||
float HVcur = datalayer.charger.charger_stat_HVcur;
|
|
||||||
|
|
||||||
content += formatPowerValue("Charger Output Power", chgPwrDC, "", 1);
|
|
||||||
content += "<h4 style='color: white;'>Charger HVDC Output V: " + String(HVvol, 2) + " V</h4>";
|
|
||||||
content += "<h4 style='color: white;'>Charger HVDC Output I: " + String(HVcur, 2) + " A</h4>";
|
|
||||||
content += "<h4 style='color: white;'>Charger AC Input V: " + String(ACvol, 2) + " VAC</h4>";
|
|
||||||
#endif // NISSANLEAF_CHARGER
|
|
||||||
// Close the block
|
|
||||||
content += "</div>";
|
|
||||||
#endif // defined CHEVYVOLT_CHARGER || defined NISSANLEAF_CHARGER
|
|
||||||
|
|
||||||
if (emulator_pause_request_ON)
|
if (emulator_pause_request_ON)
|
||||||
content += "<button onclick='PauseBattery(false)'>Resume charge/discharge</button> ";
|
content += "<button onclick='PauseBattery(false)'>Resume charge/discharge</button> ";
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue