diff --git a/Software/Software.ino b/Software/Software.ino index 6ba1b4a4..a0d4ac34 100644 --- a/Software/Software.ino +++ b/Software/Software.ino @@ -25,6 +25,8 @@ #include "src/datalayer/datalayer.h" +#ifdef WIFI +#include "src/devboard/wifi/wifi.h" #ifdef WEBSERVER #include "src/devboard/webserver/webserver.h" #ifdef MDNSRESPONDER @@ -35,6 +37,7 @@ #error WEBSERVER needs to be enabled for MDNSRESPONDER! #endif // MDNSRSPONDER #endif // WEBSERVER +#endif // WIFI Preferences settings; // Store user settings // The current software version, shown on webserver @@ -129,7 +132,7 @@ void setup() { init_stored_settings(); -#ifdef WEBSERVER +#ifdef WIFI xTaskCreatePinnedToCore((TaskFunction_t)&connectivity_loop, "connectivity_loop", 4096, &connectivity_task_time_us, TASK_CONNECTIVITY_PRIO, &connectivity_loop_task, WIFI_CORE); #endif @@ -171,10 +174,16 @@ void loop() { #endif } -#ifdef WEBSERVER +#ifdef WIFI void connectivity_loop(void* task_time_us) { - // Init + + // Init wifi + init_WiFi(); + +#ifdef WEBSERVER + // Init webserver init_webserver(); +#endif #ifdef MDNSRESPONDER init_mDNS(); #endif @@ -185,6 +194,9 @@ void connectivity_loop(void* task_time_us) { while (true) { START_TIME_MEASUREMENT(wifi); wifi_monitor(); +#ifdef WEBSERVER + ota_monitor(); +#endif END_TIME_MEASUREMENT_MAX(wifi, datalayer.system.status.wifi_task_10s_max_us); #ifdef MQTT START_TIME_MEASUREMENT(mqtt); @@ -298,27 +310,6 @@ void core_loop(void* task_time_us) { } } -#ifdef MDNSRESPONDER -// Initialise mDNS -void init_mDNS() { - - // Calulate the host name using the last two chars from the MAC address so each one is likely unique on a network. - // e.g batteryemulator8C.local where the mac address is 08:F9:E0:D1:06:8C - String mac = WiFi.macAddress(); - String mdnsHost = "batteryemulator" + mac.substring(mac.length() - 2); - - // Initialize mDNS .local resolution - if (!MDNS.begin(mdnsHost)) { -#ifdef DEBUG_VIA_USB - Serial.println("Error setting up MDNS responder!"); -#endif - } else { - // Advertise via bonjour the service so we can auto discover these battery emulators on the local network. - MDNS.addService("battery_emulator", "tcp", 80); - } -} -#endif // MDNSRESPONDER - // Initialization functions void init_serial() { // Init Serial monitor diff --git a/Software/USER_SETTINGS.cpp b/Software/USER_SETTINGS.cpp index 82d9ad7a..d3054709 100644 --- a/Software/USER_SETTINGS.cpp +++ b/Software/USER_SETTINGS.cpp @@ -1,6 +1,7 @@ #include "USER_SETTINGS.h" #include #include "src/devboard/hal/hal.h" + /* This file contains all the battery settings and limits */ /* They can be defined here, or later on in the WebUI */ /* Most important is to select which CAN interface each component is connected to */ @@ -18,22 +19,34 @@ volatile CAN_Configuration can_config = { .charger = CAN_NATIVE // (OPTIONAL) Which CAN is your charger connected to? }; -#ifdef WEBSERVER +#ifdef WIFI + volatile uint8_t AccessPointEnabled = true; //Set to either true/false to enable direct wifi access point std::string ssid = "REPLACE_WITH_YOUR_SSID"; // Maximum of 63 characters 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* 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 + +#ifdef WIFICONFIG +// Set your Static IP address +IPAddress local_IP(192, 168, 10, 150); +// Set your Gateway IP address +IPAddress gateway(192, 168, 10, 1); +// Set your Subnet IP address +IPAddress subnet(255, 255, 255, 0); +#endif +#ifdef WEBSERVER const char* http_username = "admin"; // username to webserver authentication; -const char* http_password = "admin"; // password to webserver authentication; +const char* http_password = "admin"; // password to webserver authentication; // MQTT #ifdef MQTT -const char* mqtt_user = "REDACTED"; // Set NULL for no username +const char* mqtt_user = "REDACTED"; // Set NULL for no username const char* mqtt_password = "REDACTED"; // Set NULL for no password -#endif // USE_MQTT -#endif // WEBSERVER +#endif // USE_MQTT +#endif // WEBSERVER +#endif // WIFI /* Charger settings (Optional, when using generator charging) */ volatile float CHARGER_SET_HV = 384; // Reasonably appropriate 4.0v per cell charging of a 96s pack diff --git a/Software/USER_SETTINGS.h b/Software/USER_SETTINGS.h index b43581f1..02de686b 100644 --- a/Software/USER_SETTINGS.h +++ b/Software/USER_SETTINGS.h @@ -1,5 +1,6 @@ #ifndef __USER_SETTINGS_H__ #define __USER_SETTINGS_H__ +#include #include /* This file contains all the battery/inverter protocol settings Battery-Emulator software */ @@ -55,6 +56,8 @@ //#define USE_CANFD_INTERFACE_AS_CLASSIC_CAN // Enable this line if you intend to use the CANFD as normal CAN //#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 WIFI +//#define WIFICONFIG //Enable this line to set a static IP address / gateway /subnet mask for the device. see USER_SETTINGS.cpp for the 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. @@ -116,4 +119,12 @@ extern volatile float CHARGER_END_A; extern bool charger_HV_enabled; extern bool charger_aux12V_enabled; +#ifdef WIFICONFIG +extern IPAddress local_IP; +// Set your Gateway IP address +extern IPAddress gateway; +// Set your Subnet IP address +extern IPAddress subnet; +#endif + #endif // __USER_SETTINGS_H__ diff --git a/Software/src/devboard/utils/events.cpp b/Software/src/devboard/utils/events.cpp index 7ed7b121..fa9e4cb4 100644 --- a/Software/src/devboard/utils/events.cpp +++ b/Software/src/devboard/utils/events.cpp @@ -201,6 +201,8 @@ void init_events(void) { events.entries[EVENT_RESET_CPU_LOCKUP].level = EVENT_LEVEL_WARNING; events.entries[EVENT_PAUSE_BEGIN].level = EVENT_LEVEL_WARNING; events.entries[EVENT_PAUSE_END].level = EVENT_LEVEL_INFO; + events.entries[EVENT_WIFI_CONNECT].level = EVENT_LEVEL_INFO; + events.entries[EVENT_WIFI_DISCONNECT].level = EVENT_LEVEL_INFO; events.entries[EVENT_EEPROM_WRITE].log = false; // Don't log the logger... @@ -376,6 +378,10 @@ const char* get_event_message_string(EVENTS_ENUM_TYPE event) { return "Warning: The emulator is trying to pause the battery."; case EVENT_PAUSE_END: return "Info: The emulator is attempting to resume battery operation from pause."; + case EVENT_WIFI_CONNECT: + return "Info: Wifi connected."; + case EVENT_WIFI_DISCONNECT: + return "Info: Wifi disconnected."; default: return ""; } diff --git a/Software/src/devboard/utils/events.h b/Software/src/devboard/utils/events.h index b536790f..c4404e79 100644 --- a/Software/src/devboard/utils/events.h +++ b/Software/src/devboard/utils/events.h @@ -96,6 +96,8 @@ XX(EVENT_RESET_CPU_LOCKUP) \ XX(EVENT_PAUSE_BEGIN) \ XX(EVENT_PAUSE_END) \ + XX(EVENT_WIFI_CONNECT) \ + XX(EVENT_WIFI_DISCONNECT) \ XX(EVENT_NOF_EVENTS) typedef enum { EVENTS_ENUM_TYPE(GENERATE_ENUM) } EVENTS_ENUM_TYPE; diff --git a/Software/src/devboard/webserver/webserver.cpp b/Software/src/devboard/webserver/webserver.cpp index ff1ac892..7935ce01 100644 --- a/Software/src/devboard/webserver/webserver.cpp +++ b/Software/src/devboard/webserver/webserver.cpp @@ -17,39 +17,12 @@ unsigned long ota_progress_millis = 0; #include "index_html.cpp" #include "settings_html.h" -enum WifiState { - INIT, //before connecting first time - RECONNECTING, //we've connected before, but lost connection - CONNECTED //we are connected -}; - -WifiState wifi_state = INIT; - MyTimer ota_timeout_timer = MyTimer(15000); bool ota_active = false; -unsigned const long WIFI_MONITOR_INTERVAL_TIME = 15000; -unsigned const long INIT_WIFI_CONNECT_TIMEOUT = 8000; // Timeout for initial WiFi connect in milliseconds -unsigned const long DEFAULT_WIFI_RECONNECT_INTERVAL = 1000; // Default WiFi reconnect interval in ms -unsigned const long MAX_WIFI_RETRY_INTERVAL = 90000; // Maximum wifi retry interval in ms -unsigned long last_wifi_monitor_time = millis(); //init millis so wifi monitor doesn't run immediately -unsigned long wifi_reconnect_interval = DEFAULT_WIFI_RECONNECT_INTERVAL; -unsigned long last_wifi_attempt_time = millis(); //init millis so wifi monitor doesn't run immediately const char get_firmware_info_html[] = R"rawliteral(%X%)rawliteral"; void init_webserver() { - // Configure WiFi -#ifdef WIFIAP - if (AccessPointEnabled) { - WiFi.mode(WIFI_AP_STA); // Simultaneous WiFi AP and Router connection - init_WiFi_AP(); - } else { - WiFi.mode(WIFI_STA); // Only Router connection - } -#else - WiFi.mode(WIFI_STA); // Only Router connection -#endif // WIFIAP - init_WiFi_STA(ssid.c_str(), password.c_str(), wifi_channel); String content = index_html; @@ -352,29 +325,8 @@ void init_webserver() { // Start server server.begin(); - -#ifdef MQTT - // Init MQTT - init_mqtt(); -#endif // MQTT } -#ifdef WIFIAP -void init_WiFi_AP() { -#ifdef DEBUG_VIA_USB - Serial.println("Creating Access Point: " + String(ssidAP)); - Serial.println("With password: " + String(passwordAP)); -#endif // DEBUG_VIA_USB - WiFi.softAP(ssidAP, passwordAP); - IPAddress IP = WiFi.softAPIP(); -#ifdef DEBUG_VIA_USB - Serial.println("Access Point created."); - Serial.print("IP address: "); - Serial.println(IP); -#endif // DEBUG_VIA_USB -} -#endif // WIFIAP - String getConnectResultString(wl_status_t status) { switch (status) { case WL_CONNECTED: @@ -398,42 +350,7 @@ String getConnectResultString(wl_status_t status) { } } -void wifi_monitor() { - unsigned long currentMillis = millis(); - if (currentMillis - last_wifi_monitor_time > WIFI_MONITOR_INTERVAL_TIME) { - last_wifi_monitor_time = currentMillis; - wl_status_t status = WiFi.status(); - if (status != WL_CONNECTED && status != WL_IDLE_STATUS) { -#ifdef DEBUG_VIA_USB - Serial.println(getConnectResultString(status)); -#endif // DEBUG_VIA_USB - if (wifi_state == INIT) { //we haven't been connected yet, try the init logic - init_WiFi_STA(ssid.c_str(), password.c_str(), wifi_channel); - } else { //we were connected before, try the reconnect logic - if (currentMillis - last_wifi_attempt_time > wifi_reconnect_interval) { - last_wifi_attempt_time = currentMillis; -#ifdef DEBUG_VIA_USB - Serial.println("WiFi not connected, trying to reconnect..."); -#endif // DEBUG_VIA_USB - wifi_state = RECONNECTING; - WiFi.reconnect(); - wifi_reconnect_interval = min(wifi_reconnect_interval * 2, MAX_WIFI_RETRY_INTERVAL); - } - } - } else if (status == WL_CONNECTED && wifi_state != CONNECTED) { - wifi_state = CONNECTED; - wifi_reconnect_interval = DEFAULT_WIFI_RECONNECT_INTERVAL; -// Print local IP address and start web server -#ifdef DEBUG_VIA_USB - Serial.print("Connected to WiFi network: " + String(ssid.c_str())); - Serial.print(" IP address: " + WiFi.localIP().toString()); - Serial.print(" Signal Strength: " + String(WiFi.RSSI()) + " dBm"); - Serial.println(" Channel: " + String(WiFi.channel())); - Serial.println(" Hostname: " + String(WiFi.getHostname())); -#endif // DEBUG_VIA_USB - } - } - +void ota_monitor() { if (ota_active && ota_timeout_timer.elapsed()) { // OTA timeout, try to restore can and clear the update event set_event(EVENT_OTA_UPDATE_TIMEOUT, 0); @@ -441,20 +358,6 @@ void wifi_monitor() { } } -void init_WiFi_STA(const char* ssid, const char* password, const uint8_t wifi_channel) { -// Connect to Wi-Fi network with SSID and password -#ifdef DEBUG_VIA_USB - Serial.print("Connecting to "); - Serial.println(ssid); -#endif // DEBUG_VIA_USB - WiFi.begin(ssid, password, wifi_channel); - WiFi.setAutoReconnect(true); // Enable auto reconnect - wl_status_t result = static_cast(WiFi.waitForConnectResult(INIT_WIFI_CONNECT_TIMEOUT)); - if (result) { - //TODO: Add event or serial print? - } -} - // Function to initialize ElegantOTA void init_ElegantOTA() { ElegantOTA.begin(&server); // Start ElegantOTA diff --git a/Software/src/devboard/webserver/webserver.h b/Software/src/devboard/webserver/webserver.h index e447f9a3..9f76379a 100644 --- a/Software/src/devboard/webserver/webserver.h +++ b/Software/src/devboard/webserver/webserver.h @@ -6,27 +6,18 @@ #include "../../include.h" #include "../../lib/YiannisBourkelis-Uptime-Library/src/uptime_formatter.h" #include "../../lib/ayushsharma82-ElegantOTA/src/ElegantOTA.h" -#ifdef MQTT -#include "../../lib/knolleary-pubsubclient/PubSubClient.h" -#endif #include "../../lib/me-no-dev-AsyncTCP/src/AsyncTCP.h" #include "../../lib/me-no-dev-ESPAsyncWebServer/src/ESPAsyncWebServer.h" #include "../../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h" -#ifdef MQTT -#include "../mqtt/mqtt.h" -#endif extern const char* version_number; // The current software version, shown on webserver #include -extern std::string ssid; -extern std::string password; -extern const uint8_t wifi_channel; -extern const char* ssidAP; -extern const char* passwordAP; extern const char* http_username; extern const char* http_password; +extern const char* ssidAP; + // Common charger parameters extern float charger_stat_HVcur; extern float charger_stat_HVvol; @@ -47,36 +38,6 @@ extern uint16_t OBC_Charge_Power; */ void init_webserver(); -/** - * @brief Monitoring loop for WiFi. Will attempt to reconnect to access point if the connection goes down. - * - * @param[in] void - * - * @return void - */ -void wifi_monitor(); - -#ifdef WIFIAP -/** - * @brief Initialization function that creates a WiFi Access Point. - * - * @param[in] void - * - * @return void - */ -void init_WiFi_AP(); -#endif // WIFIAP - -/** - * @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, const uint8_t channel); - // /** // * @brief Function to handle WiFi reconnection. // * @@ -145,4 +106,6 @@ String formatPowerValue(String label, T value, String unit, int precision); extern void storeSettings(); +void ota_monitor(); + #endif diff --git a/Software/src/devboard/wifi/wifi.cpp b/Software/src/devboard/wifi/wifi.cpp new file mode 100644 index 00000000..14df1391 --- /dev/null +++ b/Software/src/devboard/wifi/wifi.cpp @@ -0,0 +1,174 @@ +#include "wifi.h" +#include "../../include.h" +#include "../utils/events.h" + + +// Configuration Parameters +static const uint16_t WIFI_CHECK_INTERVAL = 5000; // 5 seconds +static const uint16_t INIT_WIFI_FULL_RECONNECT_INTERVAL = 10000; // 10 seconds +static const uint16_t MAX_WIFI_FULL_RECONNECT_INTERVAL = 60000; // 60 seconds +static const uint16_t STEP_WIFI_FULL_RECONNECT_INTERVAL = 5000; // 5 seconds +static const uint16_t MAX_RECONNECT_ATTEMPTS = 3; // Maximum number of reconnect attempts before forcing a full connection + +// State variables +static unsigned long lastReconnectAttempt = 0; +static unsigned long lastWiFiCheck = 0; +static bool hasConnectedBefore = false; +static uint16_t reconnectAttempts = 0; // Counter for reconnect attempts +static uint16_t current_full_reconnect_interval = INIT_WIFI_FULL_RECONNECT_INTERVAL; + +void init_WiFi() { + Serial.begin(115200); + +#ifdef WIFIAP + if (AccessPointEnabled) { + WiFi.mode(WIFI_AP_STA); // Simultaneous WiFi AP and Router connection + init_WiFi_AP(); + } else { + WiFi.mode(WIFI_STA); // Only Router connection + } +#else + WiFi.mode(WIFI_STA); // Only Router connection +#endif // WIFIAP + + // Set WiFi to auto reconnect + WiFi.setAutoReconnect(true); + +#ifdef WIFICONFIG + // Set static IP + WiFi.config(local_IP, gateway, subnet); +#endif + + // Initialize Wi-Fi event handlers + WiFi.onEvent(onWifiConnect, WiFiEvent_t::ARDUINO_EVENT_WIFI_STA_CONNECTED); + WiFi.onEvent(onWifiDisconnect, WiFiEvent_t::ARDUINO_EVENT_WIFI_STA_DISCONNECTED); + WiFi.onEvent(onWifiGotIP, WiFiEvent_t::ARDUINO_EVENT_WIFI_STA_GOT_IP); + + // Start Wi-Fi connection + connectToWiFi(); + +} + +// Task to monitor Wi-Fi status and handle reconnections +void wifi_monitor() { + unsigned long currentMillis = millis(); + + // Check if it's time to monitor the Wi-Fi status + if (currentMillis - lastWiFiCheck > WIFI_CHECK_INTERVAL) { + lastWiFiCheck = currentMillis; + + wl_status_t status = WiFi.status(); + if (status != WL_CONNECTED ) { + Serial.println("Wi-Fi not connected, attempting to reconnect..."); + + // Try WiFi.reconnect() if it was successfully connected at least once + if (hasConnectedBefore) { + if (WiFi.reconnect()) { + Serial.println("Wi-Fi reconnect attempt..."); + reconnectAttempts = 0; // Reset the attempt counter on successful reconnect + } else { + reconnectAttempts++; + if (reconnectAttempts >= MAX_RECONNECT_ATTEMPTS) { + Serial.println("Failed to reconnect multiple times, forcing a full connection attempt..."); + FullReconnectToWiFi(); + } + } + } else { + // If no previous connection, force a full connection attempt + if (currentMillis - lastReconnectAttempt > current_full_reconnect_interval) { + Serial.println("No previous OK connection, force a full connection attempt..."); + FullReconnectToWiFi(); + } + } + } + } + +} + +// Function to force a full reconnect to Wi-Fi +static void FullReconnectToWiFi() { + + // Increase the current reconnect interval if it's not at the maximum + if (current_full_reconnect_interval + STEP_WIFI_FULL_RECONNECT_INTERVAL <= MAX_WIFI_FULL_RECONNECT_INTERVAL) { + current_full_reconnect_interval += STEP_WIFI_FULL_RECONNECT_INTERVAL; + } + hasConnectedBefore = false; // Reset the flag to force a full reconnect + lastReconnectAttempt = millis(); // Reset the reconnect attempt timer + WiFi.disconnect(); //force disconnect from the current network + connectToWiFi(); //force a full connection attempt +} + +// Function to handle Wi-Fi connection +static void connectToWiFi() { + if (WiFi.status() != WL_CONNECTED) { + Serial.println("Connecting to Wi-Fi..."); + WiFi.begin( ssid.c_str(), password.c_str(),wifi_channel); + } else { + Serial.println("Wi-Fi already connected."); + } +} + +// Event handler for successful Wi-Fi connection +static void onWifiConnect(WiFiEvent_t event, WiFiEventInfo_t info) { + set_event(EVENT_WIFI_CONNECT, 0); + Serial.println("Wi-Fi connected."); + Serial.print("IP address: "); + Serial.println(WiFi.localIP()); + hasConnectedBefore = true; // Mark as successfully connected at least once + reconnectAttempts = 0; // Reset the attempt counter + current_full_reconnect_interval = INIT_WIFI_FULL_RECONNECT_INTERVAL; // Reset the full reconnect interval + clear_event(EVENT_WIFI_CONNECT); + +} + +// Event handler for Wi-Fi Got IP +static void onWifiGotIP(WiFiEvent_t event, WiFiEventInfo_t info) { + Serial.println("Wi-Fi Got IP."); + Serial.print("IP address: "); + Serial.println(WiFi.localIP()); +} + +// Event handler for Wi-Fi disconnection +static void onWifiDisconnect(WiFiEvent_t event, WiFiEventInfo_t info) { + set_event(EVENT_WIFI_DISCONNECT, 0); + Serial.println("Wi-Fi disconnected."); + lastReconnectAttempt = millis(); // Reset reconnection attempt timer + clear_event(EVENT_WIFI_DISCONNECT); +} + +#ifdef MDNSRESPONDER +// Initialise mDNS +void init_mDNS() { + + // Calulate the host name using the last two chars from the MAC address so each one is likely unique on a network. + // e.g batteryemulator8C.local where the mac address is 08:F9:E0:D1:06:8C + String mac = WiFi.macAddress(); + String mdnsHost = "batteryemulator" + mac.substring(mac.length() - 2); + + // Initialize mDNS .local resolution + if (!MDNS.begin(mdnsHost)) { +#ifdef DEBUG_VIA_USB + Serial.println("Error setting up MDNS responder!"); +#endif + } else { + // Advertise via bonjour the service so we can auto discover these battery emulators on the local network. + MDNS.addService("battery_emulator", "tcp", 80); + } +} +#endif // MDNSRESPONDER + +#ifdef WIFIAP +void init_WiFi_AP() { +#ifdef DEBUG_VIA_USB + Serial.println("Creating Access Point: " + String(ssidAP)); + Serial.println("With password: " + String(passwordAP)); +#endif // DEBUG_VIA_USB + WiFi.softAP(ssidAP, passwordAP); + IPAddress IP = WiFi.softAPIP(); +#ifdef DEBUG_VIA_USB + Serial.println("Access Point created."); + Serial.print("IP address: "); + Serial.println(IP); +#endif // DEBUG_VIA_USB +} +#endif // WIFIAP \ No newline at end of file diff --git a/Software/src/devboard/wifi/wifi.h b/Software/src/devboard/wifi/wifi.h new file mode 100644 index 00000000..26cdd424 --- /dev/null +++ b/Software/src/devboard/wifi/wifi.h @@ -0,0 +1,35 @@ +#ifndef WIFI_H +#define WIFI_H + +#include +#include "../../include.h" +#include + +extern std::string ssid; +extern std::string password; +extern const uint8_t wifi_channel; +extern const char* ssidAP; +extern const char* passwordAP; + + +void init_WiFi(); +void wifi_monitor(); +static void connectToWiFi(); +static void FullReconnectToWiFi(); +static void onWifiConnect(WiFiEvent_t event, WiFiEventInfo_t info); +static void onWifiDisconnect(WiFiEvent_t event, WiFiEventInfo_t info); +static void onWifiGotIP(WiFiEvent_t event, WiFiEventInfo_t info); + + + +#ifdef WIFIAP +void init_WiFi_AP(); +#endif // WIFIAP + +#ifdef MDNSRESPONDER +// Initialise mDNS +void init_mDNS(); +#endif // MDNSRESPONDER + + +#endif