Run the Wi-Fi motion detection example
Create a complete ESP-IDF project from the registry, set up Wi-Fi, and see motion events on your board. Then reuse its code in your own firmware.
Create, build, and flash
Activate ESP-IDF 5.5.5. Pick a version, including release candidates, from the production registry and replace VERSION_FROM_REGISTRY below. For a branch snapshot, or an older prerelease, use the staging registry and change the URL to https://components-staging.espressif.com.
ESPECTRE_VERSION="VERSION_FROM_REGISTRY"
ESPECTRE_REGISTRY_URL="https://components.espressif.com"
idf.py create-project-from-example --registry-url "$ESPECTRE_REGISTRY_URL" "francescopace/espectre=$ESPECTRE_VERSION:wifi_motion_detection"
cd wifi_motion_detection
The example records its SDK version and registry in main/idf_component.yml. Older staging examples list only the version: add registry_url: https://components-staging.espressif.com under francescopace/espectre before building.
Set your board's chip and serial port. Enter your Wi-Fi name and password under ESPectre example in menuconfig; they stay in your local configuration.
idf.py set-target esp32c3
idf.py menuconfig
idf.py build
idf.py -p YOUR_PORT flash monitor
The example turns on CSI, starts Wi-Fi and logging, and reports motion once calibration is done. Its guide explains what to check on the board; the installation steps explain the registry channels.
Add sensing to your application
In an existing project, add the SDK with idf.py add-dependency as shown in the installation steps. The Component Manager keeps it in managed_components/. Put your own ESPectre code in your application component:
product-firmware/
├── managed_components/
│ └── francescopace__espectre/
└── main/
├── CMakeLists.txt
├── idf_component.yml
├── main.cpp
└── product_frontend.h
idf_component.yml lists the SDK. Register your own sources in CMake:
# main/CMakeLists.txt
idf_component_register(
SRCS "main.cpp"
INCLUDE_DIRS "."
)
To copy the SDK into your project instead, download a source archive from the SDK page and follow the build integration instructions.
Choose the logging backend
The SDK has no logger of its own and does not need ESP-IDF's log component. To see its messages, register a sink before setup:
espectre::LogSink sink{
product_log_context,
&product_log_enabled,
&product_log_write,
};
if (!espectre::set_log_sink(sink)) return false;
The enabled callback gets the level and tag, so you can skip messages before they are built. The write callback gets the source line, the format string, and a va_list that is valid only during the call. Both must be thread-safe, non-blocking, and must not log back into the SDK. Remove the sink only after shutdown.
Own the runtime from one task
This example uses the sensing settings from menuconfig, ignores events until sensing is ready, and publishes outside the listener callback:
#include "espectre_sdk.h"
class ProductFrontend : public espectre::IRuntimeListener {
public:
bool setup() {
runtime_.set_config(
espectre::make_runtime_sensing_config_from_kconfig());
return runtime_.setup(this);
}
void loop() {
runtime_.loop();
if (!motion_changed_) return;
motion_changed_ = false;
publish_motion(latest_motion_); // product-owned, may queue more work
}
void shutdown() { runtime_.shutdown(); }
void on_motion_state_changed(
const espectre::RuntimeSnapshot& snapshot) override {
if (!snapshot.ready_to_publish) return;
latest_motion_ =
snapshot.motion_state == espectre::MotionState::MOTION;
motion_changed_ = true;
}
void on_runtime_fault(const char* message) override {
record_runtime_fault(message); // copy if retained after this call
}
private:
void publish_motion(bool motion);
void record_runtime_fault(const char* message);
espectre::RuntimeFrontendController runtime_;
bool latest_motion_{false};
bool motion_changed_{false};
};
publish_motion() should hand any blocking work to another task. record_runtime_fault() must copy the message if it keeps it, because the pointer is valid only during the call.Handle startup, steady state, and shutdown
Create the station before setup
Call setup after creating the Wi-Fi station and default event loop, ideally before connecting, so the radio is configured for CSI from the start. If Wi-Fi is already connected, the runtime picks up the current connection.
Check the setup result
If
setup()fails, nothing is configured. Fix the configuration or the Wi-Fi connection, then retry.Call loop continuously
loop()processes the CSI queue and delivers listener events. Slow callbacks can fill the queue, and new packets are then dropped.Shut down from the owner task
Call
shutdown()before stopping Wi-Fi or the services your code uses.
Choose a reference frontend
ESPHome, Native, and Matter use the same public SDK headers you do. Use them as examples, but build your firmware on the public SDK API.
To build one of them against a downloaded SDK bundle, set ESPECTRE_SDK_ROOT to the full path of the bundle's src/cpp folder. The CLI reference has the commands, including Docker builds for Native and Matter.
ESPHome
ESPHome lifecycle, YAML configuration, Home Assistant entities and controls, and ESPHome updates. This frontend is GPLv3 only.
Browse ESPHome frontend ↗Native
The best model for your own ESP-IDF product: Wi-Fi setup, Direct HTTP, optional MQTT, updates, diagnostics, and queued callbacks.
Browse Native frontend ↗Matter
Matter manages Wi-Fi, and ESPectre starts only after pairing. Motion appears as a standard occupancy sensor.
Browse Matter frontend ↗espectre_core_sdk.h. Your code must then prepare the CSI and handle timing, readiness, gaps, and spike filtering itself. Use the runtime's csi_pipeline.cpp as the model.