A mmWave presence sensor for the kitchen
Ordinary motion sensors have one big weakness in a kitchen. They use passive infrared (PIR), which only notices you when you move. Stand still at the counter chopping an onion and, as far as a PIR is concerned, you’ve left the room. Off go the lights, and you wave your knife at the ceiling to bring them back.
A mmWave radar sensor fixes that. It sends out a signal at around 24 GHz and watches the reflections, and it’s sensitive enough to pick up the tiny movements of someone breathing. So it can tell “nobody here” apart from “somebody here, keeping very still”. The HLK-LD2410 is the cheap, popular one, and ESPHome has a proper component for it.
Our kitchen had a PIR, and I’d already stretched its timeout to something very long to cover the still moments. It still switched the lights off on me now and then. A long timeout also means the lights stay on long after you’ve actually left, so it’s a poor fix in both directions.
The hardware
- A Lolin S3 mini, a small ESP32-S3 board.
- An LD2410, connected over a UART at a rather brisk 256,000 baud.
- A TSL2561 light sensor on I²C, so Home Assistant knows how dark it is.
It all lives in a 3D-printed case on top of the kitchen cupboards, which gives the radar a good view across the room.
The first build was in April 2024, and I kept tinkering with it until November.
Zones
The radar reports how far away its target is. It splits its range into nine “gates”, each 75 cm deep by default, and has separate thresholds for moving and still targets at every gate. I exposed every one of those thresholds to Home Assistant, plus the live energy readings for each gate. That’s a lot of sliders, but it’s the only sensible way to tune it: stand in a spot, watch the numbers, then adjust.
On top of that I defined three zones by distance, with their edges adjustable from Home Assistant:
| zone | default range |
|---|---|
| 1 | 0–50 cm |
| 2 | 50–150 cm |
| 3 | 150–250 cm |
Each zone is an occupancy sensor of its own, so an automation can tell someone standing right by the sensor from someone across the room.
There’s one slight annoyance. The kitchen and dining area are all one room, and zone 3 turns on the lights by the dining table. But the radar only reports the closest target it can see. So if someone walks into zone 1 while I’m sitting at the table, zone 3 suddenly looks empty, and the table lights would go off on me. I had to work around it in the switch-off logic: the dining lights are never turned off because one zone has gone quiet, only once all three zones have.
Two small details
The light sensor has a hotline. It reads every five seconds anyway, but the device also offers Home Assistant a service to take a reading right now. That reading lands before the lights’ one-second fade-in gets going, so it catches how dark the room was before the lights came on, rather than the kitchen lights measuring themselves. It seemed like a good idea at the time, but so far it hasn’t earned its keep.
The radar’s Bluetooth is switched off at boot. The LD2410 has Bluetooth of its own, so you can tune it from a phone app. That’s handy on the bench, but less so once it is installed, when anyone nearby with the app could have a fiddle. ESPHome turns it off every time the device starts.
The ESP32’s own Bluetooth is put to better use: like the S3-Box on my desk, it doubles as a Bluetooth proxy for Home Assistant.
Where it stands
The kitchen now has a “Radar Target” sensor, three zone sensors and a light level in Home Assistant. Between them they drive the kitchen counter lights and the uplighter strips on top of the cupboards, and zone 3 brings on the strips that run round the walls as uplights by the dining table. It didn’t need much tuning in the end, beyond the timeouts.