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