From af0327cc2eb3dc243795af20b943c48ad50af374 Mon Sep 17 00:00:00 2001
From: lenvm
Date: Wed, 15 Nov 2023 22:52:33 +0100
Subject: [PATCH] add initial version of webserver
---
Software/Software.ino | 6 +
Software/src/devboard/webserver/webserver.cpp | 180 ++++++++++++++++++
Software/src/devboard/webserver/webserver.h | 47 +++++
3 files changed, 233 insertions(+)
create mode 100644 Software/src/devboard/webserver/webserver.cpp
create mode 100644 Software/src/devboard/webserver/webserver.h
diff --git a/Software/Software.ino b/Software/Software.ino
index 9042202f7..7570cc279 100644
--- a/Software/Software.ino
+++ b/Software/Software.ino
@@ -6,6 +6,7 @@
#include "USER_SETTINGS.h"
#include "src/battery/BATTERIES.h"
#include "src/devboard/config.h"
+#include "src/devboard/webserver/webserver.h"
#include "src/inverter/INVERTERS.h"
#include "src/lib/adafruit-Adafruit_NeoPixel/Adafruit_NeoPixel.h"
#include "src/lib/eModbus-eModbus/Logging.h"
@@ -108,6 +109,8 @@ bool inverterAllowsContactorClosing = true;
void setup() {
init_serial();
+ init_WiFi();
+
init_CAN();
init_LED();
@@ -123,6 +126,9 @@ void setup() {
// Perform main program functions
void loop() {
+ // Webserver
+ run_webserver();
+
// Input
receive_can(); // Receive CAN messages. Runs as fast as possible
#ifdef DUAL_CAN
diff --git a/Software/src/devboard/webserver/webserver.cpp b/Software/src/devboard/webserver/webserver.cpp
new file mode 100644
index 000000000..224d23c88
--- /dev/null
+++ b/Software/src/devboard/webserver/webserver.cpp
@@ -0,0 +1,180 @@
+#include "webserver.h"
+
+// Replace with the credentials of the network that you want the devboard to connect with
+const char* ssid = "REPLACE_WITH_YOUR_SSID";
+const char* password = "REPLACE_WITH_YOUR_PASSWORD";
+
+// Set web server port number to 80
+WiFiServer server(80);
+
+String header; // Variable to store the HTTP request
+String wifi_state;
+bool wifi_connected;
+
+// Wifi connect time declarations and definition
+unsigned long wifi_connect_start_time;
+unsigned long wifi_connect_current_time;
+const long wifi_connect_timeout = 5000; // Timeout for WiFi connect in milliseconds
+
+// Webserver time declarations and definition
+unsigned long webserver_start_time; // Start time of webserver
+unsigned long webserver_current_time; // Current time of webserver
+const long webserver_timeout = 2000; // Timeout time of webserver in milliseconds
+
+void init_WiFi() {
+ // Configure WiFi
+ WiFi.mode(WIFI_AP_STA); // Simultaneous WiFi Access Point and WiFi STAtion
+ init_WiFi_AP();
+ init_WiFi_STA(ssid, password);
+
+ // Start webserver
+ server.begin();
+}
+
+void init_WiFi_AP() {
+ const char* ssidAP = "Battery Emulator"; // maximum of 63 characters;
+ const char* passwordAP = "123456789"; // minimum of 8 characters; set to NULL if you want the access point to be open
+ Serial.print("Creating Access Point: ");
+ Serial.println(ssidAP);
+ Serial.print("With password: ");
+ Serial.println(passwordAP);
+
+ WiFi.softAP(ssidAP, passwordAP);
+
+ IPAddress IP = WiFi.softAPIP();
+ Serial.println("Access Point created.");
+ Serial.print("IP address: ");
+ Serial.println(IP);
+}
+
+void init_WiFi_STA(const char* ssid, const char* password) {
+ // Connect to Wi-Fi network with SSID and password
+ Serial.print("Connecting to ");
+ Serial.println(ssid);
+ WiFi.begin(ssid, password);
+
+ wifi_connect_start_time = millis();
+ wifi_connect_current_time = wifi_connect_start_time;
+ while ((wifi_connect_current_time - wifi_connect_start_time) <= wifi_connect_timeout &&
+ WiFi.status() != WL_CONNECTED) { // do this loop for up to 5000ms
+ // to break the loop when the connection is not established (wrong ssid or password).
+ delay(500);
+ Serial.print(".");
+ wifi_connect_current_time = millis();
+ }
+ if (WiFi.status() == WL_CONNECTED) { // WL_CONNECTED is assigned when connected to a WiFi network
+ wifi_connected = true;
+ wifi_state = "connected";
+ // Print local IP address and start web server
+ Serial.println("");
+ Serial.print("Connected to WiFi network: ");
+ Serial.println(ssid);
+ Serial.print("IP address: ");
+ Serial.println(WiFi.localIP());
+ } else {
+ wifi_connected = false;
+ 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.");
+ }
+}
+
+void run_webserver() {
+ WiFiClient client = server.available(); // Listen for incoming clients
+
+ if (client) { // If a new client connects,
+ webserver_start_time = millis();
+ webserver_current_time = webserver_start_time;
+ Serial.println("New Client."); // print a message out in the serial port
+ String current_line = ""; // make a String to hold incoming data from the client
+ while (client.connected() &&
+ (webserver_current_time - webserver_start_time) <=
+ webserver_timeout) { // loop while the client is connected, and timeout is not reached
+ webserver_current_time = millis();
+ if (client.available()) { // if there's bytes to read from the client,
+ char c = client.read(); // read a byte, then
+ Serial.write(c); // print it out the serial monitor
+ header += c;
+ if (c == '\n') { // if the byte is a newline character
+ // if the current line is blank, you got two newline characters in a row.
+ // that's the end of the client HTTP request, so send a response:
+ if (current_line.length() == 0) {
+ // HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK)
+ // and a content-type so the client knows what's coming, then a blank line:
+ client.println("HTTP/1.1 200 OK");
+ client.println("Content-type:text/html");
+ client.println("Connection: close");
+ client.println();
+
+ // Display the HTML web page
+ client.println("");
+ client.println("");
+ client.println("");
+ // Set the background color and font-size attributes
+ client.println(
+ "");
+
+ // Web Page Heading
+ client.println("
Battery Emulator Web Server
");
+
+ // Display LED color
+ client.println("
LED color: ");
+ switch (LEDcolor) {
+ case GREEN:
+ client.println("GREEN
");
+ break;
+ case YELLOW:
+ client.println("YELLOW
");
+ break;
+ case BLUE:
+ client.println("BLUE");
+ break;
+ case RED:
+ client.println("RED");
+ break;
+ case TEST_ALL_COLORS:
+ client.println("RAINBOW");
+ break;
+ default:
+ break;
+ }
+
+ // Display ssid of network connected to and, if connected to the WiFi, its own IP
+ client.println("
SSID: " + String(ssid) + "
");
+ client.println("
status: " + wifi_state + "
");
+ if (wifi_connected == true) {
+ client.println("
IP: " + WiFi.localIP().toString() + "
");
+ }
+
+ // TODO: display battery hardware selected
+ // TODO: display emulated inverter communication protocol selected
+ // TODO: add option to add/change ssid and password and save, connect to the new ssid
+ // TODO: check if it is possible to list all available other ssids
+ // TODO: check if it is possible to always connect to the devboard with a predefined url (to not have the issue of not knowing the IP)
+ // TODO: display CAN state (indicate if there is a communication error)
+ // TODO: display battery errors in battery diagnosis tab
+ // TODO: display inverter errors in battery diagnosis tab
+ // TODO: add functionality to turn WiFi AP off
+
+ // The HTTP response ends with another blank line
+ client.println();
+ // Break out of the while loop
+ break;
+ } else { // if you got a newline, then clear current_line
+ current_line = "";
+ }
+ } else if (c != '\r') { // if you got anything else but a carriage return character,
+ current_line += c; // add it to the end of the current_line
+ }
+ }
+ }
+ // Clear the header variable
+ header = "";
+ // Close the connection
+ client.stop();
+ Serial.println("Client disconnected.");
+ Serial.println("");
+ }
+}
diff --git a/Software/src/devboard/webserver/webserver.h b/Software/src/devboard/webserver/webserver.h
new file mode 100644
index 000000000..95d6ae1c7
--- /dev/null
+++ b/Software/src/devboard/webserver/webserver.h
@@ -0,0 +1,47 @@
+#ifndef WEBSERVER_H
+#define WEBSERVER_H
+
+// Load Wi-Fi library
+#include
+#include "../config.h" // Needed for LED defines
+
+extern uint8_t LEDcolor; // Enum, 0-10
+
+/*
+ @brief Initialization function for creating WiFi Access Point and connecting to an existing WiFi network (WiFi STAtion).
+
+ @param[in] void
+
+ @return void
+ */
+void init_WiFi();
+
+/*
+ * @brief Initialization function that creates a WiFi Access Point.
+ *
+ * @param[in] void
+ *
+ * @return void
+ */
+void init_WiFi_AP();
+
+/*
+ * @brief Initialization function that connects to an existing network.
+ *
+ * @param[in] ssid WiFi network name
+ * @param[in] password WiFi network password
+ *
+ * @return void
+ */
+void init_WiFi_STA(const char* ssid, const char* password);
+
+/*
+ @brief Main webserver loop.
+
+ @param[in] void
+
+ @return void
+ */
+void run_webserver();
+
+#endif