Skip to content

wifi: allow 5 GHz channels in Monitor - #11375

Open
mikeysklar wants to merge 1 commit into
adafruit:mainfrom
mikeysklar:wifi-monitor-5ghz
Open

wifi: allow 5 GHz channels in Monitor#11375
mikeysklar wants to merge 1 commit into
adafruit:mainfrom
mikeysklar:wifi-monitor-5ghz

Conversation

@mikeysklar

Copy link
Copy Markdown
Collaborator

What

wifi.Monitor(channel=) and Monitor.channel accept 1 to 165. The espressif port raises ValueError for a channel the radio rejects.

Why

Fixes #11339. Sibling of #11374 for start_ap. The 1 to 13 clamp made 5 GHz capture impossible on the ESP32-C5.

Where Change
shared-bindings range 1..13 -> 1..165 in constructor and setter; setter reuses the constructor's validator, so %q out of bounds leaves the pot
espressif check esp_wifi_set_channel; ESP_ERR_INVALID_ARG -> ValueError: Invalid channel, construct undoes promiscuous mode and the queue first
espressif while the station is associated the IDF refuses to move the radio; the monitor stays on the station's channel and channel reports it (what the old code did silently)

Only espressif implements Monitor; raspberrypi and zephyr-cp are untouched.

Hardware tested

Board CircuitPython Host
ESP32-C5-DevKitC-1-N8R8 10.4.0-alpha.1, main at 7396914 plus this change Linux
Adafruit Metro ESP32-S2 same same

Not tested: other ESP32 variants.

How I tested it

REPL lines below are condensed from scripted runs; outputs are verbatim.

C5, no station, 20 s on channel 149. Home AP beacons carry the right channel and RSSI in the packet dict:

>>> m = wifi.Monitor(channel=149, queue=256)
frames in 20 s: 877 lost: 0 by CH: {149: 877}
home AP beacons (CH, RSSI, LEN): [(149, -47, 418), (149, -47, 418), (149, -47, 419), ...]
>>> m.channel = 37
ValueError: Invalid channel
>>> m.channel = 166
ValueError: channel must be 1-165
>>> m.channel
149

Hop across 1-13, 36-64 and 100-165 at 0.5 s each: no channel rejected in promiscuous mode, no frame tagged with a channel other than the one tuned, 0 lost.

C5 with the station associated on 149:

>>> m = wifi.Monitor(channel=6)
>>> m.channel
149
>>> m.channel = 36
>>> m.channel
149
>>> m.channel = 37
ValueError: Invalid channel

Metro ESP32-S2, 2.4 GHz only:

>>> wifi.Monitor(channel=36)
ValueError: Invalid channel
>>> m = wifi.Monitor(channel=6)   # works after the failed construct
after failed construct, ch6 monitor works: frames in 5 s 257
>>> m.channel = 149
ValueError: Invalid channel

Try it

code.py for an ESP32-C5, based on the hop script in #11339. Runs as code.py because Monitor state is reset when a REPL session ends.

import time, wifi

CHANNELS = (1, 6, 11, 36, 40, 44, 48, 149, 153, 157, 161, 165)
wifi.radio.stop_station()   # otherwise the radio stays on the station's channel
m = wifi.Monitor(channel=1, queue=256)
while True:
    for ch in CHANNELS:
        m.channel = ch
        t0 = time.monotonic()
        while time.monotonic() - t0 < 0.5:
            p = m.packet()
            if p:
                print(ch, p[wifi.Packet.CH], p[wifi.Packet.RSSI], p[wifi.Packet.LEN])

Scope

On #11339 the frame channel and RSSI looked wrong; those values were read from the 802.11 header bytes. Packet.CH and Packet.RSSI come from the IDF's rx_ctrl and are correct on the C5, whose rx_ctrl.channel is 8 bits.

AI assistance

Claude drafted the change and the test scripts. I reviewed the diff, ran every test on the boards above, and checked the IDF headers for the rx_ctrl layout and the esp_wifi_set_channel contract.

🤖 Generated with Claude Code

The channel was clamped to 1..13, so dual-band radios could not monitor
5 GHz. Accept 1..165, matching start_scanning_networks(), and check the
esp_wifi_set_channel() result: an invalid channel raises ValueError. The
setter reuses the constructor's range check, dropping one message.

While the station is associated the IDF refuses to move the radio. The
monitor then stays on the station's channel and reports it, which is
what the old code did without saying so.

Fixes adafruit#11339

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@anecdata

anecdata commented Sep 14, 2026

Copy link
Copy Markdown
Member

This looks great. I should be able to do some testing tomorrow. You're right about the channel and RSSI, I had grabbed and modified some simpler old code from when we were developing monitor (rather than my current "production" code), and it wasn't right for the frame structure coming back in RAW.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add 5GHz capability to wifi Monitor

2 participants