// Install from the Library Manager: // "LiquidCrystal I2C" // Board: "ESP32 Dev Module" #include #include #include // The ESP32's I2C pins const int SDA_PIN = 21; const int SCL_PIN = 22; // How long each network stays on (ms) const unsigned long SHOW_EACH = 3000; // At most this many networks are listed const int MAX_NETWORKS = 40; // A network that hides its name const char* HIDDEN = "(hidden)"; // I2C address: mostly 0x27, some 0x3F LiquidCrystal_I2C lcd(0x27, 16, 2); // Networks found, strongest first int order[MAX_NETWORKS]; int found = 0; // The next network to show int next = 0; unsigned long shownAt = 0; // Signal strength (dBm) as 0-4 bars int bars(int rssi) { if (rssi >= -55) return 4; if (rssi >= -67) return 3; if (rssi >= -75) return 2; if (rssi >= -85) return 1; return 0; } // The encryption's short name const char* security(wifi_auth_mode_t mode) { switch (mode) { case WIFI_AUTH_OPEN: return "Open"; case WIFI_AUTH_WEP: return "WEP"; case WIFI_AUTH_WPA_PSK: return "WPA"; case WIFI_AUTH_WPA2_PSK: return "WPA2"; case WIFI_AUTH_WPA_WPA2_PSK: return "WPA/WPA2"; case WIFI_AUTH_WPA3_PSK: return "WPA3"; case WIFI_AUTH_WPA2_WPA3_PSK: return "WPA2/WPA3"; default: return "Other"; } } // The network's name, or HIDDEN String networkName(int k) { String name = WiFi.SSID(k); if (name.length() == 0) name = HIDDEN; return name; } // Scans, then sorts strongest first void scan() { lcd.clear(); lcd.print("Scanning..."); Serial.println("Scanning..."); int count = WiFi.scanNetworks(); found = constrain(count, 0, MAX_NETWORKS); for (int i = 0; i < found; i++) { order[i] = i; } // Sorting: each network moves ahead of // the weaker ones before it for (int i = 1; i < found; i++) { int k = order[i]; int j = i - 1; while (j >= 0 && WiFi.RSSI(order[j]) < WiFi.RSSI(k)) { order[j + 1] = order[j]; j--; } order[j + 1] = k; } Serial.print(found); Serial.println(" networks found"); for (int i = 0; i < found; i++) { int k = order[i]; Serial.printf("%2d. %4d dBm channel %2d %s (%s)\n", i + 1, WiFi.RSSI(k), WiFi.channel(k), networkName(k).c_str(), security(WiFi.encryptionType(k))); } next = 0; shownAt = millis(); } // Writes one network: its name on top; // rank, strength, bars and lock (*) below void show(int i) { int k = order[i]; int rssi = WiFi.RSSI(k); char barText[] = " "; for (int b = 0; b < bars(rssi); b++) { barText[b] = '#'; } bool locked = WiFi.encryptionType(k) != WIFI_AUTH_OPEN; char line[17]; snprintf(line, sizeof line, "%2d/%-2d%4d %s %c", i + 1, found, rssi, barText, locked ? '*' : ' '); lcd.clear(); lcd.print(networkName(k).substring(0, 16)); lcd.setCursor(0, 1); lcd.print(line); } void setup() { Serial.begin(115200); Wire.begin(SDA_PIN, SCL_PIN); lcd.init(); lcd.backlight(); // Only listens; joins no network WiFi.mode(WIFI_STA); WiFi.disconnect(); delay(100); scan(); } void loop() { if (found == 0) { lcd.setCursor(0, 1); lcd.print("None found"); delay(SHOW_EACH); scan(); return; } // The first one at once, then in turn if (next > 0 && millis() - shownAt < SHOW_EACH) { return; } // All shown: scan again if (next >= found) { scan(); return; } show(next); next++; shownAt = millis(); }