#include <Arduino.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include "WiFi.h"
#include <SPI.h>
#include <Wire.h>
#include <vector>
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define RESET_OLED -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, RESET_OLED);
// Estrutura para guardar os dados da rede de forma organizada
struct RedeWiFi {
String ssid;
int rssi;
String infoLinha;
};
std::vector<RedeWiFi> listaRedes;
int indexSelecionado = 0; // Guarda qual rede está selecionada no momento
const int alturaLinha = 11; // Altura de cada linha em pixels
const int topoMenu = 16; // Onde começam as redes (deixa os primeiros 16px para o cabeçalho fixo)
void ScanWiFi() {
Serial.println("Escaneando Redes...");
listaRedes.clear();
indexSelecionado = 0;
int n = WiFi.scanNetworks();
if (n == 0) {
RedeWiFi vazia = {"", 0, "Nenhuma rede encontrada"};
listaRedes.push_back(vazia);
} else {
for (int i = 0; i < n; ++i) {
char buffer[30];
String seguranca = "";
switch (WiFi.encryptionType(i)) {
case WIFI_AUTH_OPEN: seguranca = "Open"; break;
case WIFI_AUTH_WPA_PSK: seguranca = "WPA"; break;
case WIFI_AUTH_WPA2_PSK: seguranca = "WPA2"; break;
case WIFI_AUTH_WPA3_PSK: seguranca = "WPA3"; break;
default: seguranca = "WPAx"; break;
}
// Formata a string de exibição (Limitando SSID em 10 caracteres para caber na tela)
sprintf(buffer, "%2d|%-10.10s|%d", i + 1, WiFi.SSID(i).c_str(), WiFi.RSSI(i));
RedeWiFi rede = {WiFi.SSID(i), WiFi.RSSI(i), String(buffer)};
listaRedes.push_back(rede);
}
}
WiFi.scanDelete();
Serial.println("Escaneamento concluído. Use 'w' (subir) e 's' (descer) no Serial.");
}
void desenharMenu() {
display.clearDisplay();
// 1. Cabeçalho Fixo (Não move)
display.setCursor(0, 0);
display.println(" CH | SSID | RSSI");
display.drawFastHLine(0, 10, SCREEN_WIDTH, WHITE);
if (listaRedes.empty()) {
display.setCursor(0, topoMenu);
display.println("Sem dados. Digite 'r' para scan.");
display.display();
return;
}
// 2. Cálculo matemático da janela de rolagem (Scrolling Window)
// Impede que o item selecionado suma da tela expandindo para cima ou para baixo
int maxLinhasVisiveis = (SCREEN_HEIGHT - topoMenu) / alturaLinha; // ~4 redes por vez
int mudancaJanela = 0;
if (indexSelecionado >= maxLinhasVisiveis) {
mudancaJanela = (indexSelecionado - maxLinhasVisiveis + 1) * alturaLinha;
}
// 3. Desenha as redes respeitando o deslocamento do menu
for (size_t i = 0; i < listaRedes.size(); i++) {
int yPosicaoLinha = topoMenu + (i * alturaLinha) - mudancaJanela;
// Só desenha se estiver dentro do espaço útil inferior da tela
if (yPosicaoLinha >= topoMenu && yPosicaoLinha < SCREEN_HEIGHT) {
display.setCursor(0, yPosicaoLinha);
// Se for a rede selecionada atual, desenha o indicador ">" na frente
if ((int)i == indexSelecionado) {
display.print(">");
} else {
display.print(" ");
}
display.print(listaRedes[i].infoLinha);
}
}
display.display();
}
void setup() {
Serial.begin(115200);
Wire.begin(21, 22);
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
for(;;);
}
WiFi.STA.begin();
display.setTextSize(1);
display.setTextColor(WHITE);
display.setTextWrap(false);
ScanWiFi(); // Faz o primeiro scan ao iniciar
desenharMenu();
}
void loop() {
// Escuta os comandos vindos do Monitor Serial do Arduino IDE
if (Serial.available() > 0) {
char comando = Serial.read();
if (comando == 's' || comando == 'S') { // Tecla 'S' -> Descer no Menu
if (indexSelecionado < (int)listaRedes.size() - 1) {
indexSelecionado++;
desenharMenu();
}
}
else if (comando == 'w' || comando == 'W') { // Tecla 'W' -> Subir no Menu
if (indexSelecionado > 0) {
indexSelecionado--;
desenharMenu();
}
}
else if (comando == 'r' || comando == 'R') { // Tecla 'R' -> Forçar novo Scan
ScanWiFi();
desenharMenu();
}
else if (comando == '\n' || comando == '\r') {
// Ignora quebras de linha enviadas pelo terminal
}
}
}