mirror of
https://github.com/dalathegreat/Battery-Emulator.git
synced 2025-10-06 03:50:13 +02:00
Web Server Authentication
This commit is contained in:
parent
a4e56d4b04
commit
1647a4c572
5 changed files with 77 additions and 8 deletions
|
@ -25,6 +25,9 @@ std::string password = "REPLACE_WITH_YOUR_PASSWORD"; // Minimum of 8 characters
|
||||||
const char* ssidAP = "Battery Emulator"; // Maximum of 63 characters, also used for device name on web interface
|
const char* ssidAP = "Battery Emulator"; // Maximum of 63 characters, also used for device name on web interface
|
||||||
const char* passwordAP = "123456789"; // Minimum of 8 characters; set to NULL if you want the access point to be open
|
const char* passwordAP = "123456789"; // Minimum of 8 characters; set to NULL if you want the access point to be open
|
||||||
const uint8_t wifi_channel = 0; // Set to 0 for automatic channel selection
|
const uint8_t wifi_channel = 0; // Set to 0 for automatic channel selection
|
||||||
|
const char* http_username = "admin"; // username to webserver authentication;
|
||||||
|
const char* http_password = "admin"; // password to webserver authentication;
|
||||||
|
|
||||||
// MQTT
|
// MQTT
|
||||||
#ifdef MQTT
|
#ifdef MQTT
|
||||||
const char* mqtt_user = "REDACTED"; // Set NULL for no username
|
const char* mqtt_user = "REDACTED"; // Set NULL for no username
|
||||||
|
|
|
@ -54,6 +54,8 @@
|
||||||
//#define SERIAL_LINK_RECEIVER //Enable this line to receive battery data over RS485 pins from another Lilygo (This LilyGo interfaces with inverter)
|
//#define SERIAL_LINK_RECEIVER //Enable this line to receive battery data over RS485 pins from another Lilygo (This LilyGo interfaces with inverter)
|
||||||
//#define SERIAL_LINK_TRANSMITTER //Enable this line to send battery data over RS485 pins to another Lilygo (This LilyGo interfaces with battery)
|
//#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.
|
#define WEBSERVER //Enable this line to enable WiFi, and to run the webserver. See USER_SETTINGS.cpp for the Wifi settings.
|
||||||
|
#define WEBSERVER_AUTH_REQUIRED \
|
||||||
|
false //Enable this line to enable webserver authentication. See USER_SETTINGS.cpp setting the credentials.
|
||||||
#define WIFIAP //Disable this line to permanently disable WIFI AP mode (make sure to hardcode ssid and password of you home wifi network). When enabled WIFI AP can still be disabled by a setting in the future.
|
#define WIFIAP //Disable this line to permanently disable WIFI AP mode (make sure to hardcode ssid and password of you home wifi network). When enabled WIFI AP can still be disabled by a setting in the future.
|
||||||
#define MDNSRESPONDER //Enable this line to enable MDNS, allows battery monitor te be found by .local address. Requires WEBSERVER to be enabled.
|
#define MDNSRESPONDER //Enable this line to enable MDNS, allows battery monitor te be found by .local address. Requires WEBSERVER to be enabled.
|
||||||
#define LOAD_SAVED_SETTINGS_ON_BOOT //Enable this line to read settings stored via the webserver on boot (overrides Wifi/battery settings set below)
|
#define LOAD_SAVED_SETTINGS_ON_BOOT //Enable this line to read settings stored via the webserver on boot (overrides Wifi/battery settings set below)
|
||||||
|
|
|
@ -19,6 +19,10 @@ To update the software over the air:
|
||||||
- In your webbrowser, go to the url consisting of the IP address, followed by `/update`, for instance `http://192.168.0.224/update`.
|
- In your webbrowser, go to the url consisting of the IP address, followed by `/update`, for instance `http://192.168.0.224/update`.
|
||||||
- In the webbrowser, follow the steps to select the `.bin` file and to upload the file to the board.
|
- In the webbrowser, follow the steps to select the `.bin` file and to upload the file to the board.
|
||||||
|
|
||||||
|
Security Concerns
|
||||||
|
(https://randomnerdtutorials.com/esp32-esp8266-web-server-http-authentication/)
|
||||||
|
Authentication implemented here is meant to be used in your local network to protect from anyone just typing the ESP IP address and accessing the web server (like unauthorized family member or friend).
|
||||||
|
|
||||||
## Future work
|
## Future work
|
||||||
This section lists a number of features that can be implemented as part of the webserver in the future.
|
This section lists a number of features that can be implemented as part of the webserver in the future.
|
||||||
|
|
||||||
|
|
|
@ -51,25 +51,41 @@ void init_webserver() {
|
||||||
|
|
||||||
String content = index_html;
|
String content = index_html;
|
||||||
|
|
||||||
|
server.on("/logout", HTTP_GET, [](AsyncWebServerRequest* request) { request->send(401); });
|
||||||
|
|
||||||
// Route for root / web page
|
// Route for root / web page
|
||||||
server.on("/", HTTP_GET,
|
server.on("/", HTTP_GET, [](AsyncWebServerRequest* request) {
|
||||||
[](AsyncWebServerRequest* request) { request->send_P(200, "text/html", index_html, processor); });
|
if (WEBSERVER_AUTH_REQUIRED && !request->authenticate(http_username, http_password))
|
||||||
|
return request->requestAuthentication();
|
||||||
|
request->send_P(200, "text/html", index_html, processor);
|
||||||
|
});
|
||||||
|
|
||||||
// Route for going to settings web page
|
// Route for going to settings web page
|
||||||
server.on("/settings", HTTP_GET,
|
server.on("/settings", HTTP_GET, [](AsyncWebServerRequest* request) {
|
||||||
[](AsyncWebServerRequest* request) { request->send_P(200, "text/html", index_html, settings_processor); });
|
if (WEBSERVER_AUTH_REQUIRED && !request->authenticate(http_username, http_password))
|
||||||
|
return request->requestAuthentication();
|
||||||
|
request->send_P(200, "text/html", index_html, settings_processor);
|
||||||
|
});
|
||||||
|
|
||||||
// Route for going to cellmonitor web page
|
// Route for going to cellmonitor web page
|
||||||
server.on("/cellmonitor", HTTP_GET, [](AsyncWebServerRequest* request) {
|
server.on("/cellmonitor", HTTP_GET, [](AsyncWebServerRequest* request) {
|
||||||
|
if (WEBSERVER_AUTH_REQUIRED && !request->authenticate(http_username, http_password))
|
||||||
|
return request->requestAuthentication();
|
||||||
request->send_P(200, "text/html", index_html, cellmonitor_processor);
|
request->send_P(200, "text/html", index_html, cellmonitor_processor);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Route for going to event log web page
|
// Route for going to event log web page
|
||||||
server.on("/events", HTTP_GET,
|
server.on("/events", HTTP_GET, [](AsyncWebServerRequest* request) {
|
||||||
[](AsyncWebServerRequest* request) { request->send_P(200, "text/html", index_html, events_processor); });
|
if (WEBSERVER_AUTH_REQUIRED && !request->authenticate(http_username, http_password))
|
||||||
|
return request->requestAuthentication();
|
||||||
|
request->send_P(200, "text/html", index_html, events_processor);
|
||||||
|
});
|
||||||
|
|
||||||
// Route for editing SSID
|
// Route for editing SSID
|
||||||
server.on("/updateSSID", HTTP_GET, [](AsyncWebServerRequest* request) {
|
server.on("/updateSSID", HTTP_GET, [](AsyncWebServerRequest* request) {
|
||||||
|
if (WEBSERVER_AUTH_REQUIRED && !request->authenticate(http_username, http_password))
|
||||||
|
return request->requestAuthentication();
|
||||||
|
|
||||||
if (request->hasParam("value")) {
|
if (request->hasParam("value")) {
|
||||||
String value = request->getParam("value")->value();
|
String value = request->getParam("value")->value();
|
||||||
if (value.length() <= 63) { // Check if SSID is within the allowable length
|
if (value.length() <= 63) { // Check if SSID is within the allowable length
|
||||||
|
@ -85,6 +101,8 @@ void init_webserver() {
|
||||||
});
|
});
|
||||||
// Route for editing Password
|
// Route for editing Password
|
||||||
server.on("/updatePassword", HTTP_GET, [](AsyncWebServerRequest* request) {
|
server.on("/updatePassword", HTTP_GET, [](AsyncWebServerRequest* request) {
|
||||||
|
if (WEBSERVER_AUTH_REQUIRED && !request->authenticate(http_username, http_password))
|
||||||
|
return request->requestAuthentication();
|
||||||
if (request->hasParam("value")) {
|
if (request->hasParam("value")) {
|
||||||
String value = request->getParam("value")->value();
|
String value = request->getParam("value")->value();
|
||||||
if (value.length() > 8) { // Check if password is within the allowable length
|
if (value.length() > 8) { // Check if password is within the allowable length
|
||||||
|
@ -101,6 +119,8 @@ void init_webserver() {
|
||||||
|
|
||||||
// Route for editing Wh
|
// Route for editing Wh
|
||||||
server.on("/updateBatterySize", HTTP_GET, [](AsyncWebServerRequest* request) {
|
server.on("/updateBatterySize", HTTP_GET, [](AsyncWebServerRequest* request) {
|
||||||
|
if (WEBSERVER_AUTH_REQUIRED && !request->authenticate(http_username, http_password))
|
||||||
|
return request->requestAuthentication();
|
||||||
if (request->hasParam("value")) {
|
if (request->hasParam("value")) {
|
||||||
String value = request->getParam("value")->value();
|
String value = request->getParam("value")->value();
|
||||||
datalayer.battery.info.total_capacity_Wh = value.toInt();
|
datalayer.battery.info.total_capacity_Wh = value.toInt();
|
||||||
|
@ -113,6 +133,8 @@ void init_webserver() {
|
||||||
|
|
||||||
// Route for editing USE_SCALED_SOC
|
// Route for editing USE_SCALED_SOC
|
||||||
server.on("/updateUseScaledSOC", HTTP_GET, [](AsyncWebServerRequest* request) {
|
server.on("/updateUseScaledSOC", HTTP_GET, [](AsyncWebServerRequest* request) {
|
||||||
|
if (WEBSERVER_AUTH_REQUIRED && !request->authenticate(http_username, http_password))
|
||||||
|
return request->requestAuthentication();
|
||||||
if (request->hasParam("value")) {
|
if (request->hasParam("value")) {
|
||||||
String value = request->getParam("value")->value();
|
String value = request->getParam("value")->value();
|
||||||
datalayer.battery.settings.soc_scaling_active = value.toInt();
|
datalayer.battery.settings.soc_scaling_active = value.toInt();
|
||||||
|
@ -125,6 +147,8 @@ void init_webserver() {
|
||||||
|
|
||||||
// Route for editing SOCMax
|
// Route for editing SOCMax
|
||||||
server.on("/updateSocMax", HTTP_GET, [](AsyncWebServerRequest* request) {
|
server.on("/updateSocMax", HTTP_GET, [](AsyncWebServerRequest* request) {
|
||||||
|
if (WEBSERVER_AUTH_REQUIRED && !request->authenticate(http_username, http_password))
|
||||||
|
return request->requestAuthentication();
|
||||||
if (request->hasParam("value")) {
|
if (request->hasParam("value")) {
|
||||||
String value = request->getParam("value")->value();
|
String value = request->getParam("value")->value();
|
||||||
datalayer.battery.settings.max_percentage = static_cast<uint16_t>(value.toFloat() * 100);
|
datalayer.battery.settings.max_percentage = static_cast<uint16_t>(value.toFloat() * 100);
|
||||||
|
@ -137,6 +161,8 @@ void init_webserver() {
|
||||||
|
|
||||||
// Route for editing SOCMin
|
// Route for editing SOCMin
|
||||||
server.on("/updateSocMin", HTTP_GET, [](AsyncWebServerRequest* request) {
|
server.on("/updateSocMin", HTTP_GET, [](AsyncWebServerRequest* request) {
|
||||||
|
if (WEBSERVER_AUTH_REQUIRED && !request->authenticate(http_username, http_password))
|
||||||
|
return request->requestAuthentication();
|
||||||
if (request->hasParam("value")) {
|
if (request->hasParam("value")) {
|
||||||
String value = request->getParam("value")->value();
|
String value = request->getParam("value")->value();
|
||||||
datalayer.battery.settings.min_percentage = static_cast<uint16_t>(value.toFloat() * 100);
|
datalayer.battery.settings.min_percentage = static_cast<uint16_t>(value.toFloat() * 100);
|
||||||
|
@ -149,6 +175,8 @@ void init_webserver() {
|
||||||
|
|
||||||
// Route for editing MaxChargeA
|
// Route for editing MaxChargeA
|
||||||
server.on("/updateMaxChargeA", HTTP_GET, [](AsyncWebServerRequest* request) {
|
server.on("/updateMaxChargeA", HTTP_GET, [](AsyncWebServerRequest* request) {
|
||||||
|
if (WEBSERVER_AUTH_REQUIRED && !request->authenticate(http_username, http_password))
|
||||||
|
return request->requestAuthentication();
|
||||||
if (request->hasParam("value")) {
|
if (request->hasParam("value")) {
|
||||||
String value = request->getParam("value")->value();
|
String value = request->getParam("value")->value();
|
||||||
datalayer.battery.info.max_charge_amp_dA = static_cast<uint16_t>(value.toFloat() * 10);
|
datalayer.battery.info.max_charge_amp_dA = static_cast<uint16_t>(value.toFloat() * 10);
|
||||||
|
@ -161,6 +189,8 @@ void init_webserver() {
|
||||||
|
|
||||||
// Route for editing MaxDischargeA
|
// Route for editing MaxDischargeA
|
||||||
server.on("/updateMaxDischargeA", HTTP_GET, [](AsyncWebServerRequest* request) {
|
server.on("/updateMaxDischargeA", HTTP_GET, [](AsyncWebServerRequest* request) {
|
||||||
|
if (WEBSERVER_AUTH_REQUIRED && !request->authenticate(http_username, http_password))
|
||||||
|
return request->requestAuthentication();
|
||||||
if (request->hasParam("value")) {
|
if (request->hasParam("value")) {
|
||||||
String value = request->getParam("value")->value();
|
String value = request->getParam("value")->value();
|
||||||
datalayer.battery.info.max_discharge_amp_dA = static_cast<uint16_t>(value.toFloat() * 10);
|
datalayer.battery.info.max_discharge_amp_dA = static_cast<uint16_t>(value.toFloat() * 10);
|
||||||
|
@ -174,6 +204,8 @@ void init_webserver() {
|
||||||
#ifdef TEST_FAKE_BATTERY
|
#ifdef TEST_FAKE_BATTERY
|
||||||
// Route for editing FakeBatteryVoltage
|
// Route for editing FakeBatteryVoltage
|
||||||
server.on("/updateFakeBatteryVoltage", HTTP_GET, [](AsyncWebServerRequest* request) {
|
server.on("/updateFakeBatteryVoltage", HTTP_GET, [](AsyncWebServerRequest* request) {
|
||||||
|
if (WEBSERVER_AUTH_REQUIRED && !request->authenticate(http_username, http_password))
|
||||||
|
return request->requestAuthentication();
|
||||||
if (!request->hasParam("value")) {
|
if (!request->hasParam("value")) {
|
||||||
request->send(400, "text/plain", "Bad Request");
|
request->send(400, "text/plain", "Bad Request");
|
||||||
}
|
}
|
||||||
|
@ -190,6 +222,8 @@ void init_webserver() {
|
||||||
#if defined CHEVYVOLT_CHARGER || defined NISSANLEAF_CHARGER
|
#if defined CHEVYVOLT_CHARGER || defined NISSANLEAF_CHARGER
|
||||||
// Route for editing ChargerTargetV
|
// Route for editing ChargerTargetV
|
||||||
server.on("/updateChargeSetpointV", HTTP_GET, [](AsyncWebServerRequest* request) {
|
server.on("/updateChargeSetpointV", HTTP_GET, [](AsyncWebServerRequest* request) {
|
||||||
|
if (WEBSERVER_AUTH_REQUIRED && !request->authenticate(http_username, http_password))
|
||||||
|
return request->requestAuthentication();
|
||||||
if (!request->hasParam("value")) {
|
if (!request->hasParam("value")) {
|
||||||
request->send(400, "text/plain", "Bad Request");
|
request->send(400, "text/plain", "Bad Request");
|
||||||
}
|
}
|
||||||
|
@ -212,6 +246,8 @@ void init_webserver() {
|
||||||
|
|
||||||
// Route for editing ChargerTargetA
|
// Route for editing ChargerTargetA
|
||||||
server.on("/updateChargeSetpointA", HTTP_GET, [](AsyncWebServerRequest* request) {
|
server.on("/updateChargeSetpointA", HTTP_GET, [](AsyncWebServerRequest* request) {
|
||||||
|
if (WEBSERVER_AUTH_REQUIRED && !request->authenticate(http_username, http_password))
|
||||||
|
return request->requestAuthentication();
|
||||||
if (!request->hasParam("value")) {
|
if (!request->hasParam("value")) {
|
||||||
request->send(400, "text/plain", "Bad Request");
|
request->send(400, "text/plain", "Bad Request");
|
||||||
}
|
}
|
||||||
|
@ -234,6 +270,8 @@ void init_webserver() {
|
||||||
|
|
||||||
// Route for editing ChargerEndA
|
// Route for editing ChargerEndA
|
||||||
server.on("/updateChargeEndA", HTTP_GET, [](AsyncWebServerRequest* request) {
|
server.on("/updateChargeEndA", HTTP_GET, [](AsyncWebServerRequest* request) {
|
||||||
|
if (WEBSERVER_AUTH_REQUIRED && !request->authenticate(http_username, http_password))
|
||||||
|
return request->requestAuthentication();
|
||||||
if (request->hasParam("value")) {
|
if (request->hasParam("value")) {
|
||||||
String value = request->getParam("value")->value();
|
String value = request->getParam("value")->value();
|
||||||
charger_setpoint_HV_IDC_END = value.toFloat();
|
charger_setpoint_HV_IDC_END = value.toFloat();
|
||||||
|
@ -245,6 +283,8 @@ void init_webserver() {
|
||||||
|
|
||||||
// Route for enabling/disabling HV charger
|
// Route for enabling/disabling HV charger
|
||||||
server.on("/updateChargerHvEnabled", HTTP_GET, [](AsyncWebServerRequest* request) {
|
server.on("/updateChargerHvEnabled", HTTP_GET, [](AsyncWebServerRequest* request) {
|
||||||
|
if (WEBSERVER_AUTH_REQUIRED && !request->authenticate(http_username, http_password))
|
||||||
|
return request->requestAuthentication();
|
||||||
if (request->hasParam("value")) {
|
if (request->hasParam("value")) {
|
||||||
String value = request->getParam("value")->value();
|
String value = request->getParam("value")->value();
|
||||||
charger_HV_enabled = (bool)value.toInt();
|
charger_HV_enabled = (bool)value.toInt();
|
||||||
|
@ -256,6 +296,8 @@ void init_webserver() {
|
||||||
|
|
||||||
// Route for enabling/disabling aux12v charger
|
// Route for enabling/disabling aux12v charger
|
||||||
server.on("/updateChargerAux12vEnabled", HTTP_GET, [](AsyncWebServerRequest* request) {
|
server.on("/updateChargerAux12vEnabled", HTTP_GET, [](AsyncWebServerRequest* request) {
|
||||||
|
if (WEBSERVER_AUTH_REQUIRED && !request->authenticate(http_username, http_password))
|
||||||
|
return request->requestAuthentication();
|
||||||
if (request->hasParam("value")) {
|
if (request->hasParam("value")) {
|
||||||
String value = request->getParam("value")->value();
|
String value = request->getParam("value")->value();
|
||||||
charger_aux12V_enabled = (bool)value.toInt();
|
charger_aux12V_enabled = (bool)value.toInt();
|
||||||
|
@ -267,11 +309,16 @@ void init_webserver() {
|
||||||
#endif // defined CHEVYVOLT_CHARGER || defined NISSANLEAF_CHARGER
|
#endif // defined CHEVYVOLT_CHARGER || defined NISSANLEAF_CHARGER
|
||||||
|
|
||||||
// Send a GET request to <ESP_IP>/update
|
// Send a GET request to <ESP_IP>/update
|
||||||
server.on("/debug", HTTP_GET,
|
server.on("/debug", HTTP_GET, [](AsyncWebServerRequest* request) {
|
||||||
[](AsyncWebServerRequest* request) { request->send(200, "text/plain", "Debug: all OK."); });
|
if (WEBSERVER_AUTH_REQUIRED && !request->authenticate(http_username, http_password))
|
||||||
|
return request->requestAuthentication();
|
||||||
|
request->send(200, "text/plain", "Debug: all OK.");
|
||||||
|
});
|
||||||
|
|
||||||
// Route to handle reboot command
|
// Route to handle reboot command
|
||||||
server.on("/reboot", HTTP_GET, [](AsyncWebServerRequest* request) {
|
server.on("/reboot", HTTP_GET, [](AsyncWebServerRequest* request) {
|
||||||
|
if (WEBSERVER_AUTH_REQUIRED && !request->authenticate(http_username, http_password))
|
||||||
|
return request->requestAuthentication();
|
||||||
request->send(200, "text/plain", "Rebooting server...");
|
request->send(200, "text/plain", "Rebooting server...");
|
||||||
//TODO: Should we handle contactors gracefully? Ifdef CONTACTOR_CONTROL then what?
|
//TODO: Should we handle contactors gracefully? Ifdef CONTACTOR_CONTROL then what?
|
||||||
delay(1000);
|
delay(1000);
|
||||||
|
@ -789,6 +836,8 @@ String processor(const String& var) {
|
||||||
content += "<button onclick='Events()'>Events</button>";
|
content += "<button onclick='Events()'>Events</button>";
|
||||||
content += " ";
|
content += " ";
|
||||||
content += "<button onclick='askReboot()'>Reboot Emulator</button>";
|
content += "<button onclick='askReboot()'>Reboot Emulator</button>";
|
||||||
|
if (WEBSERVER_AUTH_REQUIRED)
|
||||||
|
content += "<button onclick='logout()'>Logout</button>";
|
||||||
content += "<script>";
|
content += "<script>";
|
||||||
content += "function OTA() { window.location.href = '/update'; }";
|
content += "function OTA() { window.location.href = '/update'; }";
|
||||||
content += "function Cellmon() { window.location.href = '/cellmonitor'; }";
|
content += "function Cellmon() { window.location.href = '/cellmonitor'; }";
|
||||||
|
@ -803,6 +852,15 @@ String processor(const String& var) {
|
||||||
content += " xhr.open('GET', '/reboot', true);";
|
content += " xhr.open('GET', '/reboot', true);";
|
||||||
content += " xhr.send();";
|
content += " xhr.send();";
|
||||||
content += "}";
|
content += "}";
|
||||||
|
if (WEBSERVER_AUTH_REQUIRED) {
|
||||||
|
content += "function logout() {";
|
||||||
|
content += " var xhr = new XMLHttpRequest();";
|
||||||
|
content += " xhr.open('GET', '/logout', true);";
|
||||||
|
content += " xhr.send();";
|
||||||
|
content += " setTimeout(function(){ window.open(\"/\",\"_self\"); }, 1000);";
|
||||||
|
content += "}";
|
||||||
|
}
|
||||||
|
|
||||||
content += "</script>";
|
content += "</script>";
|
||||||
|
|
||||||
//Script for refreshing page
|
//Script for refreshing page
|
||||||
|
|
|
@ -24,6 +24,8 @@ extern std::string password;
|
||||||
extern const uint8_t wifi_channel;
|
extern const uint8_t wifi_channel;
|
||||||
extern const char* ssidAP;
|
extern const char* ssidAP;
|
||||||
extern const char* passwordAP;
|
extern const char* passwordAP;
|
||||||
|
extern const char* http_username;
|
||||||
|
extern const char* http_password;
|
||||||
|
|
||||||
// Common charger parameters
|
// Common charger parameters
|
||||||
extern float charger_stat_HVcur;
|
extern float charger_stat_HVcur;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue