First commit to public repository
This commit is contained in:
parent
bff2d844c3
commit
571a268436
10 changed files with 1513 additions and 1 deletions
BIN
INA226.zip
Normal file
BIN
INA226.zip
Normal file
Binary file not shown.
117
README.md
117
README.md
|
@ -1,2 +1,117 @@
|
|||
# ESP32_powerMC
|
||||
|
||||
# Webserver und URLs
|
||||
|
||||
Der Webserver ist auf dem ESP32 implementiert und bietet verschiedene Endpunkte für die Bedienung und Anzeige von Informationen. Hier sind die definierten URLs und ihre Funktionen:
|
||||
|
||||
- **Root Path ("/")**
|
||||
- HTTP-Methode: GET
|
||||
- Zeigt die Hauptseite mit allgemeinen Informationen an, einschließlich Links zu anderen Endpunkten.
|
||||
|
||||
- **JSON Path ("/json")**
|
||||
- HTTP-Methode: GET
|
||||
- Liefert JSON-formatierte Daten mit Informationen über Busspannung, Strom, Leistung, Energie, Temperatur, Luftfeuchtigkeit und Fehlercode.
|
||||
|
||||
Beispiel:
|
||||
```
|
||||
{
|
||||
"busVoltage": 25.6,
|
||||
"shuntVoltage": 0.0,
|
||||
"current": 10.5,
|
||||
"power": 268.8,
|
||||
"energy": 134.4,
|
||||
"temp": 28.5,
|
||||
"humidity": 45.8,
|
||||
"errorCode
|
||||
}
|
||||
```
|
||||
|
||||
- **Config Path ("/config")**
|
||||
- HTTP-Methode: GET
|
||||
- Zeigt eine Konfigurationsseite an, auf der Benutzer Einstellungen für Temperatur, Luftfeuchtigkeit und Strombereiche ändern können.
|
||||
|
||||
- **Save Config Path ("/saveConfig")**
|
||||
- HTTP-Methode: PUT
|
||||
- Behandelt die Anforderung zum Speichern der neuen Konfigurationsdaten, die durch die Konfigurationsseite festgelegt wurden.
|
||||
|
||||
Beispiel:
|
||||
```
|
||||
{
|
||||
"temp_min": 20.0,
|
||||
"temp_max": 30.0,
|
||||
"humi_min": 40.0,
|
||||
"humi_max": 60.0,
|
||||
"current_min": -5.0,
|
||||
"current_max": 5.0
|
||||
}
|
||||
```
|
||||
|
||||
- **Demo Mode 1 Path ("/demo1")**
|
||||
- HTTP-Methode: GET
|
||||
- Startet den Demo-Modus 1: Demonstriert einen lade-/entladezyklus ab der Hälfte der maximalen Kapazität mit variablem Strom bei 25,6A.
|
||||
|
||||
- **Demo Mode 2 Path ("/demo2")**
|
||||
- HTTP-Methode: GET
|
||||
- Startet den Demo-Modus 2: Demonstriert einen ladezyklus ab 97% der maximalen Kapazität auf 100% mit 200A bei 25.6V.
|
||||
|
||||
- **Demo Mode 3 Path ("/demo3")**
|
||||
- HTTP-Methode: GET
|
||||
- Startet den Demo-Modus 3: Demonstriert einen entladezyklus ab 3% der maximalen Kapazität auf 0% mit -200A bei 25.6V.
|
||||
|
||||
Die HTML-Seiten werden dynamisch generiert und enthalten JavaScript für die Aktualisierung von Daten über AJAX-Anfragen. Die Konfigurationsseite ermöglicht es Benutzern, bestimmte Parameter über Schieberegler einzustellen und Änderungen zu speichern.
|
||||
|
||||
# Fehlermeldungen für den wert `errorCode`
|
||||
|
||||
Die Variable `globalError` wird als Bitmask verwendet, wobei jedes Bit eine bestimmte Fehlerbedingung repräsentiert. Hier sind die möglichen Fehlermeldungen und ihre Bedeutungen:
|
||||
|
||||
## `ERROR_NONE` (0b0000000000000000)
|
||||
|
||||
Kein Fehler. Das Gerät funktioniert ordnungsgemäß, es liegen keine Fehler vor.
|
||||
|
||||
## `ERROR_MAX_CURRENT_EXCEEDED` (0b0000000000000001)
|
||||
|
||||
Der maximale Stromverbrauch wurde überschritten. Möglicherweise liegt eine Überlastung des Geräts vor.
|
||||
|
||||
## `ERROR_CURRENT_BELOW_MIN` (0b0000000000000010)
|
||||
|
||||
Der aktuelle Stromverbrauch liegt unter dem zulässigen Minimum. Möglicherweise gibt es ein Problem mit der Stromzufuhr.
|
||||
|
||||
## `ERROR_MAX_TEMP_EXCEEDED` (0b0000000000000100)
|
||||
|
||||
Die maximale Temperatur wurde überschritten. Das Gerät könnte überhitzen.
|
||||
|
||||
## `ERROR_TEMP_BELOW_MIN` (0b0000000000001000)
|
||||
|
||||
Die Temperatur liegt unterhalb des zulässigen Minimums. Es besteht die Gefahr von Unterkühlung oder anderen temperaturbedingten Problemen.
|
||||
|
||||
## `ERROR_MAX_HUMI_EXCEEDED` (0b0000000000010000)
|
||||
|
||||
Die maximale Luftfeuchtigkeit wurde überschritten. Dies könnte zu feuchtigkeitsbedingten Problemen führen.
|
||||
|
||||
## `ERROR_HUMI_BELOW_MIN` (0b0000000000100000)
|
||||
|
||||
Die Luftfeuchtigkeit liegt unter dem zulässigen Minimum. Es besteht die Gefahr von zu geringer Luftfeuchtigkeit.
|
||||
|
||||
Bitte beachten Sie, dass mehrere Fehler gleichzeitig auftreten können, da die Bitmasken kombiniert werden können. Zum Beispiel könnte `ERROR_MAX_TEMP_EXCEEDED | ERROR_MAX_HUMI_EXCEEDED` darauf hinweisen, dass sowohl die maximale Temperatur als auch die maximale Luftfeuchtigkeit überschritten wurden.
|
||||
|
||||
# Used libraries (Arduino)
|
||||
|
||||
WiFi at version 2.0.0
|
||||
ESP32httpUpdate at version 2.1.145
|
||||
HTTPClient at version 2.0.0
|
||||
WiFiClientSecure at version 2.0.0
|
||||
Update at version 2.0.0
|
||||
FS at version 2.0.0
|
||||
SPIFFS at version 2.0.0
|
||||
WebServer at version 2.0.0
|
||||
ArduinoJson at version 7.0.2
|
||||
WiFiManager at version 2.0.16-rc.2
|
||||
DNSServer at version 2.0.0
|
||||
EEPROM at version 2.0.0
|
||||
Wire at version 2.0.0
|
||||
INA226 at version 0.5.2
|
||||
Adafruit GFX Library at version 1.11.9
|
||||
Adafruit BusIO at version 1.15.0
|
||||
SPI at version 2.0.0
|
||||
Adafruit SSD1306 at version 2.5.9
|
||||
Adafruit Unified Sensor at version 1.1.14
|
||||
Adafruit BME280 Library at version 2.2.4
|
||||
|
|
44
firmware/config_user.h
Normal file
44
firmware/config_user.h
Normal file
|
@ -0,0 +1,44 @@
|
|||
|
||||
#define FIRMWARE_VERSION "v0.3.0"
|
||||
|
||||
//#define DEBUG_NO_I2C
|
||||
#define DEBUG_NO_SERIAL_MSG
|
||||
|
||||
#define WATCHDOG_TIMEOUT_S 5
|
||||
|
||||
#define INA226_I2C_ADDRESS 0x41
|
||||
#define BME280_I2C_ADDRESS 0x76 // oder 0x77, je nach Verbindung des ADDR-Pins
|
||||
#define OLED_I2C_ADDRESS 0x3C // -> the addresses like 0x78 which is selected on the chip is not correct
|
||||
|
||||
#define LOOP_INA226READ_DEMO_DELAY_MS 1000
|
||||
#define LOOP_DISPLAY_DELAY_MS 5000 // 5 Sekunden
|
||||
#define LOOP_DISPLAY_DEMO_DELAY_MS 1000
|
||||
#define LOOP_HANDLE_CLIENT_DELAY_MS 250
|
||||
#define LOOP_INA226CHECK_DELAY_MS 600000
|
||||
#define LOOP_WLAN_CHECK_DELAY_MS 60000
|
||||
|
||||
#define OLED_SCREEN_WIDTH 128 // OLED display width, in pixels
|
||||
#define OLED_SCREEN_HEIGHT 64 // OLED display height, in pixels
|
||||
#define OLED_RESET_PIN -1 // Reset pin # (or -1 if sharing Arduino reset pin)
|
||||
#define OLED_TEST_SIZE 2
|
||||
|
||||
#define DISPLAY_SWITCH_SHOWN_VALUE_COUNT 2
|
||||
|
||||
// default config values
|
||||
#define DEFAULT_SHUNT_VOLTAGE_DROP 85.0 // mV
|
||||
#define DEFAULT_SHUNT_CURRENT_MAX 100.0 // A
|
||||
#define DEFAULT_TEMP_MIN 20.0 // °C environment
|
||||
#define DEFAULT_TEMP_MAX 30.0 // °C environment
|
||||
#define DEFAULT_HUMI_MIN 30.0 // % humidity
|
||||
#define DEFAULT_HUMI_MAX 70.0 // % humidity
|
||||
#define DEFAULT_CURRENT_MIN -100.0 // maximum continuous discharge current
|
||||
#define DEFAULT_CURRENT_MAX 100.0 // maximum continuous discharge current
|
||||
#define DEFAULT_MAX_CAPACITY 2500.0f
|
||||
#define DEFAULT_INA226READ_DELAY_S 30 // 30 Sekunden default, overwritten by eeprom config
|
||||
|
||||
#define EEPROM_SIZE 100 // in byte
|
||||
// EEPROM-Adresse, an der die globale Energiemenge gespeichert wird
|
||||
#define EEPROM_ADDR_ENERGY 0
|
||||
#define EEPROM_ADDR_CFG_START 8 // sizeof(struct EnergyData { float energy; uint16_t checksum; };
|
||||
|
||||
#define FIRMWARE_UPDATE_URL "http://192.168.0.142:8082/firmware.ino.bin"
|
88
firmware/constants.h
Normal file
88
firmware/constants.h
Normal file
|
@ -0,0 +1,88 @@
|
|||
|
||||
const String cs_configFile = "config_user.h";
|
||||
const String cs_configPortalSSID = "powerMC_Config";
|
||||
const String cs_connectionError = "Failed to establish connection, and timeout for the configuration portal expired. Restart.";
|
||||
const String cs_connectedToWiFi = "Connected to WiFi";
|
||||
const String cs_ssd1306Init = "SSD1306 display init";
|
||||
const String cs_ssd1306NotFound = "SSD1306 display not found. Restart.";
|
||||
const String cs_ina226Init = "INA226 sensor init";
|
||||
const String cs_ina226ChipNotFound = "INA226 chip not found. Restart.";
|
||||
const String cs_bme280Init = "BME280 sensor init";
|
||||
const String cs_bme280NotFound = "Could not find BME280. Restart.";
|
||||
const String cs_webserverInit = "Webserver init";
|
||||
const String cs_rootPath = "/";
|
||||
const String cs_jsonPath = "/json";
|
||||
const String cs_configPath = "/config";
|
||||
const String cs_saveConfigPath = "/saveConfig";
|
||||
const String cs_demoMode1Path = "/demo1";
|
||||
const String cs_demoMode2Path = "/demo2";
|
||||
const String cs_demoMode3Path = "/demo3";
|
||||
const String cs_resetESPPath = "/resetESP";
|
||||
const String cs_resetWifiPath = "/resetWifi";
|
||||
const String cs_checkUpdatePath = "/checkUpdate";
|
||||
const String cs_updateFirmwareActionPath = "/updateFirmwareAction";
|
||||
const String cs_readUpdateFirmwareStatusPath = "/readUpdateFirmwareStatus";
|
||||
const String cs_handleCSSPath = "/css";
|
||||
const String cs_enableWatchdog = "Enable the WatchDog";
|
||||
const String cs_readCapacityFromEEPROM = "Read available capacity from EEPROM";
|
||||
const String cs_readConfigFromEEPROM = "Read config from EEPROM";
|
||||
const String cs_initializationComplete = "Initialization completed";
|
||||
const String cs_separatorLine = "----------";
|
||||
const String cs_busVoltageLabel = "Bus Voltage: ";
|
||||
const String cs_shuntVoltageLabel = "Shunt Voltage: ";
|
||||
const String cs_currentLabel = "Current: ";
|
||||
const String cs_powerLabel = "Power: ";
|
||||
const String cs_energyLabel = "Energy: ";
|
||||
const String cs_temperatureLabel = "Temperature: ";
|
||||
const String cs_humidityLabel = "Humidity: ";
|
||||
const String cs_configDataLabel = "Config Data:";
|
||||
const String cs_tempMinLabel = "Temp Min: ";
|
||||
const String cs_tempMaxLabel = "Temp Max: ";
|
||||
const String cs_humiMinLabel = "Humi Min: ";
|
||||
const String cs_humiMaxLabel = "Humi Max: ";
|
||||
const String cs_currentMinLabel = "Current Min: ";
|
||||
const String cs_currentMaxLabel = "Current Max: ";
|
||||
const String cs_shuntVoltageDropLabel = "Shunt voltage drop: ";
|
||||
const String cs_shuntMaxCurrentLabel = "Shunt max current: ";
|
||||
const String cs_timeIna226RefreshLabel = "Ina226 refresh time: ";
|
||||
const String cs_checksumLabel = "Checksum: ";
|
||||
const String cs_separator2 = "------------------------";
|
||||
const String cs_startingFirmwareUpdate = "Starting firmware update ";
|
||||
const String cs_finish = "finish";
|
||||
const String cs_noUpdatesAvailable = "No Updates available.";
|
||||
const String cs_fwUpdSuccess = "Firmware update successful, resetting in a few seconds.";
|
||||
const String cs_unknownStatus = "Unknown status.";
|
||||
const String cs_fwUpdRunning = "Firmware-Update is running...";
|
||||
const String cs_disablingWatchdog = "Disabling watchdog.";
|
||||
const String cs_ina226ChipNotFoundRestart = "INA226 chip not found. Restart.";
|
||||
const String cs_wifiDisconnectedRestart = "WiFi connection disconnected. Restart.";
|
||||
const String cs_textHtml = "text/html";
|
||||
const String cs_textCSS = "text/css";
|
||||
const String cs_busVoltageID = "busVoltage";
|
||||
const String cs_shuntVoltageID = "shuntVoltage";
|
||||
const String cs_currentID = "current";
|
||||
const String cs_powerID = "power";
|
||||
const String cs_energyID = "energy";
|
||||
const String cs_tempID = "temp";
|
||||
const String cs_humidityID = "humidity";
|
||||
const String cs_timeIna226RefreshID = "time_ina226_refresh";
|
||||
const String cs_errorCodeID = "errorCode";
|
||||
const String cs_applicationJson = "application/json";
|
||||
const String cs_ampereUnit = "A";
|
||||
const String cs_wattUnit = "W";
|
||||
const String cs_wattHourUnit = "Wh";
|
||||
const String cs_voltageUnit = "V";
|
||||
const String cs_stateOfChargeLabel = "SOC:";
|
||||
const String cs_percentageUnit = "%";
|
||||
const String cs_savingGlobalEnergyToEEPROM = "Saving global energy to EEPROM";
|
||||
const String cs_dataEnergy = "data.energy: ";
|
||||
const String cs_dataChecksum = "data.checksum: ";
|
||||
const String cs_eepromWriteComplete = "EEPROM write energy complete ";
|
||||
const String cs_readChecksum = "Read Checksum: ";
|
||||
const String cs_calculatedChecksum = "Calculated Checksum: ";
|
||||
const String cs_eepromReadComplete = "EEPROM read energy complete ";
|
||||
const String cs_eepromValueDamaged = "EEPROM value for capacity is damaged, returning 0.0";
|
||||
const String cs_errorCode = "Error code: 0b";
|
||||
const String cs_newChecksum = "New calculated checksum = ";
|
||||
const String cs_eepromConfigAfterRead = "After EEPROM read - ";
|
||||
const String cs_eepromSetConfigDefault = "EEPROM-Daten beschädigt! Setze auf Standardwerte.";
|
120
firmware/data_storage.ino
Normal file
120
firmware/data_storage.ino
Normal file
|
@ -0,0 +1,120 @@
|
|||
|
||||
void saveGlobalEnergyToEEPROM() {
|
||||
|
||||
#ifndef DEBUG_NO_SERIAL_MSG
|
||||
Serial.println(cs_savingGlobalEnergyToEEPROM);
|
||||
#endif
|
||||
|
||||
EnergyData data;
|
||||
data.energy = globalEnergy;
|
||||
// Berechnung der Prüfsumme nur über data.energy
|
||||
data.checksum = calculateChecksum(data.energy);
|
||||
|
||||
EEPROM.put(EEPROM_ADDR_ENERGY, data);
|
||||
EEPROM.commit(); // Dauerhaftes Speichern der Änderungen
|
||||
delay(100);
|
||||
#ifndef DEBUG_NO_SERIAL_MSG
|
||||
Serial.print(cs_eepromWriteComplete);
|
||||
Serial.println(data.energy);
|
||||
#endif
|
||||
|
||||
//readGlobalEnergyFromEEPROM();
|
||||
}
|
||||
|
||||
// Funktion zum Lesen der Energiemenge aus dem EEPROM
|
||||
float readGlobalEnergyFromEEPROM() {
|
||||
EnergyData data;
|
||||
EEPROM.get(EEPROM_ADDR_ENERGY, data);
|
||||
|
||||
/*
|
||||
Serial.print(cs_readChecksum);
|
||||
Serial.println(data.checksum);
|
||||
Serial.print(cs_calculatedChecksum);
|
||||
Serial.println(calculateChecksum(data.energy));
|
||||
*/
|
||||
|
||||
// Überprüfen der Prüfsumme nur über data.energy
|
||||
if (data.checksum == calculateChecksum(data.energy)) {
|
||||
// Prüfsumme ist korrekt, geben Sie die Energiemenge zurück
|
||||
Serial.print(cs_eepromReadComplete);
|
||||
Serial.print(data.energy);
|
||||
Serial.println();
|
||||
|
||||
return data.energy;
|
||||
|
||||
} else {
|
||||
// Prüfsumme stimmt nicht überein, möglicherweise ungültige Daten
|
||||
// Hier können Sie eine geeignete Behandlung implementieren, z. B. Standardwert zurückgeben
|
||||
Serial.println(cs_eepromValueDamaged);
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
// Funktion zum Berechnen der Prüfsumme über data.energy
|
||||
uint16_t calculateChecksum(float energy) {
|
||||
uint16_t checksum = 0;
|
||||
uint8_t *dataPtr = (uint8_t *)&energy;
|
||||
|
||||
for (int i = 0; i < sizeof(float); i++) {
|
||||
checksum ^= dataPtr[i];
|
||||
}
|
||||
|
||||
return checksum;
|
||||
}
|
||||
|
||||
void writeConfigToEEPROM() {
|
||||
globalConfigData.checksum = calculateChecksumConfig();
|
||||
|
||||
printConfigData(globalConfigData);
|
||||
|
||||
EEPROM.put(EEPROM_ADDR_CFG_START, globalConfigData);
|
||||
EEPROM.commit();
|
||||
delay(100);
|
||||
}
|
||||
|
||||
void readConfigFromEEPROM() {
|
||||
EEPROM.get(EEPROM_ADDR_CFG_START, globalConfigData);
|
||||
|
||||
Serial.print(cs_eepromConfigAfterRead);
|
||||
printConfigData(globalConfigData);
|
||||
uint16_t checksumEEPROM = globalConfigData.checksum;
|
||||
|
||||
// Überprüfe die Checksumme
|
||||
uint16_t checksum = calculateChecksumConfig();
|
||||
|
||||
if (checksum != checksumEEPROM) {
|
||||
Serial.println(cs_eepromSetConfigDefault);
|
||||
// Setze auf Standardwerte
|
||||
globalConfigData.temp_min = DEFAULT_TEMP_MIN;
|
||||
globalConfigData.temp_max = DEFAULT_TEMP_MAX;
|
||||
globalConfigData.humi_min = DEFAULT_HUMI_MIN;
|
||||
globalConfigData.humi_max = DEFAULT_HUMI_MAX;
|
||||
globalConfigData.current_min = DEFAULT_CURRENT_MIN;
|
||||
globalConfigData.current_max = DEFAULT_CURRENT_MAX;
|
||||
globalConfigData.shunt_voltage_drop = DEFAULT_SHUNT_VOLTAGE_DROP;
|
||||
globalConfigData.shunt_max_current = DEFAULT_SHUNT_CURRENT_MAX;
|
||||
globalConfigData.max_capacity = DEFAULT_MAX_CAPACITY;
|
||||
globalConfigData.time_ina226_refresh = DEFAULT_INA226READ_DELAY_S;
|
||||
globalConfigData.current_fact = 100.0; // offset 100
|
||||
globalConfigData.checksum = 0;
|
||||
|
||||
writeConfigToEEPROM();
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t calculateChecksumConfig()
|
||||
{
|
||||
// Berechne die Checksumme
|
||||
uint16_t checksum = 0;
|
||||
byte* dataPointer = (byte*)&globalConfigData;
|
||||
globalConfigData.checksum = 0;
|
||||
|
||||
for (size_t i = 0; i < sizeof(globalConfigData); ++i) {
|
||||
checksum += dataPointer[i];
|
||||
}
|
||||
|
||||
Serial.print(cs_newChecksum);
|
||||
Serial.println(checksum);
|
||||
|
||||
return checksum;
|
||||
}
|
10
firmware/error.h
Normal file
10
firmware/error.h
Normal file
|
@ -0,0 +1,10 @@
|
|||
|
||||
#define ERROR_NONE 0b0000000000000000
|
||||
#define ERROR_MAX_CURRENT_EXCEEDED 0b0000000000000001
|
||||
#define ERROR_CURRENT_BELOW_MIN 0b0000000000000010
|
||||
#define ERROR_MAX_TEMP_EXCEEDED 0b0000000000000100
|
||||
#define ERROR_TEMP_BELOW_MIN 0b0000000000001000
|
||||
#define ERROR_MAX_HUMI_EXCEEDED 0b0000000000010000
|
||||
#define ERROR_HUMI_BELOW_MIN 0b0000000000100000
|
||||
#define ERROR_INA226_UNCONFIGURED 0b1000000000000000
|
||||
|
476
firmware/firmware.ino
Normal file
476
firmware/firmware.ino
Normal file
|
@ -0,0 +1,476 @@
|
|||
|
||||
// This project is written for aESP32 WROOM-32 module (AZ Delivery ESP32 Dev Kit C v4)
|
||||
|
||||
#include <WiFi.h>
|
||||
#include <ESP32httpUpdate.h>
|
||||
#include <WebServer.h>
|
||||
#include <ArduinoJson.h>
|
||||
#include <WiFiManager.h>
|
||||
#include <esp_task_wdt.h>
|
||||
#include <EEPROM.h>
|
||||
#include <Wire.h>
|
||||
#include <INA226.h>
|
||||
#include <Adafruit_GFX.h>
|
||||
#include <Adafruit_SSD1306.h>
|
||||
#include <Adafruit_Sensor.h>
|
||||
#include <Adafruit_BME280.h>
|
||||
#include "error.h"
|
||||
#include "config_user.h" // includes preprocessor defines
|
||||
#include "constants.h"
|
||||
|
||||
#ifndef DEBUG_NO_I2C
|
||||
INA226 ina226(INA226_I2C_ADDRESS);
|
||||
Adafruit_SSD1306 display(OLED_SCREEN_WIDTH, OLED_SCREEN_HEIGHT, &Wire, OLED_RESET_PIN);
|
||||
Adafruit_BME280 bme;
|
||||
#endif
|
||||
|
||||
// WiFiManager initialisieren
|
||||
WiFiManager wifiManager;
|
||||
WebServer server(80);
|
||||
|
||||
// Struktur für die gespeicherte Energie mit Prüfsumme
|
||||
struct EnergyData {
|
||||
float energy;
|
||||
uint16_t checksum;
|
||||
};
|
||||
|
||||
struct ConfigData {
|
||||
float temp_min;
|
||||
float temp_max;
|
||||
float humi_min;
|
||||
float humi_max;
|
||||
float current_min;
|
||||
float current_max;
|
||||
float shunt_voltage_drop;
|
||||
float shunt_max_current;
|
||||
float max_capacity;
|
||||
float time_ina226_refresh;
|
||||
float current_fact;
|
||||
uint16_t checksum;
|
||||
};
|
||||
|
||||
// demo modes
|
||||
bool demoMode1 = false;
|
||||
bool demo1Increasing = false;
|
||||
bool demoMode2 = false;
|
||||
bool demoMode3 = false;
|
||||
|
||||
// Globale Variable für den Anzeigemodus
|
||||
bool displayEnergyVoltageMode = false;
|
||||
uint8_t displayEnergyVoltageModeChangeCnt = 0;
|
||||
|
||||
// Globale Variablen für INA226-Werte
|
||||
float globalBusVoltage = 0.0;
|
||||
float globalShuntVoltage = 0.0;
|
||||
float globalCurrent = 0.0;
|
||||
float globalPower = 0.0;
|
||||
float globalShuntValue = 0.0;
|
||||
// Globale Variable für die Energiemenge in Wattstunden
|
||||
float globalEnergy = 0.0;
|
||||
float globalTemp = 0.0;
|
||||
float globalHumidity = 0.0;
|
||||
|
||||
// global error code
|
||||
uint16_t globalErrorCode = ERROR_NONE;
|
||||
|
||||
uint16_t ina226Status = 0x0000;
|
||||
|
||||
unsigned long lastINA226CheckTime = 0;
|
||||
unsigned long lastWiFiCheckTime = 0;
|
||||
unsigned long lastHandleClientTime = 0;
|
||||
unsigned long lastLoopDisplayTime = 0;
|
||||
|
||||
String updateStatus;
|
||||
bool fwUpdate_isRunning = false;
|
||||
|
||||
ConfigData globalConfigData;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
|
||||
Serial.println(cs_readCapacityFromEEPROM);
|
||||
EEPROM.begin(EEPROM_SIZE);
|
||||
// Versuche, die gespeicherte Energiemenge aus dem EEPROM zu laden
|
||||
globalEnergy = readGlobalEnergyFromEEPROM();
|
||||
|
||||
Serial.println(cs_readConfigFromEEPROM);
|
||||
readConfigFromEEPROM();
|
||||
printConfigData(globalConfigData);
|
||||
|
||||
// Timeout für die Konfiguration auf 120s setzen
|
||||
wifiManager.setConfigPortalTimeout(120);
|
||||
|
||||
// Versuche, eine Verbindung herzustellen, und wenn nicht erfolgreich, starte den Konfigurationsportal
|
||||
if (!wifiManager.autoConnect(cs_configPortalSSID.c_str())) {
|
||||
Serial.println(cs_connectionError);
|
||||
delay(10000);
|
||||
// Resete und versuche es erneut
|
||||
ESP.restart();
|
||||
}
|
||||
|
||||
Serial.println(cs_connectedToWiFi);
|
||||
|
||||
// Initialisiere die I2C-Kommunikation
|
||||
Wire.begin();
|
||||
|
||||
#ifndef DEBUG_NO_I2C
|
||||
Serial.println(cs_ssd1306Init);
|
||||
// SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
|
||||
if(!display.begin(SSD1306_SWITCHCAPVCC, OLED_I2C_ADDRESS)) {
|
||||
Serial.println(cs_ssd1306NotFound);
|
||||
delay(10000); // Warte 10 Sekunden
|
||||
ESP.restart(); // Neu starten
|
||||
}
|
||||
// Clear the buffer
|
||||
display.clearDisplay();
|
||||
|
||||
Serial.println(cs_ina226Init);
|
||||
if (!ina226.begin()) {
|
||||
Serial.println(cs_ina226ChipNotFound);
|
||||
delay(10000); // Warte 10 Sekunden
|
||||
ESP.restart(); // Neu starten
|
||||
}
|
||||
|
||||
configureIna226();
|
||||
|
||||
Serial.println(cs_bme280Init);
|
||||
if (!bme.begin(BME280_I2C_ADDRESS)) {
|
||||
Serial.println(cs_bme280NotFound);
|
||||
delay(10000); // Warte 10 Sekunden
|
||||
ESP.restart(); // Neu starten
|
||||
}
|
||||
#endif // no sensor debug
|
||||
|
||||
Serial.println(cs_webserverInit);
|
||||
server.on(cs_rootPath, HTTP_GET, handleRoot);
|
||||
server.on(cs_jsonPath, HTTP_GET, handleJson);
|
||||
server.on(cs_configPath, HTTP_GET, handleConfig);
|
||||
server.on(cs_saveConfigPath, HTTP_PUT, handleSaveConfig);
|
||||
server.on(cs_demoMode1Path, HTTP_GET, handleDemoMode1);
|
||||
server.on(cs_demoMode2Path, HTTP_GET, handleDemoMode2);
|
||||
server.on(cs_demoMode3Path, HTTP_GET, handleDemoMode3);
|
||||
server.on(cs_resetESPPath, HTTP_GET, handleResetESP);
|
||||
server.on(cs_resetWifiPath, HTTP_GET, handleResetWifi);
|
||||
server.on(cs_checkUpdatePath, HTTP_GET, handleUpdateFirmware);
|
||||
server.on(cs_updateFirmwareActionPath, HTTP_GET, handleUpdateFirmwareAction);
|
||||
server.on(cs_readUpdateFirmwareStatusPath, HTTP_GET, handleReadUpdateFirmwareStatus);
|
||||
server.on(cs_handleCSSPath, HTTP_GET, handleCSS);
|
||||
server.begin();
|
||||
|
||||
enableWatchdog();
|
||||
|
||||
Serial.println(cs_initializationComplete);
|
||||
|
||||
checkError();
|
||||
|
||||
#ifndef DEBUG_NO_I2C
|
||||
//delay(1000);
|
||||
displayData();
|
||||
#endif
|
||||
}
|
||||
|
||||
void loop() {
|
||||
static unsigned long lastLoopTime = 0;
|
||||
|
||||
bool demoMode = (demoMode1 || demoMode2 || demoMode3);
|
||||
|
||||
// Führe den Code nur alle xx Sekunden aus
|
||||
if (millis() - lastLoopTime >= ((demoMode == false) ? (globalConfigData.time_ina226_refresh * 1000) : LOOP_INA226READ_DEMO_DELAY_MS)) {
|
||||
lastLoopTime = millis();
|
||||
|
||||
if (demoMode1 == true)
|
||||
{
|
||||
simulateUpDownSensorValues();
|
||||
|
||||
} else if (demoMode2 == true) {
|
||||
simulateChrgFull();
|
||||
|
||||
} else if (demoMode3 == true) {
|
||||
simulateDischrgEmpty();
|
||||
|
||||
} else {
|
||||
#ifndef DEBUG_NO_I2C
|
||||
// INA226-Werte aktualisieren
|
||||
globalBusVoltage = ina226.getBusVoltage();
|
||||
globalShuntVoltage = ina226.getShuntVoltage();
|
||||
globalCurrent = ina226.getCurrent() * (globalConfigData.current_fact / 100);
|
||||
globalPower = ina226.getPower();
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef DEBUG_NO_SERIAL_MSG
|
||||
Serial.println(cs_separatorLine);
|
||||
#endif
|
||||
|
||||
// Berechne den Energieverbrauch und aktualisiere die globale Energiemenge
|
||||
updateEnergy(globalCurrent, globalPower);
|
||||
|
||||
#ifndef DEBUG_NO_I2C
|
||||
globalTemp = bme.readTemperature();
|
||||
globalHumidity = bme.readHumidity();
|
||||
#endif
|
||||
|
||||
checkError();
|
||||
|
||||
#ifndef DEBUG_NO_SERIAL_MSG
|
||||
// Debug-Ausgabe der aktualisierten Werte
|
||||
Serial.print(cs_busVoltageLabel);
|
||||
Serial.println(globalBusVoltage);
|
||||
Serial.print(cs_shuntVoltageLabel);
|
||||
Serial.println(globalShuntVoltage);
|
||||
Serial.print(cs_currentLabel);
|
||||
Serial.println(globalCurrent);
|
||||
Serial.print(cs_powerLabel);
|
||||
Serial.println(globalPower);
|
||||
Serial.print(cs_energyLabel);
|
||||
Serial.println(globalEnergy);
|
||||
Serial.print(cs_temperatureLabel);
|
||||
Serial.println(globalTemp);
|
||||
Serial.print(cs_humidityLabel);
|
||||
Serial.println(globalHumidity);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
if (millis() - lastLoopDisplayTime >= ((demoMode == false) ? LOOP_DISPLAY_DELAY_MS : LOOP_DISPLAY_DEMO_DELAY_MS)) {
|
||||
lastLoopDisplayTime = millis();
|
||||
// Display aktualisieren
|
||||
#ifndef DEBUG_NO_I2C
|
||||
displayData();
|
||||
#endif
|
||||
}
|
||||
|
||||
if (millis() - lastHandleClientTime >= LOOP_HANDLE_CLIENT_DELAY_MS) {
|
||||
lastHandleClientTime = millis();
|
||||
server.handleClient();
|
||||
}
|
||||
|
||||
// Überprüfe, ob es Zeit ist, die Anwesenheit des INA226-Chip erneut zu überprüfen
|
||||
if (millis() - lastINA226CheckTime >= LOOP_INA226CHECK_DELAY_MS) { // 10 Minuten = 600000 Millisekunden
|
||||
lastINA226CheckTime = millis();
|
||||
|
||||
#ifndef DEBUG_NO_I2C
|
||||
if (!ina226.begin()) {
|
||||
Serial.println(cs_ina226ChipNotFoundRestart);
|
||||
delay(5000);
|
||||
ESP.restart();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Überprüfe, ob WLAN-Verbindung getrennt wurde
|
||||
if (WiFi.status() == WL_DISCONNECTED && millis() - lastWiFiCheckTime >= LOOP_WLAN_CHECK_DELAY_MS) { // 1 Minute = 60000 Millisekunden
|
||||
lastWiFiCheckTime = millis();
|
||||
Serial.println(cs_wifiDisconnectedRestart);
|
||||
delay(5000);
|
||||
ESP.restart();
|
||||
}
|
||||
|
||||
// Füttere den Watchdog-Timer, um einen Reset zu vermeiden
|
||||
esp_task_wdt_reset();
|
||||
|
||||
// Blockiere die loop() Funktion maximal 100ms
|
||||
delay(100);
|
||||
|
||||
}
|
||||
|
||||
#ifndef DEBUG_NO_I2C
|
||||
void displayData() {
|
||||
display.clearDisplay();
|
||||
|
||||
// Zeige den Stromwert an
|
||||
display.setTextSize(OLED_TEST_SIZE);
|
||||
display.setTextColor(SSD1306_WHITE);
|
||||
display.setCursor(0, 0);
|
||||
display.print(globalCurrent, 2); // Zwei Dezimalstellen anzeigen
|
||||
display.setCursor(100, 0);
|
||||
display.print(cs_ampereUnit);
|
||||
|
||||
// Zeige die Leistung an
|
||||
display.setTextColor(SSD1306_WHITE);
|
||||
display.setCursor(0, 17);
|
||||
display.print(globalPower, 2); // Zwei Dezimalstellen anzeigen
|
||||
display.setCursor(100, 17);
|
||||
display.print(cs_wattUnit);
|
||||
|
||||
//display.setTextSize(1);
|
||||
|
||||
// Zeige den Stromwert oder die Bus-Spannung basierend auf dem Anzeigemodus an
|
||||
if (displayEnergyVoltageMode) {
|
||||
// Zeige die verfügbare Energiemenge an
|
||||
display.setTextSize(OLED_TEST_SIZE);
|
||||
display.setTextColor(SSD1306_WHITE);
|
||||
display.setCursor(0, 34);
|
||||
display.print(globalEnergy, 2); // Zwei Dezimalstellen anzeigen
|
||||
display.setCursor(100, 34);
|
||||
display.print(cs_wattHourUnit);
|
||||
} else {
|
||||
// Zeige die Bus-Spannung an
|
||||
display.setTextSize(OLED_TEST_SIZE);
|
||||
display.setTextColor(SSD1306_WHITE);
|
||||
display.setCursor(0, 34);
|
||||
display.print(globalBusVoltage, 2); // Zwei Dezimalstellen anzeigen
|
||||
display.setCursor(100, 34);
|
||||
display.print(cs_voltageUnit);
|
||||
}
|
||||
|
||||
// Wechsle den Anzeigemodus für das nächste Mal
|
||||
if (displayEnergyVoltageModeChangeCnt >= DISPLAY_SWITCH_SHOWN_VALUE_COUNT)
|
||||
{
|
||||
displayEnergyVoltageMode = !displayEnergyVoltageMode;
|
||||
displayEnergyVoltageModeChangeCnt = 0;
|
||||
} else {
|
||||
displayEnergyVoltageModeChangeCnt++;
|
||||
}
|
||||
|
||||
// Zeige die maximale Kapazität an
|
||||
display.setCursor(0, 51);
|
||||
display.print(cs_stateOfChargeLabel);
|
||||
display.setCursor(50, 51);
|
||||
float batteryCapacityPercentage = (globalEnergy / globalConfigData.max_capacity) * 100.0;
|
||||
batteryCapacityPercentage = max(0.0f, min(batteryCapacityPercentage, 100.0f));
|
||||
display.print(batteryCapacityPercentage, 1); // Zwei Dezimalstellen anzeigen
|
||||
display.setCursor(115, 51);
|
||||
display.print(cs_percentageUnit);
|
||||
|
||||
// Zeige den Pfeil an
|
||||
if (globalCurrent > 0) {
|
||||
display.drawLine(120, 10, 116, 5, SSD1306_WHITE);
|
||||
display.drawLine(120, 10, 124, 5, SSD1306_WHITE);
|
||||
} else if (globalCurrent < 0) {
|
||||
display.drawLine(120, 5, 116, 10, SSD1306_WHITE);
|
||||
display.drawLine(120, 5, 124, 10, SSD1306_WHITE);
|
||||
}
|
||||
|
||||
display.display();
|
||||
}
|
||||
#endif
|
||||
|
||||
void updateEnergy(float current, float power) {
|
||||
static unsigned long lastUpdateTime = 0;
|
||||
static unsigned long lastDailyUpdateCheck = 0;
|
||||
|
||||
// Berechne die vergangene Zeit seit dem letzten Update
|
||||
unsigned long currentTime = millis();
|
||||
float timeInterval = (currentTime - lastUpdateTime) / 1000.0; // Zeitintervall in Sekunden
|
||||
|
||||
// Aktualisiere die globale Energiemenge basierend auf der Leistung und vergangener Zeit
|
||||
float energyChange = (power * timeInterval) / 3600.0; // Energieänderung in Wattstunden
|
||||
if (current > 0)
|
||||
{
|
||||
globalEnergy += energyChange;
|
||||
} else {
|
||||
globalEnergy -= energyChange;
|
||||
}
|
||||
|
||||
|
||||
// Begrenze den Wert auf das Minimum (0) und den maximalen Wert
|
||||
globalEnergy = max(0.0f, min(globalEnergy, globalConfigData.max_capacity));
|
||||
|
||||
if (demoMode1 == false && demoMode2 == false && demoMode3 == false)
|
||||
{
|
||||
// Speichere die globale Energiemenge im EEPROM
|
||||
saveGlobalEnergyToEEPROM();
|
||||
}
|
||||
|
||||
// Aktualisiere die Zeit des letzten Updates
|
||||
lastUpdateTime = currentTime;
|
||||
}
|
||||
|
||||
void checkError()
|
||||
{
|
||||
globalErrorCode = ERROR_NONE;
|
||||
|
||||
if (globalTemp >= globalConfigData.temp_max) {
|
||||
globalErrorCode |= ERROR_MAX_TEMP_EXCEEDED;
|
||||
} else if (globalTemp <= globalConfigData.temp_min) {
|
||||
globalErrorCode |= ERROR_TEMP_BELOW_MIN;
|
||||
}
|
||||
if (globalCurrent > globalConfigData.current_max) {
|
||||
globalErrorCode |= ERROR_MAX_CURRENT_EXCEEDED;
|
||||
} else if (globalCurrent < globalConfigData.current_min) {
|
||||
globalErrorCode |= ERROR_CURRENT_BELOW_MIN;
|
||||
}
|
||||
if (globalHumidity >= globalConfigData.humi_max) {
|
||||
globalErrorCode |= ERROR_MAX_HUMI_EXCEEDED;
|
||||
} else if (globalHumidity <= globalConfigData.humi_min) {
|
||||
globalErrorCode |= ERROR_HUMI_BELOW_MIN;
|
||||
}
|
||||
if (ina226.isCalibrated() == false)
|
||||
{
|
||||
globalErrorCode |= ERROR_INA226_UNCONFIGURED;
|
||||
}
|
||||
|
||||
#ifndef DEBUG_NO_SERIAL_MSG
|
||||
Serial.print(cs_errorCode);
|
||||
for (int i = 15; i >= 0; i--) {
|
||||
Serial.print((globalErrorCode >> i) & 1);
|
||||
}
|
||||
Serial.println();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void printConfigData(ConfigData c) {
|
||||
#ifndef DEBUG_NO_SERIAL_MSG
|
||||
Serial.println(cs_configDataLabel);
|
||||
Serial.print(cs_tempMinLabel);
|
||||
Serial.println(c.temp_min);
|
||||
Serial.print(cs_tempMaxLabel;
|
||||
Serial.println(c.temp_max);
|
||||
Serial.print(cs_humiMinLabel);
|
||||
Serial.println(c.humi_min);
|
||||
Serial.print(cs_humiMaxLabel);
|
||||
Serial.println(c.humi_max);
|
||||
Serial.print(cs_currentMinLabel);
|
||||
Serial.println(c.current_min);
|
||||
Serial.print(cs_currentMaxLabel);
|
||||
Serial.println(c.current_max);
|
||||
Serial.print(cs_shuntVoltageDropLabel);
|
||||
Serial.println(c.shunt_voltage_drop);
|
||||
Serial.print(cs_shuntMaxCurrentLabel);
|
||||
Serial.println(c.shunt_max_current);
|
||||
Serial.print(cs_timeIna226RefreshLabel);
|
||||
Serial.println(c.time_ina226_refresh);
|
||||
Serial.print(cs_checksumLabel);
|
||||
Serial.println(c.checksum);
|
||||
Serial.println(cs_separator2);
|
||||
#endif
|
||||
}
|
||||
|
||||
void enableWatchdog()
|
||||
{
|
||||
Serial.println(cs_enableWatchdog);
|
||||
// Initialisiere den Watchdog-Timer mit einer Timeout-Zeit von 5 Sekunden
|
||||
esp_task_wdt_init(WATCHDOG_TIMEOUT_S, true);
|
||||
// Aktiviere den Watchdog-Timer für den Hauptprozess
|
||||
esp_task_wdt_add(NULL);
|
||||
}
|
||||
|
||||
void disableWatchdog()
|
||||
{
|
||||
Serial.println(cs_disablingWatchdog);
|
||||
esp_task_wdt_deinit();
|
||||
esp_task_wdt_delete(NULL);
|
||||
}
|
||||
|
||||
void configureIna226()
|
||||
{
|
||||
ina226.setMinimalShunt(0.0001); // overwrite INA226_ERR_SHUNT_LOW
|
||||
|
||||
globalShuntValue = (globalConfigData.shunt_voltage_drop / 1000.0) / globalConfigData.shunt_max_current;
|
||||
Serial.println("Ina226 target shunt size (Ohm): " + String(globalShuntValue));
|
||||
|
||||
// normalization to 3 floatingpoint accuracy
|
||||
ina226Status = ina226.setMaxCurrentShunt(globalConfigData.shunt_max_current / 1000.0,
|
||||
globalShuntValue, true);
|
||||
if (0x0000 != ina226Status)
|
||||
{
|
||||
Serial.print("Ina226 error, invalid configuration: ");
|
||||
Serial.println(ina226Status, HEX);
|
||||
}
|
||||
ina226.setAverage(2); // 2=16 samples will be used to build an average value
|
||||
Serial.println("Ina226 mode: "+String(ina226.getMode()));
|
||||
Serial.println("Ina226 shunt ohm: "+String(ina226.getShunt()));
|
||||
Serial.println("Ina226 is calibrated: "+String(ina226.isCalibrated()));
|
||||
}
|
89
firmware/simulation_demo.ino
Normal file
89
firmware/simulation_demo.ino
Normal file
|
@ -0,0 +1,89 @@
|
|||
|
||||
void simulateUpDownSensorValues() {
|
||||
|
||||
if (demo1Increasing == false) {
|
||||
globalCurrent -= 5.0;
|
||||
globalPower = 25.6 * globalCurrent;
|
||||
|
||||
// Überprüfe, ob die maximalen Werte erreicht sind
|
||||
if (globalCurrent < -100.0) {
|
||||
demo1Increasing = true;
|
||||
globalCurrent = 0;
|
||||
}
|
||||
} else if (demo1Increasing == true) {
|
||||
globalCurrent += 5.0;
|
||||
globalPower = 25.6 * globalCurrent;
|
||||
|
||||
}
|
||||
|
||||
// Überprüfe, ob die maximalen Werte erreicht sind
|
||||
if (globalCurrent > 100.0) {
|
||||
// Setze Werte auf 0 zurück
|
||||
globalCurrent = 0.0;
|
||||
globalPower = 0.0;
|
||||
globalBusVoltage = 0.0;
|
||||
globalEnergy = 0.0;
|
||||
|
||||
demoMode1 = false;
|
||||
demo1Increasing = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void simulateChrgFull() {
|
||||
static unsigned long startTime = 0;
|
||||
|
||||
// Startzeit initialisieren, wenn es der erste Durchlauf ist
|
||||
if (startTime == 0) {
|
||||
startTime = millis();
|
||||
}
|
||||
|
||||
globalCurrent = 200.0;
|
||||
globalPower = 25.6 * globalCurrent;
|
||||
|
||||
// Zeitdauer seit dem Start berechnen
|
||||
unsigned long currentTime = millis();
|
||||
unsigned long elapsedTime = currentTime - startTime;
|
||||
|
||||
// Überprüfe, ob die Zeit von 60 Sekunden abgelaufen ist
|
||||
if (elapsedTime >= 60000) {
|
||||
// Setze Werte auf 0 zurück
|
||||
globalCurrent = 0.0;
|
||||
globalPower = 0.0;
|
||||
globalBusVoltage = 0.0;
|
||||
globalEnergy = 0.0;
|
||||
|
||||
// Setze Flags zurück
|
||||
demoMode2 = false;
|
||||
startTime = 0; // Zurücksetzen der Startzeit für den nächsten Durchlauf
|
||||
}
|
||||
}
|
||||
|
||||
void simulateDischrgEmpty() {
|
||||
static unsigned long startTime = 0;
|
||||
|
||||
// Startzeit initialisieren, wenn es der erste Durchlauf ist
|
||||
if (startTime == 0) {
|
||||
startTime = millis();
|
||||
}
|
||||
|
||||
globalCurrent = -200.0;
|
||||
globalPower = 25.6 * globalCurrent;
|
||||
|
||||
// Zeitdauer seit dem Start berechnen
|
||||
unsigned long currentTime = millis();
|
||||
unsigned long elapsedTime = currentTime - startTime;
|
||||
|
||||
// Überprüfe, ob die Zeit von 60 Sekunden abgelaufen ist
|
||||
if (elapsedTime >= 60000) {
|
||||
// Setze Werte auf 0 zurück
|
||||
globalCurrent = 0.0;
|
||||
globalPower = 0.0;
|
||||
globalBusVoltage = 0.0;
|
||||
globalEnergy = 0.0;
|
||||
|
||||
// Setze Flags zurück
|
||||
demoMode3 = false;
|
||||
startTime = 0; // Zurücksetzen der Startzeit für den nächsten Durchlauf
|
||||
}
|
||||
}
|
5
firmware/start_webserver.sh
Executable file
5
firmware/start_webserver.sh
Executable file
|
@ -0,0 +1,5 @@
|
|||
#!/bin/bash
|
||||
|
||||
cd build/esp32.esp32.esp32da && python3 -m http.server 8082
|
||||
cd -
|
||||
|
565
firmware/webserver.ino
Normal file
565
firmware/webserver.ino
Normal file
|
@ -0,0 +1,565 @@
|
|||
|
||||
void handleRoot() {
|
||||
String html = "<html><head><script src='https://code.jquery.com/jquery-3.6.4.min.js'></script>";
|
||||
html += "<link rel=\"stylesheet\" type=\"text/css\" href=\"/css\">";
|
||||
html += "<link rel='stylesheet' href='https://unpkg.com/purecss@0.6.2/build/pure-min.css'>";
|
||||
html += "<title>powerMC (ESP32) "+String(FIRMWARE_VERSION)+"</title></head>";
|
||||
html += "<body><h1>powerMC (ESP32) "+String(FIRMWARE_VERSION)+"</h1>";
|
||||
|
||||
html += "<table><tr><td>";
|
||||
|
||||
html += "<p><a href='"+cs_jsonPath+"'>JSON Daten</a></p><br>";
|
||||
html += "<p><a href='"+cs_demoMode1Path+"'>Start demo mode charge and discharge</a></p>";
|
||||
html += "<p><a href='"+cs_demoMode2Path+"'>Start demo mode charge to max</a></p>";
|
||||
html += "<p><a href='"+cs_demoMode3Path+"'>Start demo mode discharge to zero</a></p><br>";
|
||||
html += "<p><a href='"+cs_resetESPPath+"'>Reset ESP32</a></p>";
|
||||
html += "<p><a href='"+cs_resetWifiPath+"'>Reset Wifi settings</a></p><br>";
|
||||
html += "<p><a href='"+cs_checkUpdatePath+"'>Firmware update</a></p><br>";
|
||||
html += "<p><a href='"+cs_configPath+"'>Config</a></p>";
|
||||
|
||||
html += "</td><td> </td><td>";
|
||||
|
||||
html += "<p id='busVoltage'>Busvoltage: <span id='busVoltageValue'>0</span> V</p>";
|
||||
html += "<p id='shuntVoltage'>Shuntvoltage: <span id='shuntVoltageValue'>0</span> V</p>";
|
||||
html += "<p id='current'>Strom: <span id='currentValue'>0</span> A</p>";
|
||||
html += "<p id='power'>Leistung: <span id='powerValue'>0</span> W</p>";
|
||||
html += "<p id='energy'>Energie: <span id='energyValue'>0</span> Wh</p>";
|
||||
html += "<p id='temp'>Temp: <span id='tempValue'>0</span> °C</p>";
|
||||
html += "<p id='humidity'>Humidity: <span id='humidityValue'>0</span> %</p>";
|
||||
html += "<p>Shunt max voltage drop: <span>"+String(globalConfigData.shunt_voltage_drop,0)+"</span> mV</p>";
|
||||
html += "<p>Shunt max current: <span>"+String(globalConfigData.shunt_max_current,0)+"</span> A</p>";
|
||||
html += "<p>Current factor: <span>"+String(globalConfigData.current_fact/100,2)+" (div. by 100)</span></p>";
|
||||
html += "<p>Max capacity: <span>"+String(globalConfigData.max_capacity,0)+"</span> Wh</p>";
|
||||
html += "<p>Ina226 refresh period: <span>"+String(globalConfigData.time_ina226_refresh,0)+"</span> s</p>";
|
||||
html += "<p id='errorCode'>Error code: <span id='error'>0</span></p>";
|
||||
|
||||
html += "</td></tr></table>";
|
||||
|
||||
html += "<script>";
|
||||
|
||||
html += "function showNotification(message, isSuccess) {";
|
||||
html += " var notification = document.createElement('div');";
|
||||
html += " notification.className = isSuccess ? 'success-notification' : 'error-notification';";
|
||||
html += " notification.innerHTML = message;";
|
||||
html += " document.body.appendChild(notification);";
|
||||
html += " setTimeout(function() {";
|
||||
html += " document.body.removeChild(notification);";
|
||||
html += " }, 3000);";
|
||||
html += "}";
|
||||
|
||||
html += "function updateValues() {";
|
||||
html += "$.ajax({";
|
||||
html += "url: '/json',";
|
||||
html += "type: 'GET',";
|
||||
html += "dataType: 'json',";
|
||||
html += "success: function(data) {";
|
||||
html += "$('#currentValue').text(data.current);";
|
||||
html += "$('#powerValue').text(data.power);";
|
||||
html += "$('#energyValue').text(data.energy);";
|
||||
html += "$('#busVoltageValue').text(data.busVoltage);";
|
||||
html += "$('#shuntVoltageValue').text(data.shuntVoltage);";
|
||||
html += "$('#tempValue').text(data.temp.toFixed(2));";
|
||||
html += "$('#humidityValue').text(data.humidity.toFixed(2));";
|
||||
html += "$('#error').text('0b' + data.errorCode.toString(2).padStart(16, '0'));"; // Hier wird der errorCode als Binärzahl dargestellt
|
||||
html += "},";
|
||||
html += "error: function() {";
|
||||
html += "console.log('Fehler beim Abrufen der Daten.');";
|
||||
html += "}";
|
||||
html += "});";
|
||||
html += "}";
|
||||
html += "updateValues();";
|
||||
html += "setInterval(updateValues, " + String(LOOP_DISPLAY_DELAY_MS) + ");";
|
||||
html += "</script></body></html>";
|
||||
|
||||
server.send(200, cs_textHtml, html);
|
||||
}
|
||||
|
||||
void handleJson() {
|
||||
// JSON-Daten aus globalen Variablen erstellen
|
||||
DynamicJsonDocument doc(200);
|
||||
doc[cs_busVoltageID] = globalBusVoltage;
|
||||
doc[cs_shuntVoltageID] = globalShuntVoltage;
|
||||
doc[cs_currentID] = globalCurrent;
|
||||
doc[cs_powerID] = globalPower;
|
||||
doc[cs_energyID] = globalEnergy;
|
||||
doc[cs_tempID] = globalTemp;
|
||||
doc[cs_humidityID] = globalHumidity;
|
||||
doc[cs_errorCodeID] = globalErrorCode;
|
||||
doc["shuntValue"] = globalShuntValue;
|
||||
doc["ina226Status"] = ina226Status;
|
||||
doc["ina226ShuntValue"] = ina226.getShunt();
|
||||
doc["ina226AlertFlag"] = ina226.getAlertFlag();
|
||||
doc["ina226AlertLimit"] = ina226.getAlertLimit();
|
||||
doc["ina226CurrentLSB"] = ina226.getCurrentLSB();
|
||||
|
||||
String jsonData;
|
||||
serializeJson(doc, jsonData);
|
||||
|
||||
server.send(200, cs_applicationJson, jsonData);
|
||||
}
|
||||
|
||||
void handleConfig() {
|
||||
String html = "<html><head>";
|
||||
html += "<title>powerMC (ESP32) "+String(FIRMWARE_VERSION)+" - configuration</title>";
|
||||
html += "<link rel=\"stylesheet\" type=\"text/css\" href=\"/css\">";
|
||||
html += "<link rel='stylesheet' href='https://unpkg.com/purecss@0.6.2/build/pure-min.css'>";
|
||||
html += "</head>";
|
||||
|
||||
html += "<body><h1>powerMC (ESP32) "+String(FIRMWARE_VERSION)+" - configuration</h1>";
|
||||
|
||||
html += "<p><a href='"+cs_rootPath+"'>Main</a></p><br>";
|
||||
|
||||
html += "<form id=\"configForm\" action=\"/saveConfig\" method=\"post\">";
|
||||
|
||||
html += "<table>";
|
||||
|
||||
html += "<tr><td><label for=\"temp_min\">Max capacity:</label></td><td> </td>";
|
||||
html += "<td class=\"slider-container\"><input type=\"range\" id=\"max_capacity\" name=\"max_capacity\" value=\"" + String(globalConfigData.max_capacity) + "\" min=\"2000\" max=\"10000\" step=\"1\">";
|
||||
html += "<span class=\"slider-value\" id=\"max_capacity_value\">" + String(globalConfigData.max_capacity, 0) + "</span>Wh</td></tr>";
|
||||
|
||||
html += "<tr><td><label for=\"temp_min\">Shunt voltage drop:</label></td><td> </td>";
|
||||
html += "<td class=\"slider-container\"><input type=\"range\" id=\"shunt_voltage_drop\" name=\"shunt_voltage_drop\" value=\"" + String(globalConfigData.shunt_voltage_drop) + "\" min=\"10\" max=\"85\" step=\"1\">";
|
||||
html += "<span class=\"slider-value\" id=\"shunt_voltage_drop_value\">" + String(globalConfigData.shunt_voltage_drop, 0) + "</span>mV</td></tr>";
|
||||
|
||||
html += "<tr><td><label for=\"shunt_max_current\">Shunt current Max:</label></td><td> </td>";
|
||||
html += "<td class=\"slider-container\"><input type=\"range\" id=\"shunt_max_current\" name=\"shunt_max_current\" value=\"" + String(globalConfigData.shunt_max_current) + "\" min=\"10\" max=\"200\" step=\"1\">";
|
||||
html += "<span class=\"slider-value\" id=\"shunt_max_current_value\">" + String(globalConfigData.shunt_max_current, 0) + "</span>A</td></tr>";
|
||||
|
||||
html += "<tr><td><label for=\"temp_min\">Temperature Min:</label></td><td> </td>";
|
||||
html += "<td class=\"slider-container\"><input type=\"range\" id=\"temp_min\" name=\"temp_min\" value=\"" + String(globalConfigData.temp_min) + "\" min=\"0\" max=\"100\" step=\"1\">";
|
||||
html += "<span class=\"slider-value\" id=\"temp_min_value\">" + String(globalConfigData.temp_min, 0) + "</span>°C</td></tr>";
|
||||
|
||||
html += "<tr><td><label for=\"temp_max\">Temperature Max:</label></td><td> </td>";
|
||||
html += "<td class=\"slider-container\"><input type=\"range\" id=\"temp_max\" name=\"temp_max\" value=\"" + String(globalConfigData.temp_max) + "\" min=\"0\" max=\"100\" step=\"1\">";
|
||||
html += "<span class=\"slider-value\" id=\"temp_max_value\">" + String(globalConfigData.temp_max, 0) + "</span>°C</td></tr>";
|
||||
|
||||
html += "<tr><td><label for=\"humidity_min\">Himidity Min:</label></td><td> </td>";
|
||||
html += "<td class=\"slider-container\"><input type=\"range\" id=\"humi_min\" name=\"humi_min\" value=\"" + String(globalConfigData.humi_min) + "\" min=\"0\" max=\"100\" step=\"1\">";
|
||||
html += "<span class=\"slider-value\" id=\"humi_min_value\">" + String(globalConfigData.humi_min, 0) + "</span>%</td></tr>";
|
||||
|
||||
html += "<tr><td><label for=\"humidity_max\">Humidity Max:</label></td><td> </td>";
|
||||
html += "<td class=\"slider-container\"><input type=\"range\" id=\"humi_max\" name=\"humi_max\" value=\"" + String(globalConfigData.humi_max) + "\" min=\"0\" max=\"100\" step=\"1\">";
|
||||
html += "<span class=\"slider-value\" id=\"humi_max_value\">" + String(globalConfigData.humi_max, 0) + "</span>%</td></tr>";
|
||||
|
||||
html += "<tr><td><label for=\"current_min\">Current Min:</label></td><td> </td>";
|
||||
html += "<td class=\"slider-container\"><input type=\"range\" id=\"current_min\" name=\"current_min\" value=\"" + String(globalConfigData.current_min) + "\" min=\"-100\" max=\"100\" step=\"1\">";
|
||||
html += "<span class=\"slider-value\" id=\"current_min_value\">" + String(globalConfigData.current_min, 0) + "</span>A</td></tr>";
|
||||
|
||||
html += "<tr><td><label for=\"current_max\">Current Max:</label></td><td> </td>";
|
||||
html += "<td class=\"slider-container\"><input type=\"range\" id=\"current_max\" name=\"current_max\" value=\"" + String(globalConfigData.current_max) + "\" min=\"-100\" max=\"100\" step=\"1\">";
|
||||
html += "<span class=\"slider-value\" id=\"current_max_value\">" + String(globalConfigData.current_max, 0) + "</span>A</td></tr>";
|
||||
|
||||
html += "<tr><td><label for=\"current_fact\">Current correction factor:</label></td><td> </td>";
|
||||
html += "<td class=\"slider-container\"><input type=\"range\" id=\"current_fact\" name=\"current_fact\" value=\"" + String(globalConfigData.current_fact,0) + "\" min=\"1\" max=\"3000\" step=\"1\">";
|
||||
html += "<span class=\"slider-value\" id=\"current_fact_value\">" + String(globalConfigData.current_fact/100,2) + "</span>(div. by 100)</td></tr>";
|
||||
|
||||
html += "<tr><td><label for=\"time_ina226_refresh\">Ina226 update interval (s):</label></td><td> </td>";
|
||||
html += "<td class=\"slider-container\"><input type=\"range\" id=\"time_ina226_refresh\" name=\"time_ina226_refresh\" value=\"" + String(globalConfigData.time_ina226_refresh,0) + "\" min=\"10\" max=\"120\" step=\"1\">";
|
||||
html += "<span class=\"slider-value\" id=\"time_ina226_refresh_value\">" + String(globalConfigData.time_ina226_refresh,0) + "</span>sek.</td></tr>";
|
||||
|
||||
html += "</table><br>";
|
||||
|
||||
html += "<button type=\"button\" onclick=\"saveConfig()\">Save Config</button></form>";
|
||||
html += "<button onclick=\"location.reload()\">Reset</button>";
|
||||
|
||||
html += "<div id=\"responseMessage\" style=\"display: none;\"></div>";
|
||||
|
||||
html += "<script>";
|
||||
|
||||
html += "function showNotification(message, isSuccess) {";
|
||||
html += " var notification = document.createElement('div');";
|
||||
html += " notification.className = isSuccess ? 'success-notification' : 'error-notification';";
|
||||
html += " notification.innerHTML = message;";
|
||||
html += " document.body.appendChild(notification);";
|
||||
html += " setTimeout(function() {";
|
||||
html += " document.body.removeChild(notification);";
|
||||
html += " }, 3000);";
|
||||
html += "}";
|
||||
|
||||
html += "function saveConfig() {var form = document.getElementById('configForm');";
|
||||
html += "var formData = new FormData(form);";
|
||||
html += "var jsonData = {};";
|
||||
html += "formData.forEach(function(value, key){jsonData[key] = value;});";
|
||||
html += "fetch('/saveConfig', {method: 'PUT',headers: {'Content-Type': 'application/json'},body: JSON.stringify(jsonData)})";
|
||||
html += ".then(response => response.json())";
|
||||
html += ".then(data => { showNotification('Successful saved config', data.message.toLowerCase() === 'ok'); })";
|
||||
html += ".catch(error => { console.error('Error:', error); });}";
|
||||
|
||||
html += "document.getElementById('temp_min').addEventListener('input', function() {";
|
||||
html += "document.getElementById('temp_min_value').innerText = this.value;});";
|
||||
html += "document.getElementById('temp_max').addEventListener('input', function() {";
|
||||
html += "document.getElementById('temp_max_value').innerText = this.value;});";
|
||||
html += "document.getElementById('humi_min').addEventListener('input', function() {";
|
||||
html += "document.getElementById('humi_min_value').innerText = this.value;});";
|
||||
html += "document.getElementById('humi_max').addEventListener('input', function() {";
|
||||
html += "document.getElementById('humi_max_value').innerText = this.value;});";
|
||||
html += "document.getElementById('current_min').addEventListener('input', function() {";
|
||||
html += "document.getElementById('current_min_value').innerText = this.value;});";
|
||||
html += "document.getElementById('current_max').addEventListener('input', function() {";
|
||||
html += "document.getElementById('current_max_value').innerText = this.value;});";
|
||||
html += "document.getElementById('current_fact').addEventListener('input', function() {";
|
||||
html += "document.getElementById('current_fact_value').innerText = this.value / 100.0;});";
|
||||
html += "document.getElementById('shunt_voltage_drop').addEventListener('input', function() {";
|
||||
html += "document.getElementById('shunt_voltage_drop_value').innerText = this.value;});";
|
||||
html += "document.getElementById('shunt_max_current').addEventListener('input', function() {";
|
||||
html += "document.getElementById('shunt_max_current_value').innerText = this.value;});";
|
||||
html += "document.getElementById('max_capacity').addEventListener('input', function() {";
|
||||
html += "document.getElementById('max_capacity_value').innerText = this.value;});";
|
||||
html += "document.getElementById('time_ina226_refresh').addEventListener('input', function() {";
|
||||
html += "document.getElementById('time_ina226_refresh_value').innerText = this.value;});";
|
||||
|
||||
html += "</script></body></html>";
|
||||
|
||||
server.send(200, cs_textHtml, html);
|
||||
}
|
||||
|
||||
|
||||
void handleSaveConfig() {
|
||||
if (server.hasArg("plain")) {
|
||||
|
||||
Serial.println("Received new config data:");
|
||||
Serial.println(server.arg("plain"));
|
||||
|
||||
// JSON-Payload analysieren
|
||||
DynamicJsonDocument jsonDoc(1024);
|
||||
deserializeJson(jsonDoc, server.arg("plain"));
|
||||
|
||||
// Parameter überprüfen und in die Konfiguration übertragen
|
||||
if (jsonDoc.containsKey("temp_min")) {
|
||||
float temp_min = jsonDoc["temp_min"];
|
||||
// Hier prüfen und in die globale Konfiguration übertragen
|
||||
globalConfigData.temp_min = temp_min;
|
||||
}
|
||||
|
||||
if (jsonDoc.containsKey("temp_max")) {
|
||||
float temp_max = jsonDoc["temp_max"];
|
||||
// Hier prüfen und in die globale Konfiguration übertragen
|
||||
globalConfigData.temp_max = temp_max;
|
||||
}
|
||||
|
||||
if (jsonDoc.containsKey("humi_min")) {
|
||||
float humi_min = jsonDoc["humi_min"];
|
||||
// Hier prüfen und in die globale Konfiguration übertragen
|
||||
globalConfigData.humi_min = humi_min;
|
||||
}
|
||||
|
||||
if (jsonDoc.containsKey("humi_max")) {
|
||||
float humi_max = jsonDoc["humi_max"];
|
||||
// Hier prüfen und in die globale Konfiguration übertragen
|
||||
globalConfigData.humi_max = humi_max;
|
||||
}
|
||||
|
||||
if (jsonDoc.containsKey("current_min")) {
|
||||
float current_min = jsonDoc["current_min"];
|
||||
// Hier prüfen und in die globale Konfiguration übertragen
|
||||
globalConfigData.current_min = current_min;
|
||||
}
|
||||
|
||||
if (jsonDoc.containsKey("current_max")) {
|
||||
float current_max = jsonDoc["current_max"];
|
||||
// Hier prüfen und in die globale Konfiguration übertragen
|
||||
globalConfigData.current_max = current_max;
|
||||
}
|
||||
|
||||
if (jsonDoc.containsKey("shunt_voltage_drop")) {
|
||||
float shunt_voltage_drop = jsonDoc["shunt_voltage_drop"];
|
||||
// Hier prüfen und in die globale Konfiguration übertragen
|
||||
globalConfigData.shunt_voltage_drop = shunt_voltage_drop;
|
||||
}
|
||||
|
||||
if (jsonDoc.containsKey("shunt_max_current")) {
|
||||
float shunt_max_current = jsonDoc["shunt_max_current"];
|
||||
// Hier prüfen und in die globale Konfiguration übertragen
|
||||
globalConfigData.shunt_max_current = shunt_max_current;
|
||||
}
|
||||
|
||||
if (jsonDoc.containsKey("max_capacity")) {
|
||||
float max_capacity = jsonDoc["max_capacity"];
|
||||
// Hier prüfen und in die globale Konfiguration übertragen
|
||||
globalConfigData.max_capacity = max_capacity;
|
||||
}
|
||||
|
||||
if (jsonDoc.containsKey("time_ina226_refresh")) {
|
||||
float time_ina226_refresh = jsonDoc["time_ina226_refresh"];
|
||||
// Hier prüfen und in die globale Konfiguration übertragen
|
||||
globalConfigData.time_ina226_refresh = time_ina226_refresh;
|
||||
}
|
||||
|
||||
if (jsonDoc.containsKey("current_fact")) {
|
||||
float current_fact = jsonDoc["current_fact"];
|
||||
// Hier prüfen und in die globale Konfiguration übertragen
|
||||
globalConfigData.current_fact = current_fact;
|
||||
}
|
||||
|
||||
writeConfigToEEPROM();
|
||||
|
||||
if (ina226.reset())
|
||||
{
|
||||
Serial.println("Ina226 reset");
|
||||
configureIna226();
|
||||
checkError();
|
||||
} else {
|
||||
Serial.println("Ina226 error: can't reset and reconfigure.");
|
||||
}
|
||||
|
||||
// Schicke eine Bestätigung zurück
|
||||
server.send(200, "application/json", "{\"message\": \"ok\"}");
|
||||
} else {
|
||||
// Ungültige Anfrage
|
||||
server.send(400, "text/plain", "Invalid request");
|
||||
}
|
||||
}
|
||||
|
||||
void handleDemoMode1() {
|
||||
demoMode1 = true;
|
||||
demoMode2 = false;
|
||||
demoMode3 = false;
|
||||
globalBusVoltage = 25.6;
|
||||
globalEnergy = globalConfigData.max_capacity / 2;
|
||||
handleRoot();
|
||||
}
|
||||
|
||||
void handleDemoMode2() {
|
||||
demoMode1 = false;
|
||||
demoMode2 = true;
|
||||
demoMode3 = false;
|
||||
globalBusVoltage = 25.6;
|
||||
globalEnergy = globalConfigData.max_capacity * 0.97;
|
||||
handleRoot();
|
||||
}
|
||||
|
||||
void handleDemoMode3() {
|
||||
demoMode1 = false;
|
||||
demoMode2 = false;
|
||||
demoMode3 = true;
|
||||
globalBusVoltage = 25.6;
|
||||
globalEnergy = globalConfigData.max_capacity * 0.03;
|
||||
handleRoot();
|
||||
}
|
||||
|
||||
void handleResetESP() {
|
||||
|
||||
String message = "<html><head><title>powerMC (ESP32) "+String(FIRMWARE_VERSION)+" - reset</title>"
|
||||
"<script>setTimeout(function() { window.location.href = '/'; }, 10000);</script>"
|
||||
"<link rel=\"stylesheet\" type=\"text/css\" href=\"/css\">"
|
||||
"<link rel='stylesheet' href='https://unpkg.com/purecss@0.6.2/build/pure-min.css'>"
|
||||
"</head><body><h1>powerMC (ESP32) "+String(FIRMWARE_VERSION)+" - reset</h1>"
|
||||
"Rebooting...<br>"
|
||||
"</body></html>";
|
||||
|
||||
server.send(200, cs_textHtml, message);
|
||||
|
||||
delay(5000);
|
||||
|
||||
// manual reset after restart is required
|
||||
ESP.restart();
|
||||
}
|
||||
|
||||
void handleResetWifi() {
|
||||
|
||||
String message = "<html><head><title>powerMC (ESP32) "+String(FIRMWARE_VERSION)+" - reset WiFi configuration</title>"
|
||||
"<script>setTimeout(function() { window.location.href = '/'; }, 10000);</script>"
|
||||
"<link rel=\"stylesheet\" type=\"text/css\" href=\"/css\">"
|
||||
"<link rel='stylesheet' href='https://unpkg.com/purecss@0.6.2/build/pure-min.css'>"
|
||||
"</head><body><h1>owerMC (ESP32) "+String(FIRMWARE_VERSION)+" - reset WiFi configuration</h1>"
|
||||
"Reset WifiManager config, rebooting...<br>"
|
||||
"</body></html>";
|
||||
|
||||
server.send(200, cs_textHtml, message);
|
||||
|
||||
// Erase WiFi Credentials, enable, compile, flash, disable and reflash.
|
||||
wifiManager.resetSettings();
|
||||
|
||||
delay(5000);
|
||||
|
||||
// manual reset after restart is required
|
||||
ESP.restart();
|
||||
}
|
||||
|
||||
void handleUpdateFirmware() {
|
||||
String message = "<html><head><title>powerMC (ESP32) " + String(FIRMWARE_VERSION) + " - firmware update</title>"
|
||||
"<link rel=\"stylesheet\" type=\"text/css\" href=\"/css\">"
|
||||
"<link rel='stylesheet' href='https://unpkg.com/purecss@0.6.2/build/pure-min.css'>"
|
||||
"</head><body><h1>powerMC (ESP32) " + String(FIRMWARE_VERSION) + " - firmware update</h1>"
|
||||
"<p><a href='"+cs_rootPath+"'>Main</a></p><br>"
|
||||
"<button onclick='window.location.href=\"/updateFirmwareAction\";'>Update Firmware</button>"
|
||||
"</body></html>";
|
||||
|
||||
server.send(200, cs_textHtml, message);
|
||||
}
|
||||
|
||||
void handleUpdateFirmwareAction() {
|
||||
|
||||
if (fwUpdate_isRunning)
|
||||
{
|
||||
Serial.println("Firmware-Update is running...");
|
||||
if (updateStatus == "") {
|
||||
updateStatus = "Firmware-Update is running...<br>";
|
||||
}
|
||||
server.send(200, cs_textHtml, updateStatus);
|
||||
} else {
|
||||
|
||||
String message = "<html><head><title>powerMC (ESP32) " + String(FIRMWARE_VERSION) + " - firmware update</title>"
|
||||
"<script>"
|
||||
"function readUpdateFirmwareStatus() {"
|
||||
" var xhr = new XMLHttpRequest();"
|
||||
" xhr.onreadystatechange = function() {"
|
||||
" if (xhr.readyState == 4) {"
|
||||
" document.getElementById('updateStatus').innerHTML = xhr.responseText;"
|
||||
" if (xhr.responseText.includes('Firmware update successful')) { "
|
||||
" setTimeout(function() { "
|
||||
" window.location.href = '" + cs_resetESPPath + "'; "
|
||||
" }, 5000); }"
|
||||
" }"
|
||||
" };"
|
||||
" xhr.timeout = 1000;"
|
||||
" xhr.open('GET', '/readUpdateFirmwareStatus', true);"
|
||||
" xhr.send();"
|
||||
"}"
|
||||
"setInterval(readUpdateFirmwareStatus, 2000);"
|
||||
"</script>"
|
||||
"<link rel=\"stylesheet\" type=\"text/css\" href=\"/css\">"
|
||||
"<link rel='stylesheet' href='https://unpkg.com/purecss@0.6.2/build/pure-min.css'>"
|
||||
"</head><body><h1>powerMC (ESP32) " + String(FIRMWARE_VERSION) + " - firmware update</h1><br>"
|
||||
"<p>Updating...</p>"
|
||||
"<div id='updateStatus'></div>"
|
||||
"</body></html>";
|
||||
|
||||
server.send(200, cs_textHtml, message);
|
||||
|
||||
disableWatchdog();
|
||||
|
||||
updateStatus = "";
|
||||
|
||||
Serial.print(cs_startingFirmwareUpdate);
|
||||
ESPhttpUpdate.rebootOnUpdate(false);
|
||||
t_httpUpdate_return ret = ESPhttpUpdate.update(String(FIRMWARE_UPDATE_URL));
|
||||
fwUpdate_isRunning = true;
|
||||
|
||||
Serial.println(cs_finish);
|
||||
|
||||
switch (ret) {
|
||||
case HTTP_UPDATE_FAILED:
|
||||
Serial.printf("HTTP_UPDATE_FAILED Error (%d): %s\n", ESPhttpUpdate.getLastError(), ESPhttpUpdate.getLastErrorString().c_str());
|
||||
updateStatus = "<b>Firmware-Update failed.</b><br>";
|
||||
updateStatus += "<b>Last error: "+String(ESPhttpUpdate.getLastError())+"</b><br>";
|
||||
updateStatus += "<b>Last error message: "+ESPhttpUpdate.getLastErrorString()+"</b><br>";
|
||||
fwUpdate_isRunning = false;
|
||||
enableWatchdog();
|
||||
break;
|
||||
|
||||
case HTTP_UPDATE_NO_UPDATES:
|
||||
Serial.println(cs_noUpdatesAvailable);
|
||||
updateStatus = "<b>No Updates available.</b><br>";
|
||||
fwUpdate_isRunning = false;
|
||||
enableWatchdog();
|
||||
break;
|
||||
|
||||
case HTTP_UPDATE_OK:
|
||||
Serial.println(cs_fwUpdSuccess);
|
||||
updateStatus = "<b>Firmware update successful, resetting in a few seconds.</b><br>";
|
||||
fwUpdate_isRunning = false;
|
||||
break;
|
||||
|
||||
default: // other
|
||||
Serial.println(cs_unknownStatus);
|
||||
updateStatus = "<b>Unknown status.</b><br>";
|
||||
fwUpdate_isRunning = false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void handleReadUpdateFirmwareStatus() {
|
||||
if (fwUpdate_isRunning)
|
||||
{
|
||||
Serial.println(cs_fwUpdRunning);
|
||||
if (updateStatus == "") {
|
||||
updateStatus = "Firmware-Update is running...<br>";
|
||||
}
|
||||
}
|
||||
server.send(200, cs_textHtml, updateStatus);
|
||||
}
|
||||
|
||||
void handleCSS() {
|
||||
// "<link rel="stylesheet" type="text/css" href="/css">"
|
||||
String customCSS = R"(
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
margin: 20px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: #333;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 5px 0;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #0066cc;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
#busVoltage,
|
||||
#current,
|
||||
#power,
|
||||
#energy,
|
||||
#temp,
|
||||
#humidity,
|
||||
#errorCode {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
span {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
td {
|
||||
vertical-align: top;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.success-notification {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
background-color: #4CAF50;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.error-notification {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
background-color: #f44336;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
button {
|
||||
font-family: Arial, sans-serif;
|
||||
background-color: #d3d3d3;
|
||||
color: #000;
|
||||
padding: 10px 20px;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
display: inline-block;
|
||||
font-size: 16px;
|
||||
margin: 4px 2px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
button:active {
|
||||
background-color: #a9a9a9; /* Dunkleres Grau beim Drücken */
|
||||
}
|
||||
)";
|
||||
|
||||
server.send(200, cs_textCSS, customCSS);
|
||||
}
|
Loading…
Reference in a new issue