fuzzyworld

haunt

Contribute: contrib-68uq+haunt@fuzzyworld.net (how) · Report a bug: bugs-k7q4+haunt@fuzzyworld.net

git clone https://code.fuzzyworld.net/haunt.git

Open in VS Code · Open in VS Code in the browser

Recent commits

2026-05-164c8d760docs: added attributionPavel Safronov
2026-05-14558500eSync generated icons with current generateIcons task outputPavel Safronov
2026-05-14f46c066Add favicon.ico and favicon.png to repo root; include in generateIcons taskPavel Safronov
2026-05-13f34f371Keep map labels upright in orientation modePavel Safronov
2026-05-138943724Restore light state after SIGKILL mid-blinkPavel Safronov

Full log

Haunt

Android app that uses WiFi Round-Trip Time (RTT) ranging to fingerprint your phone's position and activate the corresponding Philips Hue light — no floor plans, no coordinate systems, no backend.

How it works

Three Google WiFi pucks each return a distance reading in meters. The combination of all three — a distance-triple — is unique to a physical location. During calibration you record a triple for each room. At runtime, the app finds the nearest stored triple and switches the light for that room.

See docs/wifi-rtt-hue-brief.md for the full design brief including accuracy expectations, gotchas, and development order.

Hardware required

Setup

1. Hue credentials

Press the button on your Hue Bridge, then within 30 seconds:

curl -X POST http://<bridge-ip>/api \
  -H "Content-Type: application/json" \
  -d '{"devicetype":"haunt#android"}'
# Save the username from the response

curl http://<bridge-ip>/api/<username>/lights
# Note the integer ID for each light you want to control

2. Find puck BSSIDs

Run the app in debug mode — it lists every RTT-capable AP with its BSSID. Walk up to each puck; it will auto-pin to the map when you're within 0.5 m. Rename the pinned points (e.g. "Router kitchen") so you can identify which BSSID belongs to which puck.

3. Open in Android Studio

Requires Android Studio Ladybug or later. On first open, let Gradle sync finish and generate the wrapper JAR, then run on a physical device (RTT does not work in the emulator).

App icon

The launcher icon is generated from location.png in the repo root. After replacing that file, regenerate all mipmap sizes and the adaptive-icon foreground with:

gradle :app:generateIcons

To change the background color, edit the bgColor variable at the top of the generateIcons task in app/build.gradle.kts. The task is incremental — Gradle skips it if location.png hasn't changed.

Attribution

location.png is from the Outline collection by icongeek26 on Flaticon.

Orientation mode

The map has a built-in compass mode. Tap ⊙ Orient in the toolbar to enable it. The map then rotates to keep the phone's forward direction at the top, and a red N indicator appears at the edge showing where north is.

Calibration: face your known north, hold the phone pointing that way, then drag the N circle to the top of the screen. The offset is saved and persists across restarts.

Haunt mode

Tap Haunt to enable haunt mode. While active, when you walk close to a registered Hue light (within ~1 m), that light blinks on and off slowly. When you move away or turn haunt mode off, the light returns to the state it was in before blinking started.

Development status

Layer Status Description
1 ✅ Project scaffold, permissions, RTT availability check
2 ✅ RTT ranging, debug map, add/rename/delete points, history trail
3 ✅ Hue Bridge discovery, pairing, light/group listing and blinking
4 ✅ Haunt mode — proximity detection, blink loop, state restoration
5 ✅ Compass orientation mode — live map rotation, N indicator, calibration
6 ✅ LAN device scanner — ARP + mDNS, pin network devices to map
7 — ZoneMatcher — automatic light switching without haunt button
8 — Background service — keep ranging alive when app is backgrounded
9 — Tuning — average N readings, debounce K zone changes

Package

net.fuzzyworld.haunt