Skip to content

Commit

Permalink
add initial version of webserver
Browse files Browse the repository at this point in the history
  • Loading branch information
lenvm committed Nov 16, 2023
1 parent 179b8ee commit af0327c
Show file tree
Hide file tree
Showing 3 changed files with 233 additions and 0 deletions.
6 changes: 6 additions & 0 deletions Software/Software.ino
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -108,6 +109,8 @@ bool inverterAllowsContactorClosing = true;
void setup() {
init_serial();

init_WiFi();

init_CAN();

init_LED();
Expand All @@ -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
Expand Down
180 changes: 180 additions & 0 deletions Software/src/devboard/webserver/webserver.cpp
Original file line number Diff line number Diff line change
@@ -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("<!DOCTYPE html><html>");
client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");
client.println("<link rel=\"icon\" href=\"data:,\">");
// Set the background color and font-size attributes
client.println(
"<style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: "
"center;</style></head>");

// Web Page Heading
client.println("<body><h1>Battery Emulator Web Server</h1>");

// Display LED color
client.println("<p>LED color: ");
switch (LEDcolor) {
case GREEN:
client.println("GREEN</p>");
break;
case YELLOW:
client.println("YELLOW</p>");
break;
case BLUE:
client.println("BLUE</p>");
break;
case RED:
client.println("RED</p>");
break;
case TEST_ALL_COLORS:
client.println("RAINBOW</p>");
break;
default:
break;
}

// Display ssid of network connected to and, if connected to the WiFi, its own IP
client.println("<p>SSID: " + String(ssid) + "</p>");
client.println("<p>status: " + wifi_state + "</p>");
if (wifi_connected == true) {
client.println("<p>IP: " + WiFi.localIP().toString() + "</p>");
}

// 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("");
}
}
47 changes: 47 additions & 0 deletions Software/src/devboard/webserver/webserver.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#ifndef WEBSERVER_H
#define WEBSERVER_H

// Load Wi-Fi library
#include <WiFi.h>
#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

0 comments on commit af0327c

Please sign in to comment.