ESPHomeESP32Home Assistant

ESPectre Wi-Fi motion sensor

An ESP32-C6 running the ESPHome ESPectre component reports motion from Wi-Fi channel state, with no PIR and no radar. It sees movement, not a person sitting still.

Difficulty · IntermediateSetup · 30–60 minutesHA · current stable (native API)ESPHome · 2026.10.0 or newer
Get the pack · from $9Have us set it up

Some hardware links on this page are affiliate links. As an Amazon Associate I earn from qualifying purchases. We may earn a commission if you buy through them, at no extra cost to you. See the affiliate disclosure.

A PIR needs a lens aimed at a path. ESPectre uses the Wi-Fi radio already on the ESP32. People moving through the room change how the signal arrives. The chip reads that channel state (CSI) and publishes a motion binary sensor to Home Assistant. Nothing else is soldered on. Nothing leaves the device for a cloud classifier.

Wi-Fi credentials stay in secrets.yaml. Do not publish an access-point name, a BSSID, or which room the node sits in.

A phone in the room is BLE room presence. Someone sitting still is an mmWave problem, covered in the mmWave presence guide. A door plus a PIR that latches until the door opens is wasp-in-a-box occupancy. This pack is movement in the radio field, from a bare ESP32-C6.

What problem it solves

You want a motion entity in a room that has power and Wi-Fi but no spare PIR, without a camera and without a microphone.

How it works

Needs ESPHome 2026.10.0 or newer, which is the release that added the built-in espectre component. ESP32-C6 builds with ESP-IDF. The Arduino framework is not available on this chip.

  1. One radio, one component — espectre: owns the Wi-Fi radio. A second copy will not compile into a useful node. The component turns Wi-Fi power saving off. A power_save_mode other than none is ignored, with a warning. Plan on a USB supply. This is not a deep-sleep battery sensor.
  2. It makes its own traffic — by default the chip pings the gateway and reads CSI from the replies. The detector wants on the order of a hundred packets a second. Broadcast chatter is not a reliable source. On ESP32-C6 the raw Wi-Fi frame mode is not offered. Leave the mode on ping unless you have a reason to switch.
  3. Lightweight is the default — it learns a threshold from a quiet room at startup and uses less of the chip. Keep the node still, and keep people out of the sensing area, for that calibration (about 10 seconds, up to about 30 if someone walks through). High Accuracy skips the quiet-room threshold and uses a heavier on-device detector with trained weights. Scores from the two algorithms are not comparable. The pack ships Lightweight.
  4. Motion, not occupancy — the binary sensor device class is motion. It goes on after several hits above the threshold (default 4, about a second) and off after a few quiet hits (default 3). It does not know that a person is sitting still, does not count people, and does not prove the room is empty. While it is calibrating, or CSI has gone stale, the sensor is unknown, which is not the same as “no motion.”
  5. Home Assistant — the native API exposes the motion entity. An optional movement score runs from 0 to 1 and publishes about four times a second. Leave it out unless you are tuning. A Recalibrate button relearns the Lightweight threshold after you move furniture. If you move the node itself, restart it instead.

The component also pauses roaming scans after it has connected, because a scan takes the radio off channel and empties the CSI window. It still reconnects if the access point disappears. Pin the BSSID of the strongest access point in the Wi-Fi networks entry when the house has more than one. A good signal is about −40 to −70 dBm. Do not write that BSSID into a published file.

Hardware notes

  • Board. ESP32-C6 Super Mini, the same chip family the component lists (ESP32-C6). Build with board: esp32-c6-devkitc-1 and ESP-IDF, as in the ESP32-C6 climate sensor. The upstream examples were exercised on a C6 dev board. The Super Mini uses the same variant. Leave GPIO8, GPIO9, GPIO12, GPIO13, and GPIO15 alone even though this pack wires nothing to them.
  • Power. USB-C supply. Power saving stays off, including while the node is disconnected, so a battery pack is the wrong supply.
  • Placement. Stationary, in the room you care about, not inside a metal box. One node covers one area. A second room needs a second board.
  • No extra sensor. Do not add a PIR “to make it work.” If you need still-presence, add the mmWave module from the guide instead of fighting this binary sensor.

Snippet

Pins are unused. The radio is the sensor. Secrets stay out of the file.

esp32:
  board: esp32-c6-devkitc-1
  framework:
    type: esp-idf

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  power_save_mode: none

espectre:
  id: room_csi
  detection_algorithm: lightweight

binary_sensor:
  - platform: espectre
    motion:
      name: "Room motion"
    calibrating:
      name: "Room calibrating"

button:
  - platform: espectre
    name: "Recalibrate"

The movement-score sensor and the diagnostic rates (generator, traffic, CSI accepted, CSI occupancy) are in the pack YAML. The diagnostics publish once a minute; set their update_interval to never once the node is healthy. CSI occupancy needs to sit at about 70 percent or better or the detector is starving.

Setup outline

  1. Install ESPHome 2026.10.0 or newer. Paste the YAML, set a unique device name, and put Wi-Fi in secrets.yaml.
  2. Flash over USB the first time. Leave the board on a shelf and stay out of the room until Room calibrating goes off.
  3. Adopt it in Home Assistant. Walk through the room. Room motion should go on, then off after you leave and stand still.
  4. If the house has several access points, set bssid under wifi: to the one with the strongest signal at that shelf, and reflash. Keep that value in secrets, not in the published YAML.
  5. Move a chair or a fan into the field later and press Recalibrate with the room empty. Move the board to another shelf and reboot instead.

Troubleshooting

  • Motion stays unknown. Calibration has not finished, or CSI has stopped. Check that the node is associated, then the diagnostic CSI occupancy. Under about 70 percent, the access point is too quiet or the node is roaming. Pin the BSSID. Confirm power_save_mode: none.
  • Always on. A fan, a curtain, or a person in the next room is in the field. Raise motion_on_hits (the default is 4, the maximum is 20). Recalibrate with the room actually still.
  • Walk-through is missed. motion_on_hits is high, or the node is in a drawer. Lower the hit count and move it into the open.
  • Build fails on ESP32-C6. The framework is Arduino. This chip needs type: esp-idf. ESPHome older than 2026.10.0 has no built-in espectre component.
  • OTA is slow. The component turns frame aggregation off so more frames carry CSI. That slows OTA, the web server, and audio on the same chip. Flash this node on its own. Do not combine it with a voice satellite.
  • High Accuracy never matches the old threshold. The two algorithms do not share a score. Pick one and recalibrate. The pack default is Lightweight.

Security note

This is a motion detector, not an identity check and not an alarm design. Do not publish the access-point BSSID, the SSID, or which shelf covers which room.

Credits

The detector is ESPectre (source). ESPHome 2026.10.0 added it as a built-in component: ESPectre Wi-Fi motion detection. This write-up is an original ESP32-C6 recipe for that component: Lightweight detection, a motion binary sensor, and a mains-powered Super Mini.

Changelog

v1.0 · Oct 27, 2026: First publish.