THE IDEAOne sensor is easy to fool
A PIR cannot see someone sitting still. A radar sees a ceiling fan. Wi-Fi sensing gets confused by a microwave. A phone counter thinks the neighbour is in your living room.
Ghostvisor asks a simpler question of all of them at once: how many of my sensors agree that someone is here? The answer is one 0–100 % score with four named levels, hysteresis so it does not flicker, and a plain-English reason for every change.
Wi-Fi CSI
Several ESP32 nodes feel how a person disturbs the radio path to the router. Each node learns its own empty-room baseline.
mmWave A and B
5.8 GHz and 24 GHz Zigbee radars. They see movement and breathing in a cone, and report occupied / clear.
PIR
Warm movement across its view. Quick, but blind to someone sitting still.
PAX counter
Counts nearby phones and Bluetooth gadgets. Only a hint, never one of the core sensors.
BIG PICTUREHow it fits together
Everything runs on one Raspberry Pi. Worker threads feed one queue; the screen thread never waits on I/O.
The three SONOFF sensors reach the Pi through a Zigbee dongle. The ESP32 nodes are polled over Wi-Fi as small JSON, and the PAX counter talks over USB serial.
THE SCOREHow a single number is made
The fusion engine turns each sensor's reading into evidence, adds it up, and then applies a few rules so one noisy device cannot decide alone.
- Weights. Each sensor adds points when it fires, and its silence counts against the others. A radar that stays quiet while everything else shouts is evidence too.
- Agreement bonus. Two or more sensors firing together add a bonus. A lone sensor is capped, so it can never reach
CONFIRMEDby itself. - Offline is doubt, not “empty”. A sensor that drops off adds uncertainty instead of voting that nobody is there.
- Fade, not cliff. After a sensor clears, its evidence fades over seconds instead of snapping to zero.
- It explains itself. Every level change carries a one-line reason, such as “Wi-Fi CSI 2/3 links plus mmWave B”.
| Level | Meaning | Enters at | Leaves below |
|---|---|---|---|
| CLEAR | Nothing detected | – | – |
| POSSIBLE | One sensor thinks so | 25 % | 15 % |
| LIKELY | Several agree | 50 % | 35 % |
| CONFIRMED | Strong agreement | 82 % | 68 % |
A level must hold for 0.5 s before it rises and 5 s before it falls. There are three presets: Balanced, Fewer false alarms and Catch everything.
WI-FI SENSINGCSI, in plain words
Wi-Fi signals bounce around a room. A person standing or walking in the path changes how they arrive. Channel State Information (CSI) is the fine-grained measurement the radio chip already has. No camera, no wearable.
Ping and measure
The ESP32 pings the router about 25 times a second and measures the subcarrier amplitudes of each reply. The motion score is how much that wobbles over the last ~2 s.
One baseline per link
Each node learns what an empty room looks like. Motion means its score rose well above that. A spike guard keeps a bursty link quiet.
Cooler nodes
As more nodes run, the Pi lowers their transmit power, but only for nodes with a strong, healthy link. A weak node stays at full power.
WHERE YOU SEE ITScreens everywhere
The same answer shows up on the Pi, on small ESP32 displays, in a browser and on your phone.
The Pi screen
Radar scope with feet rings, the fused level, one panel per sensor, an event log. Keys: A arm, H history, R room, P replay, O settings.
CYD displays
Small touch screens. One shows its own CSI waterfall and score; another is a mini radar fed by the Pi.
Web page
A phone-friendly dashboard at http://<pi-ip>:8470, a replay page, and a PIN-protected live copy of the Pi's screen.

WHERE AND WHENRoom view, ghost and replay
None of the sensors report a real distance, so the room view is built from which sensors overlap. It is coarse on purpose.
- Zone and direction. Zones are labels for which sensors see someone (A only, B only, A + B, PIR, CSI). Direction (entering, leaving, moving, still) comes from the order they fire.
- Prediction ghost. When every sensor goes quiet, a dashed “?” shows where the person probably still is, and fades. It is a guess and never feeds alerts.
- History and replay. Everything is logged to a local database. Press
Hfor a 7×24 heatmap, orPto scrub back through where you were, a handy way to retrace your steps.
WHEN IT MATTERSAlarm, arming and alerts
Arm it when you leave. If the fused level reaches your alert level, you get an alarm after a short grace period.
Armed mode
60 s to leave, 20 s grace to disarm, weekly schedules. Disarm in time and nothing fires.
Phone push
Pushes go to your own private ntfy topic, with per-event switches and cooldowns.
Soft sounds
Gentle chimes on the Pi, with quiet hours that mute sound but still push to your phone.
Integrations
Optional MQTT with Home Assistant discovery, and Meshtastic LoRa text alerts.
THE PARTSHardware
| Part | Role |
|---|---|
| Raspberry Pi 400 | The brain: app, web server, history database |
| SONOFF Zigbee dongle (MG24) | Zigbee coordinator for the three SONOFF sensors |
| SONOFF SNZB-06P (5.8 GHz) and SNZB-06P24 (24 GHz) | mmWave A and B, occupied / clear only |
| SONOFF SNZB-03 | PIR motion sensor |
| ESP32-C3, ESP32-C6, CYD boards | Wi-Fi CSI nodes (the CYD also shows a live panel) |
| ESP32 PAX counter | Counts nearby phones, close ones only |
| Sense HAT (optional) | LED scope that dims when idle, joystick mute, room climate |
HONESTLYWhat it cannot do
- It cannot see objects, only people moving. Replay shows where you were, not where you put something down.
- Wi-Fi sensing works through drywall but weakly through brick or concrete.
- It is a home-LAN project. The data pages on the web server are open on the LAN; controls and the live screen need a PIN. See security notes before exposing anything wider.
More detail: placement guide · measured sensor findings · security.