Build a $25 analog scanner from an ESP32 and an SA818 module
The Raspberry Pi companion is the one for digital trunking. But a lot of what's interesting on the air is plain narrow FM — marine channel 16, 2 m and 70 cm repeaters, business itinerants, fire-ground tactical channels in many counties, railroad — and for that a Pi is overkill. An ESP32 with an SA818 radio module does it on a fraction of the power, from a battery, in a box the size of a deck of cards.
Parts
- ESP32 dev board (any; the firmware is tested on a WROOM-32 and an S3).
- SA818-U (400–480 MHz) or SA818-V (134–174 MHz). It's a complete FM transceiver on a 1 W module, controlled by AT commands over serial. We only ever receive; the PTT pin stays high.
- Optional: an SX1276 or CC1101 module, which gives you an RSSI spectrum strip and sub-GHz sensor decoding (
rtl_433-style, via rtl_433_ESP). - An antenna for the band. A 70 cm whip on an SMA edge connector, or a mag-mount.
Wiring
SA818 TXD → ESP32 GPIO16 (Serial1 RX)
SA818 RXD → ESP32 GPIO17 (Serial1 TX)
SA818 SQ → ESP32 GPIO4 (squelch open = low)
SA818 AF → ESP32 GPIO36 (ADC1_CH0 / VP, through a 1 µF cap + 10k/10k bias to 1.65 V)
SA818 PTT → 3.3 V (never key up)
SA818 PD → 3.3 V
SA818 VCC → 3.3 V, 500 mA capable; GND common
The AF line is line-level audio centred near 1.5 V; the ESP32's ADC samples it at 8 kHz, encodes IMA ADPCM, and ships 40 ms frames over BLE — identical to the Pi, so the app doesn't care which it's talking to.
Firmware
It's companion/esp32/wavelens_companion/ in the repo, built with PlatformIO (pip install platformio; the platformio.ini is next to the code). A bare board with no module is pio run -e esp32 -t upload — the Wi-Fi/BLE sniffer, and the place to start. For the SA818, pick the esp32-scanner environment and set your module's pins if they differ from the defaults:
[env:esp32-scanner]
build_flags = -DHAS_SA818_U ; pins default to TX 17, RX 16, SQ 4, AF 36 — override with -DSA818U_TX=… if yours differ
pio run -e esp32-scanner -t upload
Three things that bit us on the first flash, all of which the build now avoids: the sketch has to be compiled as a .cpp (the Arduino .ino prototype pass mangles the module structs), the Wi-Fi + NimBLE image is 1.4 MB so it needs the huge_app partition table, and on Windows the board only appears as a COM port once the CP210x/CH340 driver is in. If upload picks COM1, that's the motherboard, not the board.
On boot it probes the module with AT+DMOCONNECT, advertises as Wavelens-XXXX, and its hello tells the phone exactly what it found — "sa818u":"up", or "fitted" if the module didn't answer, so a wiring mistake shows up on the Companion screen instead of as silence.
Using it
Pair it like any companion (More → Companion radio). In the app's Companion screen, the Scan list editor takes the channels you want — 156.800 marine 16, 462.5625 FRS 1, your local repeater outputs — and the ESP32 steps through them, stopping when the squelch opens. Tap a frequency in the Scanner tab to listen directly. With the SX1276 fitted, the Spectrum strip shows a live RSSI sweep of the module's band and the companion reports carriers it finds, so Follow can tune to something you didn't list.
What it won't do: digital. No P25, no DMR, no trunking — the SA818 is an FM discriminator, and the app knows (the hello carries listen and scan but not trunk). For that, the Pi. The two coexist happily; the app pairs with one companion at a time but remembers both.
Rather not build it?
Spotter $64 · Full Spectrum $499: the builds on this blog, programmed and tested, set up for where you drive, with free updates for life. The guides stay here, free, if you change your mind.
Shop Join the free Android beta
Open firmware and bridge on GitHub · receive only · every command on this blog is copied from a Pi we run