firmware/src/mesh/http/WiFiAPClient.cpp

385 lines
12 KiB
C++
Raw Normal View History

#include "mesh/http/WiFiAPClient.h"
#include "NodeDB.h"
2022-01-04 01:35:20 +00:00
#include "RTC.h"
#include "concurrency/Periodic.h"
#include "configuration.h"
#include "main.h"
#include "mesh/http/WebServer.h"
#include "mesh/wifi/WiFiServerAPI.h"
#include "mqtt/MQTT.h"
#include "target_specific.h"
2020-09-19 01:02:56 +00:00
#include <DNSServer.h>
2020-10-19 04:39:02 +00:00
#include <ESPmDNS.h>
#include <esp_wifi.h>
2020-09-19 01:51:42 +00:00
#include <WiFi.h>
2021-12-29 03:24:10 +00:00
#include <WiFiUdp.h>
2022-04-14 02:23:35 +00:00
#ifndef DISABLE_NTP
#include <NTPClient.h>
#endif
using namespace concurrency;
static void WiFiEvent(WiFiEvent_t event);
2020-09-26 07:01:02 +00:00
// DNS Server for the Captive Portal
2020-09-18 22:33:03 +00:00
DNSServer dnsServer;
2020-09-26 07:01:02 +00:00
2021-12-29 03:24:10 +00:00
// NTP
WiFiUDP ntpUDP;
2022-04-14 02:23:35 +00:00
#ifndef DISABLE_NTP
NTPClient timeClient(ntpUDP, config.network.ntp_server);
2022-04-14 02:23:35 +00:00
#endif
2021-12-29 03:24:10 +00:00
uint8_t wifiDisconnectReason = 0;
// Stores our hostname
2020-10-19 04:39:02 +00:00
char ourHost[16];
2020-12-13 02:33:52 +00:00
bool forcedSoftAP = 0;
bool APStartupComplete = 0;
static bool needReconnect = true; // If we create our reconnector, run it once at the beginning
// FIXME, veto light sleep if we have a TCP server running
#if 0
class WifiSleepObserver : public Observer<uint32_t> {
protected:
/// Return 0 if sleep is okay
virtual int onNotify(uint32_t newValue) {
}
};
static WifiSleepObserver wifiSleepObserver;
//preflightSleepObserver.observe(&preflightSleep);
#endif
static int32_t reconnectWiFi()
{
const char *wifiName = config.network.wifi_ssid;
const char *wifiPsw = config.network.wifi_psk;
2021-12-29 03:24:10 +00:00
if (config.network.wifi_enabled && needReconnect && !WiFi.isConnected()) {
2022-05-07 10:31:21 +00:00
// if (radioConfig.has_preferences && needReconnect && !WiFi.isConnected()) {
if (!*wifiPsw) // Treat empty password as no password
wifiPsw = NULL;
if (*wifiName) {
needReconnect = false;
DEBUG_MSG("... Reconnecting to WiFi access point\n");
WiFi.mode(WIFI_MODE_STA);
WiFi.begin(wifiName, wifiPsw);
2021-12-29 03:24:10 +00:00
// Starting timeClient;
}
}
2022-04-14 02:23:35 +00:00
#ifndef DISABLE_NTP
2022-01-04 01:35:20 +00:00
if (WiFi.isConnected()) {
2021-12-29 03:24:10 +00:00
DEBUG_MSG("Updating NTP time\n");
2022-01-04 01:35:20 +00:00
if (timeClient.update()) {
DEBUG_MSG("NTP Request Success - Setting RTCQualityNTP if needed\n");
struct timeval tv;
tv.tv_sec = timeClient.getEpochTime();
tv.tv_usec = 0;
perhapsSetRTC(RTCQualityNTP, &tv);
2021-12-29 03:24:10 +00:00
2022-01-04 01:35:20 +00:00
} else {
DEBUG_MSG("NTP Update failed\n");
}
2021-12-29 03:24:10 +00:00
}
2022-04-14 02:23:35 +00:00
#endif
2021-12-29 03:24:10 +00:00
return 43200 * 1000; // every 12 hours
}
static Periodic *wifiReconnect;
2020-12-13 05:43:01 +00:00
bool isSoftAPForced()
{
2020-12-13 03:09:58 +00:00
return forcedSoftAP;
}
2020-09-19 01:51:42 +00:00
bool isWifiAvailable()
{
2020-12-13 02:33:52 +00:00
if (config.network.wifi_enabled && ((config.network.wifi_ssid[0]) || forcedSoftAP)) {
2021-05-24 01:42:25 +00:00
return true;
} else {
2021-05-24 01:42:25 +00:00
return false;
}
}
// Disable WiFi
2020-09-15 03:27:49 +00:00
void deinitWifi()
{
/*
Note from Jm (jm@casler.org - Sept 16, 2020):
A bug in the ESP32 SDK was introduced in Oct 2019 that keeps the WiFi radio from
turning back on after it's shut off. See:
https://github.com/espressif/arduino-esp32/issues/3522
Until then, WiFi should only be allowed when there's no power
saving on the 2.4g transceiver.
*/
2021-12-24 02:18:07 +00:00
DEBUG_MSG("WiFi deinit\n");
if (isWifiAvailable()) {
WiFi.mode(WIFI_MODE_NULL);
DEBUG_MSG("WiFi Turned Off\n");
// WiFi.printDiag(Serial);
}
2020-09-15 03:27:49 +00:00
}
static void onNetworkConnected()
{
if (!APStartupComplete) {
// Start web server
DEBUG_MSG("... Starting network services\n");
// start mdns
if (!MDNS.begin("Meshtastic")) {
DEBUG_MSG("Error setting up MDNS responder!\n");
} else {
DEBUG_MSG("mDNS responder started\n");
DEBUG_MSG("mDNS Host: Meshtastic.local\n");
MDNS.addService("http", "tcp", 80);
MDNS.addService("https", "tcp", 443);
}
2022-04-14 02:23:35 +00:00
#ifndef DISABLE_NTP
2021-12-29 03:24:10 +00:00
DEBUG_MSG("Starting NTP time client\n");
timeClient.begin();
2022-04-14 02:23:35 +00:00
timeClient.setUpdateInterval(60 * 60); // Update once an hour
#endif
2021-12-29 03:24:10 +00:00
initWebServer();
initApiServer();
APStartupComplete = true;
}
// FIXME this is kinda yucky, instead we should just have an observable for 'wifireconnected'
if (mqtt)
mqtt->reconnect();
}
// Startup WiFi
bool initWifi(bool forceSoftAP)
{
2020-12-13 02:33:52 +00:00
forcedSoftAP = forceSoftAP;
if (config.network.wifi_enabled && ((config.network.wifi_ssid[0]) || forceSoftAP)) {
// if ((radioConfig.has_preferences && config.wifi.ssid[0]) || forceSoftAP) {
const char *wifiName = config.network.wifi_ssid;
const char *wifiPsw = config.network.wifi_psk;
2020-09-18 22:33:03 +00:00
if (forceSoftAP) {
DEBUG_MSG("WiFi ... Forced AP Mode\n");
} else if (config.network.wifi_mode == Config_NetworkConfig_WiFiMode_ACCESS_POINT) {
DEBUG_MSG("WiFi ... AP Mode\n");
} else if (config.network.wifi_mode == Config_NetworkConfig_WiFiMode_ACCESS_POINT_HIDDEN) {
2022-08-06 06:31:40 +00:00
DEBUG_MSG("WiFi ... Hidden AP Mode\n");
} else if (config.network.wifi_mode == Config_NetworkConfig_WiFiMode_CLIENT) {
DEBUG_MSG("WiFi ... Client Mode\n");
2022-08-06 06:31:40 +00:00
} else {
DEBUG_MSG("WiFi ... WiFi Disabled\n");
}
createSSLCert();
if (!*wifiPsw) // Treat empty password as no password
wifiPsw = NULL;
if (*wifiName || forceSoftAP) {
if (config.network.wifi_mode == Config_NetworkConfig_WiFiMode_ACCESS_POINT || config.network.wifi_mode == Config_NetworkConfig_WiFiMode_ACCESS_POINT_HIDDEN || forceSoftAP) {
2020-12-13 02:33:52 +00:00
IPAddress apIP(192, 168, 42, 1);
WiFi.onEvent(WiFiEvent);
2021-12-24 02:18:07 +00:00
WiFi.mode(WIFI_AP);
2020-12-13 02:33:52 +00:00
2021-12-24 02:18:07 +00:00
if (forcedSoftAP) {
const char *softAPssid = "meshtasticAdmin";
const char *softAPpasswd = "12345678";
2022-03-14 19:31:13 +00:00
int ok = WiFi.softAP(softAPssid, softAPpasswd);
DEBUG_MSG("Starting (Forced) WIFI AP: ssid=%s, ok=%d\n", softAPssid, ok);
2020-12-13 02:33:52 +00:00
2021-12-24 02:18:07 +00:00
} else {
// If AP is configured to be hidden hidden
if (config.network.wifi_mode == Config_NetworkConfig_WiFiMode_ACCESS_POINT_HIDDEN) {
// The configurations on softAP are from the espresif library
int ok = WiFi.softAP(wifiName, wifiPsw, 1, 1, 4);
2022-06-18 19:03:58 +00:00
DEBUG_MSG("Starting hidden WIFI AP: ssid=%s, ok=%d\n", wifiName, ok);
} else {
int ok = WiFi.softAP(wifiName, wifiPsw);
DEBUG_MSG("Starting WIFI AP: ssid=%s, ok=%d\n", wifiName, ok);
}
2022-03-14 19:40:57 +00:00
int ok = WiFi.softAP(wifiName, wifiPsw);
2022-03-14 19:31:13 +00:00
DEBUG_MSG("Starting WIFI AP: ssid=%s, ok=%d\n", wifiName, ok);
2021-12-24 02:18:07 +00:00
}
2020-09-18 22:33:03 +00:00
WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0));
2021-12-24 02:18:07 +00:00
DEBUG_MSG("MY IP AP ADDRESS: %s\n", WiFi.softAPIP().toString().c_str());
2021-12-24 21:08:30 +00:00
// This is needed to improve performance.
esp_wifi_set_ps(WIFI_PS_NONE); // Disable radio power saving
2020-09-18 22:33:03 +00:00
dnsServer.start(53, "*", apIP);
} else {
uint8_t dmac[6];
getMacAddr(dmac);
sprintf(ourHost, "Meshtastic-%02x%02x", dmac[4], dmac[5]);
WiFi.mode(WIFI_MODE_STA);
WiFi.setHostname(ourHost);
WiFi.onEvent(WiFiEvent);
2021-12-24 21:08:30 +00:00
// This is needed to improve performance.
esp_wifi_set_ps(WIFI_PS_NONE); // Disable radio power saving
WiFi.onEvent(
[](WiFiEvent_t event, WiFiEventInfo_t info) {
2020-09-23 04:01:31 +00:00
Serial.print("\nWiFi lost connection. Reason: ");
Serial.println(info.wifi_sta_disconnected.reason);
2020-09-26 07:01:02 +00:00
/*
If we are disconnected from the AP for some reason,
save the error code.
For a reference to the codes:
https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/wifi.html#wi-fi-reason-code
*/
wifiDisconnectReason = info.wifi_sta_disconnected.reason;
},
WiFiEvent_t::ARDUINO_EVENT_WIFI_STA_DISCONNECTED);
DEBUG_MSG("JOINING WIFI soon: ssid=%s\n", wifiName);
wifiReconnect = new Periodic("WifiConnect", reconnectWiFi);
}
}
return true;
} else {
DEBUG_MSG("Not using WIFI\n");
return false;
}
}
2020-09-26 07:01:02 +00:00
// Called by the Espressif SDK to
static void WiFiEvent(WiFiEvent_t event)
{
DEBUG_MSG("************ [WiFi-event] event: %d ************\n", event);
switch (event) {
case SYSTEM_EVENT_WIFI_READY:
DEBUG_MSG("WiFi interface ready\n");
break;
case SYSTEM_EVENT_SCAN_DONE:
DEBUG_MSG("Completed scan for access points\n");
break;
case SYSTEM_EVENT_STA_START:
DEBUG_MSG("WiFi station started\n");
break;
case SYSTEM_EVENT_STA_STOP:
DEBUG_MSG("WiFi station stopped\n");
break;
case SYSTEM_EVENT_STA_CONNECTED:
DEBUG_MSG("Connected to access point\n");
break;
case SYSTEM_EVENT_STA_DISCONNECTED:
DEBUG_MSG("Disconnected from WiFi access point\n");
// Event 5
needReconnect = true;
break;
case SYSTEM_EVENT_STA_AUTHMODE_CHANGE:
DEBUG_MSG("Authentication mode of access point has changed\n");
break;
case SYSTEM_EVENT_STA_GOT_IP:
2021-12-24 02:18:07 +00:00
DEBUG_MSG("Obtained IP address: ");
Serial.println(WiFi.localIP());
onNetworkConnected();
break;
case SYSTEM_EVENT_STA_LOST_IP:
DEBUG_MSG("Lost IP address and IP address is reset to 0\n");
break;
case SYSTEM_EVENT_STA_WPS_ER_SUCCESS:
DEBUG_MSG("WiFi Protected Setup (WPS): succeeded in enrollee mode\n");
break;
case SYSTEM_EVENT_STA_WPS_ER_FAILED:
DEBUG_MSG("WiFi Protected Setup (WPS): failed in enrollee mode\n");
break;
case SYSTEM_EVENT_STA_WPS_ER_TIMEOUT:
DEBUG_MSG("WiFi Protected Setup (WPS): timeout in enrollee mode\n");
break;
case SYSTEM_EVENT_STA_WPS_ER_PIN:
DEBUG_MSG("WiFi Protected Setup (WPS): pin code in enrollee mode\n");
break;
case SYSTEM_EVENT_AP_START:
DEBUG_MSG("WiFi access point started\n");
2021-12-24 21:08:30 +00:00
onNetworkConnected();
break;
case SYSTEM_EVENT_AP_STOP:
DEBUG_MSG("WiFi access point stopped\n");
break;
case SYSTEM_EVENT_AP_STACONNECTED:
DEBUG_MSG("Client connected\n");
break;
case SYSTEM_EVENT_AP_STADISCONNECTED:
DEBUG_MSG("Client disconnected\n");
break;
case SYSTEM_EVENT_AP_STAIPASSIGNED:
DEBUG_MSG("Assigned IP address to client\n");
break;
case SYSTEM_EVENT_AP_PROBEREQRECVED:
DEBUG_MSG("Received probe request\n");
break;
case SYSTEM_EVENT_GOT_IP6:
DEBUG_MSG("IPv6 is preferred\n");
break;
case SYSTEM_EVENT_ETH_START:
DEBUG_MSG("Ethernet started\n");
break;
case SYSTEM_EVENT_ETH_STOP:
DEBUG_MSG("Ethernet stopped\n");
break;
case SYSTEM_EVENT_ETH_CONNECTED:
DEBUG_MSG("Ethernet connected\n");
break;
case SYSTEM_EVENT_ETH_DISCONNECTED:
DEBUG_MSG("Ethernet disconnected\n");
break;
case SYSTEM_EVENT_ETH_GOT_IP:
2021-12-24 02:18:07 +00:00
DEBUG_MSG("Obtained IP address (SYSTEM_EVENT_ETH_GOT_IP)\n");
break;
default:
break;
}
2020-09-18 22:33:03 +00:00
}
2020-09-19 01:51:42 +00:00
void handleDNSResponse()
{
if (config.network.wifi_mode == Config_NetworkConfig_WiFiMode_ACCESS_POINT || config.network.wifi_mode == Config_NetworkConfig_WiFiMode_ACCESS_POINT_HIDDEN || isSoftAPForced()) {
2020-09-18 22:33:03 +00:00
dnsServer.processNextRequest();
}
}
2020-09-26 07:01:02 +00:00
uint8_t getWifiDisconnectReason()
{
return wifiDisconnectReason;
2022-03-14 19:31:13 +00:00
}