From c78f07b4b50d49895efbe08a6e65e2f755bd290a Mon Sep 17 00:00:00 2001 From: Chad Date: Tue, 31 Mar 2026 14:14:40 -0500 Subject: [PATCH] Add WiFi network scanner with dropdown selection instead of manual SSID entry --- src/main.cpp | 233 +++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 209 insertions(+), 24 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index de46da2..84806cf 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -179,6 +179,15 @@ int keyboardPos = 0; int indexScrollOffset = 0; bool needsRefresh = false; +#define MAX_SCAN_NETWORKS 15 +String scannedSSIDs[MAX_SCAN_NETWORKS]; +int scannedCount = 0; +int wifiScrollOffset = 0; +bool wifiScanDone = false; +String selectedSSID = ""; +String wifiPassword = ""; +bool enteringPassword = false; + String formatPriceUS(double price, int decimals = 2, bool includeDollar = true) { if (price <= 0) return "..."; @@ -590,6 +599,33 @@ void drawIndexCustomizeScreen() { lcd.drawString("CANCEL", SCREEN_WIDTH - 95, SCREEN_HEIGHT - 30); } +void scanWifiNetworks() { + WiFi.mode(WIFI_STA); + WiFi.disconnect(); + delay(100); + + int n = WiFi.scanNetworks(); + scannedCount = 0; + + if (n > 0) { + for (int i = 0; i < n && scannedCount < MAX_SCAN_NETWORKS; i++) { + String ssid = WiFi.SSID(i); + bool duplicate = false; + for (int j = 0; j < scannedCount; j++) { + if (scannedSSIDs[j] == ssid) { + duplicate = true; + break; + } + } + if (!duplicate && ssid.length() > 0) { + scannedSSIDs[scannedCount++] = ssid; + } + } + } + wifiScanDone = true; + wifiScrollOffset = 0; +} + void drawWifiConfigScreen() { lcd.fillScreen(TFT_BLACK); @@ -599,37 +635,94 @@ void drawWifiConfigScreen() { lcd.setTextDatum(textdatum_t::middle_center); lcd.drawString("WIFI CONFIGURATION", SCREEN_WIDTH / 2, 25); + if (!wifiScanDone) { + lcd.setTextColor(TFT_WHITE, TFT_BLACK); + lcd.setFont(&fonts::DejaVu18); + lcd.setTextDatum(textdatum_t::middle_center); + lcd.drawString("Scanning for networks...", SCREEN_WIDTH / 2, 150); + return; + } + lcd.setTextColor(TFT_WHITE, TFT_BLACK); lcd.setFont(&fonts::DejaVu18); lcd.setTextDatum(textdatum_t::middle_left); - lcd.drawString("SSID:", 100, 70); + lcd.drawString("Select Network:", 50, 60); - lcd.fillSmoothRoundRect(100, 90, 600, 40, 6, TFT_ORANGE); - lcd.setTextColor(TFT_WHITE, TFT_ORANGE); - lcd.setTextDatum(textdatum_t::middle_left); - String ssidDisplay = String(keyboardBuffer); - if (ssidDisplay.length() == 0) ssidDisplay = "_"; - lcd.drawString(ssidDisplay, 120, 110); + int listY = 85; + int itemHeight = 36; + int visibleItems = 5; + + for (int i = 0; i < visibleItems; i++) { + int idx = wifiScrollOffset + i; + if (idx >= scannedCount) break; + + int y = listY + i * (itemHeight + 4); + bool isSelected = (scannedSSIDs[idx] == selectedSSID); + uint16_t bgColor = isSelected ? TFT_ORANGE : TFT_DARKGRAY; + + lcd.fillSmoothRoundRect(50, y, 700, itemHeight, 6, bgColor); + lcd.setTextColor(TFT_WHITE, bgColor); + lcd.setTextDatum(textdatum_t::middle_left); + + String displaySSID = scannedSSIDs[idx]; + if (displaySSID.length() > 25) { + displaySSID = displaySSID.substring(0, 23) + "..."; + } + lcd.drawString(displaySSID, 70, y + itemHeight / 2); + } + + if (wifiScrollOffset > 0) { + lcd.fillSmoothRoundRect(380, listY - 28, 40, 22, 4, TFT_GRAY); + lcd.setTextColor(TFT_WHITE, TFT_GRAY); + lcd.setFont(&fonts::DejaVu18); + lcd.setTextDatum(textdatum_t::middle_center); + lcd.drawString("^", 400, listY - 17); + } + + if (wifiScrollOffset + visibleItems < scannedCount) { + lcd.fillSmoothRoundRect(380, listY + visibleItems * (itemHeight + 4) + 6, 40, 22, 4, TFT_GRAY); + lcd.setTextColor(TFT_WHITE, TFT_GRAY); + lcd.setFont(&fonts::DejaVu18); + lcd.setTextDatum(textdatum_t::middle_center); + lcd.drawString("v", 400, listY + visibleItems * (itemHeight + 4) + 17); + } lcd.setTextColor(TFT_WHITE, TFT_BLACK); - lcd.drawString("Password:", 100, 150); - - lcd.fillSmoothRoundRect(100, 170, 600, 40, 6, TFT_DARKGRAY); - lcd.setTextColor(TFT_GRAY, TFT_DARKGRAY); + lcd.setFont(&fonts::DejaVu18); lcd.setTextDatum(textdatum_t::middle_left); - lcd.drawString("(use same keyboard)", 120, 190); + lcd.drawString("Password:", 50, 285); - drawKeyboard(230); + lcd.fillSmoothRoundRect(50, 305, 700, 40, 6, enteringPassword ? TFT_ORANGE : TFT_DARKGRAY); + lcd.setTextColor(enteringPassword ? TFT_WHITE : TFT_GRAY, enteringPassword ? TFT_ORANGE : TFT_DARKGRAY); + lcd.setTextDatum(textdatum_t::middle_left); + + String pwdDisplay = wifiPassword; + if (enteringPassword && keyboardPos > 0) { + pwdDisplay = String(keyboardBuffer); + } + if (pwdDisplay.length() == 0) { + lcd.drawString("(tap to enter password)", 70, 325); + } else { + String masked = ""; + for (int i = 0; i < pwdDisplay.length(); i++) masked += "*"; + lcd.drawString(masked, 70, 325); + } - lcd.fillSmoothRoundRect(100, SCREEN_HEIGHT - 50, 150, 40, 8, TFT_GRAY); + if (enteringPassword) { + drawKeyboard(360); + } + + lcd.fillSmoothRoundRect(50, SCREEN_HEIGHT - 50, 150, 40, 8, TFT_GRAY); lcd.setTextColor(TFT_WHITE, TFT_GRAY); lcd.setFont(&fonts::DejaVu18); lcd.setTextDatum(textdatum_t::middle_center); - lcd.drawString("BACK", 175, SCREEN_HEIGHT - 30); + lcd.drawString("BACK", 125, SCREEN_HEIGHT - 30); - lcd.fillSmoothRoundRect(SCREEN_WIDTH - 250, SCREEN_HEIGHT - 50, 150, 40, 8, TFT_GREEN); - lcd.setTextColor(TFT_WHITE, TFT_GREEN); - lcd.drawString("SAVE", SCREEN_WIDTH - 175, SCREEN_HEIGHT - 30); + bool canSave = selectedSSID.length() > 0 && (wifiPassword.length() > 0 || (!enteringPassword && keyboardPos > 0)); + uint16_t saveColor = canSave ? TFT_GREEN : TFT_GRAY; + lcd.fillSmoothRoundRect(SCREEN_WIDTH - 200, SCREEN_HEIGHT - 50, 150, 40, 8, saveColor); + lcd.setTextColor(TFT_WHITE, saveColor); + lcd.drawString("CONNECT", SCREEN_WIDTH - 125, SCREEN_HEIGHT - 30); } void drawDashboard() { @@ -810,16 +903,20 @@ bool handleStockCustomizeTouch(int32_t x, int32_t y) { } bool handleWifiConfigTouch(int32_t x, int32_t y) { - if (x >= 100 && x < 250 && y >= SCREEN_HEIGHT - 50 && y < SCREEN_HEIGHT - 10) { + if (!wifiScanDone) return true; + + if (x >= 50 && x < 200 && y >= SCREEN_HEIGHT - 50 && y < SCREEN_HEIGHT - 10) { currentScreen = SCREEN_DASHBOARD; needsRefresh = true; return true; } - if (x >= SCREEN_WIDTH - 250 && x < SCREEN_WIDTH - 100 && y >= SCREEN_HEIGHT - 50 && y < SCREEN_HEIGHT - 10) { - if (keyboardPos > 0) { + if (x >= SCREEN_WIDTH - 200 && x < SCREEN_WIDTH - 50 && y >= SCREEN_HEIGHT - 50 && y < SCREEN_HEIGHT - 10) { + String pwdToSave = enteringPassword ? String(keyboardBuffer) : wifiPassword; + if (selectedSSID.length() > 0 && pwdToSave.length() > 0) { preferences.begin("wifi", false); - preferences.putString("ssid", keyboardBuffer); + preferences.putString("ssid", selectedSSID); + preferences.putString("password", pwdToSave); preferences.end(); currentScreen = SCREEN_DASHBOARD; needsRefresh = true; @@ -827,11 +924,94 @@ bool handleWifiConfigTouch(int32_t x, int32_t y) { return true; } - int keyboardY = 230; - if (handleKeyboardTouch(x, y, keyboardY)) { + int listY = 85; + int itemHeight = 36; + int visibleItems = 5; + + if (x >= 380 && x < 420 && y >= listY - 28 && y < listY - 6) { + if (wifiScrollOffset > 0) { + wifiScrollOffset--; + } return true; } + if (x >= 380 && x < 420 && y >= listY + visibleItems * (itemHeight + 4) + 6 && y < listY + visibleItems * (itemHeight + 4) + 28) { + if (wifiScrollOffset + visibleItems < scannedCount) { + wifiScrollOffset++; + } + return true; + } + + for (int i = 0; i < visibleItems; i++) { + int idx = wifiScrollOffset + i; + if (idx >= scannedCount) break; + + int iy = listY + i * (itemHeight + 4); + if (x >= 50 && x < 750 && y >= iy && y < iy + itemHeight) { + selectedSSID = scannedSSIDs[idx]; + enteringPassword = false; + keyboardPos = 0; + keyboardBuffer[0] = '\0'; + return true; + } + } + + if (x >= 50 && x < 750 && y >= 305 && y < 345) { + enteringPassword = true; + keyboardPos = 0; + keyboardBuffer[0] = '\0'; + return true; + } + + if (enteringPassword) { + int keyboardY = 360; + const char* rows[] = { + "QWERTYUIOP", + "ASDFGHJKL", + "ZXCVBNM", + "1234567890" + }; + const int numRows = 4; + const int keySize = 32; + const int keyGap = 2; + + for (int r = 0; r < numRows; r++) { + int rowLen = strlen(rows[r]); + int rowWidth = rowLen * (keySize + keyGap) - keyGap; + int startX = (SCREEN_WIDTH - rowWidth) / 2; + int keyY = keyboardY + r * (keySize + keyGap); + + for (int k = 0; k < rowLen; k++) { + int keyX = startX + k * (keySize + keyGap); + if (x >= keyX && x < keyX + keySize && y >= keyY && y < keyY + keySize) { + if (keyboardPos < 63) { + keyboardBuffer[keyboardPos++] = rows[r][k]; + keyboardBuffer[keyboardPos] = '\0'; + } + return true; + } + } + } + + int btnY = keyboardY + numRows * (keySize + keyGap) + 4; + int delX = SCREEN_WIDTH / 2 - 125; + int enterX = SCREEN_WIDTH / 2 + 5; + + if (x >= delX && x < delX + 120 && y >= btnY && y < btnY + 32) { + if (keyboardPos > 0) { + keyboardPos--; + keyboardBuffer[keyboardPos] = '\0'; + } + return true; + } + + if (x >= enterX && x < enterX + 120 && y >= btnY && y < btnY + 32) { + wifiPassword = String(keyboardBuffer); + enteringPassword = false; + return true; + } + } + return false; } @@ -944,8 +1124,13 @@ bool handleDashboardTouch(int32_t x, int32_t y) { if (x >= 20 && x < 200 && y >= SCREEN_HEIGHT - 40 && y < SCREEN_HEIGHT) { currentScreen = SCREEN_WIFI_CONFIG; + wifiScanDone = false; + wifiPassword = ""; + selectedSSID = ""; + enteringPassword = false; keyboardPos = 0; keyboardBuffer[0] = '\0'; + scanWifiNetworks(); return true; }