Skaner sieci WiFi.
Program, który wyświetla dane dostępnych sieci WiFi.
Do budowy skanera będzie potrzebne dowolne urządzenie z ESP8266, ja tradycyjnie korzystam z WeMos D1 mini.
Skaner WiFi pozwala sprawdzić jakie AP znajdują się w zasięgu tego urządzenia. Jak widać na foto obok pokaże nazwy AP, ich kanały, MAC adresy, siłę sygnału, czy AP zabezpieczony i czy nie jest ukryty. Gdy jest połączony z AP, to wyświetli jego dane. Gdy brak połączenia, to wyświetli „Brak połączenia z siecią WiFi.”. Aby połączyć się z jakimś AP należy wybrać go z wyświetlanych i podać hasło dla tego AP. LED wbudowany sygnalizuje brak połączenia z WiFi (świeci), gdy jest połączenie LED jest wyłączony.
Aby połączyć się ze Skanerem należy wybrać w sieci WiFi AP_WiFiScaner i podać hasło 12345678, dane te są ustawiane w programie. Następnie za pomocą przeglądarki www połączyć się z IP 192.168.4.1, reszta jak na ekranie. Na stronie głównej jest wyświetlany czas od uruchomienia i przycisk do strony skanowania. Najnowszy kod źródłowy tego programu znajduje się na tutaj.
Uruchom Arduino IDE.
Nowy szkic i zaraz zapisz go pod WiFiScaner.
Do pliku WiFiScaner.ino wklej poniższy kod.
//WiFiScaner.ino
#include "Arduino.h"
#include "ESP8266WiFi.h"
#include <ESP8266WebServer.h>
#include "WebWiFiScan.h"
#define pinLED BUILTIN_LED
//#define IP_STATIC
//#define DEBUG
//dane dla AP
const char* ap_ssid = "AP_WiFiScaner"; // SSID AP
const char* ap_pass = "12345678"; // password do AP
int ap_channel= 2; //numer kanału dla AP
extern ESP8266WebServer server;
#ifdef IP_STATIC
IPAddress IPadr(10,110,2,105); //stały IP
IPAddress netmask(255,255,0,0);
IPAddress gateway(10,110,0,1);
#endif
void setup()
{
#ifdef DEBUG
Serial.begin(115200);
#endif
pinMode(pinLED, OUTPUT);
digitalWrite(pinLED, LOW);
//ustaw SSID, pass i kanał dla AP
WiFi.softAP(ap_ssid, ap_pass, ap_channel);
#ifdef IP_STATIC
WiFi.config(IPadr,gateway,netmask); // stały IP
#endif
WiFi.mode(WIFI_AP_STA); //tryb AP_STATION
WiFi.begin();
int it = 20;
while ((WiFi.status() != WL_CONNECTED) and it>0) { // czekaj na połączenie z WiFi
delay(500);
it-- ;
#ifdef DEBUG
Serial.print(".");
#endif
}
#ifdef DEBUG
if (it>0) {
Serial.println("");
Serial.println("WiFi połączone");
Serial.println(WiFi.localIP());
Serial.println(WiFi.macAddress());
Serial.print("Tryb pracy: ");
Serial.println(WiFi.getMode());
Serial.print("Tryb modulacji: ");
Serial.println(WiFi.getPhyMode());
Serial.print("Nr kanału: ");
Serial.println(WiFi.channel());
Serial.print("IP AP: ");
Serial.println(WiFi.softAPIP() );
//WiFi.printDiag(Serial);
}else {
Serial.println();
Serial.println("Brak połączenia z WiFi!.");
}
#endif
setservers();
}
void loop()
{
server.handleClient();
if (WiFi.status() != WL_CONNECTED){
digitalWrite(pinLED, LOW);
if (WiFi.getMode() != WIFI_AP_STA){
WiFi.mode(WIFI_AP_STA);}
}
else{ // wyłącz LED gdy jest połączenie z WiFi
digitalWrite(pinLED, HIGH);
// if (WiFi.getMode() != WIFI_STA){
// WiFi.mode(WIFI_STA);}
}
}
Potrzebne jeszcze są dwa pliki – WebWiFiScan.h i WebWiFiScan.cpp.
/* * WebWiFiScan.h * * Created on: 11.04.2017 * Author: Jan Trzciński poljant@post.pl */ #ifndef WEBWIFISCAN_H_ #define WEBWIFISCAN_H_ #include <ESP8266WiFi.h> #include <ESP8266WebServer.h> #include <ESP8266HTTPUpdateServer.h> String HTMLHeader(); String HTMLFooter(); String HTMLPage(); String HTMLPage1(); String HTMLPage2(); String HTMLWiFiScan(); void setservers(void); #endif /* WEBWIFISCAN_H_ */
Do pliku WebWiFiScan.cpp wklej poniższy kod.
//WebWiFiScaner.cpp
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <ESP8266HTTPUpdateServer.h>
// login i hasło do sytemu
const char* www_login = "admin";
const char* www_pass = "esp8266";
const char* epass[32];
const char* essid[32];
const char* modes[] = {"NULL","STA","AP","STA+AP"};
const char* phymodes[] = { "","B", "G", "N"};
const int port = 80; // port serwera www
ESP8266WebServer server(port);
ESP8266HTTPUpdateServer httpUpdate;
char* IPAdrToStr(int ip)
{
char* ip_str = new char[16];
sprintf(ip_str, "%d.%d.%d.%d",
(ip ) & 0xFF,
(ip >> 8) & 0xFF,
(ip >> 16) & 0xFF,
(ip >> 24) & 0xFF);
return ip_str;
}
String HTMLHeader() { // nagłówek strony
String h = "<!DOCTYPE html>\n";
h += "<html>";
h += "<head>";
h += "<title> WiFi Scaner</title>";
// h += "<meta http-equiv=\"Refresh\" content=\"30\" />"; //odświerzaj stronę co 30 sek.
h += "<meta charset=\"utf-8\">";
h += "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">";
h += "<link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css\" >";
h += "</head>";
h += "<body style=\"text-align: center;color: white; background: black;font-size: 1.5em;\">\n";
return h;
}
String HTMLFooter() { // stopka strony www
String f = "";
f += "<p>Jan Trzciński © 2017</p></td></tr>";
f += "</body>\n";
f += "</html>\n";
return f;
}
String HTMLPage1() { // pierwsza część strony www
String t;
unsigned long sec = millis() / 1000;
unsigned long min = (sec / 60);
unsigned long hour = (min / 60);
unsigned long days = hour / 24;
sec = sec % 60;
min = min % 60;
hour = hour % 24;
t = "<h1>WiFi skaner</h1>";
t += "<p> Wersja oprogramowania 1.0 z dnia 11-04-2017";
t += "</p>";
t += "<p>Czas od uruchomienia dni: ";
t += (days);
t += " godz:" ;
t += ((hour<10) ? "0" : ""); //gdy mniej niż 10 wstaw zero wiodące
t += (hour);
t += ":";
t += ((min<10) ? "0" : ""); //gdy mniej niż 10 wstaw zero wiodące
t += (min);
t += ":";
t += ((sec < 10) ? "0" : ""); //gdy mniej niż 10 wstaw zero wiodące
t += (sec);
t += "</p>";
t +="<p><a href = \"/wifiscan\"><button class=\"btn btn-info\">Skanuj sieć WiFi</button></a></p>";
return t;
}
String HTMLWiFiScan(void){
String p="";
String ix="";
uint8_t n = WiFi.scanNetworks();
if (n == 0) return "<p>Brak sieci WiFi.</p>";
p +="<div><h3>Skanowanie sieci WiFi</h3></div>";
p +="<table align=\"center\" border=\"2\" >";
p +="<thead ><tr><th> </th><th style = \"text-align: center;\">SSID</th>";
p +="<th>kanał</th><th style = \"text-align: center;\">MAC</th>";
p +="<th>RSSI</th><th>zabezp</th><th>ukryta</th><tr>";
p +="</thead><tbody>";
for (uint8_t i=0; i<n;i++){
p +="<tr><td>";
p +="<form action=\"/wifiset\" metod=\"post\">";
p +="<labe><input id=\"SSID\" type=\"radio\" name=\"SSID\" value=\""+WiFi.SSID(i)+"\">";
p +="</label>";
p +="</td>";
p +="<td>"+WiFi.SSID(i)+"</td>"; //nazwa sieci
p +="<td>"+String(WiFi.channel(i))+"</td>"; //kanał
p +="<td>"+WiFi.BSSIDstr(i)+"</td>"; //MAC adres
p +="<td>"+String(WiFi.RSSI(i))+" dBm</td>"; //siła sygnału
p +="<td>";
p +=((WiFi.encryptionType(i)==ENC_TYPE_NONE) ? "nie" : "tak");//czy szyfrowanie
p +="</td><td>";
p +=((WiFi.isHidden(i)) ? "tak" : "nie");//czy sieć ukryta
p +="</td></tr>";
} //end for
p +="</tbody></table>";
p +="<div><p></p> </div>";
// gdy połączenie z WiFi
if(WiFi.status() == WL_CONNECTED){
p += "<p>Jesteś połączony z siecią </p>";
p +="<table align=\"center\" border=\"2\" ><tbody>";
p +="<thead ><tr><th style = \"text-align: center;\">SSID</th>";
p +="<th>kanał</th><th style = \"text-align: center;\">MAC</th>";
p +="<th>RSSI</th></thead><tbody>";
p += "<td>"+WiFi.SSID()+"</td>";
p += "<td>"+String(WiFi.channel())+"</td>";
p += "<td>"+WiFi.BSSIDstr()+"</td>";
p += "<td>"+String(WiFi.RSSI())+" dBm</td></tbody></table>";
p +="<label>IP: "+String(IPAdrToStr(WiFi.localIP()))+"</label>";
p += "<p>Aby zmienić sieć WiFi.</p>";
}else{ //gdy brak połączenia z WiFi.
p += "<p>Brak połączenia z siecią WiFi.</p>";
p += "<label>IP AP: "+String(IPAdrToStr(WiFi.softAPIP()))+"</label>";
} //end if
p += "<p>Wybierz sieć powyżej i podaj hasło</p>";
p +="<label for=\"password\">Hasło do WiFi:</label>";
p +="<input style=\"color: black;\" type=\"password\" name=\"password\" />" ; //required=\"required\"/>";
p +="<input style=\"text-align: center;color: black;\" type=\"submit\" value=\"Połącz z WiFi.\"/></form>";
p += "<p><a href = \"/wifiscan\"><button class=\"btn btn-info\">Skanuj ponownie</button></a></p>";
p += "<p><a href = \"/\"><button class=\"btn btn-info\">Powrót do strony głównej</button></a></p>";
return p;
}
String WebPageScan(){
return (HTMLHeader()+HTMLWiFiScan()+HTMLFooter());
}
String WebPage() { // połącz wszystkie części strony www
return (HTMLHeader()+ HTMLPage1()+HTMLFooter());
}
// funkcja ustawia wszystkie strony www
void setservers(){
httpUpdate.setup(&server,"/update", www_login, www_pass); // umożliwia aktualizację poprzez WiFi
server.on("/", [](){
server.send(200, "text/html", WebPage());
});
server.on("/wifiscan", [] ()
{
server.send(200, "text/html", WebPageScan());
});
server.on("/wifiset", [] ()
{
String ESSID = server.arg("SSID");
String Epass = server.arg("password");
const char* essid = ESSID.c_str();
const char* epass = Epass.c_str();
WiFi.disconnect() ;
WiFi.mode(WIFI_AP_STA);
WiFi.begin(essid,epass);
delay(200);
int it = 20;
while ((WiFi.status() != WL_CONNECTED and it>0)) { // czekaj na połączenie z WiFi
delay(500);
it--;
}
server.send(200, "text/html", WebPageScan());
});
server.begin(); // Start serwera www
#ifdef DEBUG
Serial.println("Server started");
#endif
}
Program zawiera sporo komentarzy, które wyjaśniają prawie wszystko. Wiele rzeczy zostało opisanych w poprzednich wpisach. Po zalogowaniu się do nowej sieci należy odczekać kilka sekund.
Po odłączeniu i ponownym włączeniu zasilania, układ pamięta dane ostatnio wybranej sieci. Aby zmienić sieć należy ponownie wybrać ją przez stronę www.
Miłej zabawy.


Thanks, great article.
Witam,
mam mały problem z biblioteką ESP8266WiFi.h.
Metody np. WiFi.SSID(parametr) czy WiFi.channel(parametr) ja w Twoim przypadku nie pozwalają na podanie parametru a tym samym nie można się odwołać do wykrytego konkretnego AP.
Osobiście używam Eclipsa w do programowania i w tym przypadku wbudowanej biblioteki.
Pozdrawiam GM
Witam
U mnie Eclipse też sygnalizuje błąd typu, ale kompiluje prawidłowo i skompilowany program działa.
Wygląda na to, że kompilator widzi błąd typu danych, ale kompiluje zgodnie z oczekiwaniem.
Nie analizowałem tego dokładnie, bo mimo wszystko program działa prawidłowo.
W Arduino nie sygnalizuje tego błędu.
pozdrawiam
Jan
Dzięki za odpowiedź.
Not yet. But if I have time, I will try.