FreqSniff runs two independent passive radio scanners simultaneously on a single ESP32 board — WiFi 2.4GHz and LoRa 868MHz — since the Heltec WiFi LoRa32 V2 has both radios built in and they operate on completely separate frequency bands with zero interference between them.
- Networks sorted by signal strength (SSID, BSSID, RSSI, channel, security)
- Hidden SSID detection
- Mesh/repeater detection (multiple BSSIDs broadcasting the same SSID)
- Overlap-weighted channel congestion analysis with best-channel recommendation
Tuned to Meshtastic's public LongFast preset (EU_868 region):
| Parameter | Value |
|---|---|
| Frequency | 869.525 MHz |
| Bandwidth | 250 kHz |
| Spreading Factor | 11 |
| Coding Rate | 4/5 |
| Sync Word | 0x2B |
- Packet header parsing (sender, destination, packet ID) — always sent unencrypted by protocol design, so this works regardless of channel key
- RSSI / SNR per packet
- Best-effort decryption using Meshtastic's publicly documented default channel key — this is the intended behavior of the open community channel (comparable to reading a public WiFi beacon), not a bypass of any protection. Custom/private channel keys are never targeted.
- Decoded text messages (portnum 1) shown in plain text; other message types show port number and payload length only
- Serial monitor — live text log of both WiFi and LoRa activity
- Web dashboard —
http://<device-ip>/orhttp://freqsniff.local/ - OLED display — project name + live network/packet counters
Heltec WiFi LoRa32 V2 — ESP32 + SX1276 LoRa transceiver + SSD1306 OLED, all on one board.
⚠️ Confirm your board is the 868 MHz (EU) variant. The frequency band is fixed in hardware (antenna + matching circuit), not software-selectable.
- VSCodium or VS Code with PlatformIO IDE
- Heltec WiFi LoRa32 V2 board
git clone https://github.com/YOUR_USERNAME/FreqSniff.git
cd FreqSniffOpen the folder in VSCodium/VS Code — PlatformIO will detect platformio.ini
and download dependencies automatically (RadioLib, ArduinoJson, SSD1306
driver).
Set your WiFi credentials in src/main.cpp:
#define WIFI_SSID "YourSSID"
#define WIFI_PASSWORD "YourPassword"Build and upload:
pio run -t upload| Function | GPIO |
|---|---|
| LoRa SCK | 5 |
| LoRa MISO | 19 |
| LoRa MOSI | 27 |
| LoRa CS (NSS) | 18 |
| LoRa RST | 14 |
| LoRa DIO0 | 26 |
| OLED SDA | 4 |
| OLED SCL | 15 |
| OLED RST | 16 |
| Vext control | 21 |
All Meshtastic radio parameters and the default channel key were verified against official documentation and firmware source before implementation:
- Meshtastic Radio Settings
- Meshtastic Overview — Sync Word
- Meshtastic Channel Configuration
- meshtastic/firmware — Channels.h (default PSK source)
- Nonce construction verified against a community reference implementation
(packet ID as little-endian uint64 + sender node as little-endian uint32
- 4 zero bytes, AES-CTR)
- Only the public default channel key is attempted — private/custom channel traffic correctly shows as "private/undecoded"
- Only
TEXT_MESSAGE_APPpayloads are decoded to readable text; other message types (position, telemetry, nodeinfo) are more deeply protobuf-encoded and only their portnum/length are shown - Receive-only: this sniffer never transmits, so LoRa duty-cycle regulations (which apply to transmission) aren't a factor here
Released into the public domain under the Unlicense.
