A pocket tool that shows the MAC address of whatever Ethernet device it is plugged into, on an e-paper screen. No IP configuration, no DHCP, no PC — just plug in a cable and read the MAC off the display.
- WIZnet W5500-EVB-Pico — RP2040 + W5500 Ethernet (SPI0, GP16–GP21)
- Waveshare Pico-ePaper-2.66 — 296×152 e-paper (SPI1, GP8–GP13)
The panel plugs straight onto the W5500-EVB-Pico's 40-pin header. The two devices use different pins, so there is no conflict:
| Function | Bus | Pins |
|---|---|---|
| W5500 Ethernet | SPI0 | MISO 16, CS 17, SCK 18, MOSI 19, RST 20, INT 21 |
| e-Paper display | SPI1 | DC 8, CS 9, SCK 10, MOSI 11, RST 12, BUSY 13 |
The W5500's socket 0 is put into MACRAW receive mode, so the chip delivers every raw Ethernet frame (it sees) on the link. The source MAC field of each frame is the hardware address of the device that transmitted it. On a direct point-to-point link that is exactly the device you plugged into. The most recently seen MACs are drawn on the e-paper.
It is entirely passive — it relies on the peer transmitting something (ARP, STP, LLDP, DHCP, IPv6 neighbour discovery, mDNS, …), which essentially every networked device does within a few seconds of link-up.
Note: If you plug into a switch rather than a single device, you may see broadcast/multicast and any traffic the switch actually forwards to this port, not just the switch.
main.py— application (capture loop + display)w5500_sniffer.py— minimal direct-SPI W5500 MACRAW driverepaper2in66.py— Waveshare 2.66" e-paper driver (vendored, MIT)selftest.py— hardware-free check of the MACRAW framing logictypings/— MicroPython type stubs for the editor (not flashed to the board)pyrightconfig.json— points the type checker attypings/
- Install MicroPython on the W5500-EVB-Pico (the standard Raspberry Pi Pico RP2040 build works).
- Copy
main.py,w5500_sniffer.py, andepaper2in66.pyto the board (e.g. withmpremoteor Thonny).main.pyruns on boot. - Plug an Ethernet cable from the tool into the device under test.
mpremote connect auto cp epaper2in66.py w5500_sniffer.py main.py :
mpremote connect auto run main.py
selftest.py runs the real read_frame() code path against an emulated W5500
on desktop Python — no board or network needed:
python3 selftest.py
# OK: recovered ['AA:BB:CC:DD:EE:01', '11:22:33:44:55:66']
MicroPython adds modules and functions that don't exist in desktop CPython
(machine, framebuf, utime, and time.sleep_ms / ticks_ms /
ticks_diff ...), so an editor's type checker flags them as unknown. The
typings/ folder provides .pyi stubs for exactly those, and
pyrightconfig.json tells the checker (Pyright / Pylance / basedpyright, as
used by Zed and VS Code) where to find them:
{
"stubPath": "typings",
"typeCheckingMode": "basic",
"reportMissingModuleSource": false
}With this in place the project reports no import errors, and you get real
autocomplete for Pin, SPI, and FrameBuffer. These files are editor-only --
do not copy typings/ or pyrightconfig.json to the board.
The stubs are board-independent, so you can drop the same typings/ folder and
pyrightconfig.json into any MicroPython project. Only the four modules used
here are covered; add more (network, rp2, neopixel, ...) as your code
needs them.

