All chargers compiled

This commit is contained in:
Jaakko Haakana 2025-05-10 06:50:15 +03:00
parent 1d733fa78f
commit 517731c4c3
14 changed files with 316 additions and 274 deletions

View file

@ -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();

View file

@ -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

View file

@ -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
}

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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;

View file

@ -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

View file

@ -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 */

View file

@ -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

View file

@ -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>&#10003;</span>";
} else {
content += "<span style='color: red;'>&#10005;</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>&#10003;</span>"; content += "<span>&#10003;</span>";
} else { } else {
content += "<span style='color: red;'>&#10005;</span>"; content += "<span style='color: red;'>&#10005;</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>&#10003;</span>";
} else {
content += "<span style='color: red;'>&#10005;</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>";

View file

@ -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>&#10003;</span>"; content += "<span>&#10003;</span>";
} else { } else {
content += "<span style='color: red;'>&#10005;</span>"; content += "<span style='color: red;'>&#10005;</span>";
}
content += "</h4>";
content += "<h4>Charger Aux12v Enabled: ";
if (datalayer.charger.charger_aux12V_enabled) {
content += "<span>&#10003;</span>";
} else {
content += "<span style='color: red;'>&#10005;</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>&#10003;</span>";
} else {
content += "<span style='color: red;'>&#10005;</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> ";