The Problem
Home‑assistant users want reliable motion detection without cameras or wearables. Traditional PIR sensors struggle through walls and generate false positives, while video‑based solutions raise privacy concerns. ESPectre addresses this gap by using Wi‑Fi channel state information (CSI) to infer motion, requiring only an inexpensive ESP32 device and a standard router.
What This Does
The repository ships two runtimes:
- Python host side – runs on a PC/Raspberry Pi, consumes CSI streams, runs detection algorithms, and forwards events via MQTT. Core files are
micro‑espectre/src/main.py,csi_streamer.py,ml_detector.py,mvs_detector.py, and the MQTT helpers insrc/mqtt/. - ESPHome component (C++) – compiled into an ESP‑Home firmware that reads raw CSI from the ESP32 radio and publishes raw packets to the host. The component lives under
components/espectre/and includescsi_manager.cpp,base_detector.cpp,ml_detector.cpp, and the UDP listener inudp_listener.cpp.
The Python side can select between the classic MVS detector (src/mvs_detector.py) and the newer neural‑net detector (src/ml_detector.py). Both expose a uniform interface defined in src/detector_interface.py.
How It Is Wired
Execution start → host
micro‑espectre/src/main.pyis the entry point (if __name__ == "__main__":).- It loads configuration from
src/config.py(orconfig_local.py.example). - A
CSIStreamerobject fromcsi_streamer.pyopens a UDP socket (configured inexamples/espectre‑c3.yamletc.) and yields raw CSI frames. - Each frame is passed to the detector selected by
detector_interface.py. For the ML path,MLDetector.detect()inml_detector.pyloads the TFLite modelmodels/motion_detector_small.tfliteand runs inference via the TensorFlow Lite interpreter. For the classic path,MVSDetector.detect()inmvs_detector.pycallsBaseDetector.process()(implemented incomponents/espectre/base_detector.cppvia the ESP‑Home component’s native API). - Detection results are handed to the MQTT handler (
src/mqtt/handler.py), which publishes a JSON payload on the topic defined insrc/mqtt/commands.py. Home Assistant subscribes and creates binary sensor entities automatically.
Execution start → ESP32
- The ESP‑Home YAML files in
examples/(e.g.,espectre‑c3.yaml) include the custom componentespectre. - During firmware compilation, ESP‑Home pulls the C++ sources from
components/espectre/. csi_manager.cppregisters a Wi‑Fi CSI callback with the ESP‑IDF driver, feeding raw packets toudp_listener.cpp.udp_listener.cppforwards each packet over UDP to the host IP/port configured in the YAML. No further processing occurs on the device unless the-mlbuild flag is used, in which caseml_detector.cppruns the TFLite model locally and publishes a binary sensor state directly via ESP‑Home’s native MQTT bridge.
Key ownership
- Network I/O –
csi_manager.cpp/udp_listener.cpp(device) andcsi_streamer.py(host). - Detection logic –
ml_detector.py+models/*.tflite(host) orml_detector.cpp(device);mvs_detector.py+base_detector.cpp(host). - Home‑Assistant integration – MQTT publishing in
src/mqtt/(host) and ESP‑Home entity definition in the YAML examples (device).
No circular dependencies are present; the host imports the detector modules, while the device code is entirely self‑contained and only communicates via UDP.
How To Use It
# Clone the repo
git clone https://github.com/moses-y/espectre
cd espectre
# Install Python host dependencies (no lockfile, reproducibility not guaranteed)
python -m venv .venv
source .venv/bin/activate
pip install -r micro-espectre/requirements.txt
# Edit the local config (copy example)
cp micro-espectre/src/config_local.py.example micro-espectre/src/config_local.py
# Adjust MQTT broker address, UDP listen port, and detector choice in that file.
# Start the host daemon
python micro-espectre/src/main.py
To flash an ESP32 device:
# Choose an example matching your board
esphome run examples/espectre-c3.yaml # requires the `esphome` CLI
The ESPHome build pulls the C++ sources automatically. After flashing, ensure the device and the host are on the same network; the host will receive UDP CSI packets and publish motion events to the MQTT broker configured in config_local.py.
Real‑World Use
A smart‑home installer adds an ESP32‑S3 sensor to the living‑room ceiling, points it at the home router, and runs the host daemon on the same Raspberry Pi that hosts Home Assistant. Motion events appear as a binary sensor binary_sensor.espectre_motion, which can trigger automations (e.g., turning on lights when motion is detected while the TV is off).
automation:
- alias: "Turn on hallway light on motion"
trigger:
- platform: state
entity_id: binary_sensor.espectre_motion
to: "on"
action:
- service: light.turn_on
target:
entity_id: light.hallway
Code Health & Issues
- Low – Dependencies declared without a lockfile –
micro-espectre/requirements.txt(reproducible builds not guaranteed). - CI defined in
.github/workflows/ci.yml; tests exist undermicro-espectre/tests/andtest/, but coverage enforcement is not evident. - No explicit license file for the Python side; the top‑level
LICENSEcovers the project overall. - No secret scanning; example YAML files contain no credentials, but real deployments must supply MQTT passwords manually.
The Bottom Line
ESPectre provides a functional, low‑cost motion‑detection pipeline that integrates cleanly with Home Assistant via MQTT. The code base is split cleanly between host‑side Python and device‑side C++, making targeted changes straightforward. The main drawback is the lack of a Python lockfile, which can cause environment drift for new developers. Suitable for engineers comfortable with ESPHome and MQTT who need privacy‑preserving motion sensing.