373 lines
11 KiB
C++
373 lines
11 KiB
C++
/*
|
|
* ESP WiFi Analyzer
|
|
* Require ESP8266/ESP32 board support.
|
|
*/
|
|
|
|
// POWER SAVING SETTING
|
|
#define SCAN_INTERVAL 3000
|
|
// #define SCAN_COUNT_SLEEP 3
|
|
// #define LCD_PWR_PIN 14
|
|
|
|
/*******************************************************************************
|
|
* Start of Arduino_GFX setting
|
|
*
|
|
* Arduino_GFX try to find the settings depends on selected board in Arduino IDE
|
|
* Or you can define the display dev kit not in the board list
|
|
* Defalult pin list for non display dev kit:
|
|
* Arduino Nano, Micro and more: CS: 9, DC: 8, RST: 7, BL: 6, SCK: 13, MOSI: 11, MISO: 12
|
|
* ESP32 various dev board : CS: 5, DC: 27, RST: 33, BL: 22, SCK: 18, MOSI: 23, MISO: nil
|
|
* ESP32-C3 various dev board : CS: 7, DC: 2, RST: 1, BL: 3, SCK: 4, MOSI: 6, MISO: nil
|
|
* ESP32-S2 various dev board : CS: 34, DC: 38, RST: 33, BL: 21, SCK: 36, MOSI: 35, MISO: nil
|
|
* ESP32-S3 various dev board : CS: 40, DC: 41, RST: 42, BL: 48, SCK: 36, MOSI: 35, MISO: nil
|
|
* ESP8266 various dev board : CS: 15, DC: 4, RST: 2, BL: 5, SCK: 14, MOSI: 13, MISO: 12
|
|
* Raspberry Pi Pico dev board : CS: 17, DC: 27, RST: 26, BL: 28, SCK: 18, MOSI: 19, MISO: 16
|
|
* RTL8720 BW16 old patch core : CS: 18, DC: 17, RST: 2, BL: 23, SCK: 19, MOSI: 21, MISO: 20
|
|
* RTL8720_BW16 Official core : CS: 9, DC: 8, RST: 6, BL: 3, SCK: 10, MOSI: 12, MISO: 11
|
|
* RTL8722 dev board : CS: 18, DC: 17, RST: 22, BL: 23, SCK: 13, MOSI: 11, MISO: 12
|
|
* RTL8722_mini dev board : CS: 12, DC: 14, RST: 15, BL: 13, SCK: 11, MOSI: 9, MISO: 10
|
|
* Seeeduino XIAO dev board : CS: 3, DC: 2, RST: 1, BL: 0, SCK: 8, MOSI: 10, MISO: 9
|
|
* Teensy 4.1 dev board : CS: 39, DC: 41, RST: 40, BL: 22, SCK: 13, MOSI: 11, MISO: 12
|
|
******************************************************************************/
|
|
#include <Arduino_GFX_Library.h>
|
|
|
|
#define GFX_BL DF_GFX_BL // default backlight pin, you may replace DF_GFX_BL to actual backlight pin
|
|
|
|
/* More dev device declaration: https://github.com/moononournation/Arduino_GFX/wiki/Dev-Device-Declaration */
|
|
#if defined(DISPLAY_DEV_KIT)
|
|
Arduino_GFX *gfx = create_default_Arduino_GFX();
|
|
#else /* !defined(DISPLAY_DEV_KIT) */
|
|
|
|
/* More data bus class: https://github.com/moononournation/Arduino_GFX/wiki/Data-Bus-Class */
|
|
Arduino_DataBus *bus = create_default_Arduino_DataBus();
|
|
|
|
/* More display class: https://github.com/moononournation/Arduino_GFX/wiki/Display-Class */
|
|
Arduino_GFX *gfx = new Arduino_ILI9341(bus, DF_GFX_RST, 3 /* rotation */, false /* IPS */);
|
|
|
|
#endif /* !defined(DISPLAY_DEV_KIT) */
|
|
/*******************************************************************************
|
|
* End of Arduino_GFX setting
|
|
******************************************************************************/
|
|
|
|
#if defined(ESP32)
|
|
#include "WiFi.h"
|
|
#else
|
|
#include "ESP8266WiFi.h"
|
|
#define log_i(format, ...) Serial.printf(format, ##__VA_ARGS__)
|
|
#endif
|
|
|
|
int16_t w, h, text_size, banner_height, graph_baseline, graph_height, channel_width, signal_width;
|
|
|
|
// RSSI RANGE
|
|
#define RSSI_CEILING -40
|
|
#define RSSI_FLOOR -100
|
|
|
|
// Channel color mapping from channel 1 to 14
|
|
uint16_t channel_color[] = {
|
|
RED, ORANGE, YELLOW, GREEN, CYAN, BLUE, MAGENTA,
|
|
RED, ORANGE, YELLOW, GREEN, CYAN, BLUE, MAGENTA};
|
|
|
|
uint8_t scan_count = 0;
|
|
|
|
void setup()
|
|
{
|
|
Serial.begin(115200);
|
|
// Serial.setDebugOutput(true);
|
|
// while(!Serial);
|
|
Serial.println("Arduino_GFX ESP WiFi Analyzer example");
|
|
|
|
// Set WiFi to station mode and disconnect from an AP if it was previously connected
|
|
WiFi.mode(WIFI_STA);
|
|
WiFi.disconnect();
|
|
delay(100);
|
|
|
|
#ifdef GFX_EXTRA_PRE_INIT
|
|
GFX_EXTRA_PRE_INIT();
|
|
#endif
|
|
|
|
#if defined(LCD_PWR_PIN)
|
|
pinMode(LCD_PWR_PIN, OUTPUT); // sets the pin as output
|
|
digitalWrite(LCD_PWR_PIN, HIGH); // power on
|
|
#endif
|
|
|
|
#ifdef GFX_BL
|
|
pinMode(GFX_BL, OUTPUT);
|
|
digitalWrite(GFX_BL, HIGH);
|
|
#endif
|
|
|
|
// Init Display
|
|
if (!gfx->begin())
|
|
{
|
|
Serial.println("gfx->begin() failed!");
|
|
}
|
|
w = gfx->width();
|
|
h = gfx->height();
|
|
text_size = (h < 200) ? 1 : 2;
|
|
banner_height = text_size * 3 * 4;
|
|
graph_baseline = h - 20; // minus 2 text lines
|
|
graph_height = graph_baseline - banner_height - 30; // minus 3 text lines
|
|
channel_width = w / 17;
|
|
signal_width = channel_width * 2;
|
|
|
|
// init banner
|
|
gfx->setTextSize(text_size);
|
|
gfx->fillScreen(BLACK);
|
|
gfx->setTextColor(RED);
|
|
gfx->setCursor(0, 0);
|
|
gfx->print("ESP");
|
|
gfx->setTextColor(WHITE);
|
|
gfx->print(" WiFi Analyzer");
|
|
}
|
|
|
|
bool matchBssidPrefix(uint8_t *a, uint8_t *b)
|
|
{
|
|
for (uint8_t i = 0; i < 5; i++)
|
|
{ // only compare first 5 bytes
|
|
if (a[i] != b[i])
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void loop()
|
|
{
|
|
uint8_t ap_count_list[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
|
int32_t noise_list[] = {RSSI_FLOOR, RSSI_FLOOR, RSSI_FLOOR, RSSI_FLOOR, RSSI_FLOOR, RSSI_FLOOR, RSSI_FLOOR, RSSI_FLOOR, RSSI_FLOOR, RSSI_FLOOR, RSSI_FLOOR, RSSI_FLOOR, RSSI_FLOOR, RSSI_FLOOR};
|
|
int32_t peak_list[] = {RSSI_FLOOR, RSSI_FLOOR, RSSI_FLOOR, RSSI_FLOOR, RSSI_FLOOR, RSSI_FLOOR, RSSI_FLOOR, RSSI_FLOOR, RSSI_FLOOR, RSSI_FLOOR, RSSI_FLOOR, RSSI_FLOOR, RSSI_FLOOR, RSSI_FLOOR};
|
|
int16_t peak_id_list[] = {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
|
|
int32_t channel;
|
|
int16_t idx;
|
|
int32_t rssi;
|
|
uint8_t *bssid;
|
|
String ssid;
|
|
uint16_t color;
|
|
int16_t height, offset, text_width;
|
|
|
|
// WiFi.scanNetworks will return the number of networks found
|
|
#if defined(ESP32)
|
|
int n = WiFi.scanNetworks(false /* async */, true /* show_hidden */, true /* passive */, 500 /* max_ms_per_chan */);
|
|
#else
|
|
int n = WiFi.scanNetworks(false /* async */, true /* show_hidden */);
|
|
#endif
|
|
|
|
// clear old graph
|
|
gfx->fillRect(0, banner_height, w, h - banner_height, BLACK);
|
|
gfx->setTextSize(1);
|
|
|
|
if (n == 0)
|
|
{
|
|
gfx->setTextColor(WHITE);
|
|
gfx->setCursor(0, banner_height);
|
|
gfx->println("no networks found");
|
|
}
|
|
else
|
|
{
|
|
for (int i = 0; i < n; i++)
|
|
{
|
|
channel = WiFi.channel(i);
|
|
idx = channel - 1;
|
|
rssi = WiFi.RSSI(i);
|
|
bssid = WiFi.BSSID(i);
|
|
|
|
// channel peak stat
|
|
if (peak_list[idx] < rssi)
|
|
{
|
|
peak_list[idx] = rssi;
|
|
peak_id_list[idx] = i;
|
|
}
|
|
|
|
// check signal come from same AP
|
|
bool duplicate_SSID = false;
|
|
for (int j = 0; j < i; j++)
|
|
{
|
|
if ((WiFi.channel(j) == channel) && matchBssidPrefix(WiFi.BSSID(j), bssid))
|
|
{
|
|
duplicate_SSID = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!duplicate_SSID)
|
|
{
|
|
ap_count_list[idx]++;
|
|
|
|
// noise stat
|
|
int32_t noise = rssi - RSSI_FLOOR;
|
|
noise *= noise;
|
|
if (channel > 4)
|
|
{
|
|
noise_list[idx - 4] += noise;
|
|
}
|
|
if (channel > 3)
|
|
{
|
|
noise_list[idx - 3] += noise;
|
|
}
|
|
if (channel > 2)
|
|
{
|
|
noise_list[idx - 2] += noise;
|
|
}
|
|
if (channel > 1)
|
|
{
|
|
noise_list[idx - 1] += noise;
|
|
}
|
|
noise_list[idx] += noise;
|
|
if (channel < 14)
|
|
{
|
|
noise_list[idx + 1] += noise;
|
|
}
|
|
if (channel < 13)
|
|
{
|
|
noise_list[idx + 2] += noise;
|
|
}
|
|
if (channel < 12)
|
|
{
|
|
noise_list[idx + 3] += noise;
|
|
}
|
|
if (channel < 11)
|
|
{
|
|
noise_list[idx + 4] += noise;
|
|
}
|
|
}
|
|
}
|
|
|
|
// plot found WiFi info
|
|
for (int i = 0; i < n; i++)
|
|
{
|
|
channel = WiFi.channel(i);
|
|
idx = channel - 1;
|
|
rssi = WiFi.RSSI(i);
|
|
color = channel_color[idx];
|
|
height = constrain(map(rssi, RSSI_FLOOR, RSSI_CEILING, 1, graph_height), 1, graph_height);
|
|
offset = (channel + 1) * channel_width;
|
|
|
|
// trim rssi with RSSI_FLOOR
|
|
if (rssi < RSSI_FLOOR)
|
|
{
|
|
rssi = RSSI_FLOOR;
|
|
}
|
|
|
|
// plot chart
|
|
// gfx->drawLine(offset, graph_baseline - height, offset - signal_width, graph_baseline + 1, color);
|
|
// gfx->drawLine(offset, graph_baseline - height, offset + signal_width, graph_baseline + 1, color);
|
|
gfx->startWrite();
|
|
gfx->writeEllipseHelper(offset, graph_baseline + 1, signal_width, height, 0b0011, color);
|
|
gfx->endWrite();
|
|
|
|
if (i == peak_id_list[idx])
|
|
{
|
|
// Print SSID, signal strengh and if not encrypted
|
|
String ssid = WiFi.SSID(i);
|
|
if (ssid.length() == 0)
|
|
{
|
|
ssid = WiFi.BSSIDstr(i);
|
|
}
|
|
text_width = (ssid.length() + 6) * 6;
|
|
if (text_width > w)
|
|
{
|
|
offset = 0;
|
|
}
|
|
else
|
|
{
|
|
offset -= signal_width;
|
|
if ((offset + text_width) > w)
|
|
{
|
|
offset = w - text_width;
|
|
}
|
|
}
|
|
gfx->setTextColor(color);
|
|
gfx->setCursor(offset, graph_baseline - 10 - height);
|
|
gfx->print(ssid);
|
|
gfx->print('(');
|
|
gfx->print(rssi);
|
|
gfx->print(')');
|
|
#if defined(ESP32)
|
|
if (WiFi.encryptionType(i) == WIFI_AUTH_OPEN)
|
|
#else
|
|
if (WiFi.encryptionType(i) == ENC_TYPE_NONE)
|
|
#endif
|
|
{
|
|
gfx->print('*');
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// print WiFi stat
|
|
gfx->setTextColor(WHITE);
|
|
gfx->setCursor(0, banner_height);
|
|
gfx->print(n);
|
|
gfx->print(" networks found, lesser noise channels: ");
|
|
bool listed_first_channel = false;
|
|
int32_t min_noise = noise_list[0]; // init with channel 1 value
|
|
for (channel = 2; channel <= 11; channel++) // channels 12-14 may not available
|
|
{
|
|
idx = channel - 1;
|
|
log_i("min_noise: %d, noise_list[%d]: %d", min_noise, idx, noise_list[idx]);
|
|
if (noise_list[idx] < min_noise)
|
|
{
|
|
min_noise = noise_list[idx];
|
|
}
|
|
}
|
|
|
|
for (channel = 1; channel <= 11; channel++) // channels 12-14 may not available
|
|
{
|
|
idx = channel - 1;
|
|
// check channel with min noise
|
|
if (noise_list[idx] == min_noise)
|
|
{
|
|
if (!listed_first_channel)
|
|
{
|
|
listed_first_channel = true;
|
|
}
|
|
else
|
|
{
|
|
gfx->print(", ");
|
|
}
|
|
gfx->print(channel);
|
|
}
|
|
}
|
|
|
|
// draw graph base axle
|
|
gfx->drawFastHLine(0, graph_baseline, 320, WHITE);
|
|
for (channel = 1; channel <= 14; channel++)
|
|
{
|
|
idx = channel - 1;
|
|
offset = (channel + 1) * channel_width;
|
|
gfx->setTextColor(channel_color[idx]);
|
|
gfx->setCursor(offset - ((channel < 10) ? 3 : 6), graph_baseline + 2);
|
|
gfx->print(channel);
|
|
if (ap_count_list[idx] > 0)
|
|
{
|
|
gfx->setCursor(offset - ((ap_count_list[idx] < 10) ? 9 : 12), graph_baseline + 8 + 2);
|
|
gfx->print('{');
|
|
gfx->print(ap_count_list[idx]);
|
|
gfx->print('}');
|
|
}
|
|
}
|
|
|
|
// Wait a bit before scanning again
|
|
delay(SCAN_INTERVAL);
|
|
|
|
#if defined(SCAN_COUNT_SLEEP)
|
|
// POWER SAVING
|
|
if (++scan_count >= SCAN_COUNT_SLEEP)
|
|
{
|
|
#if defined(LCD_PWR_PIN)
|
|
pinMode(LCD_PWR_PIN, INPUT); // disable pin
|
|
#endif
|
|
|
|
#if defined(GFX_BL)
|
|
pinMode(GFX_BL, INPUT); // disable pin
|
|
#endif
|
|
|
|
#if defined(ESP32)
|
|
esp_sleep_enable_ext0_wakeup(GPIO_NUM_36, LOW);
|
|
esp_deep_sleep_start();
|
|
#else
|
|
ESP.deepSleep(0);
|
|
#endif
|
|
}
|
|
#endif // defined(SCAN_COUNT_SLEEP)
|
|
}
|