diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..6f96ac11 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,12 @@ +# Dependabot checks for new versions of the dependencies used in the GitHub Actions used in this repository. +# Dependabot will raise pull requests for version updates for any outdated actions that it finds. After the initial +# version updates, Dependabot will continue to check for outdated versions of actions according to the schedule defined. + +version: 2 +updates: + # Enable version updates for GitHub Actions + - package-ecosystem: "github-actions" + directory: "/" + schedule: + # Check for updates to GitHub Actions every week + interval: "weekly" diff --git a/.github/workflows/run-pre-commit.yml b/.github/workflows/run-pre-commit.yml index aedd71f8..1b29384d 100644 --- a/.github/workflows/run-pre-commit.yml +++ b/.github/workflows/run-pre-commit.yml @@ -9,7 +9,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Run pre-commit - uses: pre-commit/action@v3.0.0 + uses: pre-commit/action@v3.0.1 diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index ee8d3b33..44c91fbc 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -35,7 +35,7 @@ Examples of unacceptable behavior include: address, without their explicit permission * Other conduct which could reasonably be considered inappropriate in a professional setting -* No excessive self-promotion +* Excessive self-promotion ## Enforcement Responsibilities diff --git a/Software/USER_SETTINGS.cpp b/Software/USER_SETTINGS.cpp index 7a286f90..c248b11a 100644 --- a/Software/USER_SETTINGS.cpp +++ b/Software/USER_SETTINGS.cpp @@ -36,5 +36,5 @@ const char* ssid = "REPLACE_WITH_YOUR_SSID"; // Maximum of 63 character const char* password = "REPLACE_WITH_YOUR_PASSWORD"; // Minimum of 8 characters; 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 -const char* versionNumber = "5.0.0"; // The current software version, shown on webserver +const char* versionNumber = "5.0.1"; // The current software version, shown on webserver #endif diff --git a/Software/src/battery/NISSAN-LEAF-BATTERY.cpp b/Software/src/battery/NISSAN-LEAF-BATTERY.cpp index b3df8531..7cd18000 100644 --- a/Software/src/battery/NISSAN-LEAF-BATTERY.cpp +++ b/Software/src/battery/NISSAN-LEAF-BATTERY.cpp @@ -369,8 +369,8 @@ void update_values_leaf_battery() { /* This function maps all the values fetched print_with_units(", Voltage: ", (battery_voltage * 0.1), "V "); print_with_units(", Max discharge power: ", max_target_discharge_power, "W "); print_with_units(", Max charge power: ", max_target_charge_power, "W "); - print_with_units(", Max temp: ", (temperature_max * 0.1), "°C "); - print_with_units(", Min temp: ", (temperature_min * 0.1), "°C "); + print_with_units(", Max temp: ", ((int16_t)temperature_max * 0.1), "°C "); + print_with_units(", Min temp: ", ((int16_t)temperature_min * 0.1), "°C "); Serial.println(""); Serial.print("BMS Status: "); if (bms_status == 3) { diff --git a/Software/src/devboard/webserver/webserver.cpp b/Software/src/devboard/webserver/webserver.cpp index 73324752..41a4516a 100644 --- a/Software/src/devboard/webserver/webserver.cpp +++ b/Software/src/devboard/webserver/webserver.cpp @@ -37,15 +37,21 @@ const char index_html[] PROGMEM = R"rawliteral( )rawliteral"; -String wifi_state; -bool wifi_connected; - // Wifi connect time declarations and definition -unsigned long wifi_connect_start_time; -unsigned long wifi_connect_current_time; -unsigned long wifi_connect_timeout = 5000; // Timeout for WiFi connect in milliseconds -unsigned long wifi_monitor_loop_time = 30000; // Will check if WiFi is connected and try reconnect every x milliseconds +const unsigned long MAX_WIFI_RECONNECT_BACKOFF_TIME = 60000; // Maximum backoff time of 1 minute +const unsigned long DEFAULT_WIFI_RECONNECT_BACKOFF_TIME = + 1000; // Default wifi reconnect backoff time. Start with 1 second +const unsigned long WIFI_CONNECT_TIMEOUT = 10000; // Timeout for WiFi connect in milliseconds +const unsigned long WIFI_MONITOR_LOOP_TIME = + 1000; // Will check if WiFi is connected and try reconnect every x milliseconds unsigned long last_wifi_monitor_run = 0; +unsigned long wifi_connect_start_time; +unsigned long wifi_reconnect_backoff_time = DEFAULT_WIFI_RECONNECT_BACKOFF_TIME; + +enum WiFiState { DISCONNECTED, CONNECTING, CONNECTED }; + +WiFiState wifi_state = + DISCONNECTED; //the esp library has no specific state to indicate if its connecting (only WL_IDLE_STATUS) so we keep track of it here void init_webserver() { // Configure WiFi @@ -250,79 +256,123 @@ void init_webserver() { #endif } +void print_wifi_status_message(wl_status_t status) { + switch (status) { + case WL_CONNECTED: + Serial.println("Connected to WiFi network: " + String(ssid)); + Serial.println("IP address: " + WiFi.localIP().toString()); + Serial.println("Signal Strength: " + String(WiFi.RSSI()) + " dBm"); + break; + case WL_CONNECT_FAILED: + Serial.println("Failed to connect to WiFi network: " + String(ssid)); + break; + case WL_CONNECTION_LOST: + Serial.println("Connection to WiFi network: " + String(ssid) + " lost"); + break; + case WL_DISCONNECTED: + Serial.println("Disconnected from WiFi network: " + String(ssid)); + break; + case WL_NO_SSID_AVAIL: + Serial.println("Could not find network with SSID: " + String(ssid)); + break; + case WL_IDLE_STATUS: + Serial.println("WiFi is in idle status. This can indicate it is currently trying to connect."); + break; + case WL_SCAN_COMPLETED: + Serial.println("WiFi scan completed"); + break; + case WL_NO_SHIELD: + Serial.println("No WiFi shield detected"); + break; + default: + Serial.println("Unknown WiFi status: " + String(status)); + break; + } +} + +// Function to handle WiFi reconnection. Use some timeouts and backoffs here to avoid flooding reconnection attempts/spamming the serial console +void handle_WiFi_reconnection(unsigned long currentMillis, wl_status_t status) { + if (wifi_state == CONNECTING && currentMillis - wifi_connect_start_time > WIFI_CONNECT_TIMEOUT) { + // we are here if we were trying to connect to wifi, but it took too long (more than configured timeout) + Serial.println("Failed to connect to WiFi network before timeout"); + print_wifi_status_message(status); + WiFi.disconnect(); //disconnect to clear any previous settings + wifi_state = DISCONNECTED; + wifi_connect_start_time = currentMillis; //reset the start time to now so backoff is respected on next try + // We use a backoff time before trying to connect again. Increase backoff time, up to a maximum + wifi_reconnect_backoff_time = min(wifi_reconnect_backoff_time * 2, MAX_WIFI_RECONNECT_BACKOFF_TIME); + Serial.println("Will try again in " + String(wifi_reconnect_backoff_time / 1000) + " seconds."); + } else if (wifi_state != CONNECTING && currentMillis - wifi_connect_start_time > wifi_reconnect_backoff_time) { + // we are here if the connection failed for some reason and the backoff time has now passed + print_wifi_status_message(status); + init_WiFi_STA(ssid, password); + } +} + +// Function to handle WiFi connection void WiFi_monitor_loop() { unsigned long currentMillis = millis(); - if (currentMillis - last_wifi_monitor_run > wifi_monitor_loop_time) { + if (currentMillis - last_wifi_monitor_run > WIFI_MONITOR_LOOP_TIME) { last_wifi_monitor_run = currentMillis; - if (WiFi.status() != WL_CONNECTED && wifi_state != "Connecting") { - wifi_connected = false; - wifi_state = "Not connected"; - Serial.print("Wifi disconnected. Attempting reconnection"); - init_WiFi_STA(ssid, password); - } else if (WiFi.status() == WL_CONNECTED && wifi_state != "Connected") { - wifi_connected = true; - wifi_state = "Connected"; - Serial.println("Wifi reconnected"); + wl_status_t status = WiFi.status(); + switch (status) { + case WL_CONNECTED: + if (wifi_state != CONNECTED) { //we need to update our own wifi state to indicate we are connected + wifi_reconnect_backoff_time = + DEFAULT_WIFI_RECONNECT_BACKOFF_TIME; // Reset backoff time after maintaining connection + wifi_state = CONNECTED; + print_wifi_status_message(status); + } + break; + case WL_CONNECT_FAILED: + case WL_CONNECTION_LOST: + case WL_DISCONNECTED: + case WL_NO_SSID_AVAIL: + handle_WiFi_reconnection(currentMillis, status); + break; + case WL_IDLE_STATUS: //this means the wifi is not ready to process any commands (it's probably trying to connect). do nothing + + case WL_SCAN_COMPLETED: //this will only be set when scanning for networks. We don't do that yet + case WL_NO_SHIELD: //should not happen, this means no wifi chip detected, so we can't do much + break; } } } +// Function to initialize WiFi in Station Mode (i.e. connect to another access point) +void init_WiFi_STA(const char* ssid, const char* password) { + Serial.println("Connecting to: " + String(ssid)); + wifi_state = CONNECTING; + WiFi.begin(ssid, password); + WiFi.setAutoReconnect(true); + wifi_connect_start_time = millis(); +} + +// Function to convert WiFiState enum to String +String wifi_state_to_string(WiFiState state) { + switch (state) { + case DISCONNECTED: + return "Disconnected"; + case CONNECTING: + return "Connecting"; + case CONNECTED: + return "Connected"; + default: + return "Unknown"; + } +} + +// Function to initialize WiFi in Access Point Mode void init_WiFi_AP() { - Serial.print("Creating Access Point: "); - Serial.println(ssidAP); - Serial.print("With password: "); - Serial.println(passwordAP); - + Serial.println("Creating Access Point: " + String(ssidAP)); + Serial.println("With password: " + String(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) { - // If we're already connected, there's nothing to do - if (WiFi.status() == WL_CONNECTED) { - if (wifi_state != "Connected") { - 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()); - } - return; - } - - // If we're not currently trying to connect, start the connection process - if (wifi_state != "Connecting") { - Serial.print("Connecting to: "); - Serial.println(ssid); - WiFi.begin(ssid, password); - wifi_state = "Connecting"; - wifi_connect_start_time = millis(); - return; - } - - // If we've been trying to connect for more than 5000ms, give up - if (millis() - wifi_connect_start_time > wifi_connect_timeout) { - wifi_state = "Not connected"; - Serial.print("Failed to connect to WiFi network: "); - Serial.println(ssid); - Serial.println("Please check WiFi network name and password, and if WiFi network is available."); - Serial.print("Will try again in "); - Serial.print((wifi_monitor_loop_time - (millis() - last_wifi_monitor_run)) / 1000); - Serial.println(" seconds."); - return; - } - - // Otherwise, just print a dot to indicate that we're still trying to connect - Serial.print("."); + Serial.println("IP address: " + IP.toString()); } +// Function to initialize ElegantOTA void init_ElegantOTA() { ElegantOTA.begin(&server); // Start ElegantOTA // ElegantOTA callbacks @@ -368,8 +418,8 @@ String processor(const String& var) { } // Display ssid of network connected to and, if connected to the WiFi, its own IP content += "

SSID: " + String(ssid) + "

"; - content += "

Wifi status: " + wifi_state + "

"; - if (wifi_connected == true) { + content += "

Wifi status: " + wifi_state_to_string(wifi_state) + "

"; + if (WiFi.status() == WL_CONNECTED) { content += "

IP: " + WiFi.localIP().toString() + "

"; // Get and display the signal strength (RSSI) content += "

Signal Strength: " + String(WiFi.RSSI()) + " dBm

"; diff --git a/Software/src/devboard/webserver/webserver.h b/Software/src/devboard/webserver/webserver.h index f9043c6f..79ac2646 100644 --- a/Software/src/devboard/webserver/webserver.h +++ b/Software/src/devboard/webserver/webserver.h @@ -90,6 +90,15 @@ void init_WiFi_STA(const char* ssid, const char* password); */ void WiFi_monitor_loop(); +// /** +// * @brief Function to handle WiFi reconnection. +// * +// * @param[in] void +// * +// * @return void +// */ +// void handle_WiFi_reconnection(unsigned long currentMillis); + /** * @brief Initialization function for ElegantOTA. *