Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: Add livedata to webserver #117

Merged
merged 4 commits into from
Jan 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Software/Software.ino
Original file line number Diff line number Diff line change
Expand Up @@ -490,6 +490,7 @@ void handle_LED_state() {

// BMS in fault state overrides everything
if (bms_status == FAULT) {
LEDcolor = RED;
pixels.setPixelColor(0, pixels.Color(255, 0, 0)); // Red LED full brightness
}

Expand Down
170 changes: 163 additions & 7 deletions Software/src/devboard/webserver/webserver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ unsigned long ota_progress_millis = 0;
const char index_html[] PROGMEM = R"rawliteral(
<!DOCTYPE HTML><html>
<head>
<title>Battery Emulator Web Server</title>
<title>Battery Emulator</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" href="data:,">
<link rel="icon" type="image/png" href="favicon.png">
<style>
html {font-family: Arial; display: inline-block; text-align: center;}
h2 {font-size: 3.0rem;}
Expand All @@ -26,7 +26,7 @@ const char index_html[] PROGMEM = R"rawliteral(
</style>
</head>
<body>
<h2>Battery Emulator Web Server</h2>
<h2>Battery Emulator</h2>
%PLACEHOLDER%
</script>
</body>
Expand Down Expand Up @@ -93,7 +93,7 @@ void init_WiFi_STA(const char* ssid, const char* password) {
}
if (WiFi.status() == WL_CONNECTED) { // WL_CONNECTED is assigned when connected to a WiFi network
wifi_connected = true;
wifi_state = "connected";
wifi_state = "Connected";
// Print local IP address and start web server
Serial.println("");
Serial.print("Connected to WiFi network: ");
Expand All @@ -102,7 +102,7 @@ void init_WiFi_STA(const char* ssid, const char* password) {
Serial.println(WiFi.localIP());
} else {
wifi_connected = false;
wifi_state = "not connected";
wifi_state = "Not connected";
Serial.print("Not connected to WiFi network: ");
Serial.println(ssid);
Serial.println("Please check WiFi network name and password, and if WiFi network is available.");
Expand All @@ -120,6 +120,14 @@ void init_ElegantOTA() {
String processor(const String& var) {
if (var == "PLACEHOLDER") {
String content = "";
//Page format
content += "<style>";
content += "body { background-color: black; color: white; }";
content += "</style>";

// Start a new block with a specific background color
content += "<div style='background-color: #303E47; padding: 10px; margin-bottom: 10px;border-radius: 50px'>";

// Display LED color
content += "<h4>LED color: ";
switch (LEDcolor) {
Expand All @@ -136,17 +144,165 @@ String processor(const String& var) {
content += "RED</h4>";
break;
case TEST_ALL_COLORS:
content += "RAINBOW</h4>";
content += "RGB Testing loop</h4>";
break;
default:
break;
}
// Display ssid of network connected to and, if connected to the WiFi, its own IP
content += "<h4>SSID: " + String(ssid) + "</h4>";
content += "<h4>status: " + wifi_state + "</h4>";
content += "<h4>Wifi status: " + wifi_state + "</h4>";
if (wifi_connected == true) {
content += "<h4>IP: " + WiFi.localIP().toString() + "</h4>";
}
// Close the block
content += "</div>";

// Start a new block with a specific background color
content += "<div style='background-color: #333; padding: 10px; margin-bottom: 10px; border-radius: 50px'>";

// Display which components are used
content += "<h4 style='color: white;'>Inverter protocol: ";
#ifdef BYD_CAN
content += "BYD Battery-Box Premium HVS over CAN Bus";
#endif
#ifdef BYD_MODBUS
content += "BYD 11kWh HVM battery over Modbus RTU";
#endif
#ifdef LUNA2000_MODBUS
content += "Luna2000 battery over Modbus RTU";
#endif
#ifdef PYLON_CAN
content += "Pylontech battery over CAN bus";
#endif
#ifdef SMA_CAN
content += "BYD Battery-Box H 8.9kWh, 7 mod over CAN bus";
#endif
#ifdef SOFAR_CAN
content += "Sofar Energy Storage Inverter High Voltage BMS General Protocol (Extended Frame) over CAN bus";
#endif
#ifdef SOLAX_CAN
content += "SolaX Triple Power LFP over CAN bus";
#endif
content += "</h4>";

content += "<h4 style='color: white;'>Battery protocol: ";
#ifdef BMW_I3_BATTERY
content += "BMW i3";
#endif
#ifdef CHADEMO_BATTERY
content += "Chademo V2X mode";
#endif
#ifdef IMIEV_CZERO_ION_BATTERY
content += "I-Miev / C-Zero / Ion Triplet";
#endif
#ifdef KIA_HYUNDAI_64_BATTERY
content += "Kia/Hyundai 64kWh";
#endif
#ifdef NISSAN_LEAF_BATTERY
content += "Nissan LEAF";
#endif
#ifdef RENAULT_ZOE_BATTERY
content += "Renault Zoe / Kangoo";
#endif
#ifdef TESLA_MODEL_3_BATTERY
content += "Tesla Model S/3/X/Y";
#endif
#ifdef TEST_FAKE_BATTERY
content += "Fake battery for testing purposes";
#endif
content += "</h4>";
// Close the block
content += "</div>";

// Start a new block with a specific background color. Color changes depending on BMS status
switch (LEDcolor) {
case GREEN:
content += "<div style='background-color: #2D3F2F; padding: 10px; margin-bottom: 10px; border-radius: 50px'>";
break;
case YELLOW:
content += "<div style='background-color: #F5CC00; padding: 10px; margin-bottom: 10px; border-radius: 50px'>";
break;
case BLUE:
content += "<div style='background-color: #2B35AF; padding: 10px; margin-bottom: 10px; border-radius: 50px'>";
break;
case RED:
content += "<div style='background-color: #A70107; padding: 10px; margin-bottom: 10px; border-radius: 50px'>";
break;
case TEST_ALL_COLORS: //Blue in test mode
content += "<div style='background-color: #2B35AF; padding: 10px; margin-bottom: 10px; border-radius: 50px'>";
break;
default: //Some new color, make background green
content += "<div style='background-color: #2D3F2F; padding: 10px; margin-bottom: 10px; border-radius: 50px'>";
break;
}

// Display battery statistics within this block
float socFloat = static_cast<float>(SOC) / 100.0; // Convert to float and divide by 100
float sohFloat = static_cast<float>(StateOfHealth) / 100.0; // Convert to float and divide by 100
float voltageFloat = static_cast<float>(battery_voltage) / 10.0; // Convert to float and divide by 10
float currentFloat = 0;
if (battery_current > 32767) { //Handle negative values on this unsigned value
currentFloat = static_cast<float>(-(65535 - battery_current)) / 10.0; // Convert to float and divide by 10
} else {
currentFloat = static_cast<float>(battery_current) / 10.0; // Convert to float and divide by 10
}
float powerFloat = 0;
if (stat_batt_power > 32767) { //Handle negative values on this unsigned value
powerFloat = static_cast<float>(-(65535 - stat_batt_power));
} else {
powerFloat = static_cast<float>(stat_batt_power);
}
float tempMaxFloat = 0;
float tempMinFloat = 0;
if (temperature_max > 32767) { //Handle negative values on this unsigned value
tempMaxFloat = static_cast<float>(-(65535 - temperature_max)) / 10.0; // Convert to float and divide by 10
} else {
tempMaxFloat = static_cast<float>(temperature_max) / 10.0; // Convert to float and divide by 10
}
if (temperature_min > 32767) { //Handle negative values on this unsigned value
tempMinFloat = static_cast<float>(-(65535 - temperature_min)) / 10.0; // Convert to float and divide by 10
} else {
tempMinFloat = static_cast<float>(temperature_min) / 10.0; // Convert to float and divide by 10
}
content += "<h4 style='color: white;'>SOC: " + String(socFloat, 2) + "</h4>";
content += "<h4 style='color: white;'>SOH: " + String(sohFloat, 2) + "</h4>";
content += "<h4 style='color: white;'>Voltage: " + String(voltageFloat, 1) + " V</h4>";
content += "<h4 style='color: white;'>Current: " + String(currentFloat, 1) + " A</h4>";
content += "<h4 style='color: white;'>Power: " + String(powerFloat, 0) + " W</h4>";
content += "<h4>Total capacity: " + String(capacity_Wh) + " Wh</h4>";
content += "<h4>Remaining capacity: " + String(remaining_capacity_Wh) + " Wh</h4>";
content += "<h4>Max discharge power: " + String(max_target_discharge_power) + " W</h4>";
content += "<h4>Max charge power: " + String(max_target_charge_power) + " W</h4>";
content += "<h4>Cell max: " + String(cell_max_voltage) + " mV</h4>";
content += "<h4>Cell min: " + String(cell_min_voltage) + " mV</h4>";
content += "<h4>Temperature max: " + String(tempMaxFloat, 1) + " C</h4>";
content += "<h4>Temperature min: " + String(tempMinFloat, 1) + " C</h4>";
if (bms_status == 3) {
content += "<h4>BMS Status: OK </h4>";
} else {
content += "<h4>BMS Status: FAULT </h4>";
}
if (bms_char_dis_status == 2) {
content += "<h4>Battery charging!</h4>";
} else if (bms_char_dis_status == 1) {
content += "<h4>Battery discharging!</h4>";
} else { //0 idle
content += "<h4>Battery idle</h4>";
}
// Close the block
content += "</div>";

content += "<button onclick='goToUpdatePage()'>Perform OTA update</button>";
content += "<script>";
content += "function goToUpdatePage() { window.location.href = '/update'; }";
content += "</script>";

//Script for refreshing page
content += "<script>";
content += "setTimeout(function(){ location.reload(true); }, 10000);";
content += "</script>";

return content;
}
return String();
Expand Down
20 changes: 19 additions & 1 deletion Software/src/devboard/webserver/webserver.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,25 @@
#include "../../lib/me-no-dev-ESPAsyncWebServer/src/ESPAsyncWebServer.h"
#include "../config.h" // Needed for LED defines

extern uint8_t LEDcolor; // Enum, 0-10
extern uint16_t SOC; //SOC%, 0-100.00 (0-10000)
extern uint16_t StateOfHealth; //SOH%, 0-100.00 (0-10000)
extern uint16_t battery_voltage; //V+1, 0-500.0 (0-5000)
extern uint16_t battery_current; //A+1, Goes thru convert2unsignedint16 function (5.0A = 50, -5.0A = 65485)
extern uint16_t capacity_Wh; //Wh, 0-60000
extern uint16_t remaining_capacity_Wh; //Wh, 0-60000
extern uint16_t max_target_discharge_power; //W, 0-60000
extern uint16_t max_target_charge_power; //W, 0-60000
extern uint16_t bms_status; //Enum, 0-5
extern uint16_t bms_char_dis_status; //Enum, 0-2
extern uint16_t stat_batt_power; //W, Goes thru convert2unsignedint16 function (5W = 5, -5W = 65530)
extern uint16_t temperature_min; //C+1, Goes thru convert2unsignedint16 function (15.0C = 150, -15.0C = 65385)
extern uint16_t temperature_max; //C+1, Goes thru convert2unsignedint16 function (15.0C = 150, -15.0C = 65385)
extern uint16_t cell_max_voltage; //mV, 0-4350
extern uint16_t cell_min_voltage; //mV, 0-4350
extern uint8_t LEDcolor; //Enum, 0-10
extern bool batteryAllowsContactorClosing; //Bool, 1=true, 0=false
extern bool inverterAllowsContactorClosing; //Bool, 1=true, 0=false

extern const char* ssid;
extern const char* password;
extern const char* ssidAP;
Expand Down