Diagnostics
GPS (T-Deck Plus only)
CMD> gps on # start GPS background task with live status display
CMD> gps off # stop GPS background task
CMD> gps test # one-shot GPS coordinate read + display
GPS status bar icon: grey = off, yellow = searching, green = fixed.
Cold start takes ~4 minutes outdoors. Run gps on before trackme to pre-warm the fix.
test / tst — Hardware Self-Tests
The hardware tests are sub-commands of one test command (formerly the standalone spktest / mictest / loratest):
CMD> test spk # I2S speaker
CMD> test mic # ES7210 microphone
CMD> test lora # LoRa SX1262
CMD> test touch # GT911 touch (T-Deck / T-Deck-Plus)
CMD> test keydump # raw byte from the I2C keyboard MCU (T-Deck / T-Deck-Plus)
test spk — Speaker Test
CMD> test spk
I2S speaker hardware verification and notification level test.
| Key | Action |
|---|---|
1–6 | Raw tones (220–4000 Hz) — bypass NotificationManager |
s | Play C major scale |
a / w / c / i / p | Trigger ALERT / WARNING / SUCCESS / INFO / PING notification levels |
q | Quit |
Keys a/w/c/i/p go through NotificationManager and play the configured WAV if one is set (respecting each level’s on/off toggle). Keys 1–6 bypass volume settings and play raw tones directly — use for hardware verification. To force-play a notification sound regardless of toggle, use nf test.
test mic — Microphone Test
CMD> test mic
ES7210 microphone hardware verification (the mic is on both T-Deck and T-Deck Plus — only the GPS is Plus-exclusive).
- Live level meter — peak-hold bar + scrolling bar-graph that react to sound.
- Voice-activity detection —
*** VOICE DETECTED ***flashes when speech is present (debounced). - Record + replay — capture 3 s to PSRAM and play it back through the speaker to confirm the full capture→playback path.
The capture de-duplicates the ES7210’s ALL_LEFT stream (which delivers two identical samples per audio sample) so playback is true 16 kHz mono — correct pitch and duration.
| Key | Action |
|---|---|
r | Record 3 s |
p | Replay the recording |
+ / - | Mic gain |
q | Quit |
test lora — LoRa Test
CMD> test lora
Initializes the LoRa SX1262, runs a TX test, then enters RX monitor mode. Press q to stop.
test keydump — Keyboard Raw-Byte Dump (T-Deck / T-Deck-Plus only)
CMD> test keydump
Reads one byte at a time from the LilyGo I2C keyboard MCU (0x55) and prints it as 0xHH 'c'. Press q to exit.
Use it to discover what an unmapped Sym / Alt combo actually sends. The keyboard firmware resolves modifier combos internally and hands the ESP32 one already-resolved byte — Al-Anqa can only intercept bytes it can see. If you find a key or combo that types nothing but returns a specific non-zero byte in the dump, that byte can be remapped in boardReadKey() (see Keyboard Reference — SYM+0 → = was discovered exactly this way).
Not available on T-Pager (it has its own test keymap for the same purpose, tailored to the TCA8418 driver which does key resolution in our own code).
csidetect / csi — WiFi CSI Motion Detector [EXPERIMENTAL]
Not an actual radar. The circular sweep display is a style choice only — the device cannot locate, count, or aim at people. It detects motion energy from WiFi disturbance, nothing spatial. See “Honest limits” below.
CMD> cw <ssid> <password> # connected mode: join a network first
CMD> csi # ...then open the detector (cleaner signal)
CMD> csi auto # passive mode: NO router join needed
Two modes:
csi— uses the network you’re connected to (runcwfirst). A busy link = more frames = snappier, cleaner detection.csi auto— scans, locks onto the strongest nearby AP’s beacons, and senses without associating to anything. Works against any router. Trade-off: beacon-rate is lower than a connected link, so it’s a touch laggier. It locks to a single AP on purpose (mixing multiple transmitters would read as fake motion).
A single-chip WiFi motion detector — believed to be the first WiFi-CSI sensing feature on a T-Deck. Every WiFi frame the radio receives carries Channel State Information (amplitude/phase of the OFDM subcarriers). A moving body changes the room’s multipath, so the CSI variance rises. csi tracks that, self-calibrates a floor/ceiling, and turns it into a live presence + motion readout on a double-buffered sweep-style display. No camera, no PIR, no extra hardware — it rides the WiFi your environment is already transmitting.
Reading the screen
| Element | Meaning |
|---|---|
| CLEAR (green centre) | No movement detected |
| CONTACT (red centre, pulses) | Movement near the device |
| MOTION % | How much movement right now |
Activity (STILL/FIDGET/WALK/RUN) | Rough magnitude class |
| Blips / sectors | Decorative. Blip intensity reflects real signal (how much a subcarrier band reacted), but the position/angle on the dial is arbitrary — the 8 sectors are mapped to fixed angles, NOT directions. A blip at “top” does not mean motion is in front of you. |
| Sweep cone | Decorative only — a time-based animation, not scanning or aiming at anything. |
AUTO c<ch> <ssid> / LINK c<ch> <ssid> | Source AP: mode, channel + network name (truncated; full BSSID/SSID in the CSV log) |
NBVI on/off | Smart subcarrier weighting state (toggle with n) |
fr:<n> + CSI live | Bring-up health: CSI frames received + status |
Keys
| Key | Action |
|---|---|
a / l / trackball | Sensitivity (− / +). In adaptive mode these nudge the noise-floor margin. |
c | Recalibrate — re-baseline the room (also resets the noise floor) |
t | Adaptive threshold on/off — auto-tracks the quiet-room noise floor |
n | NBVI smart-subcarrier weighting on/off (A/B test) |
s | SD logging on/off → /apps/csidetect/NNN.csv |
h | In-app help overlay |
q | Quit |
Signal processing (what makes it more precise)
- NBVI subcarrier weighting — instead of averaging all ~56 subcarriers equally, each subcarrier is weighted by its normalized variance, so the ones actually reacting to movement dominate and static ones contribute ~nothing. Auto-learned (no manual calibration); toggle
nto compare on/off. - Hampel filter — a 7-sample median/MAD outlier reject on the motion signal, so a single RF glitch can’t false-trip CONTACT.
- Adaptive threshold (
t) — instead of a fixed sensitivity, the trip level sits a small margin above the continuously-learned quiet-room noise floor. When the source gets noisier (e.g.csi auto’s sparse beacons), the bar auto-raises to match → fewer false CONTACTs.a/ladjust the margin; the panel showsTHR auto. - Single-source lock (auto mode) — only one AP’s frames feed the detector, avoiding false motion from channel traffic switching between transmitters.
SD logging (s)
Press s to record presence transitions to /apps/csidetect/NNN.csv (sequential, never overwritten — like wguard/bmon). A row is written each time the state flips CLEAR↔CONTACT, so the file stays small and answers “when was there motion.” Columns:
time,event,motion_pct,thresh_pct,zones,mode,channel,bssid,ssid
time is a real date-time when GPS/NTP is available, otherwise an @<uptime>ms counter (same convention as the other apps). mode is AUTO/LINK. channel/bssid/ssid identify the AP the motion was sensed off — the full BSSID (e.g. A1:B2:C3:D4:7F:78) and its network name (ssid, commas stripped for CSV; (hidden) if none). The panel shows L<n> next to fr: while recording. Writes are GDMA-guarded (promiscuous is paused for each write), so logging is safe even though CSI keeps the radio busy.
How to use it
- Either connect with
cwthen runcsi, or just runcsi auto(no join — it picks the strongest AP itself). A busier source gives more frames and snappier detection. - Leave it still for ~10–15 s so it learns the empty room → CLEAR.
- Move or walk near it → CONTACT + the MOTION bar rises.
- Best confidence check: leave the room → CLEAR; walk back → CONTACT, repeated.
Honest limits
- The radar layout is decorative. The circular dial, the sweeping cone, and the angle/position of every blip are a visual style only — not a map of where motion is. Only two things carry real meaning: the centre (CLEAR/CONTACT) and the MOTION % bar. A blip’s brightness ≈ how much a subcarrier band moved; its place on the dial is arbitrary.
- Single antenna = one motion-energy signal. There is no true direction, no person count, and no localization — in either
csiorcsi auto. The 8 sectors are independent signal measurements spread around the dial for readability, not a compass bearing. (Reference projects either randomize the angle or use a multi-node mesh + ML to get real position; one T-Deck can’t.) csi autolooks noisier thancsi— passive beacon-rate (~10 frames/s) is far sparser than a connected link, so the signal jitters more. Presscto recalibrate while still, lower sensitivity witha, or use connectedcsifor the cleanest read.- Motion only — a perfectly still person can read CLEAR.
- Environment-dependent — needs WiFi traffic, benefits from
crecalibration when you change rooms. Best treated as a covert motion/occupancy indicator, not a precision sensor.
Adapted from the single-device CSI path of skizzophrenic/Cardputer-CSI-Human-Detector (MIT); subcarrier-band idea from ruvnet/ruview; the NBVI subcarrier weighting, Hampel filter, and passive operation are methodology from ESPectre (GPL — no code copied). See NOTICES.