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.