mirror of
https://github.com/dalathegreat/Battery-Emulator.git
synced 2025-10-06 03:50:13 +02:00
Basic support for the Chevy Volt Gen1 charger, including webserver integration. Intended to enable use of inverters lacking charging functions and standalone charging modes.
This commit is contained in:
parent
50bf4cba05
commit
5f2c11ba35
8 changed files with 503 additions and 0 deletions
|
@ -5,6 +5,7 @@
|
|||
#include "HardwareSerial.h"
|
||||
#include "USER_SETTINGS.h"
|
||||
#include "src/battery/BATTERIES.h"
|
||||
#include "src/charger/CHARGERS.h"
|
||||
#include "src/devboard/config.h"
|
||||
#include "src/inverter/INVERTERS.h"
|
||||
#include "src/lib/adafruit-Adafruit_NeoPixel/Adafruit_NeoPixel.h"
|
||||
|
@ -68,6 +69,21 @@ uint16_t cell_max_voltage = 3700; // Stores the highest cell voltage value
|
|||
uint16_t cell_min_voltage = 3700; // Stores the minimum cell voltage value in the system
|
||||
bool LFP_Chemistry = false;
|
||||
|
||||
// Common charger parameters
|
||||
volatile float charger_setpoint_HV_VDC = 0.0f;
|
||||
volatile float charger_setpoint_HV_IDC = 0.0f;
|
||||
volatile float charger_setpoint_HV_IDC_END = 0.0f;
|
||||
bool charger_HV_enabled = false;
|
||||
bool charger_aux12V_enabled = false;
|
||||
|
||||
// Common charger statistics, instantaneous values
|
||||
float charger_stat_HVcur = 0;
|
||||
float charger_stat_HVvol = 0;
|
||||
float charger_stat_ACcur = 0;
|
||||
float charger_stat_ACvol = 0;
|
||||
float charger_stat_LVcur = 0;
|
||||
float charger_stat_LVvol = 0;
|
||||
|
||||
// LED parameters
|
||||
Adafruit_NeoPixel pixels(1, WS2812_PIN, NEO_GRB + NEO_KHZ800);
|
||||
static uint8_t brightness = 0;
|
||||
|
@ -360,6 +376,9 @@ void receive_can() { // This section checks if we have a complete CAN message i
|
|||
#endif
|
||||
#ifdef SMA_CAN
|
||||
receive_can_sma(rx_frame);
|
||||
#endif
|
||||
#ifdef CHEVYVOLT_CHARGER
|
||||
receive_can_chevyvolt_charger(rx_frame);
|
||||
#endif
|
||||
} else {
|
||||
//printf("New extended frame");
|
||||
|
@ -419,6 +438,9 @@ void send_can() {
|
|||
#ifdef TEST_FAKE_BATTERY
|
||||
send_can_test_battery();
|
||||
#endif
|
||||
#ifdef CHEVYVOLT_CHARGER
|
||||
send_can_chevyvolt_charger();
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef DUAL_CAN
|
||||
|
|
|
@ -15,6 +15,14 @@ volatile uint16_t MAXCHARGEAMP =
|
|||
volatile uint16_t MAXDISCHARGEAMP =
|
||||
300; //30.0A , BYD CAN specific setting, Max discharge speed in Amp (Some inverters needs to be artificially limited)
|
||||
|
||||
/* Charger settings */
|
||||
volatile float CHARGER_SET_HV = 384; // Reasonably appropriate 4.0v per cell charging of a 96s pack
|
||||
volatile float CHARGER_MAX_HV = 420; // Max permissible output (VDC) of charger
|
||||
volatile float CHARGER_MIN_HV = 200; // Min permissible output (VDC) of charger
|
||||
volatile float CHARGER_MAX_POWER = 3300; // Max power capable of charger, as a ceiling for validating config
|
||||
volatile float CHARGER_MAX_A = 11.5; // Max current output (amps) of charger
|
||||
volatile float CHARGER_END_A = 1.0; // Current at which charging is considered complete
|
||||
|
||||
#ifdef WEBSERVER
|
||||
volatile uint8_t AccessPointEnabled =
|
||||
true; //Set to either true or false incase you want the board to enable a direct wifi access point
|
||||
|
|
|
@ -38,6 +38,9 @@
|
|||
//#define SERIAL_LINK_TRANSMITTER //Enable this line to send battery data over RS485 pins to another Lilygo (This LilyGo interfaces with battery)
|
||||
//#define WEBSERVER //Enable this line to enable WiFi, and to run the webserver. See USER_SETTINGS.cpp for the Wifi settings.
|
||||
|
||||
/* Select charger used (Optional) */
|
||||
//#define CHEVYVOLT_CHARGER //Enable this line to control a Chevrolet Volt charger connected to battery - for example, when generator charging or using an inverter without a charging function.
|
||||
|
||||
/* Battery limits: These are set in the USER_SETTINGS.cpp file, or later on via the Webserver */
|
||||
extern volatile uint16_t BATTERY_WH_MAX;
|
||||
extern volatile uint16_t MAXPERCENTAGE;
|
||||
|
@ -45,4 +48,18 @@ extern volatile uint16_t MINPERCENTAGE;
|
|||
extern volatile uint16_t MAXCHARGEAMP;
|
||||
extern volatile uint16_t MAXDISCHARGEAMP;
|
||||
extern volatile uint8_t AccessPointEnabled;
|
||||
|
||||
/* Charger limits: Set in the USER_SETTINGS.cpp or later in the webserver */
|
||||
extern volatile float charger_setpoint_HV_VDC;
|
||||
extern volatile float charger_setpoint_HV_IDC;
|
||||
extern volatile float charger_setpoint_HV_IDC_END;
|
||||
extern volatile float CHARGER_SET_HV;
|
||||
extern volatile float CHARGER_MAX_HV;
|
||||
extern volatile float CHARGER_MIN_HV;
|
||||
extern volatile float CHARGER_MAX_POWER;
|
||||
extern volatile float CHARGER_MAX_A;
|
||||
extern volatile float CHARGER_END_A;
|
||||
extern bool charger_HV_enabled;
|
||||
extern bool charger_aux12V_enabled;
|
||||
|
||||
#endif
|
||||
|
|
8
Software/src/charger/CHARGERS.h
Normal file
8
Software/src/charger/CHARGERS.h
Normal file
|
@ -0,0 +1,8 @@
|
|||
#ifndef CHARGERS_H
|
||||
#define CHARGERS_H
|
||||
|
||||
#ifdef CHEVYVOLT_CHARGER
|
||||
#include "chevyvolt.h"
|
||||
#endif
|
||||
|
||||
#endif
|
198
Software/src/charger/chevyvolt.cpp
Normal file
198
Software/src/charger/chevyvolt.cpp
Normal file
|
@ -0,0 +1,198 @@
|
|||
#include "chevyvolt.h"
|
||||
#include "../lib/miwagner-ESP32-Arduino-CAN/CAN_config.h"
|
||||
#include "../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h"
|
||||
|
||||
/* This implements Chevy Volt / Ampera charger support (2011-2015 model years).
|
||||
*
|
||||
* This code is intended to facilitate battery charging while repurposing inverters
|
||||
* that lack embedded charging features, to facilitate standalone charging, etc.
|
||||
*
|
||||
* Key influence and inspiration informed by prior work by those such as:
|
||||
* Damien Maguire (evmbw.org, github.com/damienmaguire/AmperaCharger)
|
||||
* Tom deBree, Arber Kramer, Colin Kidder, EVTV, etc
|
||||
* Various implementation details aided by openinverter forum discussion/CAN logs
|
||||
*
|
||||
* It is very likely that Lear charger support could be added to this with minimal effort
|
||||
* (similar hardware, different firmware and CAN messages).
|
||||
*
|
||||
* 2024 smaresca
|
||||
*/
|
||||
|
||||
/* CAN cycles and timers */
|
||||
static const int interval30ms = 30; // 30ms cycle for keepalive frames
|
||||
static const int interval200ms = 200; // 200ms cycle for commanding I/V targets
|
||||
static const int interval5000ms = 5000; // 5s status printout to serial
|
||||
static unsigned long previousMillis30ms = 0;
|
||||
static unsigned long previousMillis200ms = 0;
|
||||
static unsigned long previousMillis5000ms = 0;
|
||||
|
||||
/* voltage and current settings. Validation performed to set ceiling of 3300w vol*cur */
|
||||
extern volatile float charger_setpoint_HV_VDC;
|
||||
extern volatile float charger_setpoint_HV_IDC;
|
||||
extern volatile float charger_setpoint_HV_IDC_END;
|
||||
extern bool charger_HV_enabled;
|
||||
extern bool charger_aux12V_enabled;
|
||||
|
||||
extern float charger_stat_HVcur;
|
||||
extern float charger_stat_HVvol;
|
||||
extern float charger_stat_ACcur;
|
||||
extern float charger_stat_ACvol;
|
||||
extern float charger_stat_LVcur;
|
||||
extern float charger_stat_LVvol;
|
||||
|
||||
enum CHARGER_MODES : uint8_t { MODE_DISABLED = 0, MODE_LV, MODE_HV, MODE_HVLV };
|
||||
|
||||
//Actual content messages
|
||||
static CAN_frame_t charger_keepalive_frame = {.FIR = {.B =
|
||||
{
|
||||
//one byte only, indicating enabled or disabled
|
||||
.DLC = 1,
|
||||
.FF = CAN_frame_std,
|
||||
}},
|
||||
.MsgID = 0x30E,
|
||||
.data = {MODE_DISABLED}};
|
||||
|
||||
static CAN_frame_t charger_set_targets = {.FIR = {.B =
|
||||
{
|
||||
.DLC = 4,
|
||||
.FF = CAN_frame_std,
|
||||
}},
|
||||
.MsgID = 0x304,
|
||||
|
||||
// data[0] is a static value, meaning unknown
|
||||
.data = {0x40, 0x00, 0x00, 0x00}};
|
||||
|
||||
/* We are mostly sending out not receiving */
|
||||
void receive_can_chevyvolt_charger(CAN_frame_t rx_frame) {
|
||||
uint16_t charger_stat_HVcur_temp = 0;
|
||||
uint16_t charger_stat_HVvol_temp = 0;
|
||||
uint16_t charger_stat_LVcur_temp = 0;
|
||||
uint16_t charger_stat_LVvol_temp = 0;
|
||||
uint16_t charger_stat_ACcur_temp = 0;
|
||||
uint16_t charger_stat_ACvol_temp = 0;
|
||||
|
||||
switch (rx_frame.MsgID) {
|
||||
//ID 0x212 conveys instantaneous DC charger stats
|
||||
case 0x212:
|
||||
charger_stat_HVcur_temp = (uint16_t)(rx_frame.data.u8[0] << 8 | rx_frame.data.u8[1]);
|
||||
charger_stat_HVcur = (float)(charger_stat_HVcur_temp >> 3) * 0.05;
|
||||
|
||||
charger_stat_HVvol_temp = (uint16_t)((((rx_frame.data.u8[1] << 8 | rx_frame.data.u8[2])) >> 1) & 0x3ff);
|
||||
charger_stat_HVvol = (float)(charger_stat_HVvol_temp) * .5;
|
||||
|
||||
charger_stat_LVcur_temp = (uint16_t)(((rx_frame.data.u8[2] << 8 | rx_frame.data.u8[3]) >> 1) & 0x00ff);
|
||||
charger_stat_LVcur = (float)(charger_stat_LVcur_temp) * .2;
|
||||
|
||||
charger_stat_LVvol_temp = (uint16_t)(((rx_frame.data.u8[3] << 8 | rx_frame.data.u8[4]) >> 1) & 0x00ff);
|
||||
charger_stat_LVvol = (float)(charger_stat_LVvol_temp) * .1;
|
||||
|
||||
break;
|
||||
|
||||
//ID 0x30A conveys instantaneous AC charger stats
|
||||
case 0x30A:
|
||||
charger_stat_ACcur_temp = (uint16_t)((rx_frame.data.u8[0] << 8 | rx_frame.data.u8[1]) >> 4);
|
||||
charger_stat_ACcur = (float)(charger_stat_ACcur_temp) * 0.2;
|
||||
|
||||
charger_stat_ACvol_temp = (uint16_t)(((rx_frame.data.u8[1] << 8 | rx_frame.data.u8[2]) >> 4) & 0x00ff);
|
||||
charger_stat_ACvol = (float)(charger_stat_ACvol_temp) * 2;
|
||||
|
||||
break;
|
||||
|
||||
//ID 0x266, 0x268, and 0x308 are regularly emitted by the charger but content is unknown
|
||||
// 0x266 and 0x308 are len 5
|
||||
// 0x268 may be temperature data (len 8). Could resemble the Lear charger equivalent TODO
|
||||
case 0x266:
|
||||
break;
|
||||
case 0x268:
|
||||
break;
|
||||
case 0x308:
|
||||
break;
|
||||
default:
|
||||
#ifdef DEBUG_VIA_USB
|
||||
Serial.printf("CAN Rcv unknown frame MsgID=%x\n", rx_frame.MsgID);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void send_can_chevyvolt_charger() {
|
||||
unsigned long currentMillis = millis();
|
||||
uint16_t Vol_temp = 0;
|
||||
|
||||
uint16_t setpoint_HV_VDC = floor(charger_setpoint_HV_VDC);
|
||||
uint16_t setpoint_HV_IDC = floor(charger_setpoint_HV_IDC);
|
||||
uint16_t setpoint_HV_IDC_END = floor(charger_setpoint_HV_IDC_END);
|
||||
uint8_t charger_mode = MODE_DISABLED;
|
||||
|
||||
/* Send keepalive with mode every 30ms */
|
||||
if (currentMillis - previousMillis30ms >= interval30ms) {
|
||||
previousMillis30ms = currentMillis;
|
||||
|
||||
if (charger_HV_enabled) {
|
||||
charger_mode += MODE_HV;
|
||||
|
||||
/* disable HV if end amperage reached
|
||||
* TODO - integration opportunity with battery/inverter code
|
||||
if (setpoint_HV_IDC_END > 0 && charger_stat_HVcur > setpoint_HV_IDC_END) {
|
||||
charger_mode -= MODE_HV;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
if (charger_aux12V_enabled)
|
||||
charger_mode += MODE_LV;
|
||||
|
||||
charger_keepalive_frame.data.u8[0] = charger_mode;
|
||||
|
||||
ESP32Can.CANWriteFrame(&charger_keepalive_frame);
|
||||
}
|
||||
|
||||
/* Send current targets every 200ms */
|
||||
if (currentMillis - previousMillis200ms >= interval200ms) {
|
||||
previousMillis200ms = currentMillis;
|
||||
|
||||
/* These values should be and are validated elsewhere, but adjust if needed
|
||||
* to stay within limits of hardware and user-supplied settings
|
||||
*/
|
||||
if (setpoint_HV_VDC > CHARGER_MAX_HV) {
|
||||
setpoint_HV_VDC = CHEVYVOLT_MAX_HVDC;
|
||||
}
|
||||
|
||||
if (setpoint_HV_VDC < CHARGER_MIN_HV && setpoint_HV_VDC > 0) {
|
||||
setpoint_HV_VDC = CHEVYVOLT_MIN_HVDC;
|
||||
}
|
||||
|
||||
if (setpoint_HV_IDC > CHARGER_MAX_A) {
|
||||
setpoint_HV_VDC = CHEVYVOLT_MAX_AMP;
|
||||
}
|
||||
|
||||
/* if power overcommitted, back down to just below while maintaining voltage target */
|
||||
if (setpoint_HV_IDC * setpoint_HV_VDC > CHARGER_MAX_POWER) {
|
||||
setpoint_HV_IDC = floor(CHARGER_MAX_POWER / setpoint_HV_VDC);
|
||||
}
|
||||
|
||||
/* current setting */
|
||||
charger_set_targets.data.u8[1] = setpoint_HV_IDC * 20;
|
||||
Vol_temp = setpoint_HV_VDC * 2;
|
||||
|
||||
/* first 2 bits are MSB of the voltage command */
|
||||
charger_set_targets.data.u8[2] = highByte(Vol_temp);
|
||||
|
||||
/* LSB of the voltage command. Then MSB LSB is divided by 2 */
|
||||
charger_set_targets.data.u8[3] = lowByte(Vol_temp);
|
||||
|
||||
ESP32Can.CANWriteFrame(&charger_set_targets);
|
||||
}
|
||||
|
||||
#ifdef DEBUG_VIA_USB
|
||||
/* Serial echo every 5s of charger stats */
|
||||
if (currentMillis - previousMillis5000ms >= interval5000ms) {
|
||||
previousMillis5000ms = currentMillis;
|
||||
Serial.printf("Charger AC in IAC=%fA VAC=%fV\n", charger_stat_ACcur, charger_stat_ACvol);
|
||||
Serial.printf("Charger HV out IDC=%fA VDC=%fV\n", charger_stat_HVcur, charger_stat_HVvol);
|
||||
Serial.printf("Charger LV out IDC=%fA VDC=%fV\n", charger_stat_LVcur, charger_stat_LVvol);
|
||||
Serial.printf("Charger mode=%s\n", (charger_mode > MODE_DISABLED) ? "Enabled" : "Disabled");
|
||||
Serial.printf("Charger HVset=%uV,%uA finishCurrent=%uA\n", setpoint_HV_VDC, setpoint_HV_IDC, setpoint_HV_IDC_END);
|
||||
}
|
||||
#endif
|
||||
}
|
21
Software/src/charger/chevyvolt.h
Normal file
21
Software/src/charger/chevyvolt.h
Normal file
|
@ -0,0 +1,21 @@
|
|||
#ifndef CHEVYVOLT_H
|
||||
#define CHEVYVOLT_H
|
||||
#include <Arduino.h>
|
||||
#include "../../USER_SETTINGS.h"
|
||||
#include "../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h"
|
||||
|
||||
/* Charger hardware limits
|
||||
*
|
||||
* Relative to runtime settings, expectations are:
|
||||
* hw minimum <= setting minimum <= setting maximum <= hw max
|
||||
*/
|
||||
#define CHEVYVOLT_MAX_HVDC 420.0
|
||||
#define CHEVYVOLT_MIN_HVDC 200.0
|
||||
#define CHEVYVOLT_MAX_AMP 11.5
|
||||
#define CHEVYVOLT_MAX_POWER 3300
|
||||
|
||||
void update_values_can_chevyvolt_charger();
|
||||
void send_can_chevyvolt_charger();
|
||||
void receive_can_chevyvolt_charger(CAN_frame_t rx_frame);
|
||||
|
||||
#endif
|
|
@ -115,6 +115,85 @@ void init_webserver() {
|
|||
}
|
||||
});
|
||||
|
||||
#ifdef CHEVYVOLT_CHARGER
|
||||
// Route for editing ChargerTargetV
|
||||
server.on("/updateChargeSetpointV", HTTP_GET, [](AsyncWebServerRequest* request) {
|
||||
if (!request->hasParam("value")) {
|
||||
request->send(400, "text/plain", "Bad Request");
|
||||
}
|
||||
|
||||
String value = request->getParam("value")->value();
|
||||
float val = value.toFloat();
|
||||
|
||||
if (!(val <= CHARGER_MAX_HV && val >= CHARGER_MIN_HV)) {
|
||||
request->send(400, "text/plain", "Bad Request");
|
||||
}
|
||||
|
||||
if (!(val * charger_setpoint_HV_IDC <= CHARGER_MAX_POWER)) {
|
||||
request->send(400, "text/plain", "Bad Request");
|
||||
}
|
||||
|
||||
charger_setpoint_HV_VDC = val;
|
||||
|
||||
request->send(200, "text/plain", "Updated successfully");
|
||||
});
|
||||
|
||||
// Route for editing ChargerTargetA
|
||||
server.on("/updateChargeSetpointA", HTTP_GET, [](AsyncWebServerRequest* request) {
|
||||
if (!request->hasParam("value")) {
|
||||
request->send(400, "text/plain", "Bad Request");
|
||||
}
|
||||
|
||||
String value = request->getParam("value")->value();
|
||||
float val = value.toFloat();
|
||||
|
||||
if (!(val <= MAXCHARGEAMP && val <= CHARGER_MAX_A)) {
|
||||
request->send(400, "text/plain", "Bad Request");
|
||||
}
|
||||
|
||||
if (!(val * charger_setpoint_HV_VDC <= CHARGER_MAX_POWER)) {
|
||||
request->send(400, "text/plain", "Bad Request");
|
||||
}
|
||||
|
||||
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 (request->hasParam("value")) {
|
||||
String value = request->getParam("value")->value();
|
||||
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 (request->hasParam("value")) {
|
||||
String value = request->getParam("value")->value();
|
||||
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 (request->hasParam("value")) {
|
||||
String value = request->getParam("value")->value();
|
||||
charger_aux12V_enabled = (bool)value.toInt();
|
||||
request->send(200, "text/plain", "Updated successfully");
|
||||
} else {
|
||||
request->send(400, "text/plain", "Bad Request");
|
||||
}
|
||||
});
|
||||
#endif
|
||||
|
||||
// Send a GET request to <ESP_IP>/update
|
||||
server.on("/debug", HTTP_GET,
|
||||
[](AsyncWebServerRequest* request) { request->send(200, "text/plain", "Debug: all OK."); });
|
||||
|
@ -298,6 +377,15 @@ String processor(const String& var) {
|
|||
content += "Fake battery for testing purposes";
|
||||
#endif
|
||||
content += "</h4>";
|
||||
|
||||
#ifdef CHEVYVOLT_CHARGER
|
||||
content += "<h4 style='color: white;'>Charger protocol: ";
|
||||
#ifdef CHEVYVOLT_CHARGER
|
||||
content += "Chevy Volt Gen1 Charger";
|
||||
#endif
|
||||
content += "</h4>";
|
||||
#endif
|
||||
|
||||
// Close the block
|
||||
content += "</div>";
|
||||
|
||||
|
@ -391,6 +479,42 @@ String processor(const String& var) {
|
|||
content += "<span style='color: red;'>✕</span></h4>";
|
||||
}
|
||||
|
||||
#ifdef CHEVYVOLT_CHARGER
|
||||
content += "<h4>Charger HV Enabled: ";
|
||||
if (charger_HV_enabled) {
|
||||
content += "<span>✓</span>";
|
||||
} else {
|
||||
content += "<span style='color: red;'>✕</span>";
|
||||
}
|
||||
content += "</h4>";
|
||||
|
||||
content += "<h4>Charger Aux12v Enabled: ";
|
||||
if (charger_aux12V_enabled) {
|
||||
content += "<span>✓</span>";
|
||||
} else {
|
||||
content += "<span style='color: red;'>✕</span>";
|
||||
}
|
||||
content += "</h4>";
|
||||
float chgPwrDC = static_cast<float>(charger_stat_HVcur * charger_stat_HVvol);
|
||||
float chgPwrAC = static_cast<float>(charger_stat_ACcur * charger_stat_ACvol);
|
||||
float chgEff = chgPwrDC / chgPwrAC * 100;
|
||||
float ACcur = charger_stat_ACcur;
|
||||
float ACvol = charger_stat_ACvol;
|
||||
float HVvol = charger_stat_HVvol;
|
||||
float HVcur = charger_stat_HVcur;
|
||||
float LVvol = charger_stat_LVvol;
|
||||
float LVcur = 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) + "</h4>";
|
||||
content += "<h4 style='color: white;'>Charger HVDC Output I: " + String(HVcur, 2) + "</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(ACvol, 2) + "VAC</h4>";
|
||||
#endif
|
||||
|
||||
// Close the block
|
||||
content += "</div>";
|
||||
|
||||
|
@ -445,6 +569,28 @@ String settings_processor(const String& var) {
|
|||
" A </span> <button onclick='editMaxChargeA()'>Edit</button></h4>";
|
||||
content += "<h4 style='color: white;'>Max discharge speed: " + String(MAXDISCHARGEAMP / 10.0, 1) +
|
||||
" A </span> <button onclick='editMaxDischargeA()'>Edit</button></h4>";
|
||||
#ifdef CHEVYVOLT_CHARGER
|
||||
content += "<h4 style='color: white;'>Charger HVDC Enabled: ";
|
||||
if (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 Aux12VDC Enabled: ";
|
||||
if (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(charger_setpoint_HV_VDC, 1) +
|
||||
" V </span> <button onclick='editChargerSetpointVDC()'>Edit</button></h4>";
|
||||
content += "<h4 style='color: white;'>Charger Current Setpoint: " + String(charger_setpoint_HV_IDC, 1) +
|
||||
" A </span> <button onclick='editChargerSetpointIDC()'>Edit</button></h4>";
|
||||
#endif
|
||||
|
||||
content += "<script>";
|
||||
content += "function editWh() {";
|
||||
|
@ -515,6 +661,81 @@ String settings_processor(const String& var) {
|
|||
content += " }";
|
||||
content += "}";
|
||||
content += "}";
|
||||
|
||||
#ifdef CHEVYVOLT_CHARGER
|
||||
content += "function editChargerHVDCEnabled() {";
|
||||
content += " var value = prompt('Enable or disable HV DC output. Enter 1 for enabled, 0 for disabled');";
|
||||
content += " if (value !== null) {";
|
||||
content += " if (value == 0 || value == 1) {";
|
||||
content += " var xhr = new XMLHttpRequest();";
|
||||
content += " xhr.open('GET', '/updateChargerHvEnabled?value=' + value, true);";
|
||||
content += " xhr.send();";
|
||||
content += " }";
|
||||
content += " } else {";
|
||||
content += " alert('Invalid value. Please enter 1 or 0');";
|
||||
content += " }";
|
||||
content += "}";
|
||||
|
||||
content += "function editChargerAux12vEnabled() {";
|
||||
content +=
|
||||
"var value = prompt('Enable or disable low voltage 12v auxiliary DC output. Enter 1 for enabled, 0 for "
|
||||
"disabled');";
|
||||
content += "if (value !== null) {";
|
||||
content += " if (value == 0 || value == 1) {";
|
||||
content += " var xhr = new XMLHttpRequest();";
|
||||
content += " xhr.open('GET', '/updateChargerAux12vEnabled?value=' + value, true);";
|
||||
content += " xhr.send();";
|
||||
content += " } else {";
|
||||
content += " alert('Invalid value. Please enter 1 or 0');";
|
||||
content += " }";
|
||||
content += "}";
|
||||
content += "}";
|
||||
|
||||
content += "function editChargerSetpointVDC() {";
|
||||
content +=
|
||||
"var value = prompt('Set charging voltage. Input will be validated against inverter and/or charger "
|
||||
"configuration parameters, but use sensible values like 200 to 420.');";
|
||||
content += "if (value !== null) {";
|
||||
content += " if (value >= 0 && value <= 1000) {";
|
||||
content += " var xhr = new XMLHttpRequest();";
|
||||
content += " xhr.open('GET', '/updateChargeSetpointV?value=' + value, true);";
|
||||
content += " xhr.send();";
|
||||
content += " } else {";
|
||||
content += " alert('Invalid value. Please enter a value between 0 and 1000');";
|
||||
content += " }";
|
||||
content += "}";
|
||||
content += "}";
|
||||
|
||||
content += "function editChargerSetpointIDC() {";
|
||||
content +=
|
||||
"var value = prompt('Set charging amperage. Input will be validated against inverter and/or charger "
|
||||
"configuration parameters, but use sensible values like 6 to 48.');";
|
||||
content += "if (value !== null) {";
|
||||
content += " if (value >= 0 && value <= 1000) {";
|
||||
content += " var xhr = new XMLHttpRequest();";
|
||||
content += " xhr.open('GET', '/updateChargeSetpointA?value=' + value, true);";
|
||||
content += " xhr.send();";
|
||||
content += " } else {";
|
||||
content += " alert('Invalid value. Please enter a value between 0 and 100');";
|
||||
content += " }";
|
||||
content += "}";
|
||||
content += "}";
|
||||
|
||||
content += "function editChargerSetpointEndI() {";
|
||||
content +=
|
||||
"var value = prompt('Set amperage that terminates charge as being sufficiently complete. Input will be "
|
||||
"validated against inverter and/or charger configuration parameters, but use sensible values like 1-5.');";
|
||||
content += "if (value !== null) {";
|
||||
content += " if (value >= 0 && value <= 1000) {";
|
||||
content += " var xhr = new XMLHttpRequest();";
|
||||
content += " xhr.open('GET', '/updateChargeEndA?value=' + value, true);";
|
||||
content += " xhr.send();";
|
||||
content += " } else {";
|
||||
content += " alert('Invalid value. Please enter a value between 0 and 100');";
|
||||
content += " }";
|
||||
content += "}";
|
||||
content += "}";
|
||||
#endif
|
||||
content += "</script>";
|
||||
|
||||
// Close the block
|
||||
|
|
|
@ -35,6 +35,14 @@ extern const char* ssidAP;
|
|||
extern const char* passwordAP;
|
||||
extern const char* versionNumber;
|
||||
|
||||
// Common charger parameters
|
||||
extern float charger_stat_HVcur;
|
||||
extern float charger_stat_HVvol;
|
||||
extern float charger_stat_ACcur;
|
||||
extern float charger_stat_ACvol;
|
||||
extern float charger_stat_LVcur;
|
||||
extern float charger_stat_LVvol;
|
||||
|
||||
/**
|
||||
* @brief Initialization function for the webserver.
|
||||
*
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue