A portable ESP32-S3 device for measuring indoor Wi-Fi signal quality at named locations. The device uses an OLED display and one push button to collect repeated RSSI measurements, save them in ESP32 flash memory, and export clean CSV results through the Arduino Serial Monitor.
Wi-Fi quality can change strongly inside the same room or apartment. A laptop or phone can show signal strength, but it does not usually create a structured survey with named locations, repeated samples, averages, BSSID/channel information, and a clean export.
This project solves that by turning an ESP32-S3 into a small portable Wi-Fi survey tool.
- ESP32-S3 Wi-Fi scanning
- SSD1306 OLED status screen
- One-button control
- Named indoor test locations
- 3 RSSI samples per location
- Average RSSI calculation
- Best/worst location detection
- CSV export over Serial Monitor
- Offline saved data using ESP32
Preferences - BSSID lock mode for measuring one exact access point
- ESP32-S3 development board
- SSD1306 I2C OLED display
- Push button
- Breadboard and jumper wires
- USB cable / power bank
- Soldered ESP32 cable connections for stable prototype wiring
| Component | Connection |
|---|---|
| OLED GND | ESP32 GND |
| OLED VDD | ESP32 3V3 |
| OLED SCK/SCL | ESP32 GPIO8 |
| OLED SDA | ESP32 GPIO9 |
| Button side 1 | ESP32 GPIO4 |
| Button side 2 | ESP32 GND |
| Action | Result |
|---|---|
| Short button press | Save one sample at the current location |
| Hold 2 seconds | Dump CSV data to Serial Monitor |
| Hold 5 seconds | Clear saved data |
The first version measured the strongest access point with the target SSID. During testing, multiple access points with the same SSID were detected. This can make a Wi-Fi survey less controlled because measurements may switch between access points.
The current firmware includes BSSID lock mode:
const char* TARGET_SSID = "YOUR_WIFI_NAME";
const char* TARGET_BSSID = "AA:BB:CC:DD:EE:FF"; // Leave empty "" to match by SSID onlyWhen TARGET_BSSID is set, the firmware only records samples from that exact access point. Replace with your actual network details before flashing.
| Location | Average RSSI | Quality |
|---|---|---|
| Router | -23.3 dBm | Excellent |
| Desk | -82.7 dBm | Bad |
| Bed | -73.0 dBm | Weak |
| Door | -53.0 dBm | Very good |
| Window | -73.7 dBm | Weak |
| Hallway | -73.7 dBm | Weak |
| FarCorner | -78.0 dBm | Weak |
| BehindWall | -52.7 dBm | Very good |
Best location: Router, -23.3 dBm.
Worst location: Desk, -82.7 dBm.
Signal difference: 59.4 dB.
- How to set up an ESP32-S3 board in Arduino IDE
- How to connect and test an I2C OLED display
- How to use a push button with
INPUT_PULLUP - How to debounce button input in firmware
- How to scan Wi-Fi networks from ESP32
- How to interpret RSSI values
- How to store data in ESP32 flash memory with
Preferences - How to export data as CSV over Serial Monitor
- How to identify a real engineering issue during testing: multiple access points with the same SSID
- How to solder/prepare ESP32 board connections so the screen, button, and board can be connected reliably
Final prototype showing ESP32-S3 with OLED display and push button
OLED display showing best/worst locations after survey
Serial Monitor output showing exported CSV data
Web dashboard bar chart showing signal strength by location
esp32-wifi-mapper/
├── firmware/ # ESP32-S3 firmware source
│ ├── esp32_wifi_mapper/ # Production version (placeholder SSID/BSSID)
│ └── esp32_wifi_mapper_public_template/ # Template for GitHub
├── dashboard/ # Web visualization (Flask)
│ ├── app.py # Dashboard application
│ └── requirements.txt # Python dependencies
├── results/ # Survey data and analysis
│ └── rssi_by_location.png # Dashboard visualization screenshot
├── docs/ # Documentation
├── images/ # Photos and screenshots
├── tools/ # Analysis scripts
│ └── analyze_results.py # Python analysis tool
├── platformio.ini # Build configuration
├── Makefile # Build commands
└── README.md # This file
- User presses button at a named location (Router, Desk, Bed, etc.)
- Firmware scans Wi-Fi networks using
WiFi.scanNetworks() - Filters for target AP by SSID and/or BSSID
- Records RSSI, channel, BSSID and saves to RAM and flash
- OLED displays sample count and location progress
- After all locations, user holds button to dump CSV
- CSV exported via Serial Monitor (115200 baud)
- Python dashboard visualizes the results in a browser
- Install Arduino IDE
- Install ESP32 board manager
- Open
firmware/esp32_wifi_mapper/esp32_wifi_mapper.ino - Replace
TARGET_SSIDandTARGET_BSSIDwith your network details - Upload to ESP32-S3
PlatformIO is a professional cross-platform build system for embedded development. It provides:
- Better dependency management
- Faster builds
- Integrated serial monitor
- CI/CD integration
# Install dependencies
pip install -r dashboard/requirements.txt # Flask, matplotlib
# Build the firmware
pio run
# Upload to ESP32-S3
pio run -t upload
# Open serial monitor
pio device monitorCommands:
pio run- Build firmwarepio run -t upload- Build and uploadpio device monitor- Open serial monitormake- Alternative using Makefile
This project includes a Flask web dashboard for CSV visualization:
Dashboard (dashboard/app.py)
- Flask web application that visualizes CSV data
- Shows signal strength bar chart with best/worst locations
- Open http://localhost:5000 after running
- Uses matplotlib for charts
cd dashboard
python app.py
# Open http://localhost:5000- ESP32 RSSI is useful for comparison, but it is not a professional RF measurement instrument.
- RSSI changes with antenna orientation, human body position, reflections, and router load.
- Room position is entered manually instead of using an automatic floorplan.
- The current prototype is still on a breadboard and should be moved to perfboard or a case for a cleaner portfolio demo.