pedrodinisf/otoscope-viewer
GitHub: pedrodinisf/otoscope-viewer
Stars: 0 | Forks: 0
# aisee — Python receiver & Tk viewer for the AiSee WiFi otoscope
Reverse-engineered native macOS viewer for cheap AliExpress WiFi otoscopes
that ship with the **AiSee Pro** app (`com.earmirror.i4season`, Beken BK7231U,
firmware namespace `XRH`). Streams 480×480 MJPEG over UDP. No phone needed.
The device is its own access point (open, no password) at `192.168.1.1`. The
receiver binds explicitly to `en1` via `IP_BOUND_IF`, so the otoscope Wi-Fi
coexists with your normal Ethernet — internet stays up while you view.
## Setup (one-time)
Requires **uv** (https://github.com/astral-sh/uv) and **ffmpeg** on `PATH`.
uv sync
That creates `.venv/` locally and installs Pillow. Nothing is installed globally.
## Run
1. Power on the otoscope.
2. Join the `AiSee-xxxxx` Wi-Fi on en1 (or use the in-app **Join AiSee** button).
3. `uv run python -m aisee.app`
The Tk window opens, video appears within ~2 s.
- **Snapshot** → `~/Pictures/otoscope/snap_.jpg`
- **Record** → `~/Movies/otoscope/rec_.mp4` (toggle Stop to finalize)
## Tests
uv run python -m unittest discover tests -v
Tests are pinned to byte-for-byte fixtures captured from the real device
(`tests/fixtures/{frame_packets.bin, expected_frame.jpg, discovery_reply.bin}`).
Regenerate them with `uv run python tools/extract_fixture.py` if you re-sniff.
## Protocol cheatsheet
| Step | Direction | Port | Payload (hex) |
|------|-----------|------|---------------|
| Discovery | App → Dev | UDP 10005 | `eeffeeff 00000100 01000000` |
| Discovery reply | Dev → App | UDP 10005 | `eeffeeff 00000100 010080 00 ...` (~140 B incl. `BK7231U` / `AiSee-` / MAC) |
| START | App → Dev | UDP 10006 | `eeffeeff 02000400 01000200 0000` |
| START ACK | Dev → App | UDP 10006 | `eeffeeff 02000400 01000000` |
| Video | Dev → App | UDP `` (src 10006) | 16-byte header ` <00/01_lastfrag> 09 01 <6-byte session-id> 80 02 e0 01` + JPEG bytes |
Frame reassembly: strip the 16-byte header, look for `FF D8` (SOI) to begin a
frame, `FF D9` (EOI) to finish; trim trailing zeros after EOI.