diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index 320c0f1e..c112a295 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -984,7 +984,9 @@ void DebugInfo::drawFrameWiFi(OLEDDisplay *display, OLEDDisplayUiState *state, i // The coordinates define the left starting point of the text display->setTextAlignment(TEXT_ALIGN_LEFT); - if (radioConfig.preferences.wifi_ap_mode) { + if (isSoftAPForced()) { + display->drawString(x, y, String("WiFi: Software AP (Admin)")); + } else if (radioConfig.preferences.wifi_ap_mode) { display->drawString(x, y, String("WiFi: Software AP")); } else if (WiFi.status() != WL_CONNECTED) { display->drawString(x, y, String("WiFi: Not Connected")); @@ -1007,13 +1009,15 @@ void DebugInfo::drawFrameWiFi(OLEDDisplay *display, OLEDDisplayUiState *state, i - WL_NO_SHIELD: assigned when no WiFi shield is present; */ - - if (WiFi.status() == WL_CONNECTED) { - if (radioConfig.preferences.wifi_ap_mode) { + if (WiFi.status() == WL_CONNECTED || isSoftAPForced() || radioConfig.preferences.wifi_ap_mode) { + if (radioConfig.preferences.wifi_ap_mode || isSoftAPForced()) { display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "IP: " + String(WiFi.softAPIP().toString().c_str())); } else { display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "IP: " + String(WiFi.localIP().toString().c_str())); } + display->drawString(x + SCREEN_WIDTH - display->getStringWidth("(" + String(WiFi.softAPgetStationNum()) + "/4)"), + y + FONT_HEIGHT_SMALL * 1, "(" + String(WiFi.softAPgetStationNum()) + "/4)"); + } else if (WiFi.status() == WL_NO_SSID_AVAIL) { display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "SSID Not Found"); } else if (WiFi.status() == WL_CONNECTION_LOST) { @@ -1088,10 +1092,19 @@ void DebugInfo::drawFrameWiFi(OLEDDisplay *display, OLEDDisplayUiState *state, i } } - if ((millis() / 10000) % 2) { - display->drawString(x, y + FONT_HEIGHT_SMALL * 2, "SSID: " + String(wifiName)); + if (isSoftAPForced()) { + if ((millis() / 10000) % 2) { + display->drawString(x, y + FONT_HEIGHT_SMALL * 2, "SSID: meshtasticAdmin"); + } else { + display->drawString(x, y + FONT_HEIGHT_SMALL * 2, "PWD: 12345678"); + } + } else { - display->drawString(x, y + FONT_HEIGHT_SMALL * 2, "PWD: " + String(wifiPsw)); + if ((millis() / 10000) % 2) { + display->drawString(x, y + FONT_HEIGHT_SMALL * 2, "SSID: " + String(wifiName)); + } else { + display->drawString(x, y + FONT_HEIGHT_SMALL * 2, "PWD: " + String(wifiPsw)); + } } display->drawString(x, y + FONT_HEIGHT_SMALL * 3, "http://meshtastic.local"); @@ -1185,8 +1198,7 @@ int Screen::handleStatusUpdate(const meshtastic::Status *arg) // DEBUG_MSG("Screen got status update %d\n", arg->getStatusType()); switch (arg->getStatusType()) { case STATUS_TYPE_NODE: - if (showingNormalScreen && - nodeStatus->getLastNumTotal() != nodeStatus->getNumTotal()) { + if (showingNormalScreen && nodeStatus->getLastNumTotal() != nodeStatus->getNumTotal()) { setFrames(); // Regen the list of screens } nodeDB.updateGUI = false; diff --git a/src/main.cpp b/src/main.cpp index 59773e2b..3f028613 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -241,7 +241,7 @@ class ButtonThread : public OSThread } #endif } else { - //DEBUG_MSG("Long press %u\n", (millis() - longPressTime)); + // DEBUG_MSG("Long press %u\n", (millis() - longPressTime)); } } @@ -298,6 +298,22 @@ void setup() digitalWrite(RESET_OLED, 1); #endif + // If BUTTON_PIN is held down during the startup process, + // force the device to go into a SoftAP mode. + bool forceSoftAP = 0; +#ifdef BUTTON_PIN +#ifndef NO_ESP32 + pinMode(BUTTON_PIN, INPUT); + + // BUTTON_PIN is pulled high by a 12k resistor. + if (!digitalRead(BUTTON_PIN)) { + forceSoftAP = 1; + DEBUG_MSG("-------------------- Setting forceSoftAP = 1\n"); + } + +#endif +#endif + OSThread::setup(); ledPeriodic = new Periodic("Blink", ledBlinker); @@ -467,7 +483,7 @@ void setup() #endif // Initialize Wifi - initWifi(); + initWifi(forceSoftAP); if (!rIf) recordCriticalError(ErrNoRadio); diff --git a/src/meshwifi/meshhttp.cpp b/src/meshwifi/meshhttp.cpp index 2ac81b1c..c09e6ac4 100644 --- a/src/meshwifi/meshhttp.cpp +++ b/src/meshwifi/meshhttp.cpp @@ -56,8 +56,10 @@ void handleRoot(HTTPRequest *req, HTTPResponse *res); void handleStaticBrowse(HTTPRequest *req, HTTPResponse *res); void handleStaticPost(HTTPRequest *req, HTTPResponse *res); void handleStatic(HTTPRequest *req, HTTPResponse *res); +void handleRestart(HTTPRequest *req, HTTPResponse *res); void handle404(HTTPRequest *req, HTTPResponse *res); void handleFormUpload(HTTPRequest *req, HTTPResponse *res); +void handleScanNetworks(HTTPRequest *req, HTTPResponse *res); void middlewareSpeedUp240(HTTPRequest *req, HTTPResponse *res, std::function next); void middlewareSpeedUp160(HTTPRequest *req, HTTPResponse *res, std::function next); @@ -70,10 +72,11 @@ uint32_t timeSpeedUp = 0; // We need to specify some content-type mapping, so the resources get delivered with the // right content type and are displayed correctly in the browser -char contentTypes[][2][32] = {{".txt", "text/plain"}, {".html", "text/html"}, {".js", "text/javascript"}, - {".png", "image/png"}, {".jpg", "image/jpg"}, {".gz", "application/gzip"}, - {".gif", "image/gif"}, {".json", "application/json"}, {".css", "text/css"}, - {"", ""}}; +char contentTypes[][2][32] = {{".txt", "text/plain"}, {".html", "text/html"}, + {".js", "text/javascript"}, {".png", "image/png"}, + {".jpg", "image/jpg"}, {".gz", "application/gzip"}, + {".gif", "image/gif"}, {".json", "application/json"}, + {".css", "text/css"}, {"", ""}}; void handleWebResponse() { @@ -175,9 +178,10 @@ void createSSLCert() NULL); /* Task handle. */ DEBUG_MSG("Waiting for SSL Cert to be generated.\n"); - if (isCertReady) { - DEBUG_MSG(".\n"); - delayMicroseconds(1000); + while (!isCertReady) { + DEBUG_MSG("."); + delay(1000); + yield(); } DEBUG_MSG("SSL Cert Ready!\n"); } @@ -233,8 +237,10 @@ void initWebServer() ResourceNode *nodeStaticBrowse = new ResourceNode("/static", "GET", &handleStaticBrowse); ResourceNode *nodeStaticPOST = new ResourceNode("/static", "POST", &handleStaticPost); ResourceNode *nodeStatic = new ResourceNode("/static/*", "GET", &handleStatic); + ResourceNode *nodeRestart = new ResourceNode("/restart", "POST", &handleRestart); ResourceNode *node404 = new ResourceNode("", "GET", &handle404); ResourceNode *nodeFormUpload = new ResourceNode("/upload", "POST", &handleFormUpload); + ResourceNode *nodeJsonScanNetworks = new ResourceNode("/json/scanNetworks", "GET", &handleScanNetworks); // Secure nodes secureServer->registerNode(nodeAPIv1ToRadioOptions); @@ -246,8 +252,10 @@ void initWebServer() secureServer->registerNode(nodeStaticBrowse); secureServer->registerNode(nodeStaticPOST); secureServer->registerNode(nodeStatic); + secureServer->registerNode(nodeRestart); secureServer->setDefaultNode(node404); secureServer->setDefaultNode(nodeFormUpload); + secureServer->setDefaultNode(nodeJsonScanNetworks); secureServer->addMiddleware(&middlewareSpeedUp240); @@ -261,8 +269,10 @@ void initWebServer() insecureServer->registerNode(nodeStaticBrowse); insecureServer->registerNode(nodeStaticPOST); insecureServer->registerNode(nodeStatic); + insecureServer->registerNode(nodeRestart); insecureServer->setDefaultNode(node404); insecureServer->setDefaultNode(nodeFormUpload); + insecureServer->setDefaultNode(nodeJsonScanNetworks); insecureServer->addMiddleware(&middlewareSpeedUp160); @@ -512,7 +522,6 @@ void handleStatic(HTTPRequest *req, HTTPResponse *res) // Get access to the parameters ResourceParameters *params = req->getParams(); - std::string parameter1; // Print the first parameter value if (params->getPathParameter(0, parameter1)) { @@ -560,7 +569,7 @@ void handleStatic(HTTPRequest *req, HTTPResponse *res) cTypeIdx += 1; } while (strlen(contentTypes[cTypeIdx][0]) > 0); - if(!has_set_content_type) { + if (!has_set_content_type) { // Set a default content type res->setHeader("Content-Type", "application/octet-stream"); } @@ -845,9 +854,9 @@ void handleRoot(HTTPRequest *req, HTTPResponse *res) "mt_session=" + httpsserver::intToString(random(1, 9999999)) + "; Expires=Wed, 20 Apr 2049 4:20:00 PST"); std::string cookie = req->getHeader("Cookie"); - //String cookieString = cookie.c_str(); - //uint8_t nameIndex = cookieString.indexOf("mt_session"); - //DEBUG_MSG(cookie.c_str()); + // String cookieString = cookie.c_str(); + // uint8_t nameIndex = cookieString.indexOf("mt_session"); + // DEBUG_MSG(cookie.c_str()); std::string filename = "/static/index.html"; std::string filenameGzip = "/static/index.html.gz"; @@ -860,7 +869,8 @@ void handleRoot(HTTPRequest *req, HTTPResponse *res) res->printf("

File not found: %s

\n", filename.c_str()); res->printf("

\n"); res->printf("

You have gotten this error because the filesystem for the web server has not been loaded.

\n"); - res->printf("

Please review the 'Common Problems' section of the web interface documentation.

\n"); + res->printf("

Please review the 'Common Problems' section of the web interface documentation.

\n"); return; } @@ -881,7 +891,6 @@ void handleRoot(HTTPRequest *req, HTTPResponse *res) } } - // Read the file from SPIFFS and write it to the HTTP response body size_t length = 0; do { @@ -892,6 +901,61 @@ void handleRoot(HTTPRequest *req, HTTPResponse *res) } while (length > 0); } +void handleRestart(HTTPRequest *req, HTTPResponse *res) +{ + res->setHeader("Content-Type", "text/html"); + + DEBUG_MSG("***** Restarted on HTTP(s) Request *****\n"); + res->println("Restarting"); + + ESP.restart(); +} + +void handleScanNetworks(HTTPRequest *req, HTTPResponse *res) +{ + res->setHeader("Content-Type", "application/json"); + // res->setHeader("Content-Type", "text/html"); + + int n = WiFi.scanNetworks(); + res->println("{"); + res->println("\"data\": {"); + if (n == 0) { + // No networks found. + res->println("\"networks\": []"); + + } else { + res->println("\"networks\": ["); + + for (int i = 0; i < n; ++i) { + char ssidArray[50]; + String ssidString = String(WiFi.SSID(i)); + //String ssidString = String(WiFi.SSID(i)).toCharArray(ssidArray, WiFi.SSID(i).length()); + ssidString.replace("\"", "\\\""); + ssidString.toCharArray(ssidArray, 50); + + + if (WiFi.encryptionType(i) != WIFI_AUTH_OPEN) { + //res->println("{\"ssid\": \"%s\",\"rssi\": -75}, ", String(WiFi.SSID(i).c_str() ); + + res->printf("{\"ssid\": \"%s\",\"rssi\": %d}", ssidArray, WiFi.RSSI(i) ) ; + //WiFi.RSSI(i) + if (i != n-1) { + res->printf(","); + } + } + // Yield some cpu cycles to IP stack. + // This is important in case the list is large and it takes us time to return + // to the main loop. + yield(); + } + res->println("]"); + } + res->println("},"); + res->println("\"status\": \"ok\""); + res->println("}"); + +} + void handleFavicon(HTTPRequest *req, HTTPResponse *res) { // Set Content-Type @@ -900,7 +964,6 @@ void handleFavicon(HTTPRequest *req, HTTPResponse *res) res->write(FAVICON_DATA, FAVICON_LENGTH); } - void replaceAll(std::string &str, const std::string &from, const std::string &to) { if (from.empty()) @@ -911,4 +974,3 @@ void replaceAll(std::string &str, const std::string &from, const std::string &to start_pos += to.length(); // In case 'to' contains 'from', like replacing 'x' with 'yx' } } - diff --git a/src/meshwifi/meshwifi.cpp b/src/meshwifi/meshwifi.cpp index 71c4d227..16ae6185 100644 --- a/src/meshwifi/meshwifi.cpp +++ b/src/meshwifi/meshwifi.cpp @@ -21,14 +21,32 @@ uint8_t wifiDisconnectReason = 0; // Stores our hostname char ourHost[16]; +bool forcedSoftAP = 0; + +bool APStartupComplete = 0; + +bool isSoftAPForced() +{ + return forcedSoftAP; +} + bool isWifiAvailable() { + // If wifi status is connected, return true regardless of the radio configuration. + if (isSoftAPForced()) { + return 1; + } + const char *wifiName = radioConfig.preferences.wifi_ssid; const char *wifiPsw = radioConfig.preferences.wifi_password; // strcpy(radioConfig.preferences.wifi_ssid, ""); // strcpy(radioConfig.preferences.wifi_password, ""); + // strcpy(radioConfig.preferences.wifi_ssid, "meshtasticAdmin"); + // strcpy(radioConfig.preferences.wifi_password, "12345678"); + // radioConfig.preferences.wifi_ap_mode = true; + if (*wifiName && *wifiPsw) { return 1; } else { @@ -58,20 +76,44 @@ void deinitWifi() } // Startup WiFi -void initWifi() +void initWifi(bool forceSoftAP) { - if (isWifiAvailable() == 0) { - return; + + if (forceSoftAP) { + // do nothing + // DEBUG_MSG("----- Forcing SoftAP\n"); + } else { + if (isWifiAvailable() == 0) { + return; + } } + forcedSoftAP = forceSoftAP; + createSSLCert(); - if (radioConfig.has_preferences) { + if (radioConfig.has_preferences || forceSoftAP) { const char *wifiName = radioConfig.preferences.wifi_ssid; const char *wifiPsw = radioConfig.preferences.wifi_password; - if (*wifiName && *wifiPsw) { - if (radioConfig.preferences.wifi_ap_mode) { + if ((*wifiName && *wifiPsw) || forceSoftAP) { + if (forceSoftAP) { + + DEBUG_MSG("Forcing SoftAP\n"); + + const char *softAPssid = "meshtasticAdmin"; + const char *softAPpasswd = "12345678"; + + IPAddress apIP(192, 168, 42, 1); + WiFi.onEvent(WiFiEvent); + + WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0)); + DEBUG_MSG("STARTING WIFI AP: ssid=%s, ok=%d\n", softAPssid, WiFi.softAP(softAPssid, softAPpasswd)); + DEBUG_MSG("MY IP ADDRESS: %s\n", WiFi.softAPIP().toString().c_str()); + + dnsServer.start(53, "*", apIP); + + } else if (radioConfig.preferences.wifi_ap_mode) { IPAddress apIP(192, 168, 42, 1); WiFi.onEvent(WiFiEvent); @@ -203,9 +245,16 @@ static void WiFiEvent(WiFiEvent_t event) DEBUG_MSG("WiFi access point started\n"); Serial.println(WiFi.softAPIP()); - // Start web server - initWebServer(); - initApiServer(); + if (!APStartupComplete) { + // Start web server + DEBUG_MSG("... Starting network services\n"); + initWebServer(); + initApiServer(); + + APStartupComplete = true; + } else { + DEBUG_MSG("... Not starting network services\n"); + } break; case SYSTEM_EVENT_AP_STOP: diff --git a/src/meshwifi/meshwifi.h b/src/meshwifi/meshwifi.h index ac03e29f..9e2f8ad7 100644 --- a/src/meshwifi/meshwifi.h +++ b/src/meshwifi/meshwifi.h @@ -9,7 +9,7 @@ #include #endif -void initWifi(); +void initWifi(bool forceSoftAP); void deinitWifi(); bool isWifiAvailable(); @@ -18,5 +18,7 @@ void handleDNSResponse(); void reconnectWiFi(); +bool isSoftAPForced(); + uint8_t getWifiDisconnectReason(); diff --git a/src/nimble/BluetoothUtil.cpp b/src/nimble/BluetoothUtil.cpp index 8a0dd779..daba6937 100644 --- a/src/nimble/BluetoothUtil.cpp +++ b/src/nimble/BluetoothUtil.cpp @@ -545,7 +545,7 @@ void setBluetoothEnable(bool on) if (firstTime) { firstTime = 0; } else { - initWifi(); + initWifi(0); } } else { diff --git a/src/nrf52/wifi-stubs.cpp b/src/nrf52/wifi-stubs.cpp index 30321e5e..1c100986 100644 --- a/src/nrf52/wifi-stubs.cpp +++ b/src/nrf52/wifi-stubs.cpp @@ -1,7 +1,7 @@ #include "meshwifi/meshhttp.h" #include "meshwifi/meshwifi.h" -void initWifi() {} +void initWifi(bool forceSoftAP) {} void deinitWifi() {}