# ESPectre SDK C++ API
Version: `3.0.0-rc3`
Source commit: `d79b4be232a1e2e464e85efbc7091aa562aed84d`
[SDK guide](README.md)
## Contents
- [ESPectre SDK](#indexpage)
- [Deprecated List](#deprecated)
- [Integration details](#sdk_integration)
- [espectre](#namespaceespectre)
- [espectre::task\_scheduling](#namespaceespectre_1_1task__scheduling)
- [espectre::BaseDetector](#classespectre_1_1_base_detector)
- [espectre::CsiTrafficService](#classespectre_1_1_csi_traffic_service)
- [espectre::CsiTrafficServiceConfig](#structespectre_1_1_csi_traffic_service_config)
- [espectre::DirectHttpServiceConfig](#structespectre_1_1_direct_http_service_config)
- [espectre::DirectHttpServiceDiagnostics](#structespectre_1_1_direct_http_service_diagnostics)
- [espectre::DirectRequest](#structespectre_1_1_direct_request)
- [espectre::DirectWifiSnapshot](#structespectre_1_1_direct_wifi_snapshot)
- [espectre::EspIdfDirectHttpService](#classespectre_1_1_esp_idf_direct_http_service)
- [espectre::EspIdfMqttTransport](#classespectre_1_1_esp_idf_mqtt_transport)
- [espectre::EspIdfPeerDiscoveryService](#classespectre_1_1_esp_idf_peer_discovery_service)
- [espectre::EspectreApiEventDescriptor](#structespectre_1_1_espectre_api_event_descriptor)
- [espectre::EspectreApiRoute](#structespectre_1_1_espectre_api_route)
- [espectre::EspectreCapabilityProfile](#structespectre_1_1_espectre_capability_profile)
- [espectre::EspectreCommand](#structespectre_1_1_espectre_command)
- [espectre::EspectreDeviceConfig](#structespectre_1_1_espectre_device_config)
- [espectre::EspectreDeviceInfo](#structespectre_1_1_espectre_device_info)
- [espectre::EspectreExtensionRoute](#structespectre_1_1_espectre_extension_route)
- [espectre::EspectreNetworkInfo](#structespectre_1_1_espectre_network_info)
- [espectre::EspectreProtocolExtension](#structespectre_1_1_espectre_protocol_extension)
- [espectre::FrontendCommandContext](#structespectre_1_1_frontend_command_context)
- [espectre::FrontendCommandEngine](#classespectre_1_1_frontend_command_engine)
- [espectre::FrontendCommandResult](#structespectre_1_1_frontend_command_result)
- [espectre::FrontendDeviceConfigDefaults](#structespectre_1_1_frontend_device_config_defaults)
- [espectre::FrontendHaDiagnosticSensor](#structespectre_1_1_frontend_ha_diagnostic_sensor)
- [espectre::FrontendHaDiscoveryMessage](#structespectre_1_1_frontend_ha_discovery_message)
- [espectre::FrontendHaMqttSettings](#structespectre_1_1_frontend_ha_mqtt_settings)
- [espectre::FrontendWifiStationOptions](#structespectre_1_1_frontend_wifi_station_options)
- [espectre::HighAccuracyDetector](#classespectre_1_1_high_accuracy_detector)
- [espectre::ICsiTrafficGenerator](#classespectre_1_1_i_csi_traffic_generator)
- [espectre::ICsiTrafficIngress](#classespectre_1_1_i_csi_traffic_ingress)
- [espectre::IDirectHttpService](#classespectre_1_1_i_direct_http_service)
- [espectre::IDirectHttpService::DeferredRequestResult](#structespectre_1_1_i_direct_http_service_1_1_deferred_request_result)
- [espectre::IMqttTransport](#classespectre_1_1_i_mqtt_transport)
- [espectre::IPeerDiscoveryService](#classespectre_1_1_i_peer_discovery_service)
- [espectre::IRuntimeListener](#classespectre_1_1_i_runtime_listener)
- [espectre::IUdpDatagramSocket](#classespectre_1_1_i_udp_datagram_socket)
- [espectre::JsonFieldView](#structespectre_1_1_json_field_view)
- [espectre::JsonInput](#classespectre_1_1_json_input)
- [espectre::JsonObjectField](#structespectre_1_1_json_object_field)
- [espectre::LightweightDetector](#classespectre_1_1_lightweight_detector)
- [espectre::LogSink](#structespectre_1_1_log_sink)
- [espectre::MdnsBootstrapResponder](#classespectre_1_1_mdns_bootstrap_responder)
- [espectre::MdnsDiscoveryService](#classespectre_1_1_mdns_discovery_service)
- [espectre::MdnsDiscoveryServiceConfig](#structespectre_1_1_mdns_discovery_service_config)
- [espectre::MqttTransportDiagnostics](#structespectre_1_1_mqtt_transport_diagnostics)
- [espectre::NetworkTrafficSnapshot](#structespectre_1_1_network_traffic_snapshot)
- [espectre::PeerDiscoveryCandidate](#structespectre_1_1_peer_discovery_candidate)
- [espectre::PeerDiscoverySnapshot](#structespectre_1_1_peer_discovery_snapshot)
- [espectre::PendingEvent](#classespectre_1_1_pending_event)
- [espectre::PendingQueue](#classespectre_1_1_pending_queue)
- [espectre::RawCsiHttpFramePrefix](#structespectre_1_1_raw_csi_http_frame_prefix)
- [espectre::RawCsiPacketView](#structespectre_1_1_raw_csi_packet_view)
- [espectre::RawCsiRecordHeaderV8](#structespectre_1_1_raw_csi_record_header_v8)
- [espectre::RawCsiSessionConfig](#structespectre_1_1_raw_csi_session_config)
- [espectre::RawCsiSessionController](#classespectre_1_1_raw_csi_session_controller)
- [espectre::RawCsiSessionDiagnostics](#structespectre_1_1_raw_csi_session_diagnostics)
- [espectre::RuntimeCapabilities](#structespectre_1_1_runtime_capabilities)
- [espectre::RuntimeConfig](#structespectre_1_1_runtime_config)
- [espectre::RuntimeControlUpdate](#structespectre_1_1_runtime_control_update)
- [espectre::RuntimeDiagnosticsSample](#structespectre_1_1_runtime_diagnostics_sample)
- [espectre::RuntimeDiagnosticsSampler](#classespectre_1_1_runtime_diagnostics_sampler)
- [espectre::RuntimeDiagnosticsSnapshot](#structespectre_1_1_runtime_diagnostics_snapshot)
- [espectre::RuntimeDiagnosticsSnapshot::Csi](#structespectre_1_1_runtime_diagnostics_snapshot_1_1_csi)
- [espectre::RuntimeDiagnosticsSnapshot::Link](#structespectre_1_1_runtime_diagnostics_snapshot_1_1_link)
- [espectre::RuntimeDiagnosticsSnapshot::Performance](#structespectre_1_1_runtime_diagnostics_snapshot_1_1_performance)
- [espectre::RuntimeDiagnosticsSnapshot::Platform](#structespectre_1_1_runtime_diagnostics_snapshot_1_1_platform)
- [espectre::RuntimeDiagnosticsSnapshot::Traffic](#structespectre_1_1_runtime_diagnostics_snapshot_1_1_traffic)
- [espectre::RuntimeDirectHttpBridge](#classespectre_1_1_runtime_direct_http_bridge)
- [espectre::RuntimeDirectHttpBridgeConfig](#structespectre_1_1_runtime_direct_http_bridge_config)
- [espectre::RuntimeEventMailbox](#classespectre_1_1_runtime_event_mailbox)
- [espectre::RuntimeFrontendController](#classespectre_1_1_runtime_frontend_controller)
- [espectre::RuntimeSnapshot](#structespectre_1_1_runtime_snapshot)
- [espectre::StandaloneWifiAccessPoint](#structespectre_1_1_standalone_wifi_access_point)
- [espectre::StandaloneWifiConfig](#structespectre_1_1_standalone_wifi_config)
- [espectre::StandaloneWifiInfo](#structespectre_1_1_standalone_wifi_info)
- [espectre::StandaloneWifiService](#classespectre_1_1_standalone_wifi_service)
- [espectre::StoredWifiConfig](#structespectre_1_1_stored_wifi_config)
- [espectre::TemporalCsiSampler](#classespectre_1_1_temporal_csi_sampler)
- [espectre::TrafficGeneratorManager](#classespectre_1_1_traffic_generator_manager)
- [espectre::UdpDatagramPeer](#structespectre_1_1_udp_datagram_peer)
- [espectre::WiFiLifecycleManager](#classespectre_1_1_wi_fi_lifecycle_manager)
- [espectre::WifiBssidPinService](#classespectre_1_1_wifi_bssid_pin_service)
- [espectre::WifiBssidPinServiceConfig](#structespectre_1_1_wifi_bssid_pin_service_config)
- [espectre::WifiBssidPinStationState](#structespectre_1_1_wifi_bssid_pin_station_state)
- [espectre::WifiProvisioningDefaults](#structespectre_1_1_wifi_provisioning_defaults)
- [espectre::WifiProvisioningService](#classespectre_1_1_wifi_provisioning_service)
- [espectre\_diagnostic\_field\_t](#structespectre__diagnostic__field__t)
- [base\_detector.h](#base__detector_8h)
- [csi\_capture\_profile.h](#csi__capture__profile_8h)
- [csi\_format.h](#csi__format_8h)
- [csi\_raw\_record.h](#csi__raw__record_8h)
- [csi\_traffic\_service.h](#csi__traffic__service_8h)
- [csi\_types.h](#csi__types_8h)
- [detector\_limits.h](#detector__limits_8h)
- [detector\_types.h](#detector__types_8h)
- [device\_config\_store.h](#device__config__store_8h)
- [device\_identity.h](#device__identity_8h)
- [diagnostic\_fields.h](#diagnostic__fields_8h)
- [direct\_http\_protocol.h](#direct__http__protocol_8h)
- [direct\_http\_service.h](#direct__http__service_8h)
- [direct\_http\_service\_esp\_idf.h](#direct__http__service__esp__idf_8h)
- [direct\_wifi\_snapshot\_esp\_idf.h](#direct__wifi__snapshot__esp__idf_8h)
- [espectre\_banner.h](#espectre__banner_8h)
- [espectre\_core\_sdk.h](#espectre__core__sdk_8h)
- [espectre\_log.h](#espectre__log_8h)
- [espectre\_mqtt\_sdk.h](#espectre__mqtt__sdk_8h)
- [espectre\_protocol.h](#espectre__protocol_8h)
- [espectre\_protocol\_sdk.h](#espectre__protocol__sdk_8h)
- [espectre\_sdk.h](#espectre__sdk_8h)
- [espectre\_sdk\_version.h](#espectre__sdk__version_8h)
- [espectre\_services\_sdk.h](#espectre__services__sdk_8h)
- [filter\_config.h](#filter__config_8h)
- [frontend\_bootstrap\_helpers.h](#frontend__bootstrap__helpers_8h)
- [frontend\_command\_engine.h](#frontend__command__engine_8h)
- [frontend\_ha\_mqtt\_helpers.h](#frontend__ha__mqtt__helpers_8h)
- [frontend\_mqtt\_helpers.h](#frontend__mqtt__helpers_8h)
- [high\_accuracy\_detector.h](#high__accuracy__detector_8h)
- [lightweight\_detector.h](#lightweight__detector_8h)
- [mdns\_bootstrap\_responder.h](#mdns__bootstrap__responder_8h)
- [mdns\_discovery\_service.h](#mdns__discovery__service_8h)
- [mqtt\_payload\_assembler.h](#mqtt__payload__assembler_8h)
- [mqtt\_transport.h](#mqtt__transport_8h)
- [mqtt\_transport\_esp\_idf.h](#mqtt__transport__esp__idf_8h)
- [network\_traffic.h](#network__traffic_8h)
- [nvs\_helpers.h](#nvs__helpers_8h)
- [peer\_discovery.h](#peer__discovery_8h)
- [peer\_discovery\_service\_esp\_idf.h](#peer__discovery__service__esp__idf_8h)
- [pending\_event.h](#pending__event_8h)
- [pending\_queue.h](#pending__queue_8h)
- [protocol\_json.h](#protocol__json_8h)
- [raw\_csi.h](#raw__csi_8h)
- [raw\_csi\_session\_controller.h](#raw__csi__session__controller_8h)
- [runtime\_capabilities.h](#runtime__capabilities_8h)
- [runtime\_config.h](#runtime__config_8h)
- [runtime\_config\_utils.h](#runtime__config__utils_8h)
- [runtime\_diagnostics.h](#runtime__diagnostics_8h)
- [runtime\_diagnostics\_protocol.h](#runtime__diagnostics__protocol_8h)
- [runtime\_direct\_http\_bridge.h](#runtime__direct__http__bridge_8h)
- [runtime\_event\_mailbox.h](#runtime__event__mailbox_8h)
- [runtime\_events.h](#runtime__events_8h)
- [runtime\_frontend\_controller.h](#runtime__frontend__controller_8h)
- [runtime\_sensing\_kconfig.h](#runtime__sensing__kconfig_8h)
- [runtime\_sensing\_schema.h](#runtime__sensing__schema_8h)
- [runtime\_snapshot.h](#runtime__snapshot_8h)
- [runtime\_time.h](#runtime__time_8h)
- [standalone\_wifi\_service.h](#standalone__wifi__service_8h)
- [task\_scheduling\_config.h](#task__scheduling__config_8h)
- [temporal\_csi\_sampler.h](#temporal__csi__sampler_8h)
- [traffic\_generator\_manager.h](#traffic__generator__manager_8h)
- [udp\_datagram\_socket.h](#udp__datagram__socket_8h)
- [wifi\_band\_helpers.h](#wifi__band__helpers_8h)
- [wifi\_bssid\_pin\_service.h](#wifi__bssid__pin__service_8h)
- [wifi\_lifecycle.h](#wifi__lifecycle_8h)
- [wifi\_provisioning\_service.h](#wifi__provisioning__service_8h)
<a id="indexpage"></a>
## ESPectre SDK
This reference covers the supported integration surface only. Every declaration included in the reference follows the SDK version contract; implementation dependencies that merely ship in the bundle are internal and may change in any release.
Start with the [SDK README](<https://github.com/francescopace/espectre/blob/d79b4be232a1e2e464e85efbc7091aa562aed84d/docs/SDK.md>) for installation and a minimal application. Use [espectre\_sdk.h](#espectre__sdk_8h) for the sensing runtime, [espectre\_core\_sdk.h](#espectre__core__sdk_8h) for custom capture pipelines, [espectre\_protocol\_sdk.h](#espectre__protocol__sdk_8h) for the ESPectre Protocol and its transports, [espectre\_services\_sdk.h](#espectre__services__sdk_8h) for optional services, and [espectre\_mqtt\_sdk.h](#espectre__mqtt__sdk_8h) for the ESP-IDF MQTT implementation.
[Integration details](#sdk_integration) documents lifecycle, threading, source compatibility, and advanced integration contracts for this version of the SDK.
<a id="deprecated"></a>
## Deprecated List
Member [espectre::espectre\_device\_id\_from\_mac](#namespaceespectre_1adc03ef2a0c49d818c944747283819e1a) (const uint8\_t \*mac, size\_t mac\_len)
<a id="deprecated_1_deprecated000001"></a>
Runtime firmware uses the cached, domain-separated SHA-256 pseudonym from [`derive_runtime_device_id()`](#namespaceespectre_1a34031a60d78bbb6306047b3540b4f905) instead.
<a id="sdk_integration"></a>
## Integration details
This guide covers the lifecycle, ownership, and compatibility contracts for the SDK sources identified by this reference.
Start with the [SDK README](<https://github.com/francescopace/espectre/blob/d79b4be232a1e2e464e85efbc7091aa562aed84d/docs/SDK.md>) for installation and a minimal application.
<a id="sdk_integration_1integration_logging"></a>
### Logging
All SDK facades expose the portable logging contract in [`core/espectre_log.h`](#espectre__log_8h). ESPectre does not install a sink or fall back to `stdio`, so integrations that do not need logs have no logger dependency and do not evaluate filtered log arguments. To receive shared logs, register a complete `LogSink` before runtime setup:
```cpp
espectre::LogSink sink{
product_context,
&product_log_enabled,
&product_log_write,
};
if (!espectre::set_log_sink(sink)) {
return false;
}
```
The `enabled` callback decides whether a level and tag should be formatted. The `write` callback receives the level, tag, source line, format string, and a `va_list` that remains valid only for that call. ESPectre copies the callback value but does not own its context. Keep the context alive until `clear_log_sink()`, and register, replace, or clear the sink only while no runtime is active. Callbacks may arrive from the runtime owner task, ESP-IDF service tasks, or CSI capture paths, so they must be thread-safe, bounded, non-blocking, and must not call the ESPectre logger recursively.
For ESP-IDF Log v2, your sink can pass the callback's `va_list` to `esp_log_va`. ESP-IDF adds the standard level, timestamp, tag, and line ending. The included example shows how to register this adapter; declare the `log` dependency in your application component.
<a id="sdk_integration_1integration_supported_hardware"></a>
### Supported hardware
The targets listed in [Requirements](<https://github.com/francescopace/espectre/blob/d79b4be232a1e2e464e85efbc7091aa562aed84d/docs/SDK.md#requirements>) use standard single-antenna Wi-Fi CSI with AGC active and 20 MHz bandwidth. No extra sensors or radio hardware are required.
Set `RuntimeConfig::wifi_band_policy` to choose `BAND_2G`, `BAND_5G`, or `AUTO`. Both a directly constructed `RuntimeConfig` and the Kconfig default use `AUTO`, which uses every band the radio has: automatic 2.4/5 GHz selection on ESP32-C5, and 2.4 GHz on single-band targets. The runtime applies the selected policy and pins 20 MHz bandwidth on the active band or bands. Unsupported policies fail setup instead of falling back silently, and packets outside the selected capture profile are dropped and counted.
Set `RuntimeConfig::csi_capture_policy` before setup to choose `CsiCapturePolicy::AUTO`, `LLTF`, or `HT_VHT`. `AUTO` uses LLTF20 for internal `wifi_raw`, VHT20 on a supported 5 GHz link, and HT20 otherwise, including on ESP32 and ESP32-S2. `LLTF` always selects LLTF20; `HT_VHT` selects VHT20 on a supported 5 GHz link and HT20 otherwise. All three policies work with automatic band selection on ESP32-C5. `wifi_raw` requires `AUTO` or `LLTF`. There is no runtime profile setter or persisted profile override. The canonical `device` resource reports the effective profile as the read-only `csi_profile`. [CSI.md](<https://github.com/francescopace/espectre/blob/d79b4be232a1e2e464e85efbc7091aa562aed84d/docs/CSI.md#capture-profiles>) describes capture behavior and normalization.
<a id="sdk_integration_1integration_runtime_contract"></a>
### Runtime contract
These sections describe how the full runtime behaves once your firmware owns a `RuntimeFrontendController`.
<a id="sdk_integration_1integration_threading"></a>
#### Threading
The control surface is single-owner. Internal bounded mailboxes protect callback-to-loop handoff, but they do not make control calls thread-safe.
- Run `setup()`, `loop()`, and `shutdown()` on one task.
- Every `IRuntimeListener` callback is delivered on the caller's task: from `loop()` for sensing events, or inline on the task that invoked a control method. Work raised in the Wi-Fi CSI callback is deferred through an internal mailbox first, so no listener callback runs in interrupt or Wi-Fi driver context.
- Keep callbacks bounded and non-blocking. A slow callback delays the next `loop()` iteration; sufficiently long work can fill the bounded CSI mailbox and drop incoming frames. Queue network publication, NVS writes, and other potentially blocking work for a separate task.
- Call the controller setters only from the owner task. Queue commands received by network callbacks and apply them from that task's loop.
- Raw CSI packet callbacks are the deliberate exception: they run synchronously in the Wi-Fi CSI capture context. Keep them bounded, non-blocking, and allocation-free, and copy accepted samples into a preallocated bounded queue when another task must process them. Returning false reports a caller-owned drop or backpressure event; it does not stop collection.
Stopping raw collection synchronizes with any packet callback already in progress before releasing its context. The caller can reclaim that context after `stop_raw_collection()` succeeds. Raw callbacks must follow the owner-task rule for runtime controls; they must not stop collection themselves.
<a id="sdk_integration_1integration_advanced_task_scheduling"></a>
#### Advanced task scheduling
Full-runtime ESP-IDF integrations expose ESPectre-owned FreeRTOS priorities under the `Advanced task scheduling` menu. These settings are compile-time policies, not runtime controls. Values range from `1` to `10`; higher-priority tasks preempt lower-priority work. Change them only with workload-specific validation because an unsuitable priority can starve sensing, Direct delivery, managed traffic, or system networking. ESP-IDF continues to own the internal Wi-Fi and lwIP task priorities.
The shared runtime defines these priorities:
| Kconfig option | Default | Owner |
| --- | --- | --- |
| [`CONFIG_ESPECTRE_DIRECT_HTTPD_TASK_PRIORITY`](#task__scheduling__config_8h_1a1c07ae2423b6566d454316bfd9a8dcfa) | `1` | Direct HTTP server |
| [`CONFIG_ESPECTRE_DIRECT_WORKER_TASK_PRIORITY`](#task__scheduling__config_8h_1ab21ce3fdcc4837c2a0aecb8b3b58ca04) | `2` | Direct control responses and SSE delivery |
| [`CONFIG_ESPECTRE_RAW_WORKER_TASK_PRIORITY`](#task__scheduling__config_8h_1ac541f938b4a9aee9eb3e7edc08296acd) | `3` | Raw CSI HTTP delivery |
| [`CONFIG_ESPECTRE_TRAFFIC_TASK_PRIORITY`](#task__scheduling__config_8h_1a89bc52af94882fc610139f6ac25a80c8) | `1` | Managed PING or DNS traffic |
Your application owns the task that calls `RuntimeFrontendController::loop()`. Select its priority as part of your scheduling policy; the SDK's task settings do not set that priority.
The Direct HTTP server defaults to priority `1` on every target. Custom integrations can override it after workload-specific validation. Existing `sdkconfig` files retain explicitly saved priorities; set [`CONFIG_ESPECTRE_DIRECT_HTTPD_TASK_PRIORITY=1`](#task__scheduling__config_8h_1a1c07ae2423b6566d454316bfd9a8dcfa) to adopt the shared default in those builds.
<a id="sdk_integration_1integration_raw_csi_storage"></a>
#### Raw CSI storage
`prepare_ht20_detector_input` prepares a private centered buffer after the raw branch: it handles both LLTF edge tones and hardware-invalid classic +1, using explicit source metadata. `impute_ht20_lltf_detector_bins` is an older wrapper that handles only the LLTF edge tones. See [CSI.md](<https://github.com/francescopace/espectre/blob/d79b4be232a1e2e464e85efbc7091aa562aed84d/docs/CSI.md#detector-input-and-raw-collection>) for the shared preparation policy.
The built-in capture pipeline normalizes LLTF, HT, and VHT samples to `HT20_CSI_LEN`: 128 bytes containing 64 complex subcarriers. `RawCsiPacketView` exposes this normalized view. Size capture queues for the normalized payload. `RAW_CSI_MAX_PAYLOAD_BYTES` defines the separate 512-byte payload limit for stored and transmitted records.
`EspIdfDirectHttpService` uses a 16-slot raw queue with 128 payload bytes per slot and sends records in batches of up to four. It allocates raw buffers when a session starts and releases them when it stops.
The queue can overflow during a stalled send, regardless of each slot's payload capacity. Inspect `raw_csi.raw_drop_total` separately from capture-quality rejections; see [CSI.md](<https://github.com/francescopace/espectre/blob/d79b4be232a1e2e464e85efbc7091aa562aed84d/docs/CSI.md#capture-quality>).
<a id="sdk_integration_1integration_lifecycle"></a>
#### Lifecycle
`set_config()` -> `setup(listener)` -> `loop()` repeatedly -> `shutdown()`. Create the default station interface and ESP event loop before `setup()`. Prefer setup before association so the CSI radio policy is applied at `WIFI_EVENT_STA_START`; setup after association is also supported and restores the station's current IPv4 state. The controller is reusable after `shutdown()`: the configuration survives and `set_config()` becomes effective again. `setup()` is idempotent, and a failed `setup()` leaves the controller un-setup so you can fix the config and retry.
By default the runtime remembers live control changes across reboots. `setup()` restores the traffic generator mode and motion hits saved in NVS, plus the detector when `RuntimeConfig::runtime_detector_selection_enabled` is set, and each controller setter saves its new value. The threshold is never saved. The runtime logs at INFO each saved value that differs from the config. Set `RuntimeConfig::persist_runtime_overrides` to false when your firmware owns configuration, for example from YAML or a cloud service: the config you pass is then the only source of truth, and the runtime neither reads nor writes saved controls.
The ESP-IDF runtime starts capture, traffic, and calibration immediately after connection or rearming. It observes startup traffic and attempts a receive-path refresh only if traffic continues for one second without any CSI callback. One second without observed traffic progress resets that observation. A callback suppresses recovery even when the packet is rejected by the detector; an absent or stopped external sender does not trigger recovery. This startup check is not a continuous watchdog for later traffic loss.
Recovery uses at most one asynchronous scan per sensing activation. Busy scan or connection state, or unconsumed scan results, defer the request in 500-ms intervals within a 15-second observation window. An accepted scan has a 30-second timeout. Success, failure, and timeout resume capture without repeating recovery in that activation. Disconnection, shutdown, and disarming cancel pending recovery; raw collection is not interrupted by it. Keep calling `loop()` throughout recovery.
The SDK reserves its scanner across recovery and result cleanup; `StandaloneWifiService::request_scan()` refuses overlapping requests. By default, the runtime releases its remaining scan results on the next loop turn after completion. Independent scanners must wait until `WiFiLifecycleManager::csi_receive_path_refresh_active()` becomes false before starting a scan. An idle driver does not prove result ownership: a subsequent scan can finish while its completion event is still queued.
For Wi-Fi stacks that scan autonomously and consume scan results, set `RuntimeConfig::wifi_scan_results_managed_externally` before setup. The runtime then leaves the driver result list to the Wi-Fi stack on completion, cancellation, and timeout, so delayed cleanup cannot erase a subsequent scan's results. The Wi-Fi stack is responsible for consuming or releasing recovery scan results, including partial results from failed scans. Independent calls to ESP-IDF scan APIs must still be serialized with the recovery request; the driver's busy check cannot atomically reserve the radio against another task starting a scan.
Stopping managed traffic never blocks `loop()`. The generator's task leaves its send on its own; the runtime disables CSI and resumes sensing from a later `loop()` once it has. A task still inside a socket call is left to finish, because deleting a task inside lwIP could leave the stack locked. It is logged after 2 seconds and raises a runtime fault only after 30 seconds, since Wi-Fi TX stalls and beacon-timeout disconnects release it well before then. Once the worker exits, an unread timeout is dropped, so a later runtime does not report a stop that already finished.
`RuntimeFrontendController::shutdown()` does not wait for that task, so you can call it from the loop task, including in response to a fault. The controller keeps its traffic generator across backends: a later `setup()` on the same controller starts traffic only after the old task has exited, and `loop()` reaps that task even while no backend exists. Destroying the controller, or a `TrafficGeneratorManager` you own, waits until its task has exited, however long its socket call takes; do that outside a watched loop task, or keep the object for the device's lifetime. Firmware that drives `TrafficGeneratorManager` or `CsiTrafficService` directly must keep calling their `loop()` after `stop()`. A station service that reconfigures the radio can wait for that stop with `StandaloneWifiService::set_radio_work_ready_callback()`. The callback stays false after `shutdown()` until the worker has left its send.
Register an optional `LogSink` before `setup()`. Do not replace or clear it until every runtime and callback source using it has shut down.
High Accuracy preserves the configured or live threshold when sensing starts, Wi-Fi reconnects, or raw collection ends. Explicit recalibration and switching detectors restore the detector's default threshold. Lightweight continues to derive its threshold through startup calibration.
Every calibration guards itself against motion. An evaluation above `BaseDetector::calibration_motion_ceiling()` restarts the calibration window and returns `calibration_packets` to zero. A recalibration on the channel, capture profile, and traffic generator mode of the last successful calibration also restarts above the live threshold when it is lower. If no full window fits within three calibration budgets, the calibration ends with `on_calibration_finished(snapshot, false)` and the threshold in force stays; after a rejected startup calibration, that is the configured threshold.
A calibration spends at least its base packet budget. While `BaseDetector::startup_calibration_conclusive()` returns false once the budget is spent, the calibration continues in steps of half that budget, up to three budgets, and `calibration_target_packets` grows with each step. Lightweight's rules and bounds are in [startup threshold calibration](<https://github.com/francescopace/espectre/blob/d79b4be232a1e2e464e85efbc7091aa562aed84d/docs/ALGORITHMS.md#startup-threshold-calibration>).
`RuntimeSnapshot::ready_to_publish` clears at once while calibrating, when sensing services or the link stop, when the newest detector input is one detector window old, and while the window refills after a history reset. Temporal admission leaves some slots empty even at the nominal packet rate, so window coverage can briefly fall under the detector's valid-slot floor while input keeps arriving. Once sensing is ready, such a dip clears readiness only if it lasts one detector window; shorter dips never reach `on_sensing_readiness_changed()` or `snapshot()`. The runtime logs every readiness transition with its reason.
See [ALGORITHMS.md](<https://github.com/francescopace/espectre/blob/d79b4be232a1e2e464e85efbc7091aa562aed84d/docs/ALGORITHMS.md#motion-hit-filtering>) for how evaluation cadence and hit filtering determine publish delay.
<a id="sdk_integration_1integration_errors"></a>
#### Errors
The control surface reports failure through `bool` returns and never throws. Runtime-backend, temporal-sampler, and detector storage allocations are non-throwing; an allocation failure makes `setup()` return false and reports the fault synchronously to the listener. A `false` means the call was rejected or could not be applied, and the runtime is unchanged. A call returns false for one of these reasons:
1. The value is outside the range published in [`runtime_sensing_schema.h`](#runtime__sensing__schema_8h).
2. The active runtime does not advertise the matching capability.
3. The runtime is not in a state that allows the call: for example, recalibration before `setup()` or while a calibration or raw collection is active, or raw collection without a Wi-Fi link.
4. The backend refused the change.
5. `setup()` could not allocate the runtime's bounded working storage.
Each method's documentation lists the cases that apply to it.
Asynchronous failures arrive instead through `IRuntimeListener::on_runtime_fault()`. Calibration outcome is reported by `on_calibration_finished(snapshot, success)`; a `false` there is not fatal, the runtime keeps sensing with the threshold that was in force before the calibration.
<a id="sdk_integration_1integration_capabilities"></a>
#### Capabilities
`RuntimeCapabilities` defaults every flag to false, so a runtime declares what it offers rather than inheriting a permissive default. Read `controller.capabilities()` after `setup()` and expose only what it advertises. The controller already refuses capability-gated calls; this check keeps unsupported controls out of the product interface.
<a id="sdk_integration_1integration_diagnostics"></a>
#### Diagnostics
Read `RuntimeFrontendController::diagnostics_sample()` for diagnostics. It returns the runtime's shared one-second `RuntimeDiagnosticsSample`: traffic and CSI rates plus the current link. Read the same sample across your transport adapters so their observation windows agree. It is `nullptr` before `setup()`.
`RuntimeDiagnosticsSample::csi_admitted_pps` is the detector input rate after temporal admission. `csi_accepted_pps` is the rate accepted by capture validation, before admission. Compare admitted PPS with `RuntimeConfig::csi_target_pps` together with `csi_occupancy_ratio`, callback-queue overflow, same-slot excess, missing-slot, stale, and out-of-order rates when a deployment underperforms. Occupancy is diagnostic telemetry and does not change the device send rate. [API.md](<https://github.com/francescopace/espectre/blob/d79b4be232a1e2e464e85efbc7091aa562aed84d/docs/API.md#diagnostics>) owns the corresponding wire field names, units, and optionality.
<a id="sdk_integration_1integration_diagnostics_advanced"></a>
##### Advanced: cumulative counters
`RuntimeFrontendController::diagnostics()` returns the cumulative `RuntimeDiagnosticsSnapshot` behind the sample, grouped as `link`, `traffic`, `csi`, `platform`, and `performance`. The `csi` group also carries the callback queue's drop counter, occupancy, and capacity. Use it when you need totals, or a sampling interval other than one second. `RuntimeDiagnosticsSampler` turns two reads into rates without requiring a separate timer:
```cpp
// once, after runtime_.setup() succeeds
sampler_.reset(runtime_.diagnostics(), now_ms);
// whenever the existing periodic sensing callback runs
latest_ = sampler_.sample(runtime_.diagnostics(), now_ms);
```
The ESP-IDF runtime always collects these counters and bounded performance windows. `RuntimeDiagnosticsSnapshot` also reports heap and CPU frequency in `platform`, loop load and detector timing in `performance`, and CSI provenance rejection in `csi`. [API.md](<https://github.com/francescopace/espectre/blob/d79b4be232a1e2e464e85efbc7091aa562aed84d/docs/API.md#diagnostics>) defines their transport representation.
<a id="sdk_integration_1integration_performance_sampling"></a>
#### Performance sampling
The runtime aggregates loop load and timing plus sampled detector evaluation timing in bounded 10-second windows. `RuntimeDiagnosticsSnapshot::performance` holds the latest complete window, and `platform` holds current, minimum, and largest-block heap values and configured CPU frequency. Collection is unconditional and does not emit a periodic debug log.
When one `loop()` iteration, or the wait since the previous one, reaches 100 ms, the runtime logs one warning. It lists the steps that took at least 1 ms. Log-sink time and listener time are separate, and listener time does not include the sink, so a frontend that logs inside a callback is not counted twice. The summary covers the iteration and the wait before it.
`performance.runtime_load_percent` measures wall time spent inside the ESPectre runtime loop, not whole-system CPU utilization. Wi-Fi callbacks only normalize and enqueue CSI; detector processing, inference, state transitions, and listener callback delivery run in the owning loop task. Transport work on private tasks is outside this measurement. Detector timing is sampled on an evaluation tick after approximately 1,000 detector packets. For High Accuracy, it covers ML feature extraction, inference, and state update.
<a id="sdk_integration_1integration_transport_adapters"></a>
### Transport adapters
SDK transport adapters should pass parsed requests through `FrontendCommandEngine` and preserve the canonical distinction between requester-scoped query results and state changes published to active transports. [API.md](<https://github.com/francescopace/espectre/blob/d79b4be232a1e2e464e85efbc7091aa562aed84d/docs/API.md#contract-principles>) owns the message fields and cross-transport semantics; [ARCHITECTURE.md](<https://github.com/francescopace/espectre/blob/d79b4be232a1e2e464e85efbc7091aa562aed84d/docs/ARCHITECTURE.md#shared-protocol-and-transport-services>) owns command-engine and adapter placement. Pass `RuntimeFrontendController::validate_control_update()` as the engine's sensing preflight, so an `update_sensing` request applies completely or not at all.
`RuntimeDirectHttpBridgeConfig::loop_time_ms_getter` optionally supplies the latest complete application loop duration in milliseconds. Measure the loop body that calls the runtime and processes application events; exclude work on other tasks and time between loop calls. If you omit the callback, selecting `loop_time_ms` returns `null`. This measurement is independent of the runtime performance-window average exposed as `loop_avg_us`.
The shared Direct service owns HTTP request lifetime, SSE delivery, deferred responses, and the owner-bound raw CSI session used by ESPectre. The ESP-IDF implementation assigns an opaque monotonically increasing token to each live connection, removes inbound work by token rather than file descriptor, and completes deferred work only while that token still identifies the originating client. The default interface implementation reports deferred delivery as unsupported, preserving source compatibility for transports that implement only synchronous requests.
<a id="sdk_integration_1integration_protocol_extensions"></a>
### Protocol extensions
All command parameters use `EspectreCommandValidator`: the parser checks JSON syntax and request structure, then invokes the callback registered on the SDK or application route. The callback receives decoded `JsonObjectField` values, validates parameters, and fills the command before dispatch. It must not change device state. For extension commands, `extension_parameters` initially contains the whole request from `parse_espectre_command()`, or the parameter object from `parse_espectre_command_request()`; the validator may replace it with normalized JSON built from the decoded fields. The SDK validator checks parameter types and ranges, including thresholds in `0–1` and motion hit counts in `1–20`.
`FrontendCommandEngine::execute()` and application extension handlers require a successfully parsed command. They check capabilities and operational state without repeating parameter validation. Direct runtime and service APIs retain their own argument checks because integrators can call them without a protocol parser.
`EspectreCapabilityProfile::extension` accepts an optional `EspectreProtocolExtension` supplied by your application. Each route declares its HTTP method and path, resource or operation name, command name, asynchronous behavior, MQTT availability, raw-collection policy, and parameter validator. The extension also lists its event names. `validate_protocol_extension()` rejects invalid descriptors and collisions with SDK routes, command names, resources, or events.
Use the same immutable catalog for capability output, `DirectHttpServiceConfig::protocol_extension`, `direct_http_request_to_command()`, and `parse_espectre_command()`. Keep it alive while the adapters use it. Direct and MQTT then validate parameters through the same callback, and an unregistered extension command is rejected. Your application enforces each route's MQTT availability, implements its commands, and publishes extension events through the normal transports. Advertise only extensions your application has enabled.
Your application owns firmware updates. You can use protocol extensions to expose its update commands while keeping the update mechanism and release policy in your application.
`RuntimeFrontendController::quiesce()` is a generic suspension operation: it disables telemetry and sensing services and stops active raw collection while retaining the configured backend. The caller restores its desired service and telemetry gates when resuming. It is useful before a firmware update or another temporary activity that needs CSI and sensing traffic to stop.
<a id="sdk_integration_1integration_versioning"></a>
### Versioning
Supply your application version explicitly through `EspectreDeviceInfo::firmware_version` and discovery or provisioning configuration. The SDK does not read the ESP-IDF application descriptor to determine it.
[`ESPECTRE_SDK_VERSION_STRING`](#espectre__sdk__version_8h_1a63ca6448380d44c069980a49a9584c74) identifies the SDK sources you compiled against. Use the component-wise [`ESPECTRE_SDK_VERSION_AT_LEAST(major, minor, patch)`](#espectre__sdk__version_8h_1a84f438434c7a7b020e175e84ae3ca6e8) to guard code that needs a given release. [`ESPECTRE_SDK_VERSION_NUMBER`](#espectre__sdk__version_8h_1addabd247bcb8243d35a37657c029571b) retains the historical `MMmmpp` packing for compatibility and compact telemetry, but it is not an ordering contract because Semantic Versioning components are not limited to two digits.
ESPectre uses Semantic Versioning for the published C++ source API:
- Patch releases preserve source compatibility and documented lifecycle, validation, ownership, threading, capability, and error semantics. Detector coefficients and generated model weights may change when validation gates demonstrate a compatible quality fix; exact floating-point telemetry is not a compatibility guarantee.
- Minor releases may append fields, add callbacks with default implementations, and add types, functions, or overloads. Existing calls keep their meaning, closed enums do not gain values, and removals require a prior deprecation in a released minor version.
- Major releases may remove deprecated APIs or otherwise break source compatibility, with migration notes in `CHANGELOG.md`.
- Prerelease and rolling `preview` or `develop` bundles may change before the corresponding final release. The compatibility promise begins at the final numeric release.
The SDK is distributed and consumed as source. It does not promise a stable binary ABI: rebuild the SDK and integration together with the same C++ standard library and ESP-IDF toolchain. Construct public configuration and snapshot structs with their defaults, then assign named fields as shown in this guide; positional aggregate initialization is outside the compatibility contract so new fields can be appended safely.
Everything reachable from [`espectre_sdk.h`](#espectre__sdk_8h) belongs to the stable runtime surface. The protocol contracts in [`espectre_protocol_sdk.h`](#espectre__protocol__sdk_8h) follow the same source-compatibility rules, and so do the public methods and configuration types that [`espectre_services_sdk.h`](#espectre__services__sdk_8h) and [`espectre_mqtt_sdk.h`](#espectre__mqtt__sdk_8h) expose for optional ESP-IDF services. [`espectre_core_sdk.h`](#espectre__core__sdk_8h) is a separate opt-in for custom capture pipelines. Its detector classes and documented public methods follow the same rules. Feature trackers, generated weights, and headers included only as implementation dependencies are not independent extension points.
The SDK reads its identity only from [`runtime/espectre_sdk_version.h`](#espectre__sdk__version_8h) and explicit compiler definitions. It does not inspect Git, source refs, environment variables, or the application version. Published SDK bundles stamp the release identity into that header and `idf_component.yml`; the CI packaging tools determine the identity before producing the bundle.
Integrators can stamp the same header or override all four macros together: [`ESPECTRE_SDK_VERSION_STRING`](#espectre__sdk__version_8h_1a63ca6448380d44c069980a49a9584c74), [`ESPECTRE_SDK_VERSION_MAJOR`](#espectre__sdk__version_8h_1a1c56ebb77dae087ea795df71afe1b36a), [`ESPECTRE_SDK_VERSION_MINOR`](#espectre__sdk__version_8h_1ab49f9a44dcd3be82d3b3e742d9334c23), and [`ESPECTRE_SDK_VERSION_PATCH`](#espectre__sdk__version_8h_1a74f3ae0b42f726bf3302abae42655339). A complete compiler override takes precedence over the packaged values. The string and numeric components must describe the same SDK release, and definitions must be consistent across the SDK and its consumers.
Without a complete identity, the SDK uses `"0.0.0"` and zero for all numeric version components. Incomplete overrides also fall back to these values rather than mixing metadata from different sources or failing compilation. `espectre_sdk_version()` always returns a non-null string; `"0.0.0"` means the SDK version is unknown, and version guards for newer releases evaluate to false. A source checkout without stamped metadata therefore reports `"0.0.0"`, even if it has Git tags.
The SDK manifest exposes the packaged identity once as `version`; `release_tag` names the GitHub release that carries the assets and may differ for rolling channels. Rolling GitHub tags remain `snapshot` for `preview` and `snapshot-dev` for `develop`. SDK identity is separate from the application version supplied by the integrator and `ESPECTRE_PROTOCOL_VERSION`, which versions the wire format.
<a id="sdk_integration_1integration_advanced_integrations"></a>
### Advanced integrations
The core-only path and source-list builds let an application supply more of the capture and build infrastructure.
<a id="sdk_integration_1integration_core_only"></a>
#### Core-only
If your firmware already owns Wi-Fi and CSI capture, include [`espectre_core_sdk.h`](#espectre__core__sdk_8h) and consume the detectors directly. The `core` detectors accept normalized CSI payloads and expose motion state, movement metric, and threshold control. The same facade exposes `TemporalCsiSampler`, which applies the production fixed-grid admission before `process_packet()`.
Detector and sampler working buffers use non-throwing allocation. Check `detector.is_valid()` after construction and the result of `sampler.configure(...)` before starting a custom pipeline; a false result means the requested bounded storage was unavailable. These objects are movable and intentionally non-copyable because their buffers own live temporal state.
The sampler tracks timing and slots; your integration stores the selected CSI payload. Handle each input in this order:
1. Call `admit()` before replacing the stored payload.
2. If `admit()` returns `true`, consume the stored payload: clear detector history when `reset_required()` is true, call `advance_missing_slots(missing_slots_before())`, and then call `process_packet()`.
3. If `gap_reset_required()` is true, clear detector history again before admitting post-gap data.
4. If `selected_current()` is true, replace the stored payload with the current normalized CSI.
At the end of a finite stream, call `flush()` and consume the stored payload if it returns `true`.
After each `update_state()`, re-read `get_threshold()`: Lightweight can lower it without a setter call, and the core-only path has no `on_threshold_changed()` hook. The sampler owns admission only; use `runtime/esp_idf/csi_pipeline.cpp` as the reference for CSI normalization, evaluation cadence, and hit filtering before committing to custom wiring.
A core-only integration owns the same two-view boundary between raw and detector input. Normalize the payload into the centered HT20 convention. For LLTF captures, call `zero_ht20_lltf_missing_bins()` on the raw view. Then copy the payload into a private detector buffer and call `prepare_ht20_detector_input()` only on that copy, passing the capture profile and the source metadata.
<a id="sdk_integration_1integration_build_integration"></a>
#### Build integration
Component Manager configures the registered component automatically. The following alternatives apply when you vendor SDK sources or maintain your own CMake target. Set the SDK root to the directory containing `espectre_sources.cmake`: the root of the registry archive, or `src/cpp/` in a GitHub/web bundle.
- **Core-only CMake**: include `espectre_sources.cmake` from the SDK root, compile `ESPECTRE_CORE_SOURCES`, and add `ESPECTRE_SHARED_INCLUDE_DIRS`. No ESP-IDF runtime sources are required.
- **Full-runtime CMake / ESP-IDF**: compile `ESPECTRE_CORE_SOURCES` and `ESPECTRE_RUNTIME_ESP_IDF_SOURCES`, then add `ESPECTRE_RUNTIME_FRONTEND_SUPPORT_SOURCES` or the per-capability Direct HTTP, MQTT, and provisioning lists only when the integration uses them. Add `ESPECTRE_SHARED_INCLUDE_DIRS` and the dependencies listed under [Optional capability groups](<https://github.com/francescopace/espectre/blob/d79b4be232a1e2e464e85efbc7091aa562aed84d/docs/SDK.md#optional-capability-groups>). Link the target with `ESPECTRE_RUNTIME_ESP_IDF_TRAFFIC_LINK_OPTIONS`, and with `ESPECTRE_RUNTIME_ESP_IDF_DIRECT_LINK_OPTIONS` when it compiles the Direct sources, which also need the `private_include` directory of the `espressif__mdns` component.
- **Vendored ESP-IDF component**: copy the SDK root to your project's `components/espectre/` directory and add [`espectre`](#namespaceespectre) to your own component's `REQUIRES`. The sensing runtime is always built; the optional groups are opt-in under the "ESPectre SDK" menuconfig menu.
- **Toolchain**: C++17, ESP-IDF `>=5.5.3` for the `runtime/esp_idf` services. Repository builds use ESP-IDF `5.5.5`.
Source-list integrations and vendored ESP-IDF components use the version header directly; no version resolution step is required. For a GitHub/web SDK bundle extracted into `espectre/`, a complete core-only target is:
```cpp
set(ESPECTRE_CPP_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/espectre/src/cpp")
include("${ESPECTRE_CPP_ROOT}/espectre_sources.cmake")
add_library(espectre_core STATIC ${ESPECTRE_CORE_SOURCES})
target_compile_features(espectre_core PUBLIC cxx_std_17)
target_include_directories(espectre_core PUBLIC ${ESPECTRE_SHARED_INCLUDE_DIRS})
```
Link the application target to `espectre_core` to inherit the includes and C++ standard. Adjust `ESPECTRE_CPP_ROOT` to the SDK's location. If overriding the packaged SDK identity, apply all four version macros with `target_compile_definitions(espectre_core PUBLIC ...)` so consumers inherit them. The same approach works for a full-runtime source-list target.
The shared component does not require ESP-IDF's `log` component. A product that registers an `esp_log` adapter declares that dependency in its application component.
`ESPECTRE_SHARED_INCLUDE_DIRS` contains only the SDK root. Include the facades by name and any other SDK header by its layer-prefixed path, such as [`#include "runtime/runtime_config.h"`](#runtime__config_8h). SDK sources use the same form, so the layer directories stay off your search path: generic SDK basenames such as `utils.h` and `filters.h` cannot collide with headers of your own in either direction.
<a id="sdk_integration_1integration_published_sdk_channels"></a>
### Published SDK channels
The GitHub/web SDK bundles provide source archives for vendoring and evaluation. They use the repository-style layout below, separately from the registry component, and follow the firmware release channels:
| Channel | Source | Intended use |
| --- | --- | --- |
| `release` | latest tagged semver GitHub Release and `https://espectre.dev/artifacts/sdk/release/` | Final numeric versions are production candidates; prerelease tags are published explicitly as evaluation builds |
| `preview` | rolling `snapshot` GitHub prerelease and `https://espectre.dev/artifacts/sdk/preview/` | Validate `main` before the next release |
| `develop` | rolling `snapshot-dev` GitHub prerelease and `https://espectre.dev/artifacts/sdk/develop/` | Pre-main validation from `develop` |
Rolling releases publish `sdk-manifest-preview.json` and `sdk-manifest-develop.json`; the manifest filename follows the channel, while `release_tag` retains the GitHub tag shown above. Tagged releases publish `sdk-manifest-<release-tag>.json`.
Each GitHub/web SDK bundle includes:
- `docs/SDK.md`
- [`src/cpp/espectre_sdk.h`](#espectre__sdk_8h)
- [`src/cpp/espectre_core_sdk.h`](#espectre__core__sdk_8h)
- [`src/cpp/espectre_services_sdk.h`](#espectre__services__sdk_8h)
- [`src/cpp/espectre_mqtt_sdk.h`](#espectre__mqtt__sdk_8h)
- [`src/cpp/espectre_protocol_sdk.h`](#espectre__protocol__sdk_8h)
- `src/cpp/core/`
- `src/cpp/runtime/`
- `src/cpp/runtime/esp_idf/espectre_config/`
- `src/cpp/espectre_sources.cmake`
- `src/cpp/CMakeLists.txt`
- `src/cpp/idf_component.yml`
- `src/cpp/Kconfig.projbuild`
- `src/cpp/Doxyfile`
- `src/cpp/sdk_integration.dox`
- generated `src/cpp/core/ml_weights.h`
- `LICENSE`, `LICENSING.md`, and `THIRD_PARTY_NOTICES.md`
The published bundle is a versioned C++ source SDK with stamped packaging metadata, ready to vendor or unpack into your firmware tree. ESPectre is compiled together with the product firmware; the bundle does not include chip-specific precompiled libraries or promise binary ABI compatibility. In the bundled copy of this guide, repository-relative links point to GitHub URLs pinned to the commit or release tag used for that package. The `.tar.gz` and `.zip` archives are generated deterministically from the source commit timestamp, and the SDK manifest records a SHA-256 digest for each archive so consumers can verify downloaded bytes.
<a id="namespaceespectre"></a>
## espectre
[`espectre::BaseDetector`](#classespectre_1_1_base_detector)
[`espectre::CsiTrafficService`](#classespectre_1_1_csi_traffic_service)
[`espectre::CsiTrafficServiceConfig`](#structespectre_1_1_csi_traffic_service_config)
[`espectre::DirectHttpServiceConfig`](#structespectre_1_1_direct_http_service_config)
[`espectre::DirectHttpServiceDiagnostics`](#structespectre_1_1_direct_http_service_diagnostics)
[`espectre::DirectRequest`](#structespectre_1_1_direct_request)
[`espectre::DirectWifiSnapshot`](#structespectre_1_1_direct_wifi_snapshot)
[`espectre::EspectreApiEventDescriptor`](#structespectre_1_1_espectre_api_event_descriptor)
[`espectre::EspectreApiRoute`](#structespectre_1_1_espectre_api_route)
[`espectre::EspectreCapabilityProfile`](#structespectre_1_1_espectre_capability_profile)
[`espectre::EspectreCommand`](#structespectre_1_1_espectre_command)
[`espectre::EspectreDeviceConfig`](#structespectre_1_1_espectre_device_config)
[`espectre::EspectreDeviceInfo`](#structespectre_1_1_espectre_device_info)
[`espectre::EspectreExtensionRoute`](#structespectre_1_1_espectre_extension_route)
[`espectre::EspectreNetworkInfo`](#structespectre_1_1_espectre_network_info)
[`espectre::EspectreProtocolExtension`](#structespectre_1_1_espectre_protocol_extension)
[`espectre::EspIdfDirectHttpService`](#classespectre_1_1_esp_idf_direct_http_service)
[`espectre::EspIdfMqttTransport`](#classespectre_1_1_esp_idf_mqtt_transport)
[`espectre::EspIdfPeerDiscoveryService`](#classespectre_1_1_esp_idf_peer_discovery_service)
[`espectre::FrontendCommandContext`](#structespectre_1_1_frontend_command_context)
[`espectre::FrontendCommandEngine`](#classespectre_1_1_frontend_command_engine)
[`espectre::FrontendCommandResult`](#structespectre_1_1_frontend_command_result)
[`espectre::FrontendDeviceConfigDefaults`](#structespectre_1_1_frontend_device_config_defaults)
[`espectre::FrontendHaDiagnosticSensor`](#structespectre_1_1_frontend_ha_diagnostic_sensor)
[`espectre::FrontendHaDiscoveryMessage`](#structespectre_1_1_frontend_ha_discovery_message)
[`espectre::FrontendHaMqttSettings`](#structespectre_1_1_frontend_ha_mqtt_settings)
[`espectre::FrontendWifiStationOptions`](#structespectre_1_1_frontend_wifi_station_options)
[`espectre::HighAccuracyDetector`](#classespectre_1_1_high_accuracy_detector)
[`espectre::ICsiTrafficGenerator`](#classespectre_1_1_i_csi_traffic_generator)
[`espectre::ICsiTrafficIngress`](#classespectre_1_1_i_csi_traffic_ingress)
[`espectre::IDirectHttpService`](#classespectre_1_1_i_direct_http_service)
[`espectre::IMqttTransport`](#classespectre_1_1_i_mqtt_transport)
[`espectre::IPeerDiscoveryService`](#classespectre_1_1_i_peer_discovery_service)
[`espectre::IRuntimeListener`](#classespectre_1_1_i_runtime_listener)
[`espectre::IUdpDatagramSocket`](#classespectre_1_1_i_udp_datagram_socket)
[`espectre::JsonFieldView`](#structespectre_1_1_json_field_view)
[`espectre::JsonInput`](#classespectre_1_1_json_input)
[`espectre::JsonObjectField`](#structespectre_1_1_json_object_field)
[`espectre::LightweightDetector`](#classespectre_1_1_lightweight_detector)
[`espectre::LogSink`](#structespectre_1_1_log_sink)
[`espectre::MdnsBootstrapResponder`](#classespectre_1_1_mdns_bootstrap_responder)
[`espectre::MdnsDiscoveryService`](#classespectre_1_1_mdns_discovery_service)
[`espectre::MdnsDiscoveryServiceConfig`](#structespectre_1_1_mdns_discovery_service_config)
[`espectre::MqttTransportDiagnostics`](#structespectre_1_1_mqtt_transport_diagnostics)
[`espectre::NetworkTrafficSnapshot`](#structespectre_1_1_network_traffic_snapshot)
[`espectre::PeerDiscoveryCandidate`](#structespectre_1_1_peer_discovery_candidate)
[`espectre::PeerDiscoverySnapshot`](#structespectre_1_1_peer_discovery_snapshot)
[`espectre::PendingEvent`](#classespectre_1_1_pending_event)
[`espectre::PendingQueue`](#classespectre_1_1_pending_queue)
[`espectre::RawCsiHttpFramePrefix`](#structespectre_1_1_raw_csi_http_frame_prefix)
[`espectre::RawCsiPacketView`](#structespectre_1_1_raw_csi_packet_view)
[`espectre::RawCsiRecordHeaderV8`](#structespectre_1_1_raw_csi_record_header_v8)
[`espectre::RawCsiSessionConfig`](#structespectre_1_1_raw_csi_session_config)
[`espectre::RawCsiSessionController`](#classespectre_1_1_raw_csi_session_controller)
[`espectre::RawCsiSessionDiagnostics`](#structespectre_1_1_raw_csi_session_diagnostics)
[`espectre::RuntimeCapabilities`](#structespectre_1_1_runtime_capabilities)
[`espectre::RuntimeConfig`](#structespectre_1_1_runtime_config)
[`espectre::RuntimeControlUpdate`](#structespectre_1_1_runtime_control_update)
[`espectre::RuntimeDiagnosticsSample`](#structespectre_1_1_runtime_diagnostics_sample)
[`espectre::RuntimeDiagnosticsSampler`](#classespectre_1_1_runtime_diagnostics_sampler)
[`espectre::RuntimeDiagnosticsSnapshot`](#structespectre_1_1_runtime_diagnostics_snapshot)
[`espectre::RuntimeDirectHttpBridge`](#classespectre_1_1_runtime_direct_http_bridge)
[`espectre::RuntimeDirectHttpBridgeConfig`](#structespectre_1_1_runtime_direct_http_bridge_config)
[`espectre::RuntimeEventMailbox`](#classespectre_1_1_runtime_event_mailbox)
[`espectre::RuntimeFrontendController`](#classespectre_1_1_runtime_frontend_controller)
[`espectre::RuntimeSnapshot`](#structespectre_1_1_runtime_snapshot)
[`espectre::StandaloneWifiAccessPoint`](#structespectre_1_1_standalone_wifi_access_point)
[`espectre::StandaloneWifiConfig`](#structespectre_1_1_standalone_wifi_config)
[`espectre::StandaloneWifiInfo`](#structespectre_1_1_standalone_wifi_info)
[`espectre::StandaloneWifiService`](#classespectre_1_1_standalone_wifi_service)
[`espectre::StoredWifiConfig`](#structespectre_1_1_stored_wifi_config)
[`espectre::TemporalCsiSampler`](#classespectre_1_1_temporal_csi_sampler)
[`espectre::TrafficGeneratorManager`](#classespectre_1_1_traffic_generator_manager)
[`espectre::UdpDatagramPeer`](#structespectre_1_1_udp_datagram_peer)
[`espectre::WifiBssidPinService`](#classespectre_1_1_wifi_bssid_pin_service)
[`espectre::WifiBssidPinServiceConfig`](#structespectre_1_1_wifi_bssid_pin_service_config)
[`espectre::WifiBssidPinStationState`](#structespectre_1_1_wifi_bssid_pin_station_state)
[`espectre::WiFiLifecycleManager`](#classespectre_1_1_wi_fi_lifecycle_manager)
[`espectre::WifiProvisioningDefaults`](#structespectre_1_1_wifi_provisioning_defaults)
[`espectre::WifiProvisioningService`](#classespectre_1_1_wifi_provisioning_service)
[`espectre::task_scheduling`](#namespaceespectre_1_1task__scheduling)
<a id="namespaceespectre_1a1eaac1c4c744a0c2aa7a1013a884087e"></a>
### `SelectedSubcarriers`
```cpp
using espectre::SelectedSubcarriers = std::array<uint8_t, HT20_SELECTED_BAND_SIZE>
```
A selection of [`HT20_SELECTED_BAND_SIZE`](#namespaceespectre_1a634c531cce6a62b80e8e6b30cd9c68e2) subcarrier indices.
<a id="namespaceespectre_1a173e10371ac46c7dcb7e9fa395102541"></a>
### `HT20_NUM_SUBCARRIERS`
```cpp
constexpr uint16_t espectre::HT20_NUM_SUBCARRIERS = 64U
```
<a id="namespaceespectre_1ad7a70d37c99a12759ec87883d9bf5651"></a>
### `HT20_CSI_LEN`
```cpp
constexpr uint16_t espectre::HT20_CSI_LEN = 128U
```
Normalized payload size in bytes: 64 subcarriers of I/Q.
<a id="namespaceespectre_1abc9115b9cb972953049e3dee66e7aa16"></a>
### `HT20_CSI_LEN_DOUBLE`
```cpp
constexpr uint16_t espectre::HT20_CSI_LEN_DOUBLE = 256U
```
Raw size of a payload carrying two HT20 estimates.
<a id="namespaceespectre_1a95d2500724b3e1de4424ce0ec2dc4aae"></a>
### `HT20_CSI_LEN_SHORT`
```cpp
constexpr uint16_t espectre::HT20_CSI_LEN_SHORT = 114U
```
Raw size of a short HT estimate: 57 subcarriers.
<a id="namespaceespectre_1aaa977261eaadbc6e80a6a9d0201b061d"></a>
### `LLTF20_CSI_LEN_SHORT`
```cpp
constexpr uint16_t espectre::LLTF20_CSI_LEN_SHORT = 106U
```
Raw size of a compact LLTF estimate: 53 subcarriers, `-26..+26`.
<a id="namespaceespectre_1a3807e5300bedcf7488f0db72003bab08"></a>
### `HT20_CSI_LEN_SHORT_DOUBLE`
```cpp
constexpr uint16_t espectre::HT20_CSI_LEN_SHORT_DOUBLE = 228U
```
Raw size of a payload carrying two short HT estimates.
<a id="namespaceespectre_1a591e14532ba43e92d1c5d222343a48f5"></a>
### `HT20_CSI_LEN_SHORT_LEFT_PAD`
```cpp
constexpr uint8_t espectre::HT20_CSI_LEN_SHORT_LEFT_PAD = 8U
```
Bytes of padding before a short HT estimate when it is normalized.
<a id="namespaceespectre_1acd18a86eaa0c26991bb7007b43c0c653"></a>
### `HT20_GUARD_BAND_LOW`
```cpp
constexpr uint8_t espectre::HT20_GUARD_BAND_LOW = 4U
```
First live subcarrier index; lower bins are guard tones.
<a id="namespaceespectre_1ab563bdf9c7b5fc82fac271db91e70349"></a>
### `HT20_GUARD_BAND_HIGH`
```cpp
constexpr uint8_t espectre::HT20_GUARD_BAND_HIGH = 60U
```
Last live subcarrier index; higher bins are guard tones.
<a id="namespaceespectre_1ae8f908725d3ea09ffe13d62ab0b3afbd"></a>
### `HT20_DC_SUBCARRIER`
```cpp
constexpr uint8_t espectre::HT20_DC_SUBCARRIER = 32U
```
Index of the DC null in the centered layout.
<a id="namespaceespectre_1a634c531cce6a62b80e8e6b30cd9c68e2"></a>
### `HT20_SELECTED_BAND_SIZE`
```cpp
constexpr uint8_t espectre::HT20_SELECTED_BAND_SIZE = 12U
```
Number of subcarriers the detectors measure on.
<a id="namespaceespectre_1ab5d5a6532e6d524fa4932baec3f9c86f"></a>
### `DEFAULT_SUBCARRIERS`
```cpp
constexpr uint8_t espectre::DEFAULT_SUBCARRIERS[HT20_SELECTED_BAND_SIZE][HT20_SELECTED_BAND_SIZE] = {
4U, 8U, 13U, 18U, 23U, 28U, 36U, 41U, 46U, 51U, 56U, 60U,
}
```
Subcarriers the detectors measure on; fixed for this SDK version.
<a id="namespaceespectre_1a09a51380aebbfbfacbb14b51c7604653"></a>
### `make_default_subcarriers`
```cpp
constexpr SelectedSubcarriers espectre::make_default_subcarriers()
```
DEFAULT\_SUBCARRIERS as a [SelectedSubcarriers](#namespaceespectre_1a1eaac1c4c744a0c2aa7a1013a884087e) value.
<a id="namespaceespectre_1a99ebf34bc489f9258115ae3fc39c84cc"></a>
### `FrontendReadPayloadCallback`
```cpp
using espectre::FrontendReadPayloadCallback = std::function<std::string(const EspectreCommand &command)>
```
Build the JSON data for a read command such as `device` or `sensing`.
Return an empty string when the data is unavailable.
<a id="namespaceespectre_1a8e42108419d4fce5a5d1a958dd7674b0"></a>
### `FrontendDeviceLabelCallback`
```cpp
using espectre::FrontendDeviceLabelCallback = std::function<bool(const std::string &device_label, std::string *message)>
```
Apply a new user-facing device label; empty clears it.
<a id="namespaceespectre_1a7ef25a2cd5bc69f39d5c604bfa7205c1"></a>
### `FrontendThresholdCallback`
```cpp
using espectre::FrontendThresholdCallback = std::function<bool(float threshold, std::string *message)>
```
Apply a validated threshold on the 0..1 scale.
<a id="namespaceespectre_1ac9bb8399a317cda44a26fabc384d9415"></a>
### `FrontendMotionHitsCallback`
```cpp
using espectre::FrontendMotionHitsCallback =
std::function<bool(uint8_t motion_on_hits, uint8_t motion_off_hits, std::string *message)>
```
Apply validated motion hit counts.
<a id="namespaceespectre_1ad31097089074dcd8b9cda39c061fe6fa"></a>
### `FrontendTrafficGeneratorModeCallback`
```cpp
using espectre::FrontendTrafficGeneratorModeCallback = std::function<bool(TrafficGeneratorMode mode, std::string *message)>
```
Switch the traffic generator mode.
<a id="namespaceespectre_1aeb40ee64d61b2f1df17f0a2fdd91edbc"></a>
### `FrontendDetectorCallback`
```cpp
using espectre::FrontendDetectorCallback = std::function<bool(DetectionAlgorithm algorithm, std::string *message)>
```
Switch the active detector.
<a id="namespaceespectre_1aa3d2cbbf3ae5675785b1f944ffedfd84"></a>
### `FrontendRecalibrateCallback`
```cpp
using espectre::FrontendRecalibrateCallback = std::function<bool(std::string *message)>
```
Start a recalibration; false reports the `busy` result code.
<a id="namespaceespectre_1ae7042efa563d462c22f07520e14049af"></a>
### `FrontendWifiBssidCallback`
```cpp
using espectre::FrontendWifiBssidCallback =
std::function<bool(const EspectreCommand &command, std::string *message)>
```
Handle `scan_wifi`, `set_wifi_bssid`, `clear_wifi_bssid`, or `clear_wifi_credentials`, as named by `command.command`.
<a id="namespaceespectre_1a9bd446908b7d5f2991698aa087668f76"></a>
### `FrontendMqttConfigCallback`
```cpp
using espectre::FrontendMqttConfigCallback =
std::function<bool(const EspectreCommand &command, bool clear, std::string *message)>
```
Apply `update_mqtt`, or clear the broker settings when `clear` is true.
<a id="namespaceespectre_1a0dde9bbbb9dbdb4c4fe1502ddf47ea7a"></a>
### `FrontendSensingControlCallback`
```cpp
using espectre::FrontendSensingControlCallback = std::function<bool(bool enabled, std::string *message)>
```
Arm or disarm the sensing services.
<a id="namespaceespectre_1a8d7fd8b1b46a31094dd6cdba42bfa903"></a>
### `FrontendSensingPreflightCallback`
```cpp
using espectre::FrontendSensingPreflightCallback =
std::function<bool(const RuntimeControlUpdate &update, std::string *message)>
```
Check every sensing field of one `update_sensing` before any is applied.
Frontends built on [RuntimeFrontendController](#classespectre_1_1_runtime_frontend_controller) pass [`RuntimeFrontendController::validate_control_update()`](#classespectre_1_1_runtime_frontend_controller_1a4022d8f2e85a66c50222aac5d0cbd4f3).
<a id="namespaceespectre_1ad97c50bf378e0be4ecca2d57aae35f21"></a>
### `ESPECTRE_RAW_CSI_ENDPOINT`
```cpp
constexpr char espectre::ESPECTRE_RAW_CSI_ENDPOINT[][] = "/espectre/v1/csi"
```
Path of the binary collection endpoint.
<a id="namespaceespectre_1a1571e2dbb44f5b5edacc83b4d1539ea9"></a>
### `ESPECTRE_RAW_CSI_PROTOCOL_VERSION`
```cpp
constexpr uint8_t espectre::ESPECTRE_RAW_CSI_PROTOCOL_VERSION = 1U
```
Version of the stream framing in [`RawCsiHttpFramePrefix::version`](#structespectre_1_1_raw_csi_http_frame_prefix_1ac4f5786b99681c4cad962c0f97dfafbf).
<a id="namespaceespectre_1a2c47aea6a64e9bbf1699a0066f9c437f"></a>
### `ESPECTRE_RAW_CSI_RECORD_VERSION`
```cpp
constexpr uint8_t espectre::ESPECTRE_RAW_CSI_RECORD_VERSION = RAW_CSI_RECORD_VERSION_V8
```
Version of the record that follows each prefix.
<a id="namespaceespectre_1a74df0adfb1aeee5b74d72ff5650afc51"></a>
### `ESPECTRE_RAW_CSI_SESSION_ID_BYTES`
```cpp
constexpr size_t espectre::ESPECTRE_RAW_CSI_SESSION_ID_BYTES = 16U
```
Size of a session identifier.
<a id="namespaceespectre_1ad78ee1950a9973d84c25e6b5e925aff4"></a>
### `ESPECTRE_RAW_CSI_RESPONSE_MAGIC`
```cpp
constexpr uint32_t espectre::ESPECTRE_RAW_CSI_RESPONSE_MAGIC = 0x52505345U
```
Value of [`RawCsiHttpFramePrefix::magic`](#structespectre_1_1_raw_csi_http_frame_prefix_1aff63ce4fc7a4e08371da97d54cb746c5), the bytes `ESPR` on the wire.
<a id="namespaceespectre_1a0480250c15d0e8b1a160fc5a825823bf"></a>
### `LIGHTWEIGHT_DEFAULT_THRESHOLD`
```cpp
constexpr float espectre::LIGHTWEIGHT_DEFAULT_THRESHOLD = 0.6621854538596202f
```
Lightweight threshold in force until startup calibration replaces it.
<a id="namespaceespectre_1ad5207970e48af47dc7eb1604269bdc58"></a>
### `LIGHTWEIGHT_MIN_THRESHOLD`
```cpp
constexpr float espectre::LIGHTWEIGHT_MIN_THRESHOLD = 0.0f
```
<a id="namespaceespectre_1ad092437163d2cdb5c5df9649cdd4c66d"></a>
### `LIGHTWEIGHT_MAX_THRESHOLD`
```cpp
constexpr float espectre::LIGHTWEIGHT_MAX_THRESHOLD = 1.0f
```
<a id="namespaceespectre_1a738158b5a07a1d20dd13553fefe9aba4"></a>
### `LIGHTWEIGHT_STARTUP_THRESHOLD_FACTOR`
```cpp
constexpr float espectre::LIGHTWEIGHT_STARTUP_THRESHOLD_FACTOR = 1.0f
```
See [`BaseDetector::get_startup_threshold_factor()`](#classespectre_1_1_base_detector_1ab3ff821066a78493f9f91dda37001310).
<a id="namespaceespectre_1aa2efb98c798884ab306a6643c116b2a0"></a>
### `HIGH_ACCURACY_DEFAULT_THRESHOLD`
```cpp
constexpr float espectre::HIGH_ACCURACY_DEFAULT_THRESHOLD = 0.5f
```
High Accuracy threshold learned at training time.
<a id="namespaceespectre_1a9133aa008e101764566e0cb2742e7184"></a>
### `HIGH_ACCURACY_MIN_THRESHOLD`
```cpp
constexpr float espectre::HIGH_ACCURACY_MIN_THRESHOLD = 0.0f
```
<a id="namespaceespectre_1a8300aec6a3a88076cfd2a44a2aa1484e"></a>
### `HIGH_ACCURACY_MAX_THRESHOLD`
```cpp
constexpr float espectre::HIGH_ACCURACY_MAX_THRESHOLD = 1.0f
```
<a id="namespaceespectre_1af86772d17580cec4bfe57f8481c5c88c"></a>
### `HIGH_ACCURACY_METRIC_SCALE`
```cpp
constexpr float espectre::HIGH_ACCURACY_METRIC_SCALE = 1.0f
```
Upper end of the High Accuracy metric.
<a id="namespaceespectre_1ade1005795568ea8d80776ac6b6c222c8"></a>
### `LOWPASS_CUTOFF_DEFAULT`
```cpp
constexpr float espectre::LOWPASS_CUTOFF_DEFAULT = 11.0f
```
<a id="namespaceespectre_1aac038424c0e9b371ea394c5def3b5158"></a>
### `LOWPASS_CUTOFF_MIN`
```cpp
constexpr float espectre::LOWPASS_CUTOFF_MIN = 5.0f
```
<a id="namespaceespectre_1a4accb9aa168687b87a9c3b8202af831c"></a>
### `LOWPASS_CUTOFF_MAX`
```cpp
constexpr float espectre::LOWPASS_CUTOFF_MAX = 20.0f
```
<a id="namespaceespectre_1a71e1289119eb2029acb401ef6d5b0aec"></a>
### `LOWPASS_SAMPLE_RATE`
```cpp
constexpr float espectre::LOWPASS_SAMPLE_RATE = 100.0f
```
Sample rate the filter is designed for: the nominal 100 pps.
<a id="namespaceespectre_1a5cf095597de0a42f1bbe7f2838440b19"></a>
### `HAMPEL_TURBULENCE_WINDOW_MIN`
```cpp
constexpr uint8_t espectre::HAMPEL_TURBULENCE_WINDOW_MIN = 3U
```
Smallest window, in samples.
<a id="namespaceespectre_1a43683e30117786c03a0f4d5a05bee629"></a>
### `HAMPEL_TURBULENCE_WINDOW_MAX`
```cpp
constexpr uint8_t espectre::HAMPEL_TURBULENCE_WINDOW_MAX = 11U
```
Largest window, in samples.
<a id="namespaceespectre_1a6014322636960da116aac379b07e896e"></a>
### `HAMPEL_TURBULENCE_WINDOW_DEFAULT`
```cpp
constexpr uint8_t espectre::HAMPEL_TURBULENCE_WINDOW_DEFAULT = 7U
```
<a id="namespaceespectre_1aaaab9e2cd7ff1dda6dccd548c48dfd97"></a>
### `HAMPEL_TURBULENCE_THRESHOLD_DEFAULT`
```cpp
constexpr float espectre::HAMPEL_TURBULENCE_THRESHOLD_DEFAULT = 5.0f
```
Default outlier threshold, as a multiple of the median absolute deviation.
<a id="namespaceespectre_1af5dd9de9f8a533814ab31e3a9b488355"></a>
### `LIGHTWEIGHT_AUTOCORR_CENTER`
```cpp
constexpr float espectre::LIGHTWEIGHT_AUTOCORR_CENTER = 0.3919344866784947f
```
<a id="namespaceespectre_1ae572d68a06e48c1544396336d7c412aa"></a>
### `LIGHTWEIGHT_AUTOCORR_SCALE`
```cpp
constexpr float espectre::LIGHTWEIGHT_AUTOCORR_SCALE = 0.3798648330757351f
```
<a id="namespaceespectre_1a5e4947ea9b5684a8fbd155531a727666"></a>
### `LIGHTWEIGHT_AUTOCORR_WEIGHT`
```cpp
constexpr float espectre::LIGHTWEIGHT_AUTOCORR_WEIGHT = 5.083034533668216f
```
<a id="namespaceespectre_1aca6d5e503235ecac39b4e8ec723ba222"></a>
### `LIGHTWEIGHT_TURB_IQR_OVER_MEAN_AGGR_CENTER`
```cpp
constexpr float espectre::LIGHTWEIGHT_TURB_IQR_OVER_MEAN_AGGR_CENTER = 0.24612139211074338f
```
<a id="namespaceespectre_1a1b4a48f416593b0a97f723dc2f4def92"></a>
### `LIGHTWEIGHT_TURB_IQR_OVER_MEAN_AGGR_SCALE`
```cpp
constexpr float espectre::LIGHTWEIGHT_TURB_IQR_OVER_MEAN_AGGR_SCALE = 0.20056599613462603f
```
<a id="namespaceespectre_1a47e21f8dcc7a45f3a90efcbae0803d6e"></a>
### `LIGHTWEIGHT_TURB_IQR_OVER_MEAN_AGGR_WEIGHT`
```cpp
constexpr float espectre::LIGHTWEIGHT_TURB_IQR_OVER_MEAN_AGGR_WEIGHT = 4.997501915217463f
```
<a id="namespaceespectre_1a183fb0399b6369183f9ee7b498d27379"></a>
### `LIGHTWEIGHT_INTERCEPT`
```cpp
constexpr float espectre::LIGHTWEIGHT_INTERCEPT = 1.0776769868761f
```
<a id="namespaceespectre_1ad874aec6dbb9e9e06005175f622a5d91"></a>
### `LIGHTWEIGHT_TRAIN_IDLE_Q95_LOGIT`
```cpp
constexpr float espectre::LIGHTWEIGHT_TRAIN_IDLE_Q95_LOGIT = -2.253902812716911f
```
<a id="namespaceespectre_1a8a8f6f5076e59d8c14e9b68b6b15d071"></a>
### `LIGHTWEIGHT_STARTUP_QUANTILE`
```cpp
constexpr float espectre::LIGHTWEIGHT_STARTUP_QUANTILE = 0.95f
```
<a id="namespaceespectre_1a46e2adfff54810a8e86d93dc6e0acf04"></a>
### `LIGHTWEIGHT_STARTUP_STRENGTH`
```cpp
constexpr float espectre::LIGHTWEIGHT_STARTUP_STRENGTH = 0.5f
```
<a id="namespaceespectre_1a453cecc04ac26e8ba1da62b5e55f36aa"></a>
### `LIGHTWEIGHT_STARTUP_SAMPLE_LIMIT`
```cpp
constexpr uint8_t espectre::LIGHTWEIGHT_STARTUP_SAMPLE_LIMIT = 120U
```
<a id="namespaceespectre_1ab9ef1c62b9a0dfe2f0df849fafc39c79"></a>
### `LIGHTWEIGHT_STARTUP_BASE_SAMPLES`
```cpp
constexpr uint8_t espectre::LIGHTWEIGHT_STARTUP_BASE_SAMPLES = 40U
```
<a id="namespaceespectre_1afbf741d652247d7e0cb7aabc79ce3716"></a>
### `LIGHTWEIGHT_STARTUP_BURST_SAMPLES`
```cpp
constexpr uint8_t espectre::LIGHTWEIGHT_STARTUP_BURST_SAMPLES = 20U
```
<a id="namespaceespectre_1ab52047428b1805ee4d7f3f68b4ad9fd2"></a>
### `LIGHTWEIGHT_STARTUP_RECHECK_SAMPLES`
```cpp
constexpr uint8_t espectre::LIGHTWEIGHT_STARTUP_RECHECK_SAMPLES = 12U
```
<a id="namespaceespectre_1a0fe088856427bd90fb5f1a39f10a2844"></a>
### `LIGHTWEIGHT_STARTUP_BURST_LOGITS`
```cpp
constexpr float espectre::LIGHTWEIGHT_STARTUP_BURST_LOGITS = 2.5f
```
<a id="namespaceespectre_1a78b7a41d61a00786ee8108d4701b094e"></a>
### `LIGHTWEIGHT_STARTUP_MIN_SAMPLES`
```cpp
constexpr uint8_t espectre::LIGHTWEIGHT_STARTUP_MIN_SAMPLES = 28U
```
<a id="namespaceespectre_1abc0f3d7eab8e80060094c75444814dd1"></a>
### `LIGHTWEIGHT_CALIBRATION_MOTION_LOGIT`
```cpp
constexpr float espectre::LIGHTWEIGHT_CALIBRATION_MOTION_LOGIT = 5.0f
```
<a id="namespaceespectre_1ae63029cfe685635a12ca9c03b4b8550f"></a>
### `LIGHTWEIGHT_NOISY_LINK_THRESHOLD`
```cpp
constexpr float espectre::LIGHTWEIGHT_NOISY_LINK_THRESHOLD = 0.89f
```
<a id="namespaceespectre_1a01b743a22c6a69557f80126341092991"></a>
### `LIGHTWEIGHT_SETTLE_BLOCKS`
```cpp
constexpr uint8_t espectre::LIGHTWEIGHT_SETTLE_BLOCKS = 12U
```
<a id="namespaceespectre_1ad4819b7e3ae66e4891815046b4675f7d"></a>
### `LIGHTWEIGHT_SETTLE_BLOCK_EVALUATIONS`
```cpp
constexpr uint8_t espectre::LIGHTWEIGHT_SETTLE_BLOCK_EVALUATIONS = 20U
```
<a id="namespaceespectre_1a54ab674f4c505a089ca14218b46b1fa1"></a>
### `LIGHTWEIGHT_SETTLE_MARGIN_LOGITS`
```cpp
constexpr float espectre::LIGHTWEIGHT_SETTLE_MARGIN_LOGITS = 2.7f
```
<a id="namespaceespectre_1a8911611945c4d9384150e5a08552bda0"></a>
### `DETECTOR_WINDOW_SIZE_MS_MIN`
```cpp
constexpr uint32_t espectre::DETECTOR_WINDOW_SIZE_MS_MIN = 1000U
```
Shortest supported detector window, in milliseconds.
<a id="namespaceespectre_1a57fa4ae3e3020de3ce66fd00fd14b939"></a>
### `DETECTOR_WINDOW_SIZE_MS_MAX`
```cpp
constexpr uint32_t espectre::DETECTOR_WINDOW_SIZE_MS_MAX = 2000U
```
Longest supported detector window, in milliseconds.
<a id="namespaceespectre_1a7f6cf82a5d4e26e53ee0f6b852dbabb2"></a>
### `DETECTOR_WINDOW_SIZE_MS_DEFAULT`
```cpp
constexpr uint32_t espectre::DETECTOR_WINDOW_SIZE_MS_DEFAULT = 1000U
```
<a id="namespaceespectre_1a292d263e8e374c65abb1c76af1121781"></a>
### `DETECTOR_DEFAULT_WINDOW_SIZE`
```cpp
constexpr uint16_t espectre::DETECTOR_DEFAULT_WINDOW_SIZE = 100
```
Default window in packets: the default duration at 100 pps.
<a id="namespaceespectre_1af760f0ac7095300522fff6ea2edb6d7c"></a>
### `DETECTOR_MIN_WINDOW_SIZE`
```cpp
constexpr uint16_t espectre::DETECTOR_MIN_WINDOW_SIZE = 1
```
Smallest window in packets a detector accepts.
<a id="namespaceespectre_1ac7c47f062cc8d9adfd7881bd9fdbfdfb"></a>
### `DETECTOR_MAX_WINDOW_SIZE`
```cpp
constexpr uint16_t espectre::DETECTOR_MAX_WINDOW_SIZE = 1000
```
Largest window in packets a detector accepts.
<a id="namespaceespectre_1ade89f4e051867c201a53266ca487bc00"></a>
### `EVALUATION_INTERVAL_US`
```cpp
constexpr uint32_t espectre::EVALUATION_INTERVAL_US = 250000U
```
Time between detector evaluations.
<a id="namespaceespectre_1a24a334c3fa5dbbc227cf527faf402913"></a>
### `L1_DELTA_LAG_US`
```cpp
constexpr uint32_t espectre::L1_DELTA_LAG_US = 100000U
```
High Accuracy profile-displacement lag.
<a id="namespaceespectre_1ae59e57079a7c71da7ba4b2c9a87868b3"></a>
### `TURB_AUTOCORR_LAG_US`
```cpp
constexpr uint32_t espectre::TURB_AUTOCORR_LAG_US = 10000U
```
Lightweight turbulence autocorrelation lag.
<a id="namespaceespectre_1a988bb4b92b7b0de94be5d39ea3083d2f"></a>
### `wifi_band_policy_name`
```cpp
const char * espectre::wifi_band_policy_name(WifiBandPolicy policy)
```
Name of a Wi-Fi band policy: `2g`, `5g`, or `auto`.
<a id="namespaceespectre_1a587a11cb65ff1679a68d9d13ab53d2cb"></a>
### `traffic_generator_mode_name`
```cpp
const char * espectre::traffic_generator_mode_name(TrafficGeneratorMode mode)
```
Name of a traffic generator mode, such as `ping`, `dns`, or `external`.
<a id="namespaceespectre_1a00b12f22b91595a0e1c0fa56be36753d"></a>
### `detection_algorithm_name`
```cpp
const char * espectre::detection_algorithm_name(DetectionAlgorithm algorithm)
```
Name of a detector: `lightweight` or `high_accuracy`.
<a id="namespaceespectre_1a89421b6006f8113b7d9f54cb4ed202b8"></a>
### `parse_traffic_generator_mode`
```cpp
TrafficGeneratorMode espectre::parse_traffic_generator_mode(const char *mode)
```
Parse a traffic generator mode name.
Defaults to [`TrafficGeneratorMode::PING`](#namespaceespectre_1a41663f63d8455701e3a3d8e2ee838aa5ae07ff41a486c27c095a15898dcca34d1).
<a id="namespaceespectre_1a58cce43945e826bdfe8db0e85cd5732c"></a>
### `parse_detection_algorithm`
```cpp
DetectionAlgorithm espectre::parse_detection_algorithm(const char *algorithm)
```
Parse a detector name.
Defaults to [`DetectionAlgorithm::LIGHTWEIGHT`](#namespaceespectre_1ae6098340c58c0355e67beaa092880c6ba56ab46ae63b63cb014aef408f34863a9).
<a id="namespaceespectre_1a21438506ac935cbc46862e5166c3d1eb"></a>
### `parse_wifi_band_policy`
```cpp
WifiBandPolicy espectre::parse_wifi_band_policy(const char *policy)
```
Parse a Wi-Fi band policy name.
Defaults to [`WifiBandPolicy::BAND_2G`](#namespaceespectre_1adb2211d7a11969b4ed8db08213d7b086ae5b0b1eaa95367f057b2c7cc12ec2301).
<a id="namespaceespectre_1ae9a5c52124fc67ad49536d43fd6d0077"></a>
### `format_espectre_device_id`
```cpp
std::string espectre::format_espectre_device_id(uint64_t device_id)
```
Format a device id in its canonical wire form.
<a id="namespaceespectre_1a56f23162b469f148e7bfeca818d5105b"></a>
### `parse_espectre_device_id`
```cpp
bool espectre::parse_espectre_device_id(const std::string &value, uint64_t *device_id)
```
Parse a device id from its wire form.
**Parameters**
- `value`: Formatted device id, as produced by [`format_espectre_device_id()`](#namespaceespectre_1ae9a5c52124fc67ad49536d43fd6d0077).
- `device_id`: Written only when parsing succeeds.
**Returns:** false on a malformed value, leaving the output untouched.
<a id="namespaceespectre_1adc03ef2a0c49d818c944747283819e1a"></a>
### `espectre_device_id_from_mac`
```cpp
uint64_t espectre::espectre_device_id_from_mac(const uint8_t *mac, size_t mac_len)
```
Pack the first six MAC bytes into the historical numeric representation.
**Deprecated:**
Runtime firmware uses the cached, domain-separated SHA-256 pseudonym from [`derive_runtime_device_id()`](#namespaceespectre_1a34031a60d78bbb6306047b3540b4f905) instead.
<a id="namespaceespectre_1ae5c4f0a710fbd64b9efdda153e83b3b3"></a>
### `espectre_device_name`
```cpp
std::string espectre::espectre_device_name(uint64_t device_id, const char *chip=nullptr)
```
Conventional device name derived from the immutable device identifier.
<a id="namespaceespectre_1a975d496a575840d95675209e1294dda1"></a>
### `espectre_effective_device_id_u64`
```cpp
uint64_t espectre::espectre_effective_device_id_u64(const EspectreDeviceConfig &config)
```
The id actually in use.
Frontend startup replaces the zero sentinel.
<a id="namespaceespectre_1a7132956b729065dbed22f00e9edd8e7b"></a>
### `espectre_effective_device_id`
```cpp
std::string espectre::espectre_effective_device_id(const EspectreDeviceConfig &config)
```
[`espectre_effective_device_id_u64()`](#namespaceespectre_1a975d496a575840d95675209e1294dda1) in wire form.
<a id="namespaceespectre_1acaed5bdf8f0dd7e1592aa8c49fbc73be"></a>
### `espectre_effective_device_label`
```cpp
std::string espectre::espectre_effective_device_label(const EspectreDeviceConfig &config)
```
The configured label, or the effective device id when no label is set.
<a id="namespaceespectre_1aeaa6010650a78e01b8ad2c078335d102"></a>
### `normalize_protocol_device_info`
```cpp
EspectreDeviceInfo espectre::normalize_protocol_device_info(const EspectreDeviceInfo &info, const RuntimeSnapshot *snapshot, const char *default_frontend, const char *default_chip=nullptr)
```
Fill in the parts of a device info block the frontend did not set.
Takes the detector from `snapshot`, and `default_frontend` / `default_chip` where the caller left the field empty, so each frontend only states what is genuinely its own.
**Parameters**
- `info`: What the frontend knows about itself.
- `snapshot`: Source of the detector name. May be `nullptr` when no snapshot exists yet.
- `default_frontend`: Frontend name used when `info.frontend` is empty.
- `default_chip`: Chip name used when `info.chip` is empty.
**Returns:** A copy of `info` with the gaps filled.
<a id="namespaceespectre_1ac1edf42e0c351a6a291c91e0bf1ec7b0"></a>
### `clear_espectre_mqtt_config`
```cpp
void espectre::clear_espectre_mqtt_config(EspectreDeviceConfig *config)
```
Erase broker settings while preserving identity, for a config reset.
<a id="namespaceespectre_1a7d53b6c1f2382ba21a1bc8e3bd41d962"></a>
### `validate_espectre_mqtt_config`
```cpp
bool espectre::validate_espectre_mqtt_config(const EspectreDeviceConfig &config, std::string *error=nullptr)
```
Validate the complete MQTT endpoint in a device configuration.
The endpoint requires an exact `mqtt` or `mqtts` scheme, a DNS hostname, IPv4 address, or IPv6 address without URI framing, and a non-zero port.
**Parameters**
- `config`: Device configuration carrying the MQTT endpoint.
- `error`: Receives a human-readable reason on failure. May be `nullptr`.
**Returns:** `true` only when the complete endpoint is valid.
<a id="namespaceespectre_1abc400447710392b7e9d5cba40dbe685f"></a>
### `espectre_mqtt_configured`
```cpp
bool espectre::espectre_mqtt_configured(const EspectreDeviceConfig &config)
```
Return whether `config` contains a complete, valid MQTT endpoint.
<a id="namespaceespectre_1a32edcf9be1977beb72e27fd4900afc37"></a>
### `espectre_topic`
```cpp
std::string espectre::espectre_topic(const EspectreDeviceConfig &config, const char *suffix)
```
Build a full topic from this device's prefix and a trailing segment.
<a id="namespaceespectre_1af7d9b8dfa07f2d15f8ab478be3aafb48"></a>
### `espectre_health_payload`
```cpp
std::string espectre::espectre_health_payload(const EspectreDeviceConfig &config, bool online, uint32_t timestamp_ms)
```
Availability payload.
Publish it retained so late subscribers see it.
<a id="namespaceespectre_1aaf2c60d3cf259dfc145c5aa55b49162d"></a>
### `espectre_device_payload`
```cpp
std::string espectre::espectre_device_payload(const EspectreDeviceConfig &config, const EspectreDeviceInfo &info)
```
Stable device identity and build description.
Publish retained on connect.
<a id="namespaceespectre_1a2d5f998a0d1b9266434071e44192dee0"></a>
### `espectre_capabilities_payload`
```cpp
std::string espectre::espectre_capabilities_payload(const EspectreDeviceConfig &config, const EspectreDeviceInfo &info, const EspectreCapabilityProfile &capabilities)
```
Filtered command, event, feature, and configuration catalog.
<a id="namespaceespectre_1a10c3fe709e07f14529952203afcc3e8d"></a>
### `espectre_capabilities_payload`
```cpp
std::string espectre::espectre_capabilities_payload(const EspectreDeviceConfig &config, const EspectreDeviceInfo &info, bool supports_status=true, bool supports_config=false, bool supports_sensing_control=false, bool supports_wifi_bssid=false, bool supports_mqtt_config=false, bool supports_peer_discovery=false, bool supports_raw_csi=false, const EspectreProtocolExtension *extension=nullptr)
```
Flag-per-section form of the capability catalog.
Prefer the [`EspectreCapabilityProfile`](#structespectre_1_1_espectre_capability_profile) overload, which represents readable sections and individual commands independently.
<a id="namespaceespectre_1aec53df228c0e4a8235a57886f272fc16"></a>
### `espectre_motion_payload`
```cpp
std::string espectre::espectre_motion_payload(const EspectreDeviceConfig &config, const RuntimeSnapshot &snapshot, uint32_t timestamp_ms, uint32_t uptime_s, const char *frontend)
```
Current motion state and score.
The payload behind every detector evaluation.
<a id="namespaceespectre_1a6bc2369abcef6f55305c1f528ee32d2b"></a>
### `espectre_diagnostics_payload`
```cpp
std::string espectre::espectre_diagnostics_payload(const EspectreDeviceConfig &config, const RuntimeSnapshot &snapshot, uint32_t timestamp_ms, uint32_t uptime_s, float free_memory_kb, float loop_time_ms, const RuntimeDiagnosticsSample *diagnostics=nullptr)
```
Health counters plus optional rate and link diagnostics.
`diagnostics` carries CSI and link rates from [`RuntimeDiagnosticsSampler`](#classespectre_1_1_runtime_diagnostics_sampler). Pass `nullptr` only for a frontend that does not expose extended diagnostics.
<a id="namespaceespectre_1a23723f52835cb183d122bbaf8c5348f7"></a>
### `espectre_command_result_payload`
```cpp
std::string espectre::espectre_command_result_payload(const EspectreDeviceConfig &config, const EspectreCommand &command, bool accepted, const char *code, const char *message, const std::string &data_json={})
```
Acknowledge a command, echoing its `command_id`.
Publish one for every command you parse, accepted or not; clients correlate on the id and otherwise cannot tell rejection from packet loss.
<a id="namespaceespectre_1ad3b52b52f70db1fa6a3a65c861702371"></a>
### `espectre_command_request_payload`
```cpp
std::string espectre::espectre_command_request_payload(const std::string &command_id, const std::string &command, const std::string ¶ms_json="{}")
```
Build the canonical flat command request carried by MQTT and Direct HTTP.
<a id="namespaceespectre_1a7a2bb328d061562636f101a7201f5d72"></a>
### `espectre_fault_payload`
```cpp
std::string espectre::espectre_fault_payload(const EspectreDeviceConfig &config, const char *message, uint32_t timestamp_ms)
```
Runtime fault event shared by every transport.
<a id="namespaceespectre_1ab3c981ce263a1f565b33cdd705306a45"></a>
### `espectre_message_catalog_payload`
```cpp
std::string espectre::espectre_message_catalog_payload(const EspectreProtocolExtension *extension=nullptr)
```
One sample of every canonical message, for protocol inspection and conformance tests.
<a id="namespaceespectre_1affd612c44046053715f0e4947c579959"></a>
### `parse_espectre_command`
```cpp
bool espectre::parse_espectre_command(const std::string &payload, EspectreCommand *command, std::string *error, const EspectreProtocolExtension *extension=nullptr)
```
Parse a canonical flat command request, as received on the MQTT command topic.
**Parameters**
- `payload`: Raw message body as received.
- `command`: Populated on success. Check the `has_*` flags to see which fields the peer actually sent. On failure it is reset and may keep the `command_id` for the result payload.
- `error`: Receives a human-readable reason on failure. May be `nullptr`.
- `extension`: Optional frontend routes and their parameter validators.
**Returns:** false on malformed input or invalid parameters. An unknown command name parses successfully; [FrontendCommandEngine](#classespectre_1_1_frontend_command_engine) rejects it with the `unsupported` result code.
<a id="namespaceespectre_1a3719c5d411370f85344e700a2eb961a5"></a>
### `parse_espectre_command_request`
```cpp
bool espectre::parse_espectre_command_request(const std::string &command_id, const std::string &command_name, const std::string ¶ms_json, EspectreCommand *command, std::string *error, const std::string &protocol_version=ESPECTRE_PROTOCOL_VERSION, const EspectreProtocolExtension *extension=nullptr)
```
Parse an already separated command name plus a JSON parameter object.
Frontend adapters use this after separating a canonical flat request into internal fields. Validation follows canonical envelope order: correlation identifier, protocol version, command name, and parameters.
<a id="namespaceespectre_1a688469ee24c9b9691d715dc273feaf95"></a>
### `parse_espectre_config_command`
```cpp
bool espectre::parse_espectre_config_command(const std::string &command, EspectreDeviceConfig *config, std::string *error)
```
Parse a legacy ASCII `SET_DEVICE_CONFIG:` command.
Carries one `key=value` pair, applied in place. A rejected command writes nothing.
**Parameters**
- `command`: Full command string, including the `SET_DEVICE_CONFIG:` prefix.
- `config`: Updated in place on success.
- `error`: Receives a human-readable reason on failure. May be `nullptr`.
<a id="namespaceespectre_1a89f2455d1366f9cca351588f426b9425"></a>
### `parse_espectre_mqtt_config_command`
```cpp
bool espectre::parse_espectre_mqtt_config_command(const std::string &command, EspectreDeviceConfig *config, std::string *error)
```
Parse a `SET_MQTT_CONFIG:` command, carrying the broker settings.
The complete command is parsed and validated before `config` is changed, so rejection leaves the previous value intact. `scheme`, `host`, and `port` are required; the rest keep their previous values.
<a id="namespaceespectre_1a3e05f93260fcedb1a0f010c52825ac67"></a>
### `has_json_key`
```cpp
bool espectre::has_json_key(const std::string &payload, const char *key)
```
Whether `"key":` appears in `payload`.
<a id="namespaceespectre_1ada7befc8e455d080569e41b4072dffa6"></a>
### `extract_json_string`
```cpp
std::string espectre::extract_json_string(const std::string &payload, const char *key)
```
The first string value of `key`, unescaped; empty when absent.
<a id="namespaceespectre_1ac22e051693ae366770a862f8ae6511de"></a>
### `extract_json_number_token`
```cpp
std::string espectre::extract_json_number_token(const std::string &payload, const char *key)
```
The raw numeric token after `key`, unconverted; empty when absent.
<a id="namespaceespectre_1a2cf603b44b19bbfa3bb19e238387e886"></a>
### `load_stored_wifi_config`
```cpp
esp_err_t espectre::load_stored_wifi_config(StoredWifiConfig *config)
```
Load the saved station configuration; `ESP_ERR_INVALID_ARG` for a null `config`.
<a id="namespaceespectre_1aedba313a714d86f0c2f5e4c27e930c26"></a>
### `save_stored_wifi_config`
```cpp
esp_err_t espectre::save_stored_wifi_config(const StoredWifiConfig &config)
```
Save and commit the station configuration.
<a id="namespaceespectre_1a748cc12e82891ff8357c5400ddeba8be"></a>
### `clear_stored_wifi_config`
```cpp
esp_err_t espectre::clear_stored_wifi_config()
```
Erase the saved station configuration.
<a id="namespaceespectre_1a0b38592b6457d7241bf7d27ed727e206"></a>
### `load_pending_wifi_config`
```cpp
esp_err_t espectre::load_pending_wifi_config(StoredWifiConfig *config, bool *has_pending)
```
Load a staged candidate that has not been verified yet.
`has_pending` reports whether one exists. Used by [WifiProvisioningService](#classespectre_1_1_wifi_provisioning_service) to resume verification after a reboot.
<a id="namespaceespectre_1aad6feb37ea2ad9bf489303f43fe1b356"></a>
### `save_pending_wifi_config`
```cpp
esp_err_t espectre::save_pending_wifi_config(const StoredWifiConfig &config)
```
Stage a candidate configuration before applying it.
<a id="namespaceespectre_1a8096ad0bac3ccebebe9f58089d27a0fc"></a>
### `clear_pending_wifi_config`
```cpp
esp_err_t espectre::clear_pending_wifi_config()
```
Discard the staged candidate.
<a id="namespaceespectre_1aefa05fb8f5d8a1be93d9dd3a6d0fb39e"></a>
### `load_stored_device_config`
```cpp
esp_err_t espectre::load_stored_device_config(EspectreDeviceConfig *config, bool *has_saved_config)
```
Load the saved device label and broker settings into `config`.
`has_saved_config` may be `nullptr`; otherwise it reports whether saved settings exist. When they do, `config` is replaced and every field that is not stored takes its default, including `device_id`. Otherwise `config` is left unchanged.
<a id="namespaceespectre_1a895dff951a4439b9cc6f9469057602c7"></a>
### `save_stored_device_config`
```cpp
esp_err_t espectre::save_stored_device_config(const EspectreDeviceConfig &config)
```
Save and commit the device label and broker settings.
<a id="namespaceespectre_1a283d26d4b901e79e0d50bb31defa0af7"></a>
### `clear_stored_device_config`
```cpp
esp_err_t espectre::clear_stored_device_config()
```
Erase the saved device label and broker settings.
<a id="namespaceespectre_1a83022e1a22fdb212c86c99fc85d8b22a"></a>
### `RawCsiChipType`
```cpp
enum class RawCsiChipType : uint8_t
```
Chip that captured a raw record.
<a id="namespaceespectre_1a83022e1a22fdb212c86c99fc85d8b22aa696b031073e74bf2cb98e5ef201d4aa3"></a>
`UNKNOWN = 0`
<a id="namespaceespectre_1a83022e1a22fdb212c86c99fc85d8b22aa789c376b43dbba68180fd04da73286da"></a>
`ESP32 = 1`
<a id="namespaceespectre_1a83022e1a22fdb212c86c99fc85d8b22aab9eeaf6a16ca49f37df57620aed91b62"></a>
`S2 = 2`
<a id="namespaceespectre_1a83022e1a22fdb212c86c99fc85d8b22aa1cf733d786a614c74862934365c1b5ca"></a>
`RESERVED_LEGACY_S2 = S2`
Older name for `S2`.
<a id="namespaceespectre_1a83022e1a22fdb212c86c99fc85d8b22aae2ab7c65b21ed8cc1c3b642b5e36429e"></a>
`S3 = 3`
<a id="namespaceespectre_1a83022e1a22fdb212c86c99fc85d8b22aa3abe124ecc82bf2c2e22e6058f38c50c"></a>
`C3 = 4`
<a id="namespaceespectre_1a83022e1a22fdb212c86c99fc85d8b22aafea813d4ddba3c46cf8b8e664b92cdaa"></a>
`C5 = 5`
<a id="namespaceespectre_1a83022e1a22fdb212c86c99fc85d8b22aa7e8b9f5cab4a8fe24fad9fe4b7452702"></a>
`C6 = 6`
<a id="namespaceespectre_1a967920764a50523f0ce8f7c5e36a3a21"></a>
### `RawCsiRecordFlags`
```cpp
enum RawCsiRecordFlags : uint8_t
```
Bits of [`RawCsiPacketView::record_flags`](#structespectre_1_1_raw_csi_packet_view_1a4550d70cf63fd67ecaaba4a96f7532aa) and [`RawCsiRecordHeaderV8::flags`](#structespectre_1_1_raw_csi_record_header_v8_1a7e2b9459ba67ad46bb4a93384b35beff).
<a id="namespaceespectre_1a967920764a50523f0ce8f7c5e36a3a21a8d36260ce1b4352270abab92bfd65e38"></a>
`RAW_CSI_FLAG_FIRST_WORD_INVALID = 1u << 0`
The hardware marked the first four source bytes invalid.
<a id="namespaceespectre_1a967920764a50523f0ce8f7c5e36a3a21a4e720bd9bc21639dc5557441624cef2a"></a>
`RAW_CSI_FLAG_WIFI_RX_TS_VALID = 1u << 1`
`wifi_rx_ts_us` holds a driver timestamp.
<a id="namespaceespectre_1a967920764a50523f0ce8f7c5e36a3a21ad3840b82f9a900c6c97204ff67f6b8be"></a>
`RAW_CSI_FLAG_WIFI_RX_START_TS_NS_VALID = 1u << 2`
`wifi_rx_start_ts_ns` holds a receive start time.
<a id="namespaceespectre_1a967920764a50523f0ce8f7c5e36a3a21a0051718291384eb75885c9b62e79cfa2"></a>
`RAW_CSI_FLAG_FRESH = 1u << 3`
Set on every emitted raw CSI record.
<a id="namespaceespectre_1a679285b0ae641ff6d1446f1a7cb6a363"></a>
### `RawCsiPhyMode`
```cpp
enum class RawCsiPhyMode : uint8_t
```
PHY of the frame that produced the CSI.
<a id="namespaceespectre_1a679285b0ae641ff6d1446f1a7cb6a363a696b031073e74bf2cb98e5ef201d4aa3"></a>
`UNKNOWN = 0`
<a id="namespaceespectre_1a679285b0ae641ff6d1446f1a7cb6a363a456d016bd133625e5036aa9a556f2730"></a>
`LEGACY = 1`
<a id="namespaceespectre_1a679285b0ae641ff6d1446f1a7cb6a363a90d64eeba8247d656ef6b4800ec0f52f"></a>
`HT = 2`
<a id="namespaceespectre_1a679285b0ae641ff6d1446f1a7cb6a363a2d425dd35e072d51beffedbbefe7b7d9"></a>
`VHT = 3`
<a id="namespaceespectre_1a679285b0ae641ff6d1446f1a7cb6a363a384604b568b86c1b44f899ad0bb52cde"></a>
`HE_SU = 4`
<a id="namespaceespectre_1a679285b0ae641ff6d1446f1a7cb6a363a03deb58782326a275810c5b0d35b125c"></a>
`HE_MU = 5`
<a id="namespaceespectre_1a679285b0ae641ff6d1446f1a7cb6a363ad5a697bbf088741bb5857cc870674d51"></a>
`HE_ERSU = 6`
<a id="namespaceespectre_1a679285b0ae641ff6d1446f1a7cb6a363a803d1726aa04a7d2ced45ac2099bb57d"></a>
`HE_TB = 7`
<a id="namespaceespectre_1a04fa1bf9323c3efd3ff9998892a32e9e"></a>
### `RawCsiLtfType`
```cpp
enum class RawCsiLtfType : uint8_t
```
Training field the CSI was estimated from.
<a id="namespaceespectre_1a04fa1bf9323c3efd3ff9998892a32e9ea696b031073e74bf2cb98e5ef201d4aa3"></a>
`UNKNOWN = 0`
<a id="namespaceespectre_1a04fa1bf9323c3efd3ff9998892a32e9ea23995e76e6c517049199861bd20a5f7f"></a>
`LLTF = 1`
<a id="namespaceespectre_1a04fa1bf9323c3efd3ff9998892a32e9ea1d815e95673dac609a01bfb986c2cceb"></a>
`HT_LTF = 2`
<a id="namespaceespectre_1a04fa1bf9323c3efd3ff9998892a32e9ea7b3f0f06d9c6307397f670944b74eabd"></a>
`VHT_LTF = 3`
<a id="namespaceespectre_1a04fa1bf9323c3efd3ff9998892a32e9ea2115a1e7b50842efe5fd7f8ee5793795"></a>
`HE_LTF = 4`
<a id="namespaceespectre_1a74c31f33edc1dcd2760c4cf242d01c97"></a>
### `RawCsiChannelWidth`
```cpp
enum class RawCsiChannelWidth : uint8_t
```
Channel width of the frame that produced the CSI.
<a id="namespaceespectre_1a74c31f33edc1dcd2760c4cf242d01c97a696b031073e74bf2cb98e5ef201d4aa3"></a>
`UNKNOWN = 0`
<a id="namespaceespectre_1a74c31f33edc1dcd2760c4cf242d01c97a6776ebfc3912b4527d387fd703a69587"></a>
`MHZ_20 = 1`
<a id="namespaceespectre_1a74c31f33edc1dcd2760c4cf242d01c97a0fac4da3580d6b66a5c1dc27478b7290"></a>
`MHZ_40 = 2`
<a id="namespaceespectre_1a74c31f33edc1dcd2760c4cf242d01c97a5d49cf11445a99bc8fed070ce53db290"></a>
`MHZ_80 = 3`
<a id="namespaceespectre_1a74c31f33edc1dcd2760c4cf242d01c97adc07c66d483ad17443b20de9fa00d9f8"></a>
`MHZ_160 = 4`
<a id="namespaceespectre_1a74c31f33edc1dcd2760c4cf242d01c97a6a082d35c82fdef562036b955f5b2836"></a>
`MHZ_80_80 = 5`
<a id="namespaceespectre_1adb2211d7a11969b4ed8db08213d7b086"></a>
### `WifiBandPolicy`
```cpp
enum class WifiBandPolicy : uint8_t
```
Bands the Wi-Fi station may associate on.
The PHY stays at 20 MHz.
<a id="namespaceespectre_1adb2211d7a11969b4ed8db08213d7b086ae5b0b1eaa95367f057b2c7cc12ec2301"></a>
`BAND_2G = 0`
Restrict association to 2.4 GHz.
<a id="namespaceespectre_1adb2211d7a11969b4ed8db08213d7b086ac18a21d672f2013842acfe84a52dd1ff"></a>
`BAND_5G = 1`
Restrict association to 5 GHz.
Supported only by dual-band targets.
<a id="namespaceespectre_1adb2211d7a11969b4ed8db08213d7b086ae1f2d5134ed2543d38a0de9751cf75d9"></a>
`AUTO = 2`
Use every band the radio has.
A dual-band radio chooses between 2.4 GHz and 5 GHz; a 2.4 GHz-only radio behaves as `BAND_2G`. The default.
<a id="namespaceespectre_1aa28375cf8afd113582387290089d9d09"></a>
### `RuntimeOperationState`
```cpp
enum class RuntimeOperationState : uint8_t
```
Transient operation the runtime is performing.
<a id="namespaceespectre_1aa28375cf8afd113582387290089d9d09a9f53d28f082938342669ff6fa150947a"></a>
`SENSING = 0U`
Normal motion sensing.
<a id="namespaceespectre_1aa28375cf8afd113582387290089d9d09ad22e88ebf186a446048c76b8d21ca82d"></a>
`RAW_COLLECTION = 1U`
Raw CSI collection; motion detection and derived events are paused.
<a id="namespaceespectre_1af156112b0ff4ebaccc0dd4792a7b894b"></a>
### `RawCsiStopReason`
```cpp
enum class RawCsiStopReason : uint8_t
```
Why a raw CSI collection session ended.
<a id="namespaceespectre_1af156112b0ff4ebaccc0dd4792a7b894ba889d4358e2fdc68185c59ee7e3173f58"></a>
`REQUESTED = 0U`
The owner stopped it.
<a id="namespaceespectre_1af156112b0ff4ebaccc0dd4792a7b894bacad7f17799e0f75686d4c2b5487c0222"></a>
`RAW_DISCONNECTED = 2U`
The binary stream connection closed.
<a id="namespaceespectre_1af156112b0ff4ebaccc0dd4792a7b894ba5b37c1f5e31bc66cb745596d15f9eb77"></a>
`WIFI_LOST = 3U`
The Wi-Fi link dropped.
<a id="namespaceespectre_1af156112b0ff4ebaccc0dd4792a7b894ba18ec90ed92f5ba900fc659058639a089"></a>
`CHANNEL_CHANGED = 4U`
The association moved to another channel.
<a id="namespaceespectre_1af156112b0ff4ebaccc0dd4792a7b894ba5764d112dd5a2400b2474fe0655aa647"></a>
`SLOW_CLIENT = 6U`
A send to the client failed.
<a id="namespaceespectre_1af156112b0ff4ebaccc0dd4792a7b894bab9984206799a7f9fe4bd1b6c18db8112"></a>
`SHUTDOWN = 7U`
The service or runtime shut down.
<a id="namespaceespectre_1af156112b0ff4ebaccc0dd4792a7b894bae8c0c70879b5895c615677261d64a1ee"></a>
`INTERNAL_ERROR = 8U`
An unexpected failure ended the session.
<a id="namespaceespectre_1a55fec3458e3b4db441f3bc69b8b4d531"></a>
### `CsiCaptureProfile`
```cpp
enum class CsiCaptureProfile : uint8_t
```
Training field and PHY the runtime captures CSI from, always at 20 MHz.
<a id="namespaceespectre_1a55fec3458e3b4db441f3bc69b8b4d531a24f04967c622932f7e0d14c6c6116bb9"></a>
`HT20 = 0`
HT long training field.
<a id="namespaceespectre_1a55fec3458e3b4db441f3bc69b8b4d531a730bbbd2dbfeb3f9e7bbfc62c5d691dd"></a>
`LLTF20 = 1`
Legacy long training field; lacks the edge tones.
<a id="namespaceespectre_1a55fec3458e3b4db441f3bc69b8b4d531a6044439528133be9d5881fe2ffa3a740"></a>
`VHT20 = 2`
VHT long training field, on supported 5 GHz links.
<a id="namespaceespectre_1a3ac8602b3ece6440ded84d1b663b0645"></a>
### `CsiCapturePolicy`
```cpp
enum class CsiCapturePolicy : uint8_t
```
Build-time policy resolved to a physical capture profile after association.
<a id="namespaceespectre_1a3ac8602b3ece6440ded84d1b663b0645ae1f2d5134ed2543d38a0de9751cf75d9"></a>
`AUTO = 0`
LLTF20 for internal `wifi_raw` traffic, otherwise as `HT_VHT`.
<a id="namespaceespectre_1a3ac8602b3ece6440ded84d1b663b0645a23995e76e6c517049199861bd20a5f7f"></a>
`LLTF = 1`
Always LLTF20.
<a id="namespaceespectre_1a3ac8602b3ece6440ded84d1b663b0645aac7a6fd4ec8779cfac29a9102c93df3d"></a>
`HT_VHT = 2`
VHT20 on a supported 5 GHz link, HT20 otherwise.
<a id="namespaceespectre_1ae6098340c58c0355e67beaa092880c6b"></a>
### `DetectionAlgorithm`
```cpp
enum class DetectionAlgorithm
```
Which detector runs.
See [ALGORITHMS.md](<https://github.com/francescopace/espectre/blob/main/docs/ALGORITHMS.md>) for how they differ.
<a id="namespaceespectre_1ae6098340c58c0355e67beaa092880c6ba56ab46ae63b63cb014aef408f34863a9"></a>
`LIGHTWEIGHT`
Lightweight feature fusion.
Self-calibrates, and needs no training data. Default.
<a id="namespaceespectre_1ae6098340c58c0355e67beaa092880c6ba3b9afd5243cb84a8cbef8865bce2b816"></a>
`HIGH_ACCURACY`
High-accuracy neural detector using the trained weights in `core/ml_weights.h`.
<a id="namespaceespectre_1a41663f63d8455701e3a3d8e2ee838aa5"></a>
### `TrafficGeneratorMode`
```cpp
enum class TrafficGeneratorMode
```
How the device gets the traffic that produces CSI.
CSI is only produced when packets arrive, so something has to keep the link busy. The first four modes run the internal generator at `csi_target_pps` with the given packet; `EXTERNAL` leaves it to another host.
<a id="namespaceespectre_1a41663f63d8455701e3a3d8e2ee838aa5ae07ff41a486c27c095a15898dcca34d1"></a>
`PING`
Internal generator, ICMP echo.
Default.
<a id="namespaceespectre_1a41663f63d8455701e3a3d8e2ee838aa5aed5f2bdecbd4bd349d09412d1ff6a6fb"></a>
`DNS`
Internal generator, DNS queries over connectionless UDP.
<a id="namespaceespectre_1a41663f63d8455701e3a3d8e2ee838aa5a8ad9afc2b5c72f5ed884633f4b187446"></a>
`DNS_TCP`
Internal generator, length-prefixed DNS queries over a persistent TCP connection.
<a id="namespaceespectre_1a41663f63d8455701e3a3d8e2ee838aa5a470317edc5e9cd9b77e1c82fc82879de"></a>
`WIFI_RAW`
Internal generator, raw Wi-Fi Null Data frames addressed to the associated AP.
<a id="namespaceespectre_1a41663f63d8455701e3a3d8e2ee838aa5a3932d629fb5e2be9d09b3a4485b3cc9d"></a>
`EXTERNAL`
No internal generator: another host sends exact UDP markers or unicast ICMP Echo Requests, and the runtime listens for them.
<a id="namespaceespectre_1afaec94f4ee217bc8f3f8f5214443c93e"></a>
### `RuntimeConfigError`
```cpp
enum class RuntimeConfigError : uint8_t
```
Machine-readable reason a [`RuntimeConfig`](#structespectre_1_1_runtime_config) cannot be applied.
<a id="namespaceespectre_1afaec94f4ee217bc8f3f8f5214443c93eab50339a10e1de285ac99d4c3990b8693"></a>
`NONE = 0`
<a id="namespaceespectre_1afaec94f4ee217bc8f3f8f5214443c93eadb9ba49fd4f85872bd7304b9ce73532b"></a>
`WIFI_BAND_POLICY`
<a id="namespaceespectre_1afaec94f4ee217bc8f3f8f5214443c93eabb9749dba30f14d44df3d90ff2f49347"></a>
`DETECTION_ALGORITHM`
<a id="namespaceespectre_1afaec94f4ee217bc8f3f8f5214443c93ea27eed88a405a5a259e3ef61b30a00774"></a>
`SEGMENTATION_THRESHOLD`
<a id="namespaceespectre_1afaec94f4ee217bc8f3f8f5214443c93ea80da7e62ceda7e8dc0eb0585fa571560"></a>
`SEGMENTATION_WINDOW_SIZE_MS`
<a id="namespaceespectre_1afaec94f4ee217bc8f3f8f5214443c93eadc199c0de12fee330627b30dea330860"></a>
`CSI_TARGET_PPS`
<a id="namespaceespectre_1afaec94f4ee217bc8f3f8f5214443c93eae056f1164f35461290677cb1f67ef46c"></a>
`TRAFFIC_GENERATOR_MODE`
<a id="namespaceespectre_1afaec94f4ee217bc8f3f8f5214443c93eac49034d17b98b5149a39f1a81fc810d2"></a>
`CSI_TRAFFIC_UDP_PORT`
<a id="namespaceespectre_1afaec94f4ee217bc8f3f8f5214443c93ea775c24445714bd79b49d74b40ce5b984"></a>
`CSI_TRAFFIC_MULTICAST_GROUP`
<a id="namespaceespectre_1afaec94f4ee217bc8f3f8f5214443c93ea5a0515c621312c6f547a75ca3179a5d8"></a>
`EVALUATION_INTERVAL_MS`
<a id="namespaceespectre_1afaec94f4ee217bc8f3f8f5214443c93eadc4869da089da59f51f497b0428ddc37"></a>
`MOTION_HITS`
<a id="namespaceespectre_1afaec94f4ee217bc8f3f8f5214443c93ea0b76f6df73c97bc34b5b05f921ba26ab"></a>
`LOWPASS_CUTOFF`
<a id="namespaceespectre_1afaec94f4ee217bc8f3f8f5214443c93ea20fa3b1aa41abbfaa8ec4bea23294cdf"></a>
`HAMPEL_WINDOW`
<a id="namespaceespectre_1afaec94f4ee217bc8f3f8f5214443c93eac9f13f6f6e556f06cf8f11c44e878cf6"></a>
`HAMPEL_THRESHOLD`
<a id="namespaceespectre_1afaec94f4ee217bc8f3f8f5214443c93ea36cb89ee1128f761a86aa8488f6a7dff"></a>
`TRAFFIC_GENERATOR_TARGET_IP`
<a id="namespaceespectre_1afaec94f4ee217bc8f3f8f5214443c93ea10dc1b07406c7d3f6d4bc6fbd4bbffdf"></a>
`CSI_CAPTURE_PROFILE`
<a id="namespaceespectre_1afaec94f4ee217bc8f3f8f5214443c93ead0b82b03047ac28ad4989621265b475f"></a>
`CSI_CAPTURE_PROFILE_TRAFFIC`
<a id="namespaceespectre_1afca4c79a12b4b401c979d6232c2a0bd8"></a>
### `EspectreDirectMethod`
```cpp
enum class EspectreDirectMethod : uint8_t
```
A capability a frontend advertises in [`EspectreCapabilityProfile`](#structespectre_1_1_espectre_capability_profile).
Each value gates the commands and routes named after it; the route registry returned by [espectre\_api\_routes()](#namespaceespectre_1a1f22c8af7f655d2ab62a805f5827bcec) lists the exact mapping.
<a id="namespaceespectre_1afca4c79a12b4b401c979d6232c2a0bd8a4a82c34eb02c0a85df93d1ce03d8cb73"></a>
`CAPABILITIES = 0`
`capabilities`.
<a id="namespaceespectre_1afca4c79a12b4b401c979d6232c2a0bd8a551b723eafd6a31d444fcb2f5920fbd3"></a>
`INFO`
`device`.
<a id="namespaceespectre_1afca4c79a12b4b401c979d6232c2a0bd8a5f241c8c8f985b3c51e05d39cf030f4c"></a>
`STATUS`
`health` and the event stream.
<a id="namespaceespectre_1afca4c79a12b4b401c979d6232c2a0bd8a73e99d350a4aa6f1a5af04ec29173f73"></a>
`CONFIG`
`sensing`, `wifi`, and `mqtt` reads.
<a id="namespaceespectre_1afca4c79a12b4b401c979d6232c2a0bd8ab84a5c31b5eb0f818f696c05c86cdc12"></a>
`DIAGNOSTICS`
`read_diagnostics`.
<a id="namespaceespectre_1afca4c79a12b4b401c979d6232c2a0bd8a6c64768599b8a2e5122925893460dea5"></a>
`SET_SENSING`
The `sensing_enabled` field of `update_sensing`.
<a id="namespaceespectre_1afca4c79a12b4b401c979d6232c2a0bd8a1b4ee44dec7b7dc5418ea6a2a1657cea"></a>
`SET_DEVICE_LABEL`
`update_device`.
<a id="namespaceespectre_1afca4c79a12b4b401c979d6232c2a0bd8a1e11be2ec8de268d919215833fb1a548"></a>
`SET_THRESHOLD`
The `threshold` field of `update_sensing`.
<a id="namespaceespectre_1afca4c79a12b4b401c979d6232c2a0bd8a886b96586a5750ee3fa941509fce3583"></a>
`SET_MOTION_HITS`
The motion hit fields of `update_sensing`.
<a id="namespaceespectre_1afca4c79a12b4b401c979d6232c2a0bd8a64ecc60dfa1e5eef76e5ed276b19f502"></a>
`SET_DETECTOR`
The `detector` field of `update_sensing`.
<a id="namespaceespectre_1afca4c79a12b4b401c979d6232c2a0bd8aa59a90d8e320711bc5365ecb24ec0f4e"></a>
`RECALIBRATE`
`recalibrate`.
<a id="namespaceespectre_1afca4c79a12b4b401c979d6232c2a0bd8ada16c5572a2d2983a2189d55399d72a4"></a>
`START_RAW_STREAM`
Opening raw collection with `GET /csi`; advertise it with `STOP_RAW_STREAM`.
<a id="namespaceespectre_1afca4c79a12b4b401c979d6232c2a0bd8a08a5be2be93c4e9dcd813383eb4231fa"></a>
`STOP_RAW_STREAM`
Ending raw collection; advertise it with `START_RAW_STREAM`.
<a id="namespaceespectre_1afca4c79a12b4b401c979d6232c2a0bd8a3f95f7923d4f70750d2d491cc662d6da"></a>
`SET_TRAFFIC_GENERATOR_MODE`
The `traffic_generator_mode` field of `update_sensing`.
<a id="namespaceespectre_1afca4c79a12b4b401c979d6232c2a0bd8a1c09b3b226ddea0b13c18f4e294b4205"></a>
`WIFI_ACCESS_POINTS`
`wifi_access_points`.
<a id="namespaceespectre_1afca4c79a12b4b401c979d6232c2a0bd8a950b1d4cdc7a4119ca268ccc34cb51c5"></a>
`SCAN_WIFI_ACCESS_POINTS`
`scan_wifi`.
<a id="namespaceespectre_1afca4c79a12b4b401c979d6232c2a0bd8a9de29080e74b98b067c928209641ee96"></a>
`SET_WIFI_BSSID`
`set_wifi_bssid`.
<a id="namespaceespectre_1afca4c79a12b4b401c979d6232c2a0bd8af1547d17befcf56ea02805e78b8a0a36"></a>
`CLEAR_WIFI_BSSID`
`clear_wifi_bssid`.
<a id="namespaceespectre_1afca4c79a12b4b401c979d6232c2a0bd8af9f8177feaa1ee5fcc28d65333f4b285"></a>
`CLEAR_WIFI_CONFIG`
`clear_wifi_credentials`.
<a id="namespaceespectre_1afca4c79a12b4b401c979d6232c2a0bd8a1ff395f3838c8af5d53a3d0cbe18368d"></a>
`SET_MQTT_CONFIG`
`update_mqtt`.
<a id="namespaceespectre_1afca4c79a12b4b401c979d6232c2a0bd8aa6cb515e3f7b084732d0890c5763eb20"></a>
`CLEAR_MQTT_CONFIG`
`clear_mqtt`.
<a id="namespaceespectre_1afca4c79a12b4b401c979d6232c2a0bd8a1211f2728fa92bbcd91b84b900a5e464"></a>
`DISCOVER_PEERS`
`devices`, the peer discovery result.
<a id="namespaceespectre_1afca4c79a12b4b401c979d6232c2a0bd8a4905ac9d6a22bdfc1ae096094ce6248d"></a>
`COUNT`
Number of values; not a capability.
<a id="namespaceespectre_1afc7c8d567fb0888be484d8ebdda994a8"></a>
### `EspectreConfigSection`
```cpp
enum class EspectreConfigSection : uint8_t
```
A readable configuration section of the `capabilities` catalog.
<a id="namespaceespectre_1afc7c8d567fb0888be484d8ebdda994a8ae5f5cd9fe71ac064a678f27c7d539ae8"></a>
`RUNTIME = 0`
Sensing configuration.
<a id="namespaceespectre_1afc7c8d567fb0888be484d8ebdda994a8ae10b6ab6a278644ce40631f62f360b6d"></a>
`DEVICE`
Device label.
<a id="namespaceespectre_1afc7c8d567fb0888be484d8ebdda994a8a2f0b4d2c0c3d64bbb2cd525dbba8b0d0"></a>
`WIFI`
Wi-Fi station settings.
<a id="namespaceespectre_1afc7c8d567fb0888be484d8ebdda994a8aab0a7cf5deeda86b66467df64c3b6122"></a>
`MQTT`
Broker settings.
<a id="namespaceespectre_1afc7c8d567fb0888be484d8ebdda994a8a4905ac9d6a22bdfc1ae096094ce6248d"></a>
`COUNT`
Number of values; not a section.
<a id="namespaceespectre_1a8c8b3454eae8a719a4f529bf205bf0ff"></a>
### `EspectreEvent`
```cpp
enum class EspectreEvent : uint8_t
```
A family of events a frontend publishes.
<a id="namespaceespectre_1a8c8b3454eae8a719a4f529bf205bf0ffabb3d2d909c73fe49800949a344775f8b"></a>
`TELEMETRY = 0`
`motion` telemetry.
<a id="namespaceespectre_1a8c8b3454eae8a719a4f529bf205bf0ffa5f241c8c8f985b3c51e05d39cf030f4c"></a>
`STATUS`
`health`.
<a id="namespaceespectre_1a8c8b3454eae8a719a4f529bf205bf0ffa551b723eafd6a31d444fcb2f5920fbd3"></a>
`INFO`
`device`.
<a id="namespaceespectre_1a8c8b3454eae8a719a4f529bf205bf0ffa73e99d350a4aa6f1a5af04ec29173f73"></a>
`CONFIG`
`sensing` and `wifi`.
<a id="namespaceespectre_1a8c8b3454eae8a719a4f529bf205bf0ffa893b3aaf1661e3717b18e8335ff93a72"></a>
`FAULT`
`fault`.
<a id="namespaceespectre_1a8c8b3454eae8a719a4f529bf205bf0ffa4905ac9d6a22bdfc1ae096094ce6248d"></a>
`COUNT`
Number of values; not an event.
<a id="namespaceespectre_1a673de3f0a8dc83c71f9a080a6e195084"></a>
### `EspectreApiRouteKind`
```cpp
enum class EspectreApiRouteKind : uint8_t
```
How a route behaves.
<a id="namespaceespectre_1a673de3f0a8dc83c71f9a080a6e195084a4f49da9035f276c0947466eb7c42249a"></a>
`RESOURCE = 0`
Reads a resource.
<a id="namespaceespectre_1a673de3f0a8dc83c71f9a080a6e195084ad6a0beecbcc46b64a23307ffc084ed36"></a>
`OPERATION`
Changes state or starts an action.
<a id="namespaceespectre_1a673de3f0a8dc83c71f9a080a6e195084a2f05998d2a71cdc19b7109549bbe2646"></a>
`STREAM`
Opens a long-lived stream, such as events or raw CSI.
<a id="namespaceespectre_1ac017ab0ef298a8a5cd2ba8876dc67846"></a>
### `JsonValueType`
```cpp
enum class JsonValueType : uint8_t
```
Type of a JSON value.
<a id="namespaceespectre_1ac017ab0ef298a8a5cd2ba8876dc67846a63b588d5559f64f89a416e656880b949"></a>
`STRING = 0`
<a id="namespaceespectre_1ac017ab0ef298a8a5cd2ba8876dc67846a34f55eca38e0605a84f169ff61a2a396"></a>
`NUMBER`
<a id="namespaceespectre_1ac017ab0ef298a8a5cd2ba8876dc67846ac48d5da12d702e73d6966069f2687376"></a>
`BOOLEAN`
<a id="namespaceespectre_1ac017ab0ef298a8a5cd2ba8876dc67846aa9f0aff2067f91437e50e4872b229e6a"></a>
`NULL_VALUE`
<a id="namespaceespectre_1ac017ab0ef298a8a5cd2ba8876dc67846a8eee8e217391199668cbac89472ace53"></a>
`OBJECT`
<a id="namespaceespectre_1ac017ab0ef298a8a5cd2ba8876dc67846acb4fb1757fb37c43cded35d3eb857c43"></a>
`ARRAY`
<a id="namespaceespectre_1adfd78003c463a47035e2de0ecd39cadb"></a>
### `LogLevel`
```cpp
enum class LogLevel : uint8_t
```
Severity attached to one ESPectre log message.
<a id="namespaceespectre_1adfd78003c463a47035e2de0ecd39cadbabb1ca97ec761fc37101737ba0aa2e7c5"></a>
`ERROR = 1`
<a id="namespaceespectre_1adfd78003c463a47035e2de0ecd39cadba059e9861e0400dfbe05c98a841f3f96b"></a>
`WARNING = 2`
<a id="namespaceespectre_1adfd78003c463a47035e2de0ecd39cadba551b723eafd6a31d444fcb2f5920fbd3"></a>
`INFO = 3`
<a id="namespaceespectre_1adfd78003c463a47035e2de0ecd39cadbadc30ec20708ef7b0f641ef78b7880a15"></a>
`DEBUG = 4`
<a id="namespaceespectre_1adfd78003c463a47035e2de0ecd39cadbaec1f06e9fb39c4ef0729b3c7c9c8e8cc"></a>
`VERBOSE = 5`
<a id="namespaceespectre_1a7d37681f3243ed6bdd97aee1ed776857"></a>
### `MotionState`
```cpp
enum class MotionState
```
Debounced detector state.
<a id="namespaceespectre_1a7d37681f3243ed6bdd97aee1ed776857aa5daf7f2ebbba4975d61dab1c40188c7"></a>
`IDLE`
<a id="namespaceespectre_1a7d37681f3243ed6bdd97aee1ed776857af96e6ea7a7375bd60bad3f3caae3cf27"></a>
`MOTION`
<a id="namespaceespectre_1a1a2af5566391edd860e3585c8f8b4bb3"></a>
### `Ht20BinLayout`
```cpp
enum class Ht20BinLayout : uint8_t
```
Bin ordering of a 64-subcarrier HT20 payload.
<a id="namespaceespectre_1a1a2af5566391edd860e3585c8f8b4bb3a696b031073e74bf2cb98e5ef201d4aa3"></a>
`UNKNOWN = 0`
Not determined.
<a id="namespaceespectre_1a1a2af5566391edd860e3585c8f8b4bb3a21c97af368df9b59d1244bd698506814"></a>
`CENTERED`
Bin = subcarrier + 32, DC at bin 32.
The detectors expect this layout.
<a id="namespaceespectre_1a1a2af5566391edd860e3585c8f8b4bb3a21994d6177b29e1128b2d7f0f8342057"></a>
`CLASSIC`
Bin = subcarrier mod 64, DC at bin 0.
<a id="namespaceespectre_1a66960f4a1cf7a867acd1d1a7c9f52d18"></a>
### `MdnsResponderMode`
```cpp
enum class MdnsResponderMode : uint8_t
```
Who owns the ESP-IDF mDNS responder.
<a id="namespaceespectre_1a66960f4a1cf7a867acd1d1a7c9f52d18a2a353b2cdb13a76f32641ff7f25e4cea"></a>
`OWN_RESPONDER = 0`
This service initializes the responder, sets the hostname and instance name, and frees the responder at shutdown when it started it.
<a id="namespaceespectre_1a66960f4a1cf7a867acd1d1a7c9f52d18af8944176f9ecbfea29c227b401ad4a92"></a>
`USE_EXISTING_RESPONDER`
Another component, such as the Matter stack, owns the responder; this service only adds its DNS-SD service and announces it.
<a id="namespaceespectre_1afb799961d21e38195f1ad899880c3189"></a>
### `UdpReceiveResult`
```cpp
enum class UdpReceiveResult
```
Outcome of [IUdpDatagramSocket::receive()](#classespectre_1_1_i_udp_datagram_socket_1afb8cf45cdfbf8d5ef06a9a05474d754f).
<a id="namespaceespectre_1afb799961d21e38195f1ad899880c3189a0334b8669eb43f45f9bccb223186be65"></a>
`PACKET`
A datagram was received.
<a id="namespaceespectre_1afb799961d21e38195f1ad899880c3189aba2b45bdc11e2a4a6e86aab2ac693cbb"></a>
`EMPTY`
Nothing is waiting.
<a id="namespaceespectre_1afb799961d21e38195f1ad899880c3189abb1ca97ec761fc37101737ba0aa2e7c5"></a>
`ERROR`
The socket failed or is closed.
<a id="namespaceespectre_1afd04e6f466bb9a85e3f867421d5291fa"></a>
### `WifiBssidPinApplyState`
```cpp
enum class WifiBssidPinApplyState : uint8_t
```
Progress of a BSSID pin change.
<a id="namespaceespectre_1afd04e6f466bb9a85e3f867421d5291faaa5daf7f2ebbba4975d61dab1c40188c7"></a>
`IDLE = 0`
No change in progress.
<a id="namespaceespectre_1afd04e6f466bb9a85e3f867421d5291faa4ea687957de9caaad1e098e3e95aae9e"></a>
`VERIFYING`
The pin is applied and waiting for association and an address.
<a id="namespaceespectre_1afd04e6f466bb9a85e3f867421d5291faa704940fadc36a1ea05e200e3ccaeb298"></a>
`ROLLING_BACK`
The change failed; the previous pin is being restored.
<a id="namespaceespectre_1afd04e6f466bb9a85e3f867421d5291faaa949e143063cf0e9ab61dc7004280c35"></a>
`APPLIED`
The station connected with the requested pin, and it was saved.
<a id="namespaceespectre_1afd04e6f466bb9a85e3f867421d5291faaed701d1c3d474e00c7a2f416f8d6858c"></a>
`ROLLED_BACK`
The change failed or was discarded, and the previous pin is back.
<a id="namespaceespectre_1afd04e6f466bb9a85e3f867421d5291faab0abcd2350d0f34995a7eb78c6a3c035"></a>
`RECOVERY_REQUIRED`
Rollback failed or timed out; the station may need recovery.
<a id="namespaceespectre_1a31d1131642dc8c0436b043e4c899c339"></a>
### `WifiProvisioningApplyState`
```cpp
enum class WifiProvisioningApplyState : uint8_t
```
Progress of a staged Wi-Fi configuration change.
<a id="namespaceespectre_1a31d1131642dc8c0436b043e4c899c339aa5daf7f2ebbba4975d61dab1c40188c7"></a>
`IDLE = 0`
No change in progress.
<a id="namespaceespectre_1a31d1131642dc8c0436b043e4c899c339a4ea687957de9caaad1e098e3e95aae9e"></a>
`VERIFYING`
The candidate is applied and waiting for association and an address.
<a id="namespaceespectre_1a31d1131642dc8c0436b043e4c899c339a704940fadc36a1ea05e200e3ccaeb298"></a>
`ROLLING_BACK`
The candidate failed; the last-known-good settings are being restored.
<a id="namespaceespectre_1a31d1131642dc8c0436b043e4c899c339aa949e143063cf0e9ab61dc7004280c35"></a>
`APPLIED`
The candidate connected and was saved.
<a id="namespaceespectre_1a31d1131642dc8c0436b043e4c899c339aed701d1c3d474e00c7a2f416f8d6858c"></a>
`ROLLED_BACK`
The candidate failed and the last-known-good settings are back.
<a id="namespaceespectre_1a31d1131642dc8c0436b043e4c899c339ab0abcd2350d0f34995a7eb78c6a3c035"></a>
`RECOVERY_REQUIRED`
Rollback failed or timed out; reprovision over Improv Serial.
<a id="namespaceespectre_1aa730eb411cfeec940ccae2c21b7fa2aa"></a>
### `FrontendCommandChange`
```cpp
enum class FrontendCommandChange : uint8_t
```
Protocol resources a command changed, as a bit set.
Transports use it to republish the matching state after an accepted change.
<a id="namespaceespectre_1aa730eb411cfeec940ccae2c21b7fa2aaab50339a10e1de285ac99d4c3990b8693"></a>
`NONE = 0U`
<a id="namespaceespectre_1aa730eb411cfeec940ccae2c21b7fa2aaa785a1e256fca0cd6be7b3dced4281845"></a>
`HEALTH = 1U << 0U`
Health output changed.
The engine never reports it; frontends pass it to [`RuntimeDirectHttpBridge::publish_changes()`](#classespectre_1_1_runtime_direct_http_bridge_1ad59141bad149054a36f26958a9d3c1d7) to republish health.
<a id="namespaceespectre_1aa730eb411cfeec940ccae2c21b7fa2aaae10b6ab6a278644ce40631f62f360b6d"></a>
`DEVICE = 1U << 1U`
Device label or identity.
<a id="namespaceespectre_1aa730eb411cfeec940ccae2c21b7fa2aaa9f53d28f082938342669ff6fa150947a"></a>
`SENSING = 1U << 2U`
Sensing configuration or state.
<a id="namespaceespectre_1aa730eb411cfeec940ccae2c21b7fa2aaa2f0b4d2c0c3d64bbb2cd525dbba8b0d0"></a>
`WIFI = 1U << 3U`
Wi-Fi station configuration.
<a id="namespaceespectre_1aa730eb411cfeec940ccae2c21b7fa2aaaab0a7cf5deeda86b66467df64c3b6122"></a>
`MQTT = 1U << 4U`
Broker configuration.
<a id="namespaceespectre_1a78137e71d7f05fcbfbda841d3a1fc91b"></a>
### `FrontendCommandOrigin`
```cpp
enum class FrontendCommandOrigin : uint8_t
```
Transport or frontend surface a command arrived through.
<a id="namespaceespectre_1a78137e71d7f05fcbfbda841d3a1fc91ba4c5d06b02c97731aaa976179c62dcf76"></a>
`DIRECT = 0U`
Direct HTTP.
<a id="namespaceespectre_1a78137e71d7f05fcbfbda841d3a1fc91baab0a7cf5deeda86b66467df64c3b6122"></a>
`MQTT`
MQTT command topic.
Only `update_device`, `update_sensing`, `recalibrate`, and `read_diagnostics` are accepted from it.
<a id="namespaceespectre_1a78137e71d7f05fcbfbda841d3a1fc91bac31870dbba5ac72e2f563d5d66586fcd"></a>
`ESPHOME`
An ESPHome entity or service.
<a id="namespaceespectre_1a78137e71d7f05fcbfbda841d3a1fc91baa8a5f21c20fd888a9397997f73863e73"></a>
`MATTER`
A Matter attribute or command.
<a id="namespaceespectre_1a7b0352147eec65c1f73a9d8714c4596d"></a>
### `raw_csi_packet_callback_t`
```cpp
using espectre::raw_csi_packet_callback_t = bool (*)(void *context, const RawCsiPacketView &packet)
```
Consume one packet synchronously from the Wi-Fi CSI capture context.
The callback must remain bounded, non-blocking, and allocation-free. It may copy the packet into a preallocated bounded queue for another task. Returning false reports that the consumer did not accept this packet, for example because that queue was full; collection continues, and the consumer owns any drop or backpressure accounting.
`context` is the opaque caller-owned value supplied to `start_raw_collection()`. `packet` is a normalized CSI view valid only during the call. Return true when the consumer accepted the packet, or false when it dropped it; the runtime does not stop collection on false.
<a id="namespaceespectre_1a478bd5431108f78995bfb1c53acc3e25"></a>
### `EspectreCommandValidator`
```cpp
using espectre::EspectreCommandValidator = bool (*)(const std::vector<JsonObjectField> &fields,
EspectreCommand *command, std::string *error)
```
Validate decoded parameters and populate the command before dispatch.
The parser supplies valid JSON fields and the command identity. Fields from [parse\_espectre\_command()](#namespaceespectre_1affd612c44046053715f0e4947c579959) also include the request's `command_id` and `command`. Validators must not execute commands or change device state. Ignore command output after a rejected validation.
<a id="namespaceespectre_1a47f56ef0a5dfb7004c12e04f60fcc511"></a>
### `LogEnabledCallback`
```cpp
using espectre::LogEnabledCallback = bool (*)(void *context, LogLevel level, const char *tag)
```
Return whether a sink accepts a message with the supplied level and tag.
<a id="namespaceespectre_1af956f386b6f44926d0860f7ca0dffdd0"></a>
### `LogWriteCallback`
```cpp
using espectre::LogWriteCallback = void (*)(void *context, LogLevel level, const char *tag, int line,
const char *format, va_list args)
```
Consume one enabled ESPectre log message before the supplied argument list expires.
<a id="namespaceespectre_1a813ec6a7ade93fd50621b8138c0ebe92"></a>
### `FrontendMqttConnectedCallback`
```cpp
using espectre::FrontendMqttConnectedCallback = std::function<void(bool)>
```
Receives the broker connection state after each change.
<a id="namespaceespectre_1a5c8f69b635e49d299f2dadb56b43074d"></a>
### `MdnsTxtRecords`
```cpp
using espectre::MdnsTxtRecords = std::vector<std::pair<std::string, std::string>>
```
DNS-SD TXT records as key and value pairs.
A `txtvers` entry is always transmitted first.
<a id="namespaceespectre_1aaca2bec6937994f03279640eba6ea6a2"></a>
### `standalone_wifi_callback_t`
```cpp
using espectre::standalone_wifi_callback_t = std::function<void()>
```
Connection-state callback, delivered from [StandaloneWifiService::loop()](#classespectre_1_1_standalone_wifi_service_1ad1e165e7f0eb286a2c1b68b573cee60c).
<a id="namespaceespectre_1a841cce05055be401e9d7f541f67c0f17"></a>
### `standalone_wifi_scan_callback_t`
```cpp
using espectre::standalone_wifi_scan_callback_t =
std::function<void(esp_err_t, const std::vector<StandaloneWifiAccessPoint> &)>
```
Scan result callback, delivered from [StandaloneWifiService::loop()](#classespectre_1_1_standalone_wifi_service_1ad1e165e7f0eb286a2c1b68b573cee60c).
Receives `ESP_OK` or the driver error, and at most 32 access points sorted by descending RSSI.
<a id="namespaceespectre_1a8b131fc80e5f6619153aaf47d7a61dc9"></a>
### `csi_traffic_packet_callback_t`
```cpp
using espectre::csi_traffic_packet_callback_t = void (*)(void *, const UdpDatagramPeer &, uint64_t)
```
Called for each accepted external traffic packet, from the ingress loop().
Receives the registered context, the sender, and the cumulative count of accepted packets.
<a id="namespaceespectre_1a64ef59dbd1b0e33b0d19ba5ead0b9301"></a>
### `wifi_connected_callback_t`
```cpp
using espectre::wifi_connected_callback_t = std::function<void(const esp_netif_ip_info_t &)>
```
Receives the station IPv4 configuration; delivered from process\_pending\_events().
<a id="namespaceespectre_1ab5095f85174c76bb5eef718e24479044"></a>
### `wifi_disconnected_callback_t`
```cpp
using espectre::wifi_disconnected_callback_t = std::function<void()>
```
Station disconnection; delivered from process\_pending\_events().
<a id="namespaceespectre_1a2eaa099b9086c9f90afcc8001d90afdc"></a>
### `wifi_csi_rx_refresh_callback_t`
```cpp
using espectre::wifi_csi_rx_refresh_callback_t = std::function<void(esp_err_t)>
```
Outcome of a CSI receive-path refresh scan, including `ESP_ERR_TIMEOUT`.
<a id="namespaceespectre_1a664f7aebe8d7f8986a2d83e28357cc87"></a>
### `FrontendCommandCapabilities`
```cpp
using espectre::FrontendCommandCapabilities = EspectreCapabilityProfile
```
The advertised surface a command must belong to before it is executed.
<a id="namespaceespectre_1a186d8ab957e623995b7886680bed2b29"></a>
### `RAW_CSI_RECORD_MAGIC`
```cpp
constexpr uint16_t espectre::RAW_CSI_RECORD_MAGIC = 0x4353U
```
Value of [`RawCsiRecordHeaderV8::magic`](#structespectre_1_1_raw_csi_record_header_v8_1a2be7e3fe64a7ad696429405bc01eb145), the bytes `SC` on the wire.
<a id="namespaceespectre_1aa6cd6c48916e2a6c73f2a3368ba29afe"></a>
### `RAW_CSI_RECORD_VERSION_V8`
```cpp
constexpr uint8_t espectre::RAW_CSI_RECORD_VERSION_V8 = 8U
```
<a id="namespaceespectre_1acab3236d6dc24a0de6613d494177569a"></a>
### `RAW_CSI_RECORD_VERSION`
```cpp
constexpr uint8_t espectre::RAW_CSI_RECORD_VERSION = RAW_CSI_RECORD_VERSION_V8
```
Record version this SDK writes.
<a id="namespaceespectre_1a24dad547c0781d8f0f29395e0bed182f"></a>
### `RAW_CSI_MAX_PAYLOAD_BYTES`
```cpp
constexpr size_t espectre::RAW_CSI_MAX_PAYLOAD_BYTES = 512U
```
Largest payload a record may carry; the built-in pipeline sends 128 bytes.
<a id="namespaceespectre_1a6d19fef4bba723c7e98adda2a45aed2c"></a>
### `RAW_CSI_MAX_RECORD_BYTES`
```cpp
constexpr size_t espectre::RAW_CSI_MAX_RECORD_BYTES =
sizeof(RawCsiRecordHeaderV8) + RAW_CSI_MAX_PAYLOAD_BYTES
```
Largest record: header plus the maximum payload.
<a id="namespaceespectre_1a212cc7fe3aa038d9e1326fc8037ee3db"></a>
### `RUNTIME_CSI_CAPTURE_PROFILE_DEFAULT_NAME`
```cpp
constexpr const char* const espectre::RUNTIME_CSI_CAPTURE_PROFILE_DEFAULT_NAME = "auto"
```
<a id="namespaceespectre_1a177c18a106b6080f362093d71a68fabf"></a>
### `RUNTIME_TRAFFIC_GENERATOR_MODE_PING_NAME`
```cpp
constexpr const char* const espectre::RUNTIME_TRAFFIC_GENERATOR_MODE_PING_NAME = "ping"
```
<a id="namespaceespectre_1a15bc0df459745afa7ae4f9e4c6f34b5f"></a>
### `RUNTIME_TRAFFIC_GENERATOR_MODE_DNS_NAME`
```cpp
constexpr const char* const espectre::RUNTIME_TRAFFIC_GENERATOR_MODE_DNS_NAME = "dns"
```
<a id="namespaceespectre_1ae6e8beabd6199438e40524e01b53c22b"></a>
### `RUNTIME_TRAFFIC_GENERATOR_MODE_DNS_TCP_NAME`
```cpp
constexpr const char* const espectre::RUNTIME_TRAFFIC_GENERATOR_MODE_DNS_TCP_NAME = "dns_tcp"
```
<a id="namespaceespectre_1a4013ba85b37d675d5a44588073b4b670"></a>
### `RUNTIME_TRAFFIC_GENERATOR_MODE_WIFI_RAW_NAME`
```cpp
constexpr const char* const espectre::RUNTIME_TRAFFIC_GENERATOR_MODE_WIFI_RAW_NAME = "wifi_raw"
```
<a id="namespaceespectre_1a315b2fe0bb0c4b2d1ce61f619538cdde"></a>
### `RUNTIME_TRAFFIC_GENERATOR_MODE_EXTERNAL_NAME`
```cpp
constexpr const char* const espectre::RUNTIME_TRAFFIC_GENERATOR_MODE_EXTERNAL_NAME = "external"
```
<a id="namespaceespectre_1ae798b6e9325d406dacc0ab49f991df26"></a>
### `RUNTIME_TRAFFIC_GENERATOR_MODE_DEFAULT_NAME`
```cpp
constexpr const char* const espectre::RUNTIME_TRAFFIC_GENERATOR_MODE_DEFAULT_NAME = "ping"
```
<a id="namespaceespectre_1af8f4e638e243e4b5a4cc9f781821abd6"></a>
### `RUNTIME_DETECTION_ALGORITHM_LIGHTWEIGHT_NAME`
```cpp
constexpr const char* const espectre::RUNTIME_DETECTION_ALGORITHM_LIGHTWEIGHT_NAME = "lightweight"
```
<a id="namespaceespectre_1a5827219e367d7820fa6e9e996e16ea27"></a>
### `RUNTIME_DETECTION_ALGORITHM_HIGH_ACCURACY_NAME`
```cpp
constexpr const char* const espectre::RUNTIME_DETECTION_ALGORITHM_HIGH_ACCURACY_NAME = "high_accuracy"
```
<a id="namespaceespectre_1a44d5c8854bb3a570793dcee5542244d5"></a>
### `RUNTIME_DETECTION_ALGORITHM_DEFAULT_NAME`
```cpp
constexpr const char* const espectre::RUNTIME_DETECTION_ALGORITHM_DEFAULT_NAME = "lightweight"
```
<a id="namespaceespectre_1afd6e4e1d251c290d51df4263fda0750d"></a>
### `RUNTIME_THRESHOLD_MIN`
```cpp
constexpr float espectre::RUNTIME_THRESHOLD_MIN = 0.0f
```
<a id="namespaceespectre_1a5a433a007084875084bee62d094cab95"></a>
### `RUNTIME_THRESHOLD_MAX`
```cpp
constexpr float espectre::RUNTIME_THRESHOLD_MAX = 1.0f
```
<a id="namespaceespectre_1a2f7c72dc6bebf5bf906536101a6b1345"></a>
### `RUNTIME_HIGH_ACCURACY_THRESHOLD_MAX`
```cpp
constexpr float espectre::RUNTIME_HIGH_ACCURACY_THRESHOLD_MAX = 1.0f
```
<a id="namespaceespectre_1a4f0959b9772eefeae08cb0770015eee7"></a>
### `RUNTIME_THRESHOLD_DEFAULT`
```cpp
constexpr float espectre::RUNTIME_THRESHOLD_DEFAULT = LIGHTWEIGHT_DEFAULT_THRESHOLD
```
<a id="namespaceespectre_1ae1871531cd739565548b365e003788fd"></a>
### `RUNTIME_WINDOW_SIZE_MS_MIN`
```cpp
constexpr uint32_t espectre::RUNTIME_WINDOW_SIZE_MS_MIN = 1000U
```
<a id="namespaceespectre_1a4c208f0f3bb11b8ff3aa3e51674b033e"></a>
### `RUNTIME_WINDOW_SIZE_MS_MAX`
```cpp
constexpr uint32_t espectre::RUNTIME_WINDOW_SIZE_MS_MAX = 2000U
```
<a id="namespaceespectre_1a13c8a64d1ea77fb65719fc2ffb8bdb45"></a>
### `RUNTIME_WINDOW_SIZE_MS_DEFAULT`
```cpp
constexpr uint32_t espectre::RUNTIME_WINDOW_SIZE_MS_DEFAULT = 1000U
```
<a id="namespaceespectre_1abcca8e8bd6537b2fed9f7dc11e62236c"></a>
### `RUNTIME_CSI_TARGET_PPS_MIN`
```cpp
constexpr uint32_t espectre::RUNTIME_CSI_TARGET_PPS_MIN = 1U
```
<a id="namespaceespectre_1a403c34b91ec353131e952dac15bf2ff4"></a>
### `RUNTIME_CSI_TARGET_PPS_MAX`
```cpp
constexpr uint32_t espectre::RUNTIME_CSI_TARGET_PPS_MAX = 500U
```
<a id="namespaceespectre_1a583bc098543bc63653f26960274b2ad1"></a>
### `RUNTIME_CSI_TARGET_PPS_DEFAULT`
```cpp
constexpr uint32_t espectre::RUNTIME_CSI_TARGET_PPS_DEFAULT = 100U
```
<a id="namespaceespectre_1adac330f75e60dcf8bbc56efa51cac931"></a>
### `RUNTIME_HEARTBEAT_INTERVAL_MS`
```cpp
constexpr uint32_t espectre::RUNTIME_HEARTBEAT_INTERVAL_MS = 1000U
```
<a id="namespaceespectre_1aa957a79703f3f36f20564faaf6993407"></a>
### `RUNTIME_EVALUATION_INTERVAL_MS_MIN`
```cpp
constexpr uint32_t espectre::RUNTIME_EVALUATION_INTERVAL_MS_MIN = 10
```
<a id="namespaceespectre_1a76f1e1c451892d2a18476282920c5083"></a>
### `RUNTIME_EVALUATION_INTERVAL_MS_MAX`
```cpp
constexpr uint32_t espectre::RUNTIME_EVALUATION_INTERVAL_MS_MAX = 10000
```
<a id="namespaceespectre_1abc8035d1720779136e60e9a88a0e8379"></a>
### `RUNTIME_EVALUATION_INTERVAL_MS_DEFAULT`
```cpp
constexpr uint32_t espectre::RUNTIME_EVALUATION_INTERVAL_MS_DEFAULT = 250
```
<a id="namespaceespectre_1a7f65a463577a02ef0bdfe49dd9d8c1a5"></a>
### `RUNTIME_MOTION_HITS_MIN`
```cpp
constexpr uint8_t espectre::RUNTIME_MOTION_HITS_MIN = 1
```
<a id="namespaceespectre_1a42ac71e1ad53db97efbf0898dfba62a0"></a>
### `RUNTIME_MOTION_HITS_MAX`
```cpp
constexpr uint8_t espectre::RUNTIME_MOTION_HITS_MAX = 20
```
<a id="namespaceespectre_1a028b847c20853cced681ca0ff3ad147c"></a>
### `RUNTIME_MOTION_ON_HITS_DEFAULT`
```cpp
constexpr uint8_t espectre::RUNTIME_MOTION_ON_HITS_DEFAULT = 4
```
<a id="namespaceespectre_1a40824ccf41b07b064f7525a39576cf94"></a>
### `RUNTIME_MOTION_OFF_HITS_DEFAULT`
```cpp
constexpr uint8_t espectre::RUNTIME_MOTION_OFF_HITS_DEFAULT = 3
```
<a id="namespaceespectre_1a6dc500d40bcaf9eb8c919fe6e09cd022"></a>
### `RUNTIME_LOWPASS_ENABLED_DEFAULT`
```cpp
constexpr bool espectre::RUNTIME_LOWPASS_ENABLED_DEFAULT = false
```
<a id="namespaceespectre_1a0b99ade66a66ac0a13036513a81f6603"></a>
### `RUNTIME_LOWPASS_CUTOFF_MIN`
```cpp
constexpr float espectre::RUNTIME_LOWPASS_CUTOFF_MIN = 5.0f
```
<a id="namespaceespectre_1af586a478157c4558cda661fa83d923cd"></a>
### `RUNTIME_LOWPASS_CUTOFF_MAX`
```cpp
constexpr float espectre::RUNTIME_LOWPASS_CUTOFF_MAX = 20.0f
```
<a id="namespaceespectre_1a772d7d6b6983a5c8494423e18fffaf53"></a>
### `RUNTIME_LOWPASS_CUTOFF_DEFAULT`
```cpp
constexpr float espectre::RUNTIME_LOWPASS_CUTOFF_DEFAULT = 11.0f
```
<a id="namespaceespectre_1af46a5471c983b1f109895d59157feb20"></a>
### `RUNTIME_HAMPEL_ENABLED_DEFAULT`
```cpp
constexpr bool espectre::RUNTIME_HAMPEL_ENABLED_DEFAULT = true
```
<a id="namespaceespectre_1a47c2f441115ede397c06d5bc899ec450"></a>
### `RUNTIME_HAMPEL_WINDOW_MIN`
```cpp
constexpr uint8_t espectre::RUNTIME_HAMPEL_WINDOW_MIN = 3
```
<a id="namespaceespectre_1a49f3bcfd4d73eab0387bdddee7ee938b"></a>
### `RUNTIME_HAMPEL_WINDOW_MAX`
```cpp
constexpr uint8_t espectre::RUNTIME_HAMPEL_WINDOW_MAX = 11
```
<a id="namespaceespectre_1a288d1fd358e79e234ddeb67716b7a409"></a>
### `RUNTIME_HAMPEL_WINDOW_DEFAULT`
```cpp
constexpr uint8_t espectre::RUNTIME_HAMPEL_WINDOW_DEFAULT = 7
```
<a id="namespaceespectre_1ae5995a8c638215586d44542666335423"></a>
### `RUNTIME_HAMPEL_THRESHOLD_MIN`
```cpp
constexpr float espectre::RUNTIME_HAMPEL_THRESHOLD_MIN = 1.0f
```
<a id="namespaceespectre_1a0791cf4717749234bd7f410e0835296a"></a>
### `RUNTIME_HAMPEL_THRESHOLD_MAX`
```cpp
constexpr float espectre::RUNTIME_HAMPEL_THRESHOLD_MAX = 10.0f
```
<a id="namespaceespectre_1aef979169064e256a1dc21d83268a8413"></a>
### `RUNTIME_HAMPEL_THRESHOLD_DEFAULT`
```cpp
constexpr float espectre::RUNTIME_HAMPEL_THRESHOLD_DEFAULT = 5.0f
```
<a id="namespaceespectre_1a7c7e37b036bf9c750ffad94cc3f38f9b"></a>
### `RUNTIME_NETWORK_PORT_MIN`
```cpp
constexpr uint16_t espectre::RUNTIME_NETWORK_PORT_MIN = 1U
```
<a id="namespaceespectre_1a0f402dae6c22e383c6b47630879afa75"></a>
### `RUNTIME_NETWORK_PORT_MAX`
```cpp
constexpr uint16_t espectre::RUNTIME_NETWORK_PORT_MAX = UINT16_MAX
```
<a id="namespaceespectre_1aa38060237841c079d8afb7e5ad41071b"></a>
### `RUNTIME_CSI_TRAFFIC_UDP_PORT_DEFAULT`
```cpp
constexpr uint16_t espectre::RUNTIME_CSI_TRAFFIC_UDP_PORT_DEFAULT = 5555
```
<a id="namespaceespectre_1a65e83d64d1c3f527d18a1da78e0b8dab"></a>
### `RUNTIME_CSI_TRAFFIC_MULTICAST_GROUP_DEFAULT`
```cpp
constexpr const char* const espectre::RUNTIME_CSI_TRAFFIC_MULTICAST_GROUP_DEFAULT = "239.255.0.1"
```
<a id="namespaceespectre_1a7d2c42f00556433c50808762f93556bc"></a>
### `RUNTIME_CSI_TRAFFIC_MARKER_BYTES`
```cpp
constexpr uint8_t espectre::RUNTIME_CSI_TRAFFIC_MARKER_BYTES[][] = {0xF0U, 0x9FU, 0x91U, 0xBBU}
```
<a id="namespaceespectre_1a0217d11161d783391700195752d0abe9"></a>
### `RUNTIME_CSI_TRAFFIC_MARKER_LENGTH`
```cpp
constexpr size_t espectre::RUNTIME_CSI_TRAFFIC_MARKER_LENGTH = 4U
```
<a id="namespaceespectre_1a08717633496abf2eeb11f9a12f83c3e2"></a>
### `RUNTIME_CSI_TRAFFIC_MARKER_UTF8`
```cpp
constexpr const char* const espectre::RUNTIME_CSI_TRAFFIC_MARKER_UTF8 = "👻"
```
<a id="namespaceespectre_1ac0d561a007409fc2c0a940f9e5db2c8d"></a>
### `RUNTIME_CSI_TRAFFIC_EXPECTED_PAYLOAD_MAX`
```cpp
constexpr size_t espectre::RUNTIME_CSI_TRAFFIC_EXPECTED_PAYLOAD_MAX = 16U
```
<a id="namespaceespectre_1a647011431c82d51c8630e5304f968023"></a>
### `ESPECTRE_DEVICE_LABEL_MAX_LENGTH`
```cpp
constexpr size_t espectre::ESPECTRE_DEVICE_LABEL_MAX_LENGTH = 32U
```
Matter Basic Information NodeLabel limit, shared by all Direct frontends.
<a id="namespaceespectre_1a44771ad0a8deef4590f951be92242be3"></a>
### `ESPECTRE_COMMAND_MAX_PAYLOAD_SIZE`
```cpp
constexpr size_t espectre::ESPECTRE_COMMAND_MAX_PAYLOAD_SIZE = 2048U
```
Maximum serialized command-request size accepted by every transport.
<a id="namespaceespectre_1a27be540efef19a111bae40cf08a98cfe"></a>
### `ESPECTRE_PROTOCOL_VERSION`
```cpp
constexpr const char* espectre::ESPECTRE_PROTOCOL_VERSION = "1.0"
```
Protocol version reported by capabilities and discovery.
<a id="namespaceespectre_1a28134da0cfd709e9903630c9a4e1ffcd"></a>
### `ESPECTRE_DNS_SD_TXT_SCHEMA_VERSION`
```cpp
constexpr const char* espectre::ESPECTRE_DNS_SD_TXT_SCHEMA_VERSION = "1"
```
DNS-SD TXT record schema advertised as the RFC 6763 `txtvers` value.
<a id="namespaceespectre_1aa9bcecab1d67487af0b736b8637b6138"></a>
### `ESPECTRE_COMMAND_ID_MAX_LENGTH`
```cpp
constexpr size_t espectre::ESPECTRE_COMMAND_ID_MAX_LENGTH = 64U
```
Maximum canonical command correlation identifier length.
<a id="namespaceespectre_1a26505654b6fa88f6cc3c9f86b64958e9"></a>
### `ESPECTRE_TOPIC_PREFIX`
```cpp
constexpr const char* espectre::ESPECTRE_TOPIC_PREFIX = "espectre/v1/devices"
```
Default MQTT topic root.
Override per device with [`EspectreDeviceConfig::topic_prefix`](#structespectre_1_1_espectre_device_config_1ae89cde8ec77492cd8dd8fb315206630f).
<a id="namespaceespectre_1a86c5bfd099c8fce0440c7bf8aab22d86"></a>
### `ESPECTRE_DEFAULT_DEVICE_ID`
```cpp
constexpr uint64_t espectre::ESPECTRE_DEFAULT_DEVICE_ID = 0U
```
Sentinel meaning "use the runtime-generated device id".
<a id="namespaceespectre_1a13bc6643d765f244dd767ad20084a3fd"></a>
### `ESPECTRE_DEFAULT_DEVICE_LABEL`
```cpp
constexpr const char* espectre::ESPECTRE_DEFAULT_DEVICE_LABEL = ""
```
Empty label, meaning the device id is used as the display name.
<a id="namespaceespectre_1a3bc81a65899ce7cc811b7897ea57bedb"></a>
### `ESPECTRE_DIRECT_HTTP_PORT`
```cpp
constexpr uint16_t espectre::ESPECTRE_DIRECT_HTTP_PORT = 0xF47BU
```
ESPectre service port: low 16 bits of U+1F47B GHOST (0xF47B).
<a id="namespaceespectre_1a9b21dc9879a1b2d70a1582f213c49a2b"></a>
### `ESPECTRE_DIRECT_HTTP_BASE_ENDPOINT`
```cpp
constexpr const char* espectre::ESPECTRE_DIRECT_HTTP_BASE_ENDPOINT = "/espectre/v1"
```
Path prefix of every versioned Direct resource.
<a id="namespaceespectre_1a09e93416235f3d4fe07de4eee57db81f"></a>
### `ESPECTRE_DIRECT_HTTP_EVENTS_ENDPOINT`
```cpp
constexpr const char* espectre::ESPECTRE_DIRECT_HTTP_EVENTS_ENDPOINT = "/espectre/v1/events"
```
Server-sent events stream.
<a id="namespaceespectre_1a1c5ba9b3707b5eb96b6f3bab004fcfcd"></a>
### `ESPECTRE_DIRECT_HTTP_TRANSPORT`
```cpp
constexpr const char* espectre::ESPECTRE_DIRECT_HTTP_TRANSPORT = "http"
```
Transport name reported in capabilities and discovery.
<a id="namespaceespectre_1adfc7361b80006da4cca67b96224221d9"></a>
### `ESPECTRE_DIRECT_MAX_REQUEST_SIZE`
```cpp
constexpr size_t espectre::ESPECTRE_DIRECT_MAX_REQUEST_SIZE = ESPECTRE_COMMAND_MAX_PAYLOAD_SIZE
```
Largest request body accepted, in bytes.
<a id="namespaceespectre_1adb8f7243a68de4e7cd7ebad471875d51"></a>
### `ESPECTRE_DIRECT_MAX_RESPONSE_SIZE`
```cpp
constexpr size_t espectre::ESPECTRE_DIRECT_MAX_RESPONSE_SIZE = 8192U
```
Largest response body produced, in bytes.
<a id="namespaceespectre_1a66fe1d687dfe9106731a7ed5e8136092"></a>
### `HT20_CLASSIC_ONLY_NULL_BINS`
```cpp
constexpr uint8_t espectre::HT20_CLASSIC_ONLY_NULL_BINS[][] = {29, 30, 31, 33, 34, 35}
```
Bins that are null only in the classic layout.
<a id="namespaceespectre_1a460991f7f0cd4871fd1f338fc166b81c"></a>
### `HT20_CENTERED_ONLY_NULL_BINS`
```cpp
constexpr uint8_t espectre::HT20_CENTERED_ONLY_NULL_BINS[][] = {1, 2, 3, 61, 62, 63}
```
Bins that are null only in the centered layout.
<a id="namespaceespectre_1a87ab0d558b48a21c390b13b6c153c68d"></a>
### `HT20_LLTF_MISSING_BINS`
```cpp
constexpr uint8_t espectre::HT20_LLTF_MISSING_BINS[][] = {4, 5, 59, 60}
```
Centered bins that an LLTF capture cannot fill: subcarriers -28, -27, +27, and +28.
<a id="namespaceespectre_1ad8f2e24e1681c31efcee0dc5e508af26"></a>
### `TEMPORAL_CSI_MICROSECONDS_PER_SECOND`
```cpp
constexpr uint32_t espectre::TEMPORAL_CSI_MICROSECONDS_PER_SECOND = 1000000U
```
<a id="namespaceespectre_1a2af3fbdcae0da1f75af14e8a39ab629c"></a>
### `TEMPORAL_CSI_MINIMUM_COVERAGE_NUMERATOR`
```cpp
constexpr uint8_t espectre::TEMPORAL_CSI_MINIMUM_COVERAGE_NUMERATOR = 7U
```
A window is ready when at least this fraction of its slots holds a sample: `TEMPORAL_CSI_MINIMUM_COVERAGE_NUMERATOR / TEMPORAL_CSI_MINIMUM_COVERAGE_DENOMINATOR`, rounded up.
<a id="namespaceespectre_1aff60a06668015197e15387349e04bb3d"></a>
### `TEMPORAL_CSI_MINIMUM_COVERAGE_DENOMINATOR`
```cpp
constexpr uint8_t espectre::TEMPORAL_CSI_MINIMUM_COVERAGE_DENOMINATOR = 10U
```
See [`TEMPORAL_CSI_MINIMUM_COVERAGE_NUMERATOR`](#namespaceespectre_1a2af3fbdcae0da1f75af14e8a39ab629c).
<a id="namespaceespectre_1aa590854a8a59e96754371b7f35c4e48e"></a>
### `TEMPORAL_CSI_SLOT_HALF_DENOMINATOR`
```cpp
constexpr uint8_t espectre::TEMPORAL_CSI_SLOT_HALF_DENOMINATOR = 2U
```
Selected candidates are at least one slot period divided by this apart.
<a id="namespaceespectre_1aabc8a97ebb800fc8c97d279664c586eb"></a>
### `CALIBRATION_NUM_WINDOWS`
```cpp
constexpr uint16_t espectre::CALIBRATION_NUM_WINDOWS = 10
```
Detector windows in one startup calibration budget.
<a id="namespaceespectre_1aae96d7ab4eb211aac2c5f72d9b3a480c"></a>
### `CALIBRATION_DEFAULT_BUFFER_SIZE`
```cpp
constexpr uint16_t espectre::CALIBRATION_DEFAULT_BUFFER_SIZE =
DETECTOR_DEFAULT_WINDOW_SIZE * CALIBRATION_NUM_WINDOWS
```
Calibration budget in packets at the default window.
<a id="namespaceespectre_1abd53db5fbc189b5864021cac6914fb5c"></a>
### `DETECTOR_L1_DELTA_LAG_DEFAULT`
```cpp
constexpr uint16_t espectre::DETECTOR_L1_DELTA_LAG_DEFAULT = 10U
```
[`L1_DELTA_LAG_US`](#namespaceespectre_1a24a334c3fa5dbbc227cf527faf402913) in packets at 100 pps.
<a id="namespaceespectre_1adb267e831a03088b59bb2b2924af6027"></a>
### `DETECTOR_AUTOCORR_LAG_DEFAULT`
```cpp
constexpr uint16_t espectre::DETECTOR_AUTOCORR_LAG_DEFAULT = 1U
```
[`TURB_AUTOCORR_LAG_US`](#namespaceespectre_1ae59e57079a7c71da7ba4b2c9a87868b3) in packets at 100 pps.
<a id="namespaceespectre_1a7864a488a9f0bc50ab7048258047247b"></a>
### `L1_DELTA_LAG_MAX`
```cpp
constexpr uint16_t espectre::L1_DELTA_LAG_MAX = 32
```
Largest profile-displacement lag in packets; longer lags saturate.
<a id="namespaceespectre_1a5eb2d1d16fb41389c7e99d23fc36759d"></a>
### `MIN_PLAUSIBLE_PACKET_INTERVAL_US`
```cpp
constexpr uint32_t espectre::MIN_PLAUSIBLE_PACKET_INTERVAL_US = 200U
```
Packets closer than this (5000 pps) are treated as a batch, not a stream.
<a id="namespaceespectre_1ab18ef5b016f2a45b3e57911383e7a528"></a>
### `WIFI_CHANNEL_AUTO`
```cpp
constexpr int espectre::WIFI_CHANNEL_AUTO = 0
```
Channel hint meaning no hint: the station follows the access point.
<a id="namespaceespectre_1ac6072079a5ee71395587ea95286469a8"></a>
### `WIFI_CHANNEL_2G_MAX`
```cpp
constexpr int espectre::WIFI_CHANNEL_2G_MAX = 14
```
Highest 2.4 GHz channel number.
<a id="namespaceespectre_1a859a9a7b26d35879fde75cdda7a32f85"></a>
### `kEspectreAsciiLogoLines`
```cpp
constexpr const char* espectre::kEspectreAsciiLogoLines[][] = {
" _____ ____ ____ __ ",
" | ____/ ___|| _ \\ ___ ___| |_ _ __ ___ ",
" | _| \\___ \\| |_) / _ \\/ __| __| '__/ _ \\",
" | |___ ___) | __/ __/ (__| |_| | | __/",
" |_____|____/|_| \\___|\\___|\\__|_| \\___|",
}
```
Lines of the ESPectre ASCII logo.
<a id="namespaceespectre_1abc7070382b2620aad729f294d9f00e8d"></a>
### `ESPECTRE_PEER_DISCOVERY_TIMEOUT_MS`
```cpp
constexpr uint32_t espectre::ESPECTRE_PEER_DISCOVERY_TIMEOUT_MS = 3000U
```
Duration of one DNS-SD search.
<a id="namespaceespectre_1a1eb28ce7d48bbb1551343b78c62eb44a"></a>
### `ESPECTRE_PEER_DISCOVERY_MAX_DEVICES`
```cpp
constexpr size_t espectre::ESPECTRE_PEER_DISCOVERY_MAX_DEVICES = 8U
```
Devices kept in one result.
<a id="namespaceespectre_1a763c9fa6ba6bfe96f1f5d73d2f1eb1ce"></a>
### `ESPECTRE_PEER_DISCOVERY_MAX_ADDRESSES`
```cpp
constexpr size_t espectre::ESPECTRE_PEER_DISCOVERY_MAX_ADDRESSES = 2U
```
IPv4 addresses kept per device.
<a id="namespaceespectre_1a0ab265cc384a2f5d3c4b58f335984291"></a>
### `ESPECTRE_PEER_DISCOVERY_MAX_RESULT_SIZE`
```cpp
constexpr size_t espectre::ESPECTRE_PEER_DISCOVERY_MAX_RESULT_SIZE = 3584U
```
Largest serialized result, in bytes; devices that do not fit are dropped.
<a id="namespaceespectre_1a35ddf262655083501dcdf68b4d934ac0"></a>
### `espectre_sdk_version`
```cpp
constexpr const char * espectre::espectre_sdk_version()
```
The SDK version as a string, usable where a macro is not.
**Returns:** [`ESPECTRE_SDK_VERSION_STRING`](#espectre__sdk__version_8h_1a63ca6448380d44c069980a49a9584c74), or `"0.0.0"` when unknown. Never null; valid for the process lifetime.
<a id="namespaceespectre_1adf6bece0a78ea38870c47f1f721ac096"></a>
### `csi_capture_profile_name`
```cpp
constexpr const char * espectre::csi_capture_profile_name(CsiCaptureProfile profile)
```
Protocol name of a profile: `ht20`, `lltf20`, or `vht20`.
<a id="namespaceespectre_1a2d1b08a1daef9612d8f797d055f1d84f"></a>
### `csi_capture_profile_uses_lltf`
```cpp
constexpr bool espectre::csi_capture_profile_uses_lltf(CsiCaptureProfile profile)
```
Whether the profile captures the legacy training field.
<a id="namespaceespectre_1ab673d1c40a3ffe2f300776a1501b1131"></a>
### `resolve_csi_capture_profile`
```cpp
constexpr CsiCaptureProfile espectre::resolve_csi_capture_profile(bool prefers_lltf20, bool supports_vht20, uint8_t wifi_channel, CsiCapturePolicy requested=CsiCapturePolicy::AUTO)
```
Resolve the configured capture policy from target capabilities and link channel.
<a id="namespaceespectre_1afe16dc0f8dcdb90f8c11b66b03233a35"></a>
### `runtime_threshold_max`
```cpp
constexpr float espectre::runtime_threshold_max(DetectionAlgorithm algorithm)
```
<a id="namespaceespectre_1ac2918b7136144625515b36b675d28ee5"></a>
### `runtime_detection_algorithm_valid`
```cpp
constexpr bool espectre::runtime_detection_algorithm_valid(DetectionAlgorithm algorithm)
```
<a id="namespaceespectre_1ada2e034534b4f6addb0485fd61bf9924"></a>
### `runtime_traffic_generator_mode_valid`
```cpp
constexpr bool espectre::runtime_traffic_generator_mode_valid(TrafficGeneratorMode mode)
```
<a id="namespaceespectre_1a7ebccf5d9764673ec697cac7c059b6f9"></a>
### `runtime_default_threshold`
```cpp
constexpr float espectre::runtime_default_threshold(DetectionAlgorithm algorithm)
```
<a id="namespaceespectre_1ae40d935f9a093b8daca17290196df3fa"></a>
### `validate_runtime_threshold`
```cpp
bool espectre::validate_runtime_threshold(float threshold)
```
Whether a threshold is finite and inside the range shared by every detector.
<a id="namespaceespectre_1a662ded5428c534fcee07d8886852da0a"></a>
### `validate_runtime_threshold_for_algorithm`
```cpp
bool espectre::validate_runtime_threshold_for_algorithm(float threshold, DetectionAlgorithm algorithm)
```
Whether a threshold is finite and inside the range of one detector.
<a id="namespaceespectre_1a302757e6d7e73d410887f8b7728711a5"></a>
### `runtime_traffic_generator_mode_supported`
```cpp
bool espectre::runtime_traffic_generator_mode_supported(TrafficGeneratorMode mode)
```
Whether this build target supports the internal traffic source; host builds accept every valid mode.
<a id="namespaceespectre_1a067fa3b169bc3aeb3cbb2679eb388ac0"></a>
### `runtime_capture_profile_supports_traffic`
```cpp
bool espectre::runtime_capture_profile_supports_traffic(CsiCapturePolicy profile, TrafficGeneratorMode mode)
```
Whether a configured CSI profile can be combined with the internal source.
<a id="namespaceespectre_1a3204487b096871eb46f055d2a8088907"></a>
### `validate_runtime_config`
```cpp
RuntimeConfigError espectre::validate_runtime_config(const RuntimeConfig &config)
```
Validate the complete configuration before creating runtime state.
<a id="namespaceespectre_1a464f8d16630630601b5136ed82097b34"></a>
### `runtime_config_error_message`
```cpp
const char * espectre::runtime_config_error_message(RuntimeConfigError error)
```
Stable diagnostic label for a configuration error.
Never returns `nullptr`.
<a id="namespaceespectre_1a2afe57057faedef421c7c717f9cc3e33"></a>
### `apply_runtime_control_update`
```cpp
RuntimeConfig espectre::apply_runtime_control_update(RuntimeConfig config, const RuntimeControlUpdate &update)
```
Return `config` with `update` applied, as the controller setters apply it.
Fields apply in the order detector, threshold, motion hits, then traffic generator mode. Switching to a different detector also adopts that detector's default threshold unless the update sets one. Pass the result to [validate\_runtime\_config()](#namespaceespectre_1a3204487b096871eb46f055d2a8088907) to check the change before applying it.
<a id="namespaceespectre_1a87461d595b73c9764e020c3ecd7eea14"></a>
### `runtime_traffic_target_addr`
```cpp
uint32_t espectre::runtime_traffic_target_addr(const RuntimeConfig &config, uint32_t gateway_addr)
```
Resolve the internal traffic destination in network byte order; empty uses the gateway, and invalid IPv4 returns zero.
<a id="namespaceespectre_1a43f43b5fa48477941d70036166ca22c1"></a>
### `append_runtime_performance_diagnostics_json`
```cpp
void espectre::append_runtime_performance_diagnostics_json(std::string *out, const RuntimeDiagnosticsSnapshot &diagnostics, bool include_current_memory=true)
```
Append shared platform and performance fields to an existing JSON object.
The object must already contain at least one field. Metrics from an incomplete aggregation window are emitted as `null`; unsupported detector timing is identified separately by `detection_timing_supported`.
<a id="namespaceespectre_1aea3b512c1c34b6be4240d0839da17a4d"></a>
### `validate_diagnostic_fields`
```cpp
bool espectre::validate_diagnostic_fields(const std::vector< std::string > &fields, unsigned profile=ESPECTRE_DIAGNOSTIC_PROFILE_ALL)
```
Validate diagnostic paths, groups, or an exclusive wildcard against the canonical registry.
<a id="namespaceespectre_1abdb85601916430789d63639f7708ff4a"></a>
### `diagnostic_response`
```cpp
std::string espectre::diagnostic_response(const std::vector< std::string > &fields, unsigned profile, const std::function< std::string(const char *)> &value)
```
Serialize the catalog without reading values, or only selected values from the supplied provider.
`profile` is a mask of `ESPECTRE_DIAGNOSTIC_PROFILE_*` values. Empty selections return the catalog. The provider returns one JSON scalar. Unknown profile fields produce an empty response.
<a id="namespaceespectre_1ad8e4b0d6a83b94536fa09d8cc9aacc67"></a>
### `runtime_diagnostic_value`
```cpp
std::string espectre::runtime_diagnostic_value(const char *key, const RuntimeDiagnosticsSample *sample, const std::function< const RuntimeDiagnosticsSnapshot &()> &snapshot)
```
Read a shared scalar from a cached rate sample or a lazily acquired runtime snapshot.
<a id="namespaceespectre_1a9f389e2f1e12234188f554dc04490ab3"></a>
### `read_network_traffic`
```cpp
NetworkTrafficSnapshot espectre::read_network_traffic()
```
Read cumulative counters for the WIFI\_STA\_DEF station interface.
Call once to establish a rate baseline, then on each diagnostic interval. The station is recognized when the WIFI\_STA\_DEF netif is created or recreated, so a read never takes the lwIP lock. The packet hooks only compare that pointer, which keeps the per-packet cost minimal. Counters persist across sensing restarts and wrap modulo 2^32. Reads are lock-free and packet updates are thread-safe; the two counters are sampled independently. No payload is inspected.
Compile ESPECTRE\_RUNTIME\_ESP\_IDF\_TRAFFIC\_SOURCES and link with ESPECTRE\_RUNTIME\_ESP\_IDF\_TRAFFIC\_LINK\_OPTIONS when consuming the source groups directly. The SDK component already supplies these link options.
<a id="namespaceespectre_1a9864a7885166c767516635cd059a8ef6"></a>
### `apply_station_tx_rate`
```cpp
esp_err_t espectre::apply_station_tx_rate()
```
Apply the station transmit-rate policy to the associated access point.
`CONFIG_ESPECTRE_WIFI_TX_RATE_MBPS` selects Auto, OFDM 6 Mbps, or HT20 MCS0 with long GI; Auto and TX A-MPDU builds leave driver rate selection unchanged. The full runtime applies it itself. Integrations that own the Wi-Fi station call it after every association, including reassociation, and before starting CSI. Requires ESPECTRE\_RUNTIME\_ESP\_IDF\_TRAFFIC\_SOURCES.
**Returns:** `ESP_OK`, or the driver error that prevented applying the policy.
<a id="namespaceespectre_1a79c04e29909488dd8aae7ee4df04c124"></a>
### `validate_protocol_extension`
```cpp
bool espectre::validate_protocol_extension(const EspectreProtocolExtension &extension, std::string *error=nullptr)
```
Reject malformed descriptors and collisions with the SDK or another extension entry.
<a id="namespaceespectre_1a042b26831152547bc29a3a8cedd7e5d7"></a>
### `find_extension_route`
```cpp
const EspectreExtensionRoute * espectre::find_extension_route(const EspectreProtocolExtension *extension, const std::string &command)
```
Find a command in a valid extension; a null or invalid extension has no routes.
<a id="namespaceespectre_1a1f22c8af7f655d2ab62a805f5827bcec"></a>
### `espectre_api_routes`
```cpp
const EspectreApiRoute * espectre::espectre_api_routes(size_t *count)
```
Return the immutable v1 resource registry and its entry count.
<a id="namespaceespectre_1ad369de74fc2722fa68d76a20e9277e43"></a>
### `espectre_api_events`
```cpp
const EspectreApiEventDescriptor * espectre::espectre_api_events(size_t *count)
```
Return the immutable canonical event registry and its entry count.
<a id="namespaceespectre_1ad13f75740e4fefd7137021f0b3b5318f"></a>
### `parse_json_object_views`
```cpp
bool espectre::parse_json_object_views(const JsonInput &input, size_t offset, size_t length, std::vector< JsonFieldView > *fields, std::string *error=nullptr)
```
Validate an object range, rejecting duplicate fields, without copying its values.
<a id="namespaceespectre_1adf2555a878b431297e221c26e14c6800"></a>
### `parse_json_array_object_views`
```cpp
bool espectre::parse_json_array_object_views(const JsonInput &input, size_t offset, size_t length, std::vector< std::vector< JsonFieldView > > *objects, std::string *error=nullptr)
```
Validate an array of objects and retain field offsets relative to the array range.
<a id="namespaceespectre_1aba834ba61d7ff59cc037d0d8b13f6dc6"></a>
### `parse_json_string_value`
```cpp
bool espectre::parse_json_string_value(const JsonInput &input, size_t offset, size_t length, std::string *value, std::string *error=nullptr)
```
Decode one complete JSON string token from the specified input range.
<a id="namespaceespectre_1a64b54752d746f722b1176a3fe995caef"></a>
### `append_json_string`
```cpp
void espectre::append_json_string(std::string *out, const char *value)
```
Append `value` as a quoted, escaped JSON string; `nullptr` appends `""`.
<a id="namespaceespectre_1a4c1693617d0914f60a81ced263a8fb72"></a>
### `append_json_pair`
```cpp
void espectre::append_json_pair(std::string *out, const char *key, const char *value, bool first=false)
```
Append `"key":"value"`, preceded by a comma unless `first`.
<a id="namespaceespectre_1ad94497c9202bbf4d01870ca2e7ce5dd1"></a>
### `decode_urlencoded_component`
```cpp
bool espectre::decode_urlencoded_component(const std::string &encoded, std::string *decoded, std::string *error=nullptr)
```
Decode one `application/x-www-form-urlencoded` component, `+` included.
**Returns:** false for a truncated or invalid `%` escape, with a reason in `error`.
<a id="namespaceespectre_1ae9a669e530c21661ba4bf329fc86927d"></a>
### `encode_urlencoded_component`
```cpp
std::string espectre::encode_urlencoded_component(const std::string &value)
```
Percent-encode every byte except unreserved URI characters.
<a id="namespaceespectre_1a6089f509e536788cce4984fc7569bf9a"></a>
### `parse_urlencoded_key_value_pairs`
```cpp
bool espectre::parse_urlencoded_key_value_pairs(const std::string &payload, std::vector< std::pair< std::string, std::string > > *pairs, std::string *error=nullptr)
```
Split `key=value&key=value` into decoded pairs, in order.
**Returns:** false for an empty payload, an empty token, or a token without a key.
<a id="namespaceespectre_1a20e153bb946d91e4aae1899f1c26586b"></a>
### `parse_json_object_fields`
```cpp
bool espectre::parse_json_object_fields(const std::string &payload, std::vector< JsonObjectField > *fields, std::string *error=nullptr)
```
Parse and validate one complete JSON object, rejecting duplicate field names.
<a id="namespaceespectre_1ac9e20ff827dae90b16db7b332fa4dc19"></a>
### `parse_json_array_strings`
```cpp
bool espectre::parse_json_array_strings(const std::string &payload, std::vector< std::string > *strings, std::string *error=nullptr)
```
Parse a complete array containing only JSON strings.
<a id="namespaceespectre_1ae7d7210fe0bec5db1ba8ad2face750b2"></a>
### `find_json_object_field`
```cpp
const JsonObjectField * espectre::find_json_object_field(const std::vector< JsonObjectField > &fields, const char *name)
```
The field named `name`, or `nullptr`.
<a id="namespaceespectre_1a138e724fbe594802da86d2961939cd7f"></a>
### `parse_direct_http_request`
```cpp
bool espectre::parse_direct_http_request(const std::string &http_method, const std::string &path, const std::string &payload, DirectRequest *request, std::string *error=nullptr, const EspectreProtocolExtension *extension=nullptr)
```
Map an HTTP method, path, and body onto a canonical command request.
Looks the route up in the SDK registry, then in `extension`. Only `GET /espectre/v1/diagnostics` accepts a query, `?fields=`. The body must be a JSON object within [`ESPECTRE_DIRECT_MAX_REQUEST_SIZE`](#namespaceespectre_1adfc7361b80006da4cca67b96224221d9); parameter values are validated later, by [direct\_http\_request\_to\_command()](#namespaceespectre_1abcacfcd112472bfc62c59a502f647ceb).
**Returns:** false for an unknown route, a malformed query, or an invalid body, with a reason in `error`.
<a id="namespaceespectre_1abcacfcd112472bfc62c59a502f647ceb"></a>
### `direct_http_request_to_command`
```cpp
bool espectre::direct_http_request_to_command(const DirectRequest &request, EspectreCommand *command, std::string *error=nullptr, const EspectreProtocolExtension *extension=nullptr)
```
Validate a parsed Direct request and build the command, as [parse\_espectre\_command\_request()](#namespaceespectre_1a3719c5d411370f85344e700a2eb961a5) does for every transport.
<a id="namespaceespectre_1a5509432cbeaff50ecf7e2b7d5ace8bd9"></a>
### `espectre_transport_mapping_payload`
```cpp
std::string espectre::espectre_transport_mapping_payload()
```
How each canonical message maps onto Direct HTTP routes and MQTT topics.
<a id="namespaceespectre_1ac57dce35f8b2fdb1cdfe072f3f4feb14"></a>
### `espectre_protocol_catalog_payload`
```cpp
std::string espectre::espectre_protocol_catalog_payload(const EspectreProtocolExtension *extension=nullptr)
```
Combined message-model and transport-mapping catalog for protocol inspection.
<a id="namespaceespectre_1a34031a60d78bbb6306047b3540b4f905"></a>
### `derive_runtime_device_id`
```cpp
uint64_t espectre::derive_runtime_device_id()
```
Return the cached 64-bit SHA-256 pseudonym derived from the station MAC.
<a id="namespaceespectre_1a0f5171c004f18f155e1cd453c8eb4801"></a>
### `derive_runtime_device_id_string`
```cpp
std::string espectre::derive_runtime_device_id_string()
```
Return the cached canonical text for [`derive_runtime_device_id()`](#namespaceespectre_1a34031a60d78bbb6306047b3540b4f905).
<a id="namespaceespectre_1ab070877204ffb133b519d0b163420df6"></a>
### `make_runtime_sensing_config_from_kconfig`
```cpp
RuntimeConfig espectre::make_runtime_sensing_config_from_kconfig()
```
Build a [`RuntimeConfig`](#structespectre_1_1_runtime_config) from the `ESPECTRE_*` menuconfig options.
This is the ergonomic path on ESP-IDF: expose the sensing settings in menuconfig, call this at boot, and override only the fields your product computes at runtime.
```cpp
espectre::RuntimeConfig config = espectre::make_runtime_sensing_config_from_kconfig();
config.device_id = my_device_id();
controller.set_config(config);
```
Every value is range-checked against the schema in [`runtime_sensing_schema.h`](#runtime__sensing__schema_8h). An out-of-range or unparseable option falls back to the documented default and logs a warning rather than failing the boot, so a bad `sdkconfig` degrades instead of bricking the device.
Options absent from the build, for instance when the SDK Kconfig is not sourced, compile to their defaults. Fields with no Kconfig option, such as `device_id` and the stream settings, keep their [`RuntimeConfig`](#structespectre_1_1_runtime_config) defaults.
**Returns:** A validated configuration, ready for [`RuntimeFrontendController::set_config()`](#classespectre_1_1_runtime_frontend_controller_1a6bc5d2dea03c406e822c0fc917e54840).
<a id="namespaceespectre_1a4ce213aabcd22d32aa6f62e83a2bda1e"></a>
### `set_log_sink`
```cpp
bool espectre::set_log_sink(const LogSink &sink)
```
Register a complete frontend logging sink.
Registration must happen before runtime setup, and replacement is supported only while no ESPectre runtime is active. An invalid sink leaves the current registration unchanged.
**Parameters**
- `sink`: Callback value copied by ESPectre.
**Returns:** `true` when both required callbacks were registered.
<a id="namespaceespectre_1a61ab03223d965fdc086b55a8527ed204"></a>
### `clear_log_sink`
```cpp
void espectre::clear_log_sink()
```
Clear the current sink while no ESPectre runtime is active.
<a id="namespaceespectre_1aceb53f160132829964a6b4d69347ed4e"></a>
### `log_enabled`
```cpp
bool espectre::log_enabled(LogLevel level, const char *tag)
```
Return whether the current sink accepts one level and tag.
**Parameters**
- `level`: Message severity.
- `tag`: Stable logger tag.
**Returns:** `false` when no complete sink is registered or the sink filters the message.
<a id="namespaceespectre_1a6bd20096271ae7a56b205e06ac9c7e86"></a>
### `ht20_bins_with_energy`
```cpp
uint8_t espectre::ht20_bins_with_energy(const int8_t *csi_data, const uint8_t *bins, uint8_t count, bool first_word_invalid=false)
```
Count how many of `bins` carry a nonzero I/Q pair.
With `first_word_invalid`, bins 0 and 1 are skipped because the hardware marked those bytes invalid.
<a id="namespaceespectre_1a7d1d5b5cec71e45a58dfc64c0ba441cd"></a>
### `detect_ht20_bin_layout`
```cpp
Ht20BinLayout espectre::detect_ht20_bin_layout(const int8_t *csi_data, size_t csi_len, bool first_word_invalid=false)
```
Identify which HT20 bin ordering a 64-subcarrier payload uses.
Requires positive evidence in both directions: one guard set must be entirely null and the other entirely populated. Absence of energy alone is not enough, because a sparse or degenerate payload is null under both conventions.
**Parameters**
- `csi_data`: Raw CSI payload (interleaved I/Q pairs)
- `csi_len`: Payload length in bytes (must be HT20\_CSI\_LEN)
- `first_word_invalid`: Ignore the two hardware-invalid source pairs
**Returns:** The detected layout, or UNKNOWN when the evidence is inconclusive
<a id="namespaceespectre_1ad95f5d8710d3ea0b07337e581593c63e"></a>
### `zero_ht20_lltf_missing_bins`
```cpp
bool espectre::zero_ht20_lltf_missing_bins(int8_t *csi_data, size_t csi_len)
```
Mark LLTF's unavailable edge tones as missing in a normalized raw view.
**Parameters**
- `csi_data`: Centered, interleaved I/Q HT20 payload to update in place.
- `csi_len`: Payload length in bytes; must equal HT20\_CSI\_LEN.
**Returns:** true when the payload was updated, or false for invalid input.
<a id="namespaceespectre_1a56a1f68a4399f8754598fe6aa6c86a09"></a>
### `prepare_ht20_detector_input`
```cpp
bool espectre::prepare_ht20_detector_input(int8_t *csi_data, size_t csi_len, bool lltf, bool first_word_invalid=false, Ht20BinLayout source_layout=Ht20BinLayout::UNKNOWN)
```
Prepare a private centered detector buffer from normalized raw CSI.
Fill LLTF edge tones from -26/+26 and hardware-invalid classic +1 from +2. Source metadata, never a zero value, selects the latter. DC and guards stay unchanged. Call only on a private detector buffer, after raw delivery splits.
**Parameters**
- `csi_data`: Private centered, interleaved I/Q HT20 buffer to update.
- `csi_len`: Payload length in bytes; must equal HT20\_CSI\_LEN.
- `lltf`: Whether the capture profile lacks the LLTF edge tones.
- `first_word_invalid`: Whether the first four source bytes were invalid.
- `source_layout`: Original source ordering, before centered normalization.
**Returns:** true for a prepared buffer, or false for invalid input or unknown ordering of a flagged source; invalid input is not modified.
<a id="namespaceespectre_1ab70480c9cd9d9a706a1777486c4d073d"></a>
### `impute_ht20_lltf_detector_bins`
```cpp
bool espectre::impute_ht20_lltf_detector_bins(int8_t *csi_data, size_t csi_len)
```
Prepare the legacy LLTF-only detector view in a private buffer.
<a id="namespaceespectre_1a8e38da349464d03ae50a403cab4f977a"></a>
### `rotate_ht20_classic_to_centered`
```cpp
void espectre::rotate_ht20_classic_to_centered(const int8_t *csi_data, int8_t *out)
```
Rotate a classic-order HT20 payload into the centered convention.
Rotating by half the FFT size is its own inverse, so one swap of the payload halves maps `0~31, -32~-1` onto `-32~+31`.
**Parameters**
- `csi_data`: Source payload of HT20\_CSI\_LEN bytes
- `out`: Destination buffer of HT20\_CSI\_LEN bytes (must not alias the source)
<a id="namespaceespectre_1a20a50c9af4bbb66528f0c0491e92b3e8"></a>
### `calculate_spatial_turbulence`
```cpp
float espectre::calculate_spatial_turbulence(const float *magnitudes, const uint8_t *subcarriers, uint8_t num_subcarriers, uint16_t max_subcarrier=64)
```
Calculate spatial turbulence from pre-calculated magnitudes.
Spatial turbulence is the coefficient of variation (standard deviation divided by mean) of magnitudes across selected subcarriers, so it does not depend on the receiver gain. It measures the spatial variability of the Wi-Fi channel - higher values indicate motion/disturbance.
**Parameters**
- `magnitudes`: Array of magnitude values (one per subcarrier)
- `subcarriers`: Array of selected subcarrier indices
- `num_subcarriers`: Number of selected subcarriers (max 12)
- `max_subcarrier`: Maximum valid subcarrier index (default: 64 for HT20)
**Returns:** Turbulence value
<a id="namespaceespectre_1ae28970c57767d93ae75b3410225d51b1"></a>
### `extract_subcarrier_amplitudes`
```cpp
uint8_t espectre::extract_subcarrier_amplitudes(const int8_t *csi_data, size_t csi_len, const uint8_t *subcarriers, uint8_t num_subcarriers, float *out, uint8_t out_capacity)
```
Extract subcarrier amplitudes from raw CSI data (I/Q pairs).
**Parameters**
- `csi_data`: Raw CSI data (interleaved I/Q pairs, Espressif format)
- `csi_len`: Length of CSI data in bytes
- `subcarriers`: Array of selected subcarrier indices
- `num_subcarriers`: Number of selected subcarriers
- `out`: Output amplitude buffer
- `out_capacity`: Capacity of the output buffer
**Returns:** Number of amplitudes written
<a id="namespaceespectre_1ac837a8b05d79f7e5e2b3978ab2791fb8"></a>
### `extract_packet_subcarrier_amplitudes`
```cpp
uint8_t espectre::extract_packet_subcarrier_amplitudes(const int8_t *csi_data, size_t csi_len, float *out, uint8_t out_capacity)
```
Extract one packet-wide amplitude frame for reuse by multiple feature paths.
<a id="namespaceespectre_1a5a120acf2ff3297fe7d5658e12e79a25"></a>
### `fill_packet_subcarrier_energies`
```cpp
uint8_t espectre::fill_packet_subcarrier_energies(const int8_t *csi_data, size_t csi_len, float *out, uint8_t out_capacity)
```
Fill one packet-wide squared-magnitude frame for energy-domain consumers.
<a id="namespaceespectre_1a9d29e561f008ffa26b8d57f46f6e1ca5"></a>
### `energies_to_amplitudes_in_place`
```cpp
void espectre::energies_to_amplitudes_in_place(float *values, uint8_t count)
```
Replace squared magnitudes with magnitudes.
<a id="namespaceespectre_1a7ee2f120717498da48852634a0db88ca"></a>
### `select_subcarrier_amplitudes`
```cpp
uint8_t espectre::select_subcarrier_amplitudes(const float *packet_amplitudes, uint8_t packet_count, const uint8_t *subcarriers, uint8_t num_subcarriers, float *out, uint8_t out_capacity)
```
Select the configured tones from a packet-wide amplitude frame.
<a id="namespaceespectre_1a15c3caa66a486b64ea5b4baa16f6c9fc"></a>
### `select_adjacent_aggregated_subcarrier_amplitudes`
```cpp
uint8_t espectre::select_adjacent_aggregated_subcarrier_amplitudes(const float *packet_amplitudes, uint8_t packet_count, const uint8_t *subcarriers, uint8_t num_subcarriers, uint8_t width, float *out, uint8_t out_capacity)
```
Select adjacent-bin mean amplitudes from a packet-wide amplitude frame.
<a id="namespaceespectre_1ab089846cad43726fc4d5ee80271586e3"></a>
### `extract_adjacent_aggregated_subcarrier_amplitudes`
```cpp
uint8_t espectre::extract_adjacent_aggregated_subcarrier_amplitudes(const int8_t *csi_data, size_t csi_len, const uint8_t *subcarriers, uint8_t num_subcarriers, uint8_t width, float *out, uint8_t out_capacity)
```
Extract one mean magnitude per selected tone from adjacent live HT20 bins.
Windows are clamped to bins 4..60 and skip the DC null at bin 32.
<a id="namespaceespectre_1a56c215b39ccf2e01b773e922a484459b"></a>
### `calculate_spatial_turbulence_from_amplitudes`
```cpp
float espectre::calculate_spatial_turbulence_from_amplitudes(const float *amplitudes, uint8_t count)
```
Spatial turbulence, the coefficient of variation, of already selected amplitudes.
<a id="namespaceespectre_1a2dc522f2419538854cf164ca24220b66"></a>
### `calculate_spatial_turbulence_from_csi`
```cpp
float espectre::calculate_spatial_turbulence_from_csi(const int8_t *csi_data, size_t csi_len, const uint8_t *subcarriers, uint8_t num_subcarriers)
```
Calculate spatial turbulence directly from raw CSI data (I/Q pairs).
This is a convenience wrapper that calculates magnitudes internally before computing spatial turbulence, the coefficient of variation of the selected magnitudes.
HT20 only: 64 subcarriers, 128 bytes CSI data.
**Parameters**
- `csi_data`: Raw CSI data (interleaved I/Q pairs)
- `csi_len`: Length of CSI data in bytes (expected: 128 for HT20)
- `subcarriers`: Array of selected subcarrier indices
- `num_subcarriers`: Number of selected subcarriers (max 12)
**Returns:** Turbulence value
<a id="namespaceespectre_1aaec036cc9ad204a6e3fc1abd72d00ef9"></a>
### `temporal_window_slots`
```cpp
uint32_t espectre::temporal_window_slots(uint32_t target_pps, uint32_t window_size_ms)
```
Return the fixed-grid slot count for a target rate and window duration.
<a id="namespaceespectre_1a06e0cbe94d9c977e8c5f7d7976890d0d"></a>
### `temporal_minimum_valid_slots`
```cpp
uint32_t espectre::temporal_minimum_valid_slots(uint32_t window_slots)
```
Return the minimum occupied slots required for a ready window.
<a id="namespaceespectre_1a8a21858a93018db73d09ee475c20e11c"></a>
### `temporal_minimum_sample_spacing_us`
```cpp
uint32_t espectre::temporal_minimum_sample_spacing_us(uint32_t target_pps)
```
Return the minimum spacing between selected candidates at a target rate.
<a id="namespaceespectre_1ad4c7901011b5435695529f5f5a01e8bf"></a>
### `read_direct_wifi_snapshot`
```cpp
DirectWifiSnapshot espectre::read_direct_wifi_snapshot()
```
Read the current ESP-IDF station configuration and association without credentials.
<a id="namespaceespectre_1a911b097ab2cd0645acb686a8d64040b3"></a>
### `read_direct_wifi_connected`
```cpp
bool espectre::read_direct_wifi_connected()
```
Read cached IPv4 link readiness without querying the Wi-Fi driver.
<a id="namespaceespectre_1a2dab48606d782213e70dae8808b0fdd9"></a>
### `load_frontend_device_config`
```cpp
EspectreDeviceConfig espectre::load_frontend_device_config(const FrontendDeviceConfigDefaults &defaults, const char *log_tag, const char *stored_config_message, const char *load_error_prefix)
```
Load the saved device settings, or build them from `defaults`.
The device id always comes from `defaults.runtime_device_id` or [derive\_runtime\_device\_id()](#namespaceespectre_1a34031a60d78bbb6306047b3540b4f905), never from NVS. `stored_config_message` is logged when saved settings are used, and `load_error_prefix` prefixes a load failure; both use `log_tag`.
<a id="namespaceespectre_1a9c0cb264d4cfce2b1652a1da5e178fb3"></a>
### `setup_frontend_wifi_station`
```cpp
esp_err_t espectre::setup_frontend_wifi_station(WifiProvisioningService *provisioning, StandaloneWifiService *wifi_manager, const FrontendWifiStationOptions &options, const char *log_tag, const char *stored_config_message)
```
Set up the station through `provisioning`, which must already be bound to `wifi_manager`, and optionally start it.
**Returns:** `ESP_ERR_INVALID_ARG` for a null `provisioning` or an unusable channel, `ESP_ERR_NOT_SUPPORTED` for an unsupported band policy, `ESP_ERR_INVALID_STATE` when starting without `wifi_manager`, or the setup or start error.
<a id="namespaceespectre_1ae48174400d9601d7260ae60e07591908"></a>
### `frontend_ha_mqtt_enabled`
```cpp
bool espectre::frontend_ha_mqtt_enabled()
```
Whether Home Assistant discovery is enabled with `CONFIG_ESPECTRE_HA_DISCOVERY_ENABLED`.
<a id="namespaceespectre_1ad0ab3784ab4c2449af25b7fb4f8a80b6"></a>
### `build_frontend_ha_mqtt_settings`
```cpp
FrontendHaMqttSettings espectre::build_frontend_ha_mqtt_settings(const EspectreDeviceConfig &config, const EspectreDeviceInfo &info, const char *frontend_name)
```
Build the discovery topics and ids for this device; the model is `ESPectre <frontend_name>`.
<a id="namespaceespectre_1a5114c22b690a7c5684ade9d26b0294f4"></a>
### `build_frontend_ha_discovery_message`
```cpp
bool espectre::build_frontend_ha_discovery_message(const FrontendHaMqttSettings &settings, const EspectreDeviceInfo &info, bool supports_detector, bool supports_motion_hits, bool supports_traffic_control, size_t index, FrontendHaDiscoveryMessage *message)
```
Build one discovery message in publication order; false marks the end.
<a id="namespaceespectre_1ac317e956257fb2f5f6171e5fe42affd6"></a>
### `build_frontend_ha_discovery_messages`
```cpp
std::vector< FrontendHaDiscoveryMessage > espectre::build_frontend_ha_discovery_messages(const FrontendHaMqttSettings &settings, const EspectreDeviceInfo &info, bool supports_detector, bool supports_motion_hits, bool supports_traffic_control)
```
Build every discovery message at once, in publication order.
<a id="namespaceespectre_1a859fb9c76658edbda893921726ab1f0b"></a>
### `setup_frontend_mqtt_transport`
```cpp
bool espectre::setup_frontend_mqtt_transport(IMqttTransport *transport, const EspectreDeviceConfig &config, IMqttTransport::CommandCallback command_callback, FrontendMqttConnectedCallback connected_callback, const char *log_tag)
```
Configure `transport` for the device and start connecting.
Shuts the transport down and returns false when `config` has no complete MQTT endpoint. Otherwise installs the callbacks and returns the result of [IMqttTransport::setup()](#classespectre_1_1_i_mqtt_transport_1ac7f78bbd532a797bf6b53e26d005269c).
<a id="namespaceespectre_1a9f78ca0c75864d0212dc31b334b63e74"></a>
### `publish_frontend_mqtt_message`
```cpp
bool espectre::publish_frontend_mqtt_message(IMqttTransport *transport, const char *suffix, const std::string &payload, bool retain)
```
Publish under the device topic prefix; false while disconnected.
The prefix comes from the configuration passed to [IMqttTransport::setup()](#classespectre_1_1_i_mqtt_transport_1ac7f78bbd532a797bf6b53e26d005269c).
<a id="namespaceespectre_1a07966aaab03a7ae12577400864e36b30"></a>
### `publish_frontend_mqtt_status`
```cpp
bool espectre::publish_frontend_mqtt_status(IMqttTransport *transport, const EspectreDeviceConfig &config, bool online, uint32_t timestamp_ms)
```
Publish the retained `health` availability message.
<a id="namespaceespectre_1a09e7fae5dc31f12962e6537107073fad"></a>
### `publish_frontend_mqtt_command_result`
```cpp
bool espectre::publish_frontend_mqtt_command_result(IMqttTransport *transport, const EspectreDeviceConfig &config, const FrontendCommandResult &result)
```
Publish a command result on `commands/result`.
<a id="namespaceespectre_1aa9d1ab4fa6250571247a25c88d68acf7"></a>
### `nvs_init_with_erase_fallback`
```cpp
esp_err_t espectre::nvs_init_with_erase_fallback()
```
Initialize NVS, erasing it and retrying once when the partition has no free pages or holds data from a newer format version.
The erase discards every saved setting, including Wi-Fi credentials.
**Returns:** The result of the final `nvs_flash_init()`, or the erase error.
<a id="namespaceespectre_1a2a3712a02c829f91e0da24cf3eec56a6"></a>
### `apply_wifi_bssid_pin`
```cpp
bool espectre::apply_wifi_bssid_pin(const std::string &bssid, std::string *message, bool *station_transition_started=nullptr)
```
Apply or clear the ESP-IDF station BSSID pin through a Wi-Fi state-machine restart.
<a id="namespaceespectre_1a3d748e9f1b0d5dbe5388efb97e13569d"></a>
### `to_csi_traffic_config`
```cpp
CsiTrafficServiceConfig espectre::to_csi_traffic_config(const RuntimeConfig &config)
```
Project runtime configuration onto transport-independent CSI traffic policy.
<a id="namespaceespectre_1af3215fab6f83ede00987d248b8399c94"></a>
### `wifi_band_policy_is_supported`
```cpp
constexpr bool espectre::wifi_band_policy_is_supported(WifiBandPolicy policy)
```
Return whether this build can honor the requested band policy.
`AUTO` uses the bands the radio has, so it is valid everywhere and means 2.4 GHz on single-band targets. `BAND_5G` needs dual-band silicon.
<a id="namespaceespectre_1a964290548f98cd616789767c4f34b690"></a>
### `wifi_channel_matches_band_policy`
```cpp
constexpr bool espectre::wifi_channel_matches_band_policy(int channel, WifiBandPolicy policy)
```
Return whether a channel hint is compatible with the requested band.
<a id="namespaceespectre_1ae7131ef838a5d0f599a6e4dbcda5830c"></a>
### `wifi_channel_is_supported`
```cpp
constexpr bool espectre::wifi_channel_is_supported(int channel)
```
Report whether an optional channel hint is usable on this build.
2.4 GHz channels are contiguous; the 5 GHz channel numbers are the 20 MHz centers of the UNII bands, which are spaced four channels apart from 36 and from 149. Passing a 5 GHz channel a 2.4 GHz-only radio cannot tune would fail silently at association time, so those numbers are rejected there.
**Parameters**
- `channel`: Channel number, or WIFI\_CHANNEL\_AUTO for no hint
**Returns:** true when the channel can be configured on this build
<a id="namespaceespectre_1a106a2c32bc0d816e1221218b7b0c0d94"></a>
### `wifi_channel_supported_description`
```cpp
const char * espectre::wifi_channel_supported_description()
```
Describe the accepted channel hint values for operator-facing errors.
**Returns:** A short human-readable range description
<a id="namespaceespectre_1ac6f0a44c679e44a001705073485c13f4"></a>
### `wifi_channel_supported_description`
```cpp
const char * espectre::wifi_channel_supported_description(WifiBandPolicy policy)
```
Like [wifi\_channel\_supported\_description()](#namespaceespectre_1a106a2c32bc0d816e1221218b7b0c0d94), limited to the channels `policy` allows.
<a id="namespaceespectre_1a6df158d98f79adc5e2759b133ecf52e8"></a>
### `wifi_provisioning_apply_state_name`
```cpp
const char * espectre::wifi_provisioning_apply_state_name(WifiProvisioningApplyState state)
```
Protocol name of an apply state, such as `verifying` or `rolled_back`.
<a id="namespaceespectre_1a401a56fc8d13271aa575ac137e41dd93"></a>
### `log_espectre_banner`
```cpp
template <typename Logger>
void espectre::log_espectre_banner(Logger &&log_line)
```
Emit the logo through `log_line`, one call per line, framed by empty lines.
<a id="namespaceespectre_1ad29105f65f58304d2b72dfec2a198393"></a>
### `frontend_command_parse_error_code`
```cpp
const char * espectre::frontend_command_parse_error_code(const std::string &error)
```
Map a canonical command parse failure to its stable result code.
<a id="namespaceespectre_1af1ba3349774c2074ec11664168dc616f"></a>
### `operator|`
```cpp
FrontendCommandChange espectre::operator|(FrontendCommandChange lhs, FrontendCommandChange rhs)
```
Combine change flags.
<a id="namespaceespectre_1abf3a6449bc675492ac72bdb143df9948"></a>
### `frontend_command_allowed_during_raw_collection`
```cpp
bool espectre::frontend_command_allowed_during_raw_collection(const std::string &command, const EspectreProtocolExtension *extension=nullptr)
```
Whether a command may run while raw CSI collection is active.
Reads and configuration commands that do not touch sensing are allowed; extension routes declare their own policy.
<a id="namespaceespectre_1a4bebef550879193c62fbeba6f47cee5a"></a>
### `validate_peer_discovery_candidates`
```cpp
PeerDiscoverySnapshot espectre::validate_peer_discovery_candidates(const std::vector< PeerDiscoveryCandidate > &candidates, uint32_t station_address, uint32_t station_netmask, uint32_t elapsed_ms, bool timed_out)
```
Validate, deduplicate, sort, and bound one discovery result.
Keeps only addresses on the station's subnet, merges results that share a device id and endpoint, and rejects device ids advertised by conflicting endpoints. Addresses are in network byte order.
<a id="namespaceespectre_1a70a8d3f60a08466d66856679d67ad911"></a>
### `peer_discovery_snapshot_json`
```cpp
std::string espectre::peer_discovery_snapshot_json(const PeerDiscoverySnapshot &snapshot)
```
Serialize a snapshot as the `devices` resource.
Stays within [`ESPECTRE_PEER_DISCOVERY_MAX_RESULT_SIZE`](#namespaceespectre_1a0ab265cc384a2f5d3c4b58f335984291), dropping devices and marking the result truncated when needed.
<a id="namespaceespectre_1a371a57d18d999de733c9e7cfa628c6c0"></a>
### `monotonic_now_us`
```cpp
uint64_t espectre::monotonic_now_us()
```
Monotonic time since boot in microseconds: `esp_timer` on ESP-IDF, `steady_clock` on hosts.
<a id="namespaceespectre_1a74347339c609120224a1110d79205927"></a>
### `monotonic_now_ms`
```cpp
uint32_t espectre::monotonic_now_ms()
```
[monotonic\_now\_us()](#namespaceespectre_1a371a57d18d999de733c9e7cfa628c6c0) in milliseconds, wrapping modulo 2^32.
<a id="namespaceespectre_1_1task__scheduling"></a>
## espectre::task\_scheduling
FreeRTOS priorities of the tasks ESPectre services create, resolved from the `Advanced task scheduling` menu.
See the integration guide for the policy.
<a id="namespaceespectre_1_1task__scheduling_1aa4d1b82dcd846f10a6788c92d721c631"></a>
### `kDirectHttpdPriority`
```cpp
constexpr uint32_t espectre::task_scheduling::kDirectHttpdPriority =
CONFIG_ESPECTRE_DIRECT_HTTPD_TASK_PRIORITY
```
Direct HTTP server task.
<a id="namespaceespectre_1_1task__scheduling_1a7ab02a1007eac7ec5986596a9da76ef6"></a>
### `kDirectWorkerPriority`
```cpp
constexpr uint32_t espectre::task_scheduling::kDirectWorkerPriority =
CONFIG_ESPECTRE_DIRECT_WORKER_TASK_PRIORITY
```
Direct response and event delivery task.
<a id="namespaceespectre_1_1task__scheduling_1a9161d912c84e540b1a25df4ec85fcdd5"></a>
### `kRawWorkerPriority`
```cpp
constexpr uint32_t espectre::task_scheduling::kRawWorkerPriority =
CONFIG_ESPECTRE_RAW_WORKER_TASK_PRIORITY
```
Raw CSI delivery task.
<a id="namespaceespectre_1_1task__scheduling_1aeb066e2810db7b56cf4a6b62d7296998"></a>
### `kTrafficPriority`
```cpp
constexpr uint32_t espectre::task_scheduling::kTrafficPriority = CONFIG_ESPECTRE_TRAFFIC_TASK_PRIORITY
```
Managed traffic generator task.
<a id="classespectre_1_1_base_detector"></a>
## espectre::BaseDetector
```cpp
#include <core/base_detector.h>
```
```cpp
class espectre::BaseDetector
```
Abstract base class for motion detection algorithms.
Provides shared functionality:
- Turbulence buffer management (circular buffer)
- Hampel and low-pass filtering
- CSI processing and spatial turbulence calculation
Subclasses must implement:
- [update\_state()](#classespectre_1_1_base_detector_1a261ca504b8a5fb2e915c6354f3e9ddf6): detection algorithm logic; it assigns [`current_metric_`](#classespectre_1_1_base_detector_1ac744d80062fb6c9fcf64d122e2865362), which [get\_motion\_metric()](#classespectre_1_1_base_detector_1ab7ea59db54d734cc87815e0a7aebd972) returns
- [get\_threshold()](#classespectre_1_1_base_detector_1ab1b2a5a33a086a50783cc158f56a6b8c) / [set\_threshold()](#classespectre_1_1_base_detector_1a9614847f36f3a391ff2df8e0f77fc1da): threshold management
- [get\_name()](#classespectre_1_1_base_detector_1af1a3b2c9adb5ad7b550acfd7230a1503): detector name for logging
<a id="classespectre_1_1_base_detector_1a704e1cd629bbfa076f09ff78f8589449"></a>
### `turbulence_buffer_`
```cpp
float* espectre::BaseDetector::turbulence_buffer_
```
Circular buffer of filtered turbulence, [`window_size_`](#classespectre_1_1_base_detector_1a531deb4e201dd7315f89a77144c0cb66) entries.
<a id="classespectre_1_1_base_detector_1a803bf375787e80593d21eae6c86cdca1"></a>
### `ordered_turbulence_`
```cpp
float* espectre::BaseDetector::ordered_turbulence_
```
Scratch buffer behind [ordered\_turbulence()](#classespectre_1_1_base_detector_1a2d514487a053702a159e0d3435007450).
<a id="classespectre_1_1_base_detector_1a111ed542d50cc07a7d19b7d4c723d605"></a>
### `buffer_index_`
```cpp
uint16_t espectre::BaseDetector::buffer_index_
```
Next write position in [`turbulence_buffer_`](#classespectre_1_1_base_detector_1a704e1cd629bbfa076f09ff78f8589449).
<a id="classespectre_1_1_base_detector_1a5dfe97b27a2071b41ba5522df54d1d74"></a>
### `buffer_count_`
```cpp
uint16_t espectre::BaseDetector::buffer_count_
```
See [get\_buffer\_count()](#classespectre_1_1_base_detector_1a01a376fa621d31e9e122686aa1f58c1e).
<a id="classespectre_1_1_base_detector_1ab6a65687542789b85ea50d08f8889411"></a>
### `valid_buffer_count_`
```cpp
uint16_t espectre::BaseDetector::valid_buffer_count_
```
See [get\_valid\_buffer\_count()](#classespectre_1_1_base_detector_1a836410ad2d0b965fe812c249b1756a7a).
<a id="classespectre_1_1_base_detector_1a6390a37f6eab391953b2902ccad28e19"></a>
### `minimum_valid_samples_`
```cpp
uint16_t espectre::BaseDetector::minimum_valid_samples_
```
See [set\_minimum\_valid\_samples()](#classespectre_1_1_base_detector_1a9732e34f845a2eb619ac9f42e1096353).
<a id="classespectre_1_1_base_detector_1a531deb4e201dd7315f89a77144c0cb66"></a>
### `window_size_`
```cpp
uint16_t espectre::BaseDetector::window_size_
```
<a id="classespectre_1_1_base_detector_1a7c807d680f10bfd7c6956812b7413749"></a>
### `state_`
```cpp
MotionState espectre::BaseDetector::state_
```
State reported by [get\_state()](#classespectre_1_1_base_detector_1a8aa4a67f587b5e575346e3bf529f96f2); [clear\_evaluation\_state\_()](#classespectre_1_1_base_detector_1ad4b8b59d9e7d07dc689450a5c28a5f75) resets it.
<a id="classespectre_1_1_base_detector_1ac744d80062fb6c9fcf64d122e2865362"></a>
### `current_metric_`
```cpp
float espectre::BaseDetector::current_metric_
```
Metric reported by [get\_motion\_metric()](#classespectre_1_1_base_detector_1ab7ea59db54d734cc87815e0a7aebd972) and published by the runtime.
Subclasses assign it at the end of [update\_state()](#classespectre_1_1_base_detector_1a261ca504b8a5fb2e915c6354f3e9ddf6).
<a id="classespectre_1_1_base_detector_1a39ecf887d2f955fe53c2efdede92915b"></a>
### `total_packets_`
```cpp
uint32_t espectre::BaseDetector::total_packets_
```
Packets processed since the last [reset()](#classespectre_1_1_base_detector_1afeafa0d2e142db2f73eff87230164288).
<a id="classespectre_1_1_base_detector_1a71cfdb211ee4311aee2347e61b00d941"></a>
### `packet_timestamp_us_`
```cpp
uint64_t espectre::BaseDetector::packet_timestamp_us_
```
See [packet\_timestamp\_us\_or()](#classespectre_1_1_base_detector_1a8ad0a3fdd14591477ebd01681e0ce84b).
<a id="classespectre_1_1_base_detector_1ac627c02075ead3e632d29811dc4e3c20"></a>
### `has_packet_timestamp_`
```cpp
bool espectre::BaseDetector::has_packet_timestamp_
```
<a id="classespectre_1_1_base_detector_1ad8976c91d321a26c1a35ff75eb5bbeb6"></a>
### `hampel_state_`
```cpp
hampel_filter_state_t espectre::BaseDetector::hampel_state_
```
Hampel filter applied before the ring.
<a id="classespectre_1_1_base_detector_1a82b7aac2d9a18c7403a64556b64f23c6"></a>
### `lowpass_state_`
```cpp
lowpass_filter_state_t espectre::BaseDetector::lowpass_state_
```
Low-pass filter applied before the ring.
<a id="classespectre_1_1_base_detector_1ac70f1692bdd644c0589f426d8267b681"></a>
### `BaseDetector`
```cpp
explicit espectre::BaseDetector::BaseDetector(uint16_t window_size=DETECTOR_DEFAULT_WINDOW_SIZE)
```
Constructor.
**Parameters**
- `window_size`: Buffer window size in the inclusive range defined by DETECTOR\_MIN\_WINDOW\_SIZE and DETECTOR\_MAX\_WINDOW\_SIZE
<a id="classespectre_1_1_base_detector_1a2062504291217a724134d103d8a73d59"></a>
### `~BaseDetector`
```cpp
virtual espectre::BaseDetector::~BaseDetector()
```
<a id="classespectre_1_1_base_detector_1a5d2806fada882285a9b8fa8848179238"></a>
### `BaseDetector`
```cpp
espectre::BaseDetector::BaseDetector(BaseDetector &&other) noexcept
```
<a id="classespectre_1_1_base_detector_1a565d9425c07877ff82b9950feb65a429"></a>
### `operator=`
```cpp
BaseDetector & espectre::BaseDetector::operator=(BaseDetector &&other) noexcept
```
<a id="classespectre_1_1_base_detector_1a2602479812119dada1826c3d996520de"></a>
### `BaseDetector`
```cpp
espectre::BaseDetector::BaseDetector(const BaseDetector &)=delete
```
<a id="classespectre_1_1_base_detector_1a25933318888d59fa2cfa90ac594fb0c8"></a>
### `operator=`
```cpp
BaseDetector & espectre::BaseDetector::operator=(const BaseDetector &)=delete
```
<a id="classespectre_1_1_base_detector_1a121de67ca4480d53819bd6fb45bc7253"></a>
### `process_packet`
```cpp
virtual void espectre::BaseDetector::process_packet(const int8_t *csi_data, size_t csi_len, const uint8_t *selected_subcarriers=nullptr, uint8_t num_subcarriers=0, int8_t rssi_dbm=INT8_MIN)
```
Process one normalized, temporally admitted CSI packet.
Calculates spatial turbulence from CSI data, applies filtering, and stores in circular buffer.
**Parameters**
- `csi_data`: Normalized CSI data (I/Q interleaved)
- `csi_len`: Length of CSI data
- `selected_subcarriers`: Array of subcarrier indices
- `num_subcarriers`: Number of selected subcarriers
- `rssi_dbm`: Link RSSI for this packet, or INT8\_MIN when unknown
<a id="classespectre_1_1_base_detector_1ad432493bba41a1951f7d2ee2e7666a4d"></a>
### `set_packet_timestamp_us`
```cpp
void espectre::BaseDetector::set_packet_timestamp_us(uint64_t timestamp_us)
```
Supply the monotonic arrival timestamp consumed by time-binned features.
<a id="classespectre_1_1_base_detector_1afeafa0d2e142db2f73eff87230164288"></a>
### `reset`
```cpp
virtual void espectre::BaseDetector::reset()
```
Reset detector state.
Resets state machine but preserves buffer ("warm" restart).
<a id="classespectre_1_1_base_detector_1a8aa4a67f587b5e575346e3bf529f96f2"></a>
### `get_state`
```cpp
virtual MotionState espectre::BaseDetector::get_state() const
```
Get current motion state.
<a id="classespectre_1_1_base_detector_1a474ff45b6a2ef2cb061f86603e76d475"></a>
### `is_valid`
```cpp
virtual bool espectre::BaseDetector::is_valid() const
```
Return whether all base detector working storage was allocated.
<a id="classespectre_1_1_base_detector_1a909126a7761b02f5f58c19103cd91053"></a>
### `is_ready`
```cpp
virtual bool espectre::BaseDetector::is_ready() const
```
Check if detector is ready.
Ready once the window has filled and its valid slots reach the floor set by [set\_minimum\_valid\_samples()](#classespectre_1_1_base_detector_1a9732e34f845a2eb619ac9f42e1096353).
<a id="classespectre_1_1_base_detector_1a5e047ba665b25faf9e5088df58302f50"></a>
### `advance_missing_slots`
```cpp
virtual void espectre::BaseDetector::advance_missing_slots(uint32_t count)
```
Advance packet-indexed feature rings for absent temporal slots.
<a id="classespectre_1_1_base_detector_1a9732e34f845a2eb619ac9f42e1096353"></a>
### `set_minimum_valid_samples`
```cpp
void espectre::BaseDetector::set_minimum_valid_samples(uint16_t count)
```
Set the valid-slot occupancy floor used by [`is_ready()`](#classespectre_1_1_base_detector_1a909126a7761b02f5f58c19103cd91053).
<a id="classespectre_1_1_base_detector_1a4ca1de3311c1895fbaa1295e7c8ec9ec"></a>
### `get_total_packets`
```cpp
virtual uint32_t espectre::BaseDetector::get_total_packets() const
```
Get total packets processed.
<a id="classespectre_1_1_base_detector_1a261ca504b8a5fb2e915c6354f3e9ddf6"></a>
### `update_state`
```cpp
virtual void espectre::BaseDetector::update_state()=0
```
Update state machine (call at the detector evaluation interval).
Subclasses implement their detection algorithm here.
<a id="classespectre_1_1_base_detector_1ab7ea59db54d734cc87815e0a7aebd972"></a>
### `get_motion_metric`
```cpp
float espectre::BaseDetector::get_motion_metric() const
```
Get current motion metric value.
Subclasses assign [`current_metric_`](#classespectre_1_1_base_detector_1ac744d80062fb6c9fcf64d122e2865362) at the end of their [`update_state()`](#classespectre_1_1_base_detector_1a261ca504b8a5fb2e915c6354f3e9ddf6).
**Returns:** Primary metric, on the detector's 0..1 probability scale
<a id="classespectre_1_1_base_detector_1a9614847f36f3a391ff2df8e0f77fc1da"></a>
### `set_threshold`
```cpp
virtual bool espectre::BaseDetector::set_threshold(float threshold)=0
```
Set detection threshold.
**Parameters**
- `threshold`: New threshold value
**Returns:** true if value was accepted
<a id="classespectre_1_1_base_detector_1a6badc6950f8328f4bd77ff50ea47fee4"></a>
### `set_adaptive_threshold`
```cpp
virtual bool espectre::BaseDetector::set_adaptive_threshold(float threshold)
```
Apply a detector-specific startup-calibrated threshold.
<a id="classespectre_1_1_base_detector_1ab1b2a5a33a086a50783cc158f56a6b8c"></a>
### `get_threshold`
```cpp
virtual float espectre::BaseDetector::get_threshold() const =0
```
Get current threshold.
<a id="classespectre_1_1_base_detector_1af1a3b2c9adb5ad7b550acfd7230a1503"></a>
### `get_name`
```cpp
virtual const char * espectre::BaseDetector::get_name() const =0
```
Get detector name for logging.
<a id="classespectre_1_1_base_detector_1ab3ff821066a78493f9f91dda37001310"></a>
### `get_startup_threshold_factor`
```cpp
virtual float espectre::BaseDetector::get_startup_threshold_factor() const
```
Get the detector-specific automatic startup multiplier.
threshold = threshold\_metric x factor, where `threshold_metric` comes from the shared startup calibrator.
<a id="classespectre_1_1_base_detector_1ad476a9ddaeda232d21c7b85b8323f482"></a>
### `startup_gate_enabled`
```cpp
virtual bool espectre::BaseDetector::startup_gate_enabled() const
```
Whether startup calibration uses the calibrator's consistency gate.
The gate can end a calibration early on a quiet, motion, quiet pattern. No shipped detector enables it.
<a id="classespectre_1_1_base_detector_1ab7d3688dc470cfcf828d247d16baf990"></a>
### `startup_calibration_conclusive`
```cpp
virtual bool espectre::BaseDetector::startup_calibration_conclusive() const
```
Whether the calibration evidence collected so far can set a threshold.
The runtime asks each time the calibration budget is spent. While the answer is false, the calibration continues in steps of half its initial budget, up to three times that budget. The default always concludes.
<a id="classespectre_1_1_base_detector_1af95777f1e1d327c1e73fd077d4559949"></a>
### `calibration_motion_ceiling`
```cpp
virtual float espectre::BaseDetector::calibration_motion_ceiling() const
```
Motion metric above which a calibration evaluation counts as motion.
An evaluation above it restarts the calibration window. A recalibration under the setup of the last successful calibration also restarts above the live threshold when that is lower. The default, infinity, leaves calibration without an absolute reference.
<a id="classespectre_1_1_base_detector_1a23b1db60d0ab0f31516e345f571fa01c"></a>
### `on_startup_calibration_begin`
```cpp
virtual void espectre::BaseDetector::on_startup_calibration_begin()
```
Hook called immediately before startup calibration begins.
<a id="classespectre_1_1_base_detector_1af003e89702b0e5bd97028e0b5ce4591b"></a>
### `on_startup_calibration_complete`
```cpp
virtual void espectre::BaseDetector::on_startup_calibration_complete()
```
Hook called when startup calibration completes successfully.
Detectors can freeze session-specific state here before the runtime performs its warm clear between calibration and steady-state detection.
<a id="classespectre_1_1_base_detector_1a2fd7526029ee8acb74e713e70a1af750"></a>
### `on_startup_calibration_abandoned`
```cpp
virtual void espectre::BaseDetector::on_startup_calibration_abandoned()
```
Hook called when a calibration ends without a result.
The runtime keeps the threshold in force before the calibration began. Detectors discard the evidence collected since [on\_startup\_calibration\_begin()](#classespectre_1_1_base_detector_1a23b1db60d0ab0f31516e345f571fa01c) and resume the adaptation they had, or start adapting the threshold in force if no calibration has completed.
<a id="classespectre_1_1_base_detector_1a62329885a69c9b2bdadfb0635f171d61"></a>
### `configure_lowpass`
```cpp
virtual void espectre::BaseDetector::configure_lowpass(bool enabled, float cutoff_hz=LOWPASS_CUTOFF_DEFAULT)
```
Configure low-pass filter.
**Parameters**
- `enabled`: Whether to enable the filter
- `cutoff_hz`: Cutoff frequency (5.0-20.0 Hz)
<a id="classespectre_1_1_base_detector_1aa1401e5000e0a766275dfa0e37e10fb4"></a>
### `configure_hampel`
```cpp
virtual void espectre::BaseDetector::configure_hampel(bool enabled, uint8_t window_size=HAMPEL_TURBULENCE_WINDOW_DEFAULT, float threshold=HAMPEL_TURBULENCE_THRESHOLD_DEFAULT)
```
Configure Hampel filter.
**Parameters**
- `enabled`: Whether to enable the filter
- `window_size`: Window size (3-11)
- `threshold`: MAD multiplier threshold
<a id="classespectre_1_1_base_detector_1a80285cefc4541552ee897557e8339da2"></a>
### `clear_buffer`
```cpp
virtual void espectre::BaseDetector::clear_buffer()
```
Clear turbulence buffer (cold restart).
Virtual so detectors with additional state (e.g. L1-Delta profile rings) can extend the cold clear.
<a id="classespectre_1_1_base_detector_1aaf32952ebf0ad274b164f9595d6ae491"></a>
### `get_turbulence_buffer`
```cpp
const float * espectre::BaseDetector::get_turbulence_buffer() const
```
Get turbulence buffer pointer.
<a id="classespectre_1_1_base_detector_1a01a376fa621d31e9e122686aa1f58c1e"></a>
### `get_buffer_count`
```cpp
uint16_t espectre::BaseDetector::get_buffer_count() const
```
Get number of window slots filled, including missing slots.
<a id="classespectre_1_1_base_detector_1a836410ad2d0b965fe812c249b1756a7a"></a>
### `get_valid_buffer_count`
```cpp
uint16_t espectre::BaseDetector::get_valid_buffer_count() const
```
Get number of filled window slots that hold a measured sample.
<a id="classespectre_1_1_base_detector_1a76ad118e4803e800bac0df5870dbfbd4"></a>
### `get_window_size`
```cpp
uint16_t espectre::BaseDetector::get_window_size() const
```
Get configured window size.
<a id="classespectre_1_1_base_detector_1ad9b1e80293dbaf06f2ef18d56401ccef"></a>
### `get_last_turbulence`
```cpp
float espectre::BaseDetector::get_last_turbulence() const
```
Get last turbulence value.
<a id="classespectre_1_1_base_detector_1aa7baf15ce9ba07d078f09a8566f4e326"></a>
### `is_lowpass_enabled`
```cpp
bool espectre::BaseDetector::is_lowpass_enabled() const
```
Check if low-pass filter is enabled.
<a id="classespectre_1_1_base_detector_1ab9793996d7abbf858af925cd2f2fb725"></a>
### `is_hampel_enabled`
```cpp
bool espectre::BaseDetector::is_hampel_enabled() const
```
Check if Hampel filter is enabled.
<a id="classespectre_1_1_base_detector_1ad4b8b59d9e7d07dc689450a5c28a5f75"></a>
### `clear_evaluation_state_`
```cpp
void espectre::BaseDetector::clear_evaluation_state_()
```
Drop the last evaluation result.
Anything that invalidates the window must also invalidate what was derived from it, or the next publish ships a metric computed from samples the detector no longer holds.
<a id="classespectre_1_1_base_detector_1ad05573f50021c0404ed629f1500f304e"></a>
### `process_amplitudes`
```cpp
void espectre::BaseDetector::process_amplitudes(const float *amplitudes, uint8_t count)
```
Add the spatial turbulence of one amplitude frame to the ring.
<a id="classespectre_1_1_base_detector_1a8ad0a3fdd14591477ebd01681e0ce84b"></a>
### `packet_timestamp_us_or`
```cpp
uint64_t espectre::BaseDetector::packet_timestamp_us_or(uint64_t fallback) const
```
Timestamp set by [set\_packet\_timestamp\_us()](#classespectre_1_1_base_detector_1ad432493bba41a1951f7d2ee2e7666a4d) for this packet, or `fallback`.
<a id="classespectre_1_1_base_detector_1a93b91a3da1f77896a922e0a50efc9d77"></a>
### `add_turbulence_to_buffer`
```cpp
void espectre::BaseDetector::add_turbulence_to_buffer(float turbulence)
```
Add turbulence value to buffer (with filtering).
<a id="classespectre_1_1_base_detector_1a2d514487a053702a159e0d3435007450"></a>
### `ordered_turbulence`
```cpp
const float * espectre::BaseDetector::ordered_turbulence(uint16_t &count) const
```
View the turbulence ring in chronological order.
Returns the ring itself while it is still filling (already in order), and the base-owned reorder buffer once it wraps. Returns nullptr when there is nothing to read or the reorder buffer could not be allocated.
**Parameters**
- `count`: Receives the number of valid samples
<a id="classespectre_1_1_base_detector_1a1697649add47e9e80ebd4e29a50a795a"></a>
### `alloc_zeroed_floats`
```cpp
static float * espectre::BaseDetector::alloc_zeroed_floats(uint16_t count)
```
Allocate a zeroed float buffer on the heap.
Shared by the detectors so no feature helper puts a window-sized array on the CSI callback stack.
**Returns:** nullptr when count is 0 or the allocation fails
<a id="classespectre_1_1_csi_traffic_service"></a>
## espectre::CsiTrafficService
```cpp
#include <runtime/csi_traffic_service.h>
```
```cpp
class espectre::CsiTrafficService
```
Keeps CSI-bearing traffic flowing in the configured mode.
Internal modes drive the generator; `EXTERNAL` drives the listener, which accepts the ESPectre traffic marker. The full runtime owns one of these; firmware that captures CSI itself can use it directly.
**Par:** Threading
Call every method from one owner task, including [loop()](#classespectre_1_1_csi_traffic_service_1a5460f876c4d4c3d67cb964f87bfc49fe).
<a id="classespectre_1_1_csi_traffic_service_1ac9e4fa69ec1c128db3a3be5a80d13499"></a>
### `CsiTrafficService`
```cpp
espectre::CsiTrafficService::CsiTrafficService(ICsiTrafficGenerator &traffic_generator, ICsiTrafficIngress &traffic_ingress)
```
Bind the generator and listener.
Neither is owned; both must outlive the service.
<a id="classespectre_1_1_csi_traffic_service_1a2463a9630c708756b78379f60e4304d5"></a>
### `init`
```cpp
void espectre::CsiTrafficService::init(const CsiTrafficServiceConfig &config)
```
Configure the mode, rate, and listener while stopped.
<a id="classespectre_1_1_csi_traffic_service_1a055f139cc1504b5a9ea8d095b4c030da"></a>
### `start`
```cpp
bool espectre::CsiTrafficService::start(uint32_t target_addr=0U)
```
Start the source for the configured mode; a running source is left as is.
`target_addr` is the internal generator's IPv4 destination in network byte order, ignored in `EXTERNAL` mode. Returns false when the source fails to start.
<a id="classespectre_1_1_csi_traffic_service_1ac059347bfc8b0aea38d2501c18cc87f3"></a>
### `stop`
```cpp
void espectre::CsiTrafficService::stop()
```
Stop the generator and the listener.
<a id="classespectre_1_1_csi_traffic_service_1a229071da7ca53e6db7e3487c1c9624b5"></a>
### `hold_pending_restart`
```cpp
void espectre::CsiTrafficService::hold_pending_restart(bool hold)
```
Forward [hold\_pending\_restart()](#classespectre_1_1_csi_traffic_service_1a229071da7ca53e6db7e3487c1c9624b5) to the generator.
<a id="classespectre_1_1_csi_traffic_service_1a5460f876c4d4c3d67cb964f87bfc49fe"></a>
### `loop`
```cpp
void espectre::CsiTrafficService::loop()
```
Advance the running source, and let a stopped generator finish its stop.
<a id="classespectre_1_1_csi_traffic_service_1acc1994d066d676521b378a7afea9928a"></a>
### `set_packet_callback`
```cpp
void espectre::CsiTrafficService::set_packet_callback(csi_traffic_packet_callback_t callback, void *context=nullptr)
```
Register the callback for accepted external packets.
<a id="classespectre_1_1_csi_traffic_service_1a9d1a8fb3968bd5e33d9c337d318670b4"></a>
### `is_running`
```cpp
bool espectre::CsiTrafficService::is_running() const
```
Whether the source for the configured mode is running.
<a id="classespectre_1_1_csi_traffic_service_1acae25f669992dd6b02993c755607acc6"></a>
### `is_quiescent`
```cpp
bool espectre::CsiTrafficService::is_quiescent() const
```
True when the generator is not inside a send.
<a id="classespectre_1_1_csi_traffic_service_1ad21ff12464ad87f9555054431802f16b"></a>
### `generator_is_stopping`
```cpp
bool espectre::CsiTrafficService::generator_is_stopping() const
```
True between a generator [stop()](#classespectre_1_1_csi_traffic_service_1ac059347bfc8b0aea38d2501c18cc87f3) and the exit of its sender.
<a id="classespectre_1_1_csi_traffic_service_1a7fbcf65d3a0f75ee28e478bc72369945"></a>
### `source_is_active`
```cpp
bool espectre::CsiTrafficService::source_is_active() const
```
True when the configured source has a live sender, not only a deferred start.
<a id="classespectre_1_1_csi_traffic_service_1ae7b29d5f0b703327ef708a6f01943d03"></a>
### `consume_generator_start_failure`
```cpp
bool espectre::CsiTrafficService::consume_generator_start_failure()
```
True once, after a deferred generator launch fails.
<a id="classespectre_1_1_csi_traffic_service_1ae918ac7a6266ba280295b2fb26ca5b5e"></a>
### `consume_generator_stop_timeout`
```cpp
bool espectre::CsiTrafficService::consume_generator_stop_timeout()
```
True once, after a stopped generator has not exited within its grace period.
<a id="classespectre_1_1_csi_traffic_service_1adeaf0bf26e4ca70025b4039c5ea6b00b"></a>
### `get_last_sender`
```cpp
bool espectre::CsiTrafficService::get_last_sender(UdpDatagramPeer *out_peer) const
```
Sender of the latest accepted external packet; false before the first one.
<a id="classespectre_1_1_csi_traffic_service_1ae9898ad9c4e5fc4ce168ac6fc27b851e"></a>
### `get_packets_received`
```cpp
uint64_t espectre::CsiTrafficService::get_packets_received() const
```
Accepted external packets since [init()](#classespectre_1_1_csi_traffic_service_1a2463a9630c708756b78379f60e4304d5).
<a id="classespectre_1_1_csi_traffic_service_1a8d04f3ce450e6dae24e9586ca1a0e5f5"></a>
### `get_generator_packets_total`
```cpp
uint32_t espectre::CsiTrafficService::get_generator_packets_total() const
```
Successful internal generator sends; zero in external mode.
<a id="classespectre_1_1_csi_traffic_service_1a66bc64c398ab10a4921ccc6a4f0403de"></a>
### `internal_icmp_identifier`
```cpp
uint16_t espectre::CsiTrafficService::internal_icmp_identifier() const
```
ICMP identifier of the internal ping traffic.
<a id="classespectre_1_1_csi_traffic_service_1acf8e9d5ff43fdcf137613571f0a2c868"></a>
### `mode`
```cpp
TrafficGeneratorMode espectre::CsiTrafficService::mode() const
```
Mode set by the last [init()](#classespectre_1_1_csi_traffic_service_1a2463a9630c708756b78379f60e4304d5).
<a id="structespectre_1_1_csi_traffic_service_config"></a>
## espectre::CsiTrafficServiceConfig
```cpp
#include <runtime/csi_traffic_service.h>
```
```cpp
struct espectre::CsiTrafficServiceConfig
```
Traffic policy for [CsiTrafficService](#classespectre_1_1_csi_traffic_service); build it with [to\_csi\_traffic\_config()](#namespaceespectre_1a3d748e9f1b0d5dbe5388efb97e13569d).
<a id="structespectre_1_1_csi_traffic_service_config_1a9c1cdc17665c3549f07c3c5bb68cb06d"></a>
### `mode`
```cpp
TrafficGeneratorMode espectre::CsiTrafficServiceConfig::mode {TrafficGeneratorMode::PING}
```
Internal generator mode, or `EXTERNAL` to listen for another host.
<a id="structespectre_1_1_csi_traffic_service_config_1a50268f115b693da1cb0fa47cab4f6a40"></a>
### `rate_pps`
```cpp
uint32_t espectre::CsiTrafficServiceConfig::rate_pps {100U}
```
Internal generator send rate, in packets per second.
<a id="structespectre_1_1_csi_traffic_service_config_1af04a97ecbce02d1d10d0c4e31d337a42"></a>
### `udp_port`
```cpp
uint16_t espectre::CsiTrafficServiceConfig::udp_port {5555U}
```
UDP port the external listener binds.
<a id="structespectre_1_1_csi_traffic_service_config_1ae0ba87c83740f931991bb4666afa6c1d"></a>
### `multicast_group`
```cpp
std::string espectre::CsiTrafficServiceConfig::multicast_group
```
IPv4 multicast group the external listener joins; empty for unicast only.
<a id="structespectre_1_1_direct_http_service_config"></a>
## espectre::DirectHttpServiceConfig
```cpp
#include <runtime/direct_http_service.h>
```
```cpp
struct espectre::DirectHttpServiceConfig
```
Settings for an [IDirectHttpService](#classespectre_1_1_i_direct_http_service).
setup() rejects a configuration without allowed origins unless [`allow_missing_origin`](#structespectre_1_1_direct_http_service_config_1af076038c08cbdbb6811eb2b09db08762) is set, and zero limits.
<a id="structespectre_1_1_direct_http_service_config_1afdc25c605172c283f046b864fc75f536"></a>
### `allowed_origins`
```cpp
std::vector<std::string> espectre::DirectHttpServiceConfig::allowed_origins
```
Browser origins allowed to call the API, matched exactly, such as `https://espectre.dev`.
<a id="structespectre_1_1_direct_http_service_config_1ad302cbbe428f3ebf2c46b235c23f420c"></a>
### `device_id`
```cpp
uint64_t espectre::DirectHttpServiceConfig::device_id {0U}
```
Device identity used in error payloads the service builds itself.
<a id="structespectre_1_1_direct_http_service_config_1ac197b814e5841ac86aef20a349bc53c9"></a>
### `port`
```cpp
uint16_t espectre::DirectHttpServiceConfig::port {ESPECTRE_DIRECT_HTTP_PORT}
```
<a id="structespectre_1_1_direct_http_service_config_1ab2ba838a2fc400029f6f5a16c086f077"></a>
### `max_event_clients`
```cpp
size_t espectre::DirectHttpServiceConfig::max_event_clients {2U}
```
Concurrent event stream clients, 1 or 2.
<a id="structespectre_1_1_direct_http_service_config_1a06fc309448ba84ebbac7f1419bdf4f64"></a>
### `max_pending_requests`
```cpp
size_t espectre::DirectHttpServiceConfig::max_pending_requests {4U}
```
Requests received but not yet answered, across all clients.
<a id="structespectre_1_1_direct_http_service_config_1ad25d287f420112dfec65715119b10dcf"></a>
### `outbound_queue_depth`
```cpp
size_t espectre::DirectHttpServiceConfig::outbound_queue_depth {8U}
```
Events queued per event stream client.
<a id="structespectre_1_1_direct_http_service_config_1a5d5ddecc43f3c19e1534b1c593c80a07"></a>
### `max_requests_per_second`
```cpp
uint16_t espectre::DirectHttpServiceConfig::max_requests_per_second {20U}
```
Requests accepted per second, reads included.
<a id="structespectre_1_1_direct_http_service_config_1abba7b1ff7aa346cd9c4574d1771afd4f"></a>
### `max_mutations_per_minute`
```cpp
uint16_t espectre::DirectHttpServiceConfig::max_mutations_per_minute {60U}
```
State-changing requests accepted per minute.
<a id="structespectre_1_1_direct_http_service_config_1af076038c08cbdbb6811eb2b09db08762"></a>
### `allow_missing_origin`
```cpp
bool espectre::DirectHttpServiceConfig::allow_missing_origin {false}
```
Accept requests without an `Origin` header, such as those from the CLI.
<a id="structespectre_1_1_direct_http_service_config_1ae2c8f96e540149e33adc4db28ac8a95b"></a>
### `allow_http_loopback_origins`
```cpp
bool espectre::DirectHttpServiceConfig::allow_http_loopback_origins {false}
```
Also accept `http://localhost` and loopback addresses as origins, for local development.
<a id="structespectre_1_1_direct_http_service_config_1a1a1ee541cab1a782eed9074764ae269b"></a>
### `protocol_extension`
```cpp
const EspectreProtocolExtension* espectre::DirectHttpServiceConfig::protocol_extension {nullptr}
```
Optional frontend routes.
The immutable catalog must outlive this service.
<a id="structespectre_1_1_direct_http_service_config_1a937605cc8df763b5e028a051c3b47e4a"></a>
### `for_first_party_portals`
```cpp
static DirectHttpServiceConfig espectre::DirectHttpServiceConfig::for_first_party_portals()
```
Configuration for ESPectre's production and validation portals.
<a id="structespectre_1_1_direct_http_service_diagnostics"></a>
## espectre::DirectHttpServiceDiagnostics
```cpp
#include <runtime/direct_http_service.h>
```
```cpp
struct espectre::DirectHttpServiceDiagnostics
```
Counters of an [IDirectHttpService](#classespectre_1_1_i_direct_http_service) since its last setup().
<a id="structespectre_1_1_direct_http_service_diagnostics_1a9c7f0142a8d93556baeef9fdf63849a3"></a>
### `event_client_limit`
```cpp
size_t espectre::DirectHttpServiceDiagnostics::event_client_limit {0U}
```
[`DirectHttpServiceConfig::max_event_clients`](#structespectre_1_1_direct_http_service_config_1ab2ba838a2fc400029f6f5a16c086f077).
<a id="structespectre_1_1_direct_http_service_diagnostics_1ac707ab3bad71aef5cbb19e79c636f910"></a>
### `queue_capacity`
```cpp
size_t espectre::DirectHttpServiceDiagnostics::queue_capacity {0U}
```
[`DirectHttpServiceConfig::outbound_queue_depth`](#structespectre_1_1_direct_http_service_config_1ad25d287f420112dfec65715119b10dcf).
<a id="structespectre_1_1_direct_http_service_diagnostics_1a8563f7956f0a9d8ffa358cf031b090d5"></a>
### `accepted_connections`
```cpp
uint32_t espectre::DirectHttpServiceDiagnostics::accepted_connections {0U}
```
Event stream connections accepted.
<a id="structespectre_1_1_direct_http_service_diagnostics_1a46d844448509e03ed47183648d9d0eec"></a>
### `rejected_connections`
```cpp
uint32_t espectre::DirectHttpServiceDiagnostics::rejected_connections {0U}
```
Event stream connections refused, usually because the client limit was reached.
<a id="structespectre_1_1_direct_http_service_diagnostics_1a1130f2f2217163e5f7c69d96eeaaa46c"></a>
### `malformed_requests`
```cpp
uint32_t espectre::DirectHttpServiceDiagnostics::malformed_requests {0U}
```
Requests with an invalid route, query, or body.
<a id="structespectre_1_1_direct_http_service_diagnostics_1a3759c6627ef3e77a8070c56b37a938bd"></a>
### `oversized_requests`
```cpp
uint32_t espectre::DirectHttpServiceDiagnostics::oversized_requests {0U}
```
Requests larger than [`ESPECTRE_DIRECT_MAX_REQUEST_SIZE`](#namespaceespectre_1adfc7361b80006da4cca67b96224221d9).
<a id="structespectre_1_1_direct_http_service_diagnostics_1afbda12528b3158bfe8b73e1729b18f74"></a>
### `rate_limited_requests`
```cpp
uint32_t espectre::DirectHttpServiceDiagnostics::rate_limited_requests {0U}
```
Requests refused by the per-second or per-minute limits.
<a id="structespectre_1_1_direct_http_service_diagnostics_1a5fedcd05e4e07aba75115a19fd2a0b7c"></a>
### `dropped_motion_events`
```cpp
uint32_t espectre::DirectHttpServiceDiagnostics::dropped_motion_events {0U}
```
Replaceable telemetry events dropped because a client queue was full.
<a id="structespectre_1_1_direct_http_service_diagnostics_1a642fe94b20a7c7e54f41fd513b9159d7"></a>
### `send_failures`
```cpp
uint32_t espectre::DirectHttpServiceDiagnostics::send_failures {0U}
```
Failed sends to event stream clients.
<a id="structespectre_1_1_direct_http_service_diagnostics_1aec94025f197cf1408f7a52556db86fa7"></a>
### `queued_messages`
```cpp
size_t espectre::DirectHttpServiceDiagnostics::queued_messages {0U}
```
Events currently queued across clients.
<a id="structespectre_1_1_direct_request"></a>
## espectre::DirectRequest
```cpp
#include <runtime/direct_http_protocol.h>
```
```cpp
struct espectre::DirectRequest
```
A Direct HTTP request mapped onto a canonical command.
<a id="structespectre_1_1_direct_request_1adf922ed00c7a0f4e1f3639003ada642b"></a>
### `command_id`
```cpp
std::string espectre::DirectRequest::command_id
```
Correlation id; empty, because the HTTP response itself is the correlation.
<a id="structespectre_1_1_direct_request_1ad00a242692f23702edc510466a3ddd18"></a>
### `command`
```cpp
std::string espectre::DirectRequest::command
```
Canonical command name selected by the route.
<a id="structespectre_1_1_direct_request_1af1b326b84679b121e4495d128ce2f769"></a>
### `params`
```cpp
std::string espectre::DirectRequest::params {"{}"}
```
Syntactically valid JSON object containing command parameters.
<a id="structespectre_1_1_direct_request_1ad8acda6c3a8dd15be0dc5c1de5abd580"></a>
### `path`
```cpp
std::string espectre::DirectRequest::path
```
Request path, retained for resource-aware response handling.
<a id="structespectre_1_1_direct_request_1af80d15f9b41df7b5fb69e9cc2d8cde3e"></a>
### `http_method`
```cpp
std::string espectre::DirectRequest::http_method
```
HTTP method selected by the transport route.
<a id="structespectre_1_1_direct_request_1ae8e60534fc082b6e015412d3d8512ec7"></a>
### `asynchronous`
```cpp
bool espectre::DirectRequest::asynchronous {false}
```
Whether the accepted operation completes asynchronously.
<a id="structespectre_1_1_direct_wifi_snapshot"></a>
## espectre::DirectWifiSnapshot
```cpp
#include <runtime/esp_idf/direct_wifi_snapshot_esp_idf.h>
```
```cpp
struct espectre::DirectWifiSnapshot
```
Station configuration and association, without credentials, for the `wifi` resource.
<a id="structespectre_1_1_direct_wifi_snapshot_1a35fad680fbddf95dfc3d949827f25531"></a>
### `configured`
```cpp
bool espectre::DirectWifiSnapshot::configured {false}
```
Whether the station has an SSID configured.
<a id="structespectre_1_1_direct_wifi_snapshot_1a77b5b090fbac01ef3c6b04098cb774fb"></a>
### `connected`
```cpp
bool espectre::DirectWifiSnapshot::connected {false}
```
Whether the station is associated.
<a id="structespectre_1_1_direct_wifi_snapshot_1a654870b989f58fde00d8322e0fd4c09e"></a>
### `ssid`
```cpp
std::string espectre::DirectWifiSnapshot::ssid
```
<a id="structespectre_1_1_direct_wifi_snapshot_1a71e273d8802c9243de20cacf56d6257a"></a>
### `bssid`
```cpp
std::string espectre::DirectWifiSnapshot::bssid
```
Access point in use, as `AA:BB:CC:DD:EE:FF`; empty when not associated.
<a id="structespectre_1_1_direct_wifi_snapshot_1a22518d182419dba3ff69f9500ed5a0bb"></a>
### `band`
```cpp
std::string espectre::DirectWifiSnapshot::band
```
`2g` or `5g` while associated; empty otherwise.
<a id="structespectre_1_1_direct_wifi_snapshot_1aab4926f5f413440ec92938acd524c94f"></a>
### `channel`
```cpp
uint8_t espectre::DirectWifiSnapshot::channel {0U}
```
Primary channel, or zero.
<a id="structespectre_1_1_direct_wifi_snapshot_1af8aa80bf3f802d719965d1dd4acf8c2a"></a>
### `rssi_dbm`
```cpp
int16_t espectre::DirectWifiSnapshot::rssi_dbm {INT16_MIN}
```
Signal strength, or `INT16_MIN` when not associated.
<a id="classespectre_1_1_esp_idf_direct_http_service"></a>
## espectre::EspIdfDirectHttpService
```cpp
#include <runtime/esp_idf/direct_http_service_esp_idf.h>
```
```cpp
class espectre::EspIdfDirectHttpService : public espectre::IDirectHttpService
```
[IDirectHttpService](#classespectre_1_1_i_direct_http_service) over the ESP-IDF HTTP server.
Serves the versioned API, the event stream, and raw collection on [`DirectHttpServiceConfig::port`](#structespectre_1_1_direct_http_service_config_1ac197b814e5841ac86aef20a349bc53c9). Server and worker tasks only queue work; callbacks run from [loop()](#classespectre_1_1_esp_idf_direct_http_service_1abbe2a278b424a1165475d8ffca79b78a) on the owner task. Raw buffers are allocated while a raw session is open.
[`espectre::IDirectHttpService`](#classespectre_1_1_i_direct_http_service)
<a id="classespectre_1_1_esp_idf_direct_http_service_1af089ad0dc1f04f6c6df779fd334f253a"></a>
### `EspIdfDirectHttpService`
```cpp
espectre::EspIdfDirectHttpService::EspIdfDirectHttpService()
```
<a id="classespectre_1_1_esp_idf_direct_http_service_1ac347e2a473f454a0dd361a2d2993e10f"></a>
### `~EspIdfDirectHttpService`
```cpp
espectre::EspIdfDirectHttpService::~EspIdfDirectHttpService() override
```
<a id="classespectre_1_1_esp_idf_direct_http_service_1a7b8d45f4be693a762e4abe82fc2a20bf"></a>
### `setup`
```cpp
bool espectre::EspIdfDirectHttpService::setup(const DirectHttpServiceConfig &config, RequestHandler request_handler, ClientCountCallback client_count_callback) override
```
Configure and start the endpoint.
Safe to call again after shutdown.
<a id="classespectre_1_1_esp_idf_direct_http_service_1ae225e3119210aad76296207a590e13b6"></a>
### `setup_deferred`
```cpp
bool espectre::EspIdfDirectHttpService::setup_deferred(const DirectHttpServiceConfig &config, DeferredRequestHandler request_handler, ClientCountCallback client_count_callback) override
```
Configure a handler that may complete a request later.
The default preserves source compatibility for external transports that implement only synchronous Direct requests. A successful deferred handler must eventually call [complete\_deferred\_response()](#classespectre_1_1_esp_idf_direct_http_service_1a47b68b279c034d769daa2a257ae56a4e) with the opaque token.
<a id="classespectre_1_1_esp_idf_direct_http_service_1a47b68b279c034d769daa2a257ae56a4e"></a>
### `complete_deferred_response`
```cpp
bool espectre::EspIdfDirectHttpService::complete_deferred_response(uint64_t request_token, std::string response) override
```
Queue a deferred response only if the originating connection is live.
<a id="classespectre_1_1_esp_idf_direct_http_service_1abbe2a278b424a1165475d8ffca79b78a"></a>
### `loop`
```cpp
void espectre::EspIdfDirectHttpService::loop() override
```
Pump deferred receive, dispatch, send work, and application callbacks from the frontend task.
Request, client-count, and raw-stop callbacks are never delivered from HTTP server or streaming worker tasks.
<a id="classespectre_1_1_esp_idf_direct_http_service_1a69bb753b2d9164edb8e4103810dff6d0"></a>
### `shutdown`
```cpp
void espectre::EspIdfDirectHttpService::shutdown() override
```
Stop accepting clients, close sockets, and release queued messages.
<a id="classespectre_1_1_esp_idf_direct_http_service_1ada58a458d98dd8e124db39f943c3a2e5"></a>
### `running`
```cpp
bool espectre::EspIdfDirectHttpService::running() const override
```
True between a successful setup and [shutdown()](#classespectre_1_1_esp_idf_direct_http_service_1a69bb753b2d9164edb8e4103810dff6d0).
<a id="classespectre_1_1_esp_idf_direct_http_service_1ab361c7437c09142a8ef9c1c155923c49"></a>
### `event_client_count`
```cpp
size_t espectre::EspIdfDirectHttpService::event_client_count() const override
```
Connected event stream clients.
<a id="classespectre_1_1_esp_idf_direct_http_service_1a6b1b073f0208576039b7e738b4924764"></a>
### `publish_event`
```cpp
bool espectre::EspIdfDirectHttpService::publish_event(const std::string &event_name, const std::string &data_json, bool replaceable_telemetry) override
```
Queue a normalized event for every connected client.
Telemetry events may replace an older queued event with the same name. State transitions and command responses must never be replaced by telemetry. Returns false when no client can accept the event.
<a id="classespectre_1_1_esp_idf_direct_http_service_1a53a673575c7d1bcd9b5c36415bb90883"></a>
### `diagnostics`
```cpp
DirectHttpServiceDiagnostics espectre::EspIdfDirectHttpService::diagnostics() const override
```
Current counters.
<a id="classespectre_1_1_esp_idf_direct_http_service_1ac4e80472b1ff46d590b53873837ad3f5"></a>
### `set_raw_session_requested_callback`
```cpp
void espectre::EspIdfDirectHttpService::set_raw_session_requested_callback(RawSessionRequestedCallback callback) override
```
Register the frontend-task callback that opens collection for GET /csi.
<a id="classespectre_1_1_esp_idf_direct_http_service_1a109597c4e5df813e81eb915429705722"></a>
### `start_raw_session`
```cpp
bool espectre::EspIdfDirectHttpService::start_raw_session(const RawCsiSessionConfig &config, RawSessionStoppedCallback stopped_callback) override
```
Begin one owner-bound raw session on the service's binary endpoint.
<a id="classespectre_1_1_esp_idf_direct_http_service_1ac5b0595da73f263666c1db28954a6a26"></a>
### `stop_raw_session`
```cpp
bool espectre::EspIdfDirectHttpService::stop_raw_session(RawCsiStopReason reason) override
```
Stop the active raw session and close its binary socket.
The stopped callback is delivered by [loop()](#classespectre_1_1_esp_idf_direct_http_service_1abbe2a278b424a1165475d8ffca79b78a), or synchronously while [shutdown()](#classespectre_1_1_esp_idf_direct_http_service_1a69bb753b2d9164edb8e4103810dff6d0) completes on the owning frontend task.
<a id="classespectre_1_1_esp_idf_direct_http_service_1a6526110c0aa5da0fb3811dbdd53e20a7"></a>
### `offer_raw_packet`
```cpp
bool espectre::EspIdfDirectHttpService::offer_raw_packet(const RawCsiPacketView &packet) override
```
Copy one callback-scoped sample into the transport's bounded raw slots.
<a id="classespectre_1_1_esp_idf_direct_http_service_1af5f94e87f550721eca27dbbe0fda720a"></a>
### `raw_diagnostics`
```cpp
RawCsiSessionDiagnostics espectre::EspIdfDirectHttpService::raw_diagnostics() const override
```
Counters of the current or last raw session; zeros when unsupported.
<a id="classespectre_1_1_esp_idf_mqtt_transport"></a>
## espectre::EspIdfMqttTransport
```cpp
#include <runtime/esp_idf/mqtt_transport_esp_idf.h>
```
```cpp
class espectre::EspIdfMqttTransport : public espectre::IMqttTransport
```
[IMqttTransport](#classespectre_1_1_i_mqtt_transport) over the ESP-IDF `esp-mqtt` client.
Publishes at QoS 0 through a bounded local queue, in which state messages take precedence over replaceable telemetry. Callbacks run from [loop()](#classespectre_1_1_esp_idf_mqtt_transport_1aec31bc8f488bfc7a6b72555a29fc3b3b).
[`espectre::IMqttTransport`](#classespectre_1_1_i_mqtt_transport)
<a id="classespectre_1_1_esp_idf_mqtt_transport_1a2da630d0212338987259bff4a10a9d80"></a>
### `setup`
```cpp
bool espectre::EspIdfMqttTransport::setup(const EspectreDeviceConfig &config) override
```
Configure and start connecting.
Asynchronous: true means the client started, not that it reached the broker. Wait for the connection callback before expecting publishes to land. Calling it again tears down the previous client and reconfigures.
**Returns:** false when the configuration cannot produce a client, such as an empty [`EspectreDeviceConfig::mqtt_host`](#structespectre_1_1_espectre_device_config_1a6bc7843ffc079108684b040e77b59c89).
<a id="classespectre_1_1_esp_idf_mqtt_transport_1aec31bc8f488bfc7a6b72555a29fc3b3b"></a>
### `loop`
```cpp
void espectre::EspIdfMqttTransport::loop() override
```
Pump the client and dispatch callbacks.
Called from the frontend loop.
<a id="classespectre_1_1_esp_idf_mqtt_transport_1a273e04c6fb334df6d1c4e479f8a1e4b3"></a>
### `shutdown`
```cpp
void espectre::EspIdfMqttTransport::shutdown() override
```
Disconnect and release resources.
Safe to repeat.
<a id="classespectre_1_1_esp_idf_mqtt_transport_1afa5c443e6863e93a2dd9f32f2e613f35"></a>
### `connected`
```cpp
bool espectre::EspIdfMqttTransport::connected() const override
```
True while the broker connection is established.
<a id="classespectre_1_1_esp_idf_mqtt_transport_1af284c13242edeeff5b8b3d886cc65579"></a>
### `publish`
```cpp
bool espectre::EspIdfMqttTransport::publish(const std::string &topic, const std::string &payload, bool retain) override
```
Publish to an absolute topic.
**Parameters**
- `topic`: Full topic name, not a suffix.
- `payload`: Message body, copied before returning.
- `retain`: Ask the broker to retain the message, for state a late subscriber must still see, such as availability.
**Returns:** false when disconnected or the bounded publish queue rejects the message. Published at QoS 0, so true means queued locally, not delivered to the broker.
<a id="classespectre_1_1_esp_idf_mqtt_transport_1a67952e68321ad9cdcfc1b82622ec3a7b"></a>
### `publish_suffix`
```cpp
bool espectre::EspIdfMqttTransport::publish_suffix(const char *suffix, const std::string &payload, bool retain) override
```
Publish under this device's protocol topic prefix.
The prefix comes from the [`EspectreDeviceConfig`](#structespectre_1_1_espectre_device_config) passed to [`setup()`](#classespectre_1_1_esp_idf_mqtt_transport_1a2da630d0212338987259bff4a10a9d80), so callers pass only the trailing segment, for example `"motion"`.
<a id="classespectre_1_1_esp_idf_mqtt_transport_1a8cec31260ab4daf4f66751350c8ca667"></a>
### `subscribe`
```cpp
bool espectre::EspIdfMqttTransport::subscribe(const std::string &topic, MessageCallback callback) override
```
Register a topic and its handler.
Idempotent per topic: subscribing again replaces the handler. May be called before the connection is up; the subscription is issued on connect.
**Returns:** false for an empty topic or an empty callback.
<a id="classespectre_1_1_esp_idf_mqtt_transport_1aa7f6deb4f262fc2c1ec7afccfeb1200e"></a>
### `set_command_callback`
```cpp
void espectre::EspIdfMqttTransport::set_command_callback(CommandCallback callback) override
```
Handler for the device command topic, which the transport subscribes itself.
<a id="classespectre_1_1_esp_idf_mqtt_transport_1afb71bdbc4863a47767a5007d654c3b95"></a>
### `set_connection_callback`
```cpp
void espectre::EspIdfMqttTransport::set_connection_callback(ConnectionCallback callback) override
```
Handler for connection state changes, including reconnects.
<a id="classespectre_1_1_esp_idf_mqtt_transport_1a3a2d1e7ab0d60a4e392bd2fc79b4eddb"></a>
### `diagnostics`
```cpp
MqttTransportDiagnostics espectre::EspIdfMqttTransport::diagnostics() const override
```
Bounded outbound queue, drop, failure, and reconnect counters.
<a id="classespectre_1_1_esp_idf_peer_discovery_service"></a>
## espectre::EspIdfPeerDiscoveryService
```cpp
#include <runtime/esp_idf/peer_discovery_service_esp_idf.h>
```
```cpp
class espectre::EspIdfPeerDiscoveryService : public espectre::IPeerDiscoveryService
```
[IPeerDiscoveryService](#classespectre_1_1_i_peer_discovery_service) over the ESP-IDF mDNS component, searching for `_espectre._tcp` services.
Requires an initialized mDNS responder, such as [MdnsDiscoveryService](#classespectre_1_1_mdns_discovery_service).
[`espectre::IPeerDiscoveryService`](#classespectre_1_1_i_peer_discovery_service)
<a id="classespectre_1_1_esp_idf_peer_discovery_service_1a40d1c980ae37e291ab24d88d201b757c"></a>
### `~EspIdfPeerDiscoveryService`
```cpp
espectre::EspIdfPeerDiscoveryService::~EspIdfPeerDiscoveryService() override
```
<a id="classespectre_1_1_esp_idf_peer_discovery_service_1ac001c1c13c4cbf01a9c6f27c1f422ad9"></a>
### `set_local_candidate`
```cpp
void espectre::EspIdfPeerDiscoveryService::set_local_candidate(PeerDiscoveryCandidate candidate) override
```
Describe this device, so it appears in its own results.
<a id="classespectre_1_1_esp_idf_peer_discovery_service_1a7e51c6f94d43415b96582ea34fdf2f72"></a>
### `set_wifi_ready`
```cpp
void espectre::EspIdfPeerDiscoveryService::set_wifi_ready(bool ready) override
```
Report whether the station has an IPv4 address; searches need one.
<a id="classespectre_1_1_esp_idf_peer_discovery_service_1a147df34c433a40e27398f15c86fe821a"></a>
### `ready`
```cpp
bool espectre::EspIdfPeerDiscoveryService::ready() const override
```
Whether a search can start now.
<a id="classespectre_1_1_esp_idf_peer_discovery_service_1a7cfe6e21dbfb5bd468d11c133256228b"></a>
### `active`
```cpp
bool espectre::EspIdfPeerDiscoveryService::active() const override
```
Whether a search is running.
<a id="classespectre_1_1_esp_idf_peer_discovery_service_1a8dcaf36dcea15b9bbe995f8c9914d62c"></a>
### `start`
```cpp
bool espectre::EspIdfPeerDiscoveryService::start(Completion completion) override
```
Start a search; false when not ready or `completion` is empty.
<a id="classespectre_1_1_esp_idf_peer_discovery_service_1a24e9feb077b08613329dc00f73531a0f"></a>
### `loop`
```cpp
void espectre::EspIdfPeerDiscoveryService::loop() override
```
Collect results and deliver the completion when the search ends.
<a id="classespectre_1_1_esp_idf_peer_discovery_service_1ad1b83e460b89a31850f30dce514c1794"></a>
### `shutdown`
```cpp
void espectre::EspIdfPeerDiscoveryService::shutdown() override
```
Stop a running search without delivering its completion.
<a id="structespectre_1_1_espectre_api_event_descriptor"></a>
## espectre::EspectreApiEventDescriptor
```cpp
#include <runtime/espectre_protocol.h>
```
```cpp
struct espectre::EspectreApiEventDescriptor
```
One canonical event and the capability that gates it.
<a id="structespectre_1_1_espectre_api_event_descriptor_1a7a8c650cd6ccf9c4372ef17bc5b71c36"></a>
### `name`
```cpp
const char* espectre::EspectreApiEventDescriptor::name
```
Event name on the wire, such as `motion`.
<a id="structespectre_1_1_espectre_api_event_descriptor_1ace0597942f8c3f7cad93752cebf512e6"></a>
### `event`
```cpp
EspectreEvent espectre::EspectreApiEventDescriptor::event
```
Family the event belongs to.
<a id="structespectre_1_1_espectre_api_event_descriptor_1ab37408482a4f126a88e34f7cebf51bf3"></a>
### `capability`
```cpp
EspectreDirectMethod espectre::EspectreApiEventDescriptor::capability
```
Capability that must be advertised for the event to be published.
<a id="structespectre_1_1_espectre_api_route"></a>
## espectre::EspectreApiRoute
```cpp
#include <runtime/espectre_protocol.h>
```
```cpp
struct espectre::EspectreApiRoute
```
One canonical HTTP/resource mapping used by routing and capability output.
<a id="structespectre_1_1_espectre_api_route_1aa9709d67003f68cf23436eac4af47c2e"></a>
### `http_method`
```cpp
const char* espectre::EspectreApiRoute::http_method
```
HTTP method, such as `GET` or `PATCH`.
<a id="structespectre_1_1_espectre_api_route_1a6a3ed1667d54ee57d4f8fc708581fd4d"></a>
### `path`
```cpp
const char* espectre::EspectreApiRoute::path
```
Absolute path, such as `/espectre/v1/sensing`.
<a id="structespectre_1_1_espectre_api_route_1a7d6922e283a7c596184408e5ed8d5173"></a>
### `name`
```cpp
const char* espectre::EspectreApiRoute::name
```
Resource or operation name in the `capabilities` catalog.
<a id="structespectre_1_1_espectre_api_route_1a4afdd946b5eb049671a273fcc8f5de23"></a>
### `command`
```cpp
const char* espectre::EspectreApiRoute::command
```
Canonical command name; empty for streams.
<a id="structespectre_1_1_espectre_api_route_1a6e59efe828f71299c8d903d0d4799952"></a>
### `capability`
```cpp
EspectreDirectMethod espectre::EspectreApiRoute::capability
```
Capability that must be advertised for the route to exist.
<a id="structespectre_1_1_espectre_api_route_1aba7095f764f6e13917e91a3e0ea25999"></a>
### `kind`
```cpp
EspectreApiRouteKind espectre::EspectreApiRoute::kind
```
<a id="structespectre_1_1_espectre_api_route_1a028522628d85078d9bac937d34941959"></a>
### `asynchronous`
```cpp
bool espectre::EspectreApiRoute::asynchronous
```
Whether the operation completes after the response.
<a id="structespectre_1_1_espectre_api_route_1aa2589bf5cb55b904bb69b14b75096f15"></a>
### `validate`
```cpp
EspectreCommandValidator espectre::EspectreApiRoute::validate {nullptr}
```
Parameter validator; `nullptr` for streams.
<a id="structespectre_1_1_espectre_capability_profile"></a>
## espectre::EspectreCapabilityProfile
```cpp
#include <runtime/espectre_protocol.h>
```
```cpp
struct espectre::EspectreCapabilityProfile
```
Exact Direct command, event, and readable-configuration surface advertised by a frontend.
<a id="structespectre_1_1_espectre_capability_profile_1a3754a33de52acb5734ddc4c97b01db6a"></a>
### `methods`
```cpp
std::array<bool, static_cast<size_t>(EspectreDirectMethod::COUNT)> espectre::EspectreCapabilityProfile::methods {}
```
Advertised capabilities, indexed by [`EspectreDirectMethod`](#namespaceespectre_1afca4c79a12b4b401c979d6232c2a0bd8).
All off by default.
<a id="structespectre_1_1_espectre_capability_profile_1a0b35ac4d5e323f6f33573c1d8ccbe418"></a>
### `config_sections`
```cpp
std::array<bool, static_cast<size_t>(EspectreConfigSection::COUNT)> espectre::EspectreCapabilityProfile::config_sections {}
```
Readable sections, indexed by [`EspectreConfigSection`](#namespaceespectre_1afc7c8d567fb0888be484d8ebdda994a8).
All off by default.
<a id="structespectre_1_1_espectre_capability_profile_1aaa03a4984112db226532b8fdf554594e"></a>
### `events`
```cpp
std::array<bool, static_cast<size_t>(EspectreEvent::COUNT)> espectre::EspectreCapabilityProfile::events {{true, true, true, true, true}}
```
Published event families, indexed by [`EspectreEvent`](#namespaceespectre_1a8c8b3454eae8a719a4f529bf205bf0ff).
All on by default.
<a id="structespectre_1_1_espectre_capability_profile_1a06c2e9bb86e8d0a0cebddd4a0e138087"></a>
### `extension`
```cpp
const EspectreProtocolExtension* espectre::EspectreCapabilityProfile::extension {nullptr}
```
Optional frontend-owned catalog, shared with its transport parsers.
<a id="structespectre_1_1_espectre_capability_profile_1af6f094856d4f5e4108cb0751672c007f"></a>
### `supports`
```cpp
bool espectre::EspectreCapabilityProfile::supports(EspectreDirectMethod method) const
```
Whether a capability is advertised.
<a id="structespectre_1_1_espectre_capability_profile_1a19fd61ef7f0e7960ff2909a5f6243f2f"></a>
### `set`
```cpp
void espectre::EspectreCapabilityProfile::set(EspectreDirectMethod method, bool enabled=true)
```
Advertise or withdraw a capability.
<a id="structespectre_1_1_espectre_capability_profile_1acb8dbe5a2f5fc8bad1adbec8194105c0"></a>
### `has`
```cpp
bool espectre::EspectreCapabilityProfile::has(EspectreConfigSection section) const
```
Whether a configuration section is readable.
<a id="structespectre_1_1_espectre_capability_profile_1a0b55fb321de02c836169680bf579c20c"></a>
### `set`
```cpp
void espectre::EspectreCapabilityProfile::set(EspectreConfigSection section, bool enabled=true)
```
Expose or hide a configuration section.
<a id="structespectre_1_1_espectre_capability_profile_1ae2b3b98049b2856d1feb176c0b7ff19c"></a>
### `publishes`
```cpp
bool espectre::EspectreCapabilityProfile::publishes(EspectreEvent event) const
```
Whether an event family is published.
<a id="structespectre_1_1_espectre_capability_profile_1a6d960b939d2d7ed6753d984ae159ac58"></a>
### `set`
```cpp
void espectre::EspectreCapabilityProfile::set(EspectreEvent event, bool enabled=true)
```
Publish or suppress an event family.
<a id="structespectre_1_1_espectre_capability_profile_1aa8e981afc3beacf03785a5dd13580e14"></a>
### `clear_events`
```cpp
void espectre::EspectreCapabilityProfile::clear_events()
```
Suppress every event family.
<a id="structespectre_1_1_espectre_command"></a>
## espectre::EspectreCommand
```cpp
#include <runtime/espectre_protocol.h>
```
```cpp
struct espectre::EspectreCommand
```
A parsed control command.
Fields are optional by design: each `has_*` flag says whether the peer actually sent that field, so an unset value is never confused with a zero the caller meant. Apply only the flagged fields.
<a id="structespectre_1_1_espectre_command_1a80590239b5b628431a94e8a94f881fc8"></a>
### `mqtt_scheme`
```cpp
std::string espectre::EspectreCommand::mqtt_scheme
```
<a id="structespectre_1_1_espectre_command_1a6ccd1af691634288857285ddef21ce43"></a>
### `mqtt_host`
```cpp
std::string espectre::EspectreCommand::mqtt_host
```
<a id="structespectre_1_1_espectre_command_1a578d1b64dc9bfecad0b7d2acc5ebdc10"></a>
### `mqtt_username`
```cpp
std::string espectre::EspectreCommand::mqtt_username
```
<a id="structespectre_1_1_espectre_command_1a4462672aafd9991d02ccec4897ab31c8"></a>
### `mqtt_password`
```cpp
std::string espectre::EspectreCommand::mqtt_password
```
<a id="structespectre_1_1_espectre_command_1a88fdc71c132a8589fc5dd0a62ef2458a"></a>
### `mqtt_topic_prefix`
```cpp
std::string espectre::EspectreCommand::mqtt_topic_prefix
```
<a id="structespectre_1_1_espectre_command_1a970cc86b87aa22ed74f7d1761187ad27"></a>
### `mqtt_port`
```cpp
uint16_t espectre::EspectreCommand::mqtt_port {0U}
```
<a id="structespectre_1_1_espectre_command_1ae6b2b6b7f272b8168fccba36e046c4b7"></a>
### `has_mqtt_scheme`
```cpp
bool espectre::EspectreCommand::has_mqtt_scheme {false}
```
<a id="structespectre_1_1_espectre_command_1a483cee09f1e344a19ab61f85519b37b6"></a>
### `has_mqtt_host`
```cpp
bool espectre::EspectreCommand::has_mqtt_host {false}
```
<a id="structespectre_1_1_espectre_command_1ae7ba0aa42d1640c1a059992e9f3e5ad3"></a>
### `has_mqtt_username`
```cpp
bool espectre::EspectreCommand::has_mqtt_username {false}
```
<a id="structespectre_1_1_espectre_command_1a3622a2d30ac29af8409fd070dddb09c3"></a>
### `has_mqtt_password`
```cpp
bool espectre::EspectreCommand::has_mqtt_password {false}
```
<a id="structespectre_1_1_espectre_command_1aa5b9810294f426dd4f8e3b48abd810d9"></a>
### `has_mqtt_topic_prefix`
```cpp
bool espectre::EspectreCommand::has_mqtt_topic_prefix {false}
```
<a id="structespectre_1_1_espectre_command_1ac25f88011125cec697bd5a3cf2fd9067"></a>
### `has_mqtt_port`
```cpp
bool espectre::EspectreCommand::has_mqtt_port {false}
```
<a id="structespectre_1_1_espectre_command_1ae9f9733cf3d838398d3f8ef2e34b0821"></a>
### `command_id`
```cpp
std::string espectre::EspectreCommand::command_id
```
Correlation id echoed in the result payload.
May be empty.
<a id="structespectre_1_1_espectre_command_1afd0d4b74c5d8fb75f1238fed99612bcd"></a>
### `command`
```cpp
std::string espectre::EspectreCommand::command
```
Command verb, for example `"update_sensing"` or `"recalibrate"`.
<a id="structespectre_1_1_espectre_command_1a04c58cb2c7dc527168ea428e33310164"></a>
### `diagnostic_fields`
```cpp
std::vector<std::string> espectre::EspectreCommand::diagnostic_fields
```
Diagnostic paths to return; empty requests the catalog, and \["\*"\] requests all values.
<a id="structespectre_1_1_espectre_command_1a56690f670653ae3479daf1c622dfb6d2"></a>
### `sensing_enabled`
```cpp
bool espectre::EspectreCommand::sensing_enabled {false}
```
Requested sensing-service state for `update_sensing`.
<a id="structespectre_1_1_espectre_command_1ab7fce7acc1aa3eaf54985c2e2fc30918"></a>
### `has_sensing_enabled`
```cpp
bool espectre::EspectreCommand::has_sensing_enabled {false}
```
<a id="structespectre_1_1_espectre_command_1a4a6f143d3f0aa6eac8daa17e7435f316"></a>
### `device_label`
```cpp
std::string espectre::EspectreCommand::device_label
```
User-facing label requested by `update_device`; empty clears it.
<a id="structespectre_1_1_espectre_command_1aa1fe0f3fe39cfcf457a736113b33a71e"></a>
### `has_device_label`
```cpp
bool espectre::EspectreCommand::has_device_label {false}
```
Whether the command carried a valid string-valued [`device_label`](#structespectre_1_1_espectre_command_1a4a6f143d3f0aa6eac8daa17e7435f316).
<a id="structespectre_1_1_espectre_command_1ad1c410f2a60ad18eb5a257b486be4fb2"></a>
### `threshold`
```cpp
float espectre::EspectreCommand::threshold {0.0f}
```
`update_sensing` threshold, on the 0..1 scale.
<a id="structespectre_1_1_espectre_command_1a29fe6ed5b45c203e74bc9a066ff829be"></a>
### `has_threshold`
```cpp
bool espectre::EspectreCommand::has_threshold {false}
```
<a id="structespectre_1_1_espectre_command_1a80157a00785372468fa10b0b07ca1c54"></a>
### `motion_on_hits`
```cpp
uint8_t espectre::EspectreCommand::motion_on_hits {0U}
```
`update_sensing` hit counts, 1..20 each; sent together.
<a id="structespectre_1_1_espectre_command_1aea051c66df201eda9db54461f910781e"></a>
### `motion_off_hits`
```cpp
uint8_t espectre::EspectreCommand::motion_off_hits {0U}
```
<a id="structespectre_1_1_espectre_command_1a4cfaaf9bd50ec4b32f10279c611694f2"></a>
### `has_motion_hits`
```cpp
bool espectre::EspectreCommand::has_motion_hits {false}
```
<a id="structespectre_1_1_espectre_command_1a216bdbeabae77df5241b82de126dbdb4"></a>
### `traffic_generator_mode`
```cpp
std::string espectre::EspectreCommand::traffic_generator_mode
```
`update_sensing` mode name; see [parse\_traffic\_generator\_mode()](#namespaceespectre_1a89421b6006f8113b7d9f54cb4ed202b8).
<a id="structespectre_1_1_espectre_command_1a89245feb9fe935e4f9207fac6c52a379"></a>
### `has_traffic_generator_mode`
```cpp
bool espectre::EspectreCommand::has_traffic_generator_mode {false}
```
<a id="structespectre_1_1_espectre_command_1ad706b46d3d8a0128a06d88cfa7cbefbe"></a>
### `detector`
```cpp
std::string espectre::EspectreCommand::detector
```
`update_sensing` detector name; see [parse\_detection\_algorithm()](#namespaceespectre_1a58cce43945e826bdfe8db0e85cd5732c).
<a id="structespectre_1_1_espectre_command_1a754b3484de80075b8fa2cc0ea435af1c"></a>
### `has_detector`
```cpp
bool espectre::EspectreCommand::has_detector {false}
```
<a id="structespectre_1_1_espectre_command_1a24c6d08b3dacb6745b4c398b2c041234"></a>
### `wifi_bssid`
```cpp
std::string espectre::EspectreCommand::wifi_bssid
```
`set_wifi_bssid` target, as `AA:BB:CC:DD:EE:FF`.
<a id="structespectre_1_1_espectre_command_1a8d345b5004accd98a6c536e34ccfc212"></a>
### `has_wifi_bssid`
```cpp
bool espectre::EspectreCommand::has_wifi_bssid {false}
```
<a id="structespectre_1_1_espectre_command_1a269c13bff465eca13b5a9218a238cc15"></a>
### `wifi_bssid_force`
```cpp
bool espectre::EspectreCommand::wifi_bssid_force {false}
```
Force reassociation even when [`wifi_bssid`](#structespectre_1_1_espectre_command_1a24c6d08b3dacb6745b4c398b2c041234) is already active.
<a id="structespectre_1_1_espectre_command_1a6e9584841c1b52066a4d4ea1fb84e14a"></a>
### `has_wifi_bssid_force`
```cpp
bool espectre::EspectreCommand::has_wifi_bssid_force {false}
```
<a id="structespectre_1_1_espectre_command_1aec085c9f5943af0864d214935cd6c08e"></a>
### `extension_parameters`
```cpp
std::string espectre::EspectreCommand::extension_parameters
```
JSON parameters for a frontend extension command.
Initially the whole request from [parse\_espectre\_command()](#namespaceespectre_1affd612c44046053715f0e4947c579959), or the parameter object from [parse\_espectre\_command\_request()](#namespaceespectre_1a3719c5d411370f85344e700a2eb961a5); its validator may normalize them.
<a id="structespectre_1_1_espectre_device_config"></a>
## espectre::EspectreDeviceConfig
```cpp
#include <runtime/espectre_protocol.h>
```
```cpp
struct espectre::EspectreDeviceConfig
```
Device identity and broker settings.
Frontends persist this so a device keeps its identity and connection across reboots and reprovisioning.
<a id="structespectre_1_1_espectre_device_config_1a81f5bcd174ba6f52c81481ce172d274a"></a>
### `device_id`
```cpp
uint64_t espectre::EspectreDeviceConfig::device_id {ESPECTRE_DEFAULT_DEVICE_ID}
```
Stable device identity.
Zero means use the runtime-generated value.
<a id="structespectre_1_1_espectre_device_config_1aca7110074cb8deafe9fc8653dd2ded4f"></a>
### `device_label`
```cpp
std::string espectre::EspectreDeviceConfig::device_label {ESPECTRE_DEFAULT_DEVICE_LABEL}
```
Human-readable name.
Empty falls back to the formatted device id.
<a id="structespectre_1_1_espectre_device_config_1add9bc633f1f75f7c12ddf44d83965335"></a>
### `mqtt_scheme`
```cpp
std::string espectre::EspectreDeviceConfig::mqtt_scheme
```
Broker transport scheme: `mqtt` or `mqtts`.
Empty disables MQTT.
<a id="structespectre_1_1_espectre_device_config_1a6bc7843ffc079108684b040e77b59c89"></a>
### `mqtt_host`
```cpp
std::string espectre::EspectreDeviceConfig::mqtt_host
```
Broker DNS hostname, IPv4 address, or IPv6 address, without URI framing.
<a id="structespectre_1_1_espectre_device_config_1ac8aed6d2ebbe21bfc26583502a705f75"></a>
### `mqtt_port`
```cpp
uint16_t espectre::EspectreDeviceConfig::mqtt_port {0U}
```
Broker port.
Zero means MQTT is not configured.
<a id="structespectre_1_1_espectre_device_config_1aaedefcaaec63f7b9bf2d46e69be0e6cb"></a>
### `mqtt_username`
```cpp
std::string espectre::EspectreDeviceConfig::mqtt_username
```
Broker user name.
Leave empty for anonymous brokers.
<a id="structespectre_1_1_espectre_device_config_1afe6956ffef02ae5a6a5b807c3fbe47cc"></a>
### `mqtt_password`
```cpp
std::string espectre::EspectreDeviceConfig::mqtt_password
```
Broker password.
Never published by the protocol.
<a id="structespectre_1_1_espectre_device_config_1ae89cde8ec77492cd8dd8fb315206630f"></a>
### `topic_prefix`
```cpp
std::string espectre::EspectreDeviceConfig::topic_prefix {ESPECTRE_TOPIC_PREFIX}
```
Topic root.
Change it only if you also change every consumer.
<a id="structespectre_1_1_espectre_device_info"></a>
## espectre::EspectreDeviceInfo
```cpp
#include <runtime/espectre_protocol.h>
```
```cpp
struct espectre::EspectreDeviceInfo
```
What the device advertises about itself.
The `supports_*` flags are internal inputs used to build the filtered `capabilities` catalog. They are deliberately omitted from `info` so clients have one authoritative feature-discovery surface.
<a id="structespectre_1_1_espectre_device_info_1a372030a3cb91330001da9723f4398247"></a>
### `supports_info`
```cpp
bool espectre::EspectreDeviceInfo::supports_info {true}
```
<a id="structespectre_1_1_espectre_device_info_1a437aec304310ffbadb7ed306345486f7"></a>
### `supports_diagnostics`
```cpp
bool espectre::EspectreDeviceInfo::supports_diagnostics {false}
```
<a id="structespectre_1_1_espectre_device_info_1a3d5ea9c20ebbdf08c195ebf44860af6d"></a>
### `supports_device_config`
```cpp
bool espectre::EspectreDeviceInfo::supports_device_config {false}
```
`update_device` is honored and persists the user-facing label.
<a id="structespectre_1_1_espectre_device_info_1ac71dfcd58f5a2e8acc8496b742789344"></a>
### `supports_runtime_threshold`
```cpp
bool espectre::EspectreDeviceInfo::supports_runtime_threshold {false}
```
<a id="structespectre_1_1_espectre_device_info_1aa5dc916c596456bf20292c70a0ff57d3"></a>
### `supports_runtime_motion_hits`
```cpp
bool espectre::EspectreDeviceInfo::supports_runtime_motion_hits {false}
```
<a id="structespectre_1_1_espectre_device_info_1a1dc9fa2a45b8c5264b74378f5a62a0de"></a>
### `supports_runtime_detector`
```cpp
bool espectre::EspectreDeviceInfo::supports_runtime_detector {false}
```
<a id="structespectre_1_1_espectre_device_info_1a7cf705f7ef81bc61231f21342ead22ae"></a>
### `supports_manual_recalibration`
```cpp
bool espectre::EspectreDeviceInfo::supports_manual_recalibration {false}
```
<a id="structespectre_1_1_espectre_device_info_1ab96702463074b99a02d75e8448457920"></a>
### `supports_traffic_control`
```cpp
bool espectre::EspectreDeviceInfo::supports_traffic_control {false}
```
<a id="structespectre_1_1_espectre_device_info_1a98e0874253f5cc0a4fb98aaa26ecfcab"></a>
### `frontend`
```cpp
std::string espectre::EspectreDeviceInfo::frontend {"unknown"}
```
Frontend name, for example `"native"`, `"matter"`, or your own.
<a id="structespectre_1_1_espectre_device_info_1a30cedb7142b425b1a8e7ad27840191d1"></a>
### `firmware_version`
```cpp
std::string espectre::EspectreDeviceInfo::firmware_version {"unknown"}
```
Application version supplied by the frontend or integrator.
<a id="structespectre_1_1_espectre_device_info_1ac0ea5c264b21400d093ec20f44c690a9"></a>
### `chip`
```cpp
std::string espectre::EspectreDeviceInfo::chip {"unknown"}
```
Chip target, normally `CONFIG_IDF_TARGET`.
<a id="structespectre_1_1_espectre_device_info_1afeac4f05b3c3cc10e8db70d07ce07aab"></a>
### `detector`
```cpp
std::string espectre::EspectreDeviceInfo::detector
```
Active detector.
Left empty, it is filled from the snapshot.
<a id="structespectre_1_1_espectre_device_info_1a8cb8d65d9f6669566e70928e93bd8428"></a>
### `csi_profile`
```cpp
std::string espectre::EspectreDeviceInfo::csi_profile
```
Automatically selected CSI capture profile.
Left empty, it is filled from the snapshot.
<a id="structespectre_1_1_espectre_device_info_1a1ae5306a262f1fceb0ace63065f3319a"></a>
### `traffic_mode`
```cpp
std::string espectre::EspectreDeviceInfo::traffic_mode
```
Traffic generator mode: `"ping"`, `"dns"`, `"dns_tcp"`, `"wifi_raw"`, or `"external"`.
Omitted from `info` when empty.
<a id="structespectre_1_1_espectre_device_info_1a9c6cd13342039c01196f9daa1bcf923b"></a>
### `csi_target_pps`
```cpp
uint32_t espectre::EspectreDeviceInfo::csi_target_pps {0U}
```
Internal traffic generator and temporal-grid target rate, in packets per second.
Omitted from `info` when zero.
<a id="structespectre_1_1_espectre_device_info_1addb54a961ad4acc29e410accb302b7f3"></a>
### `csi_traffic_udp_port`
```cpp
uint16_t espectre::EspectreDeviceInfo::csi_traffic_udp_port {0U}
```
UDP destination port used by the external CSI traffic generator.
<a id="structespectre_1_1_espectre_device_info_1a5e0e130624c638beeb2ca61c619bdecd"></a>
### `csi_traffic_multicast_group`
```cpp
std::string espectre::EspectreDeviceInfo::csi_traffic_multicast_group
```
IPv4 multicast group used by external CSI traffic, or empty for unicast-only operation.
<a id="structespectre_1_1_espectre_device_info_1a3dd182a7125e610e68f7158e3c09e20e"></a>
### `evaluation_interval_ms`
```cpp
uint32_t espectre::EspectreDeviceInfo::evaluation_interval_ms {0U}
```
Detector evaluation cadence, in milliseconds.
Omitted from `info` when zero. Canonical MQTT telemetry follows this interval.
<a id="structespectre_1_1_espectre_device_info_1a538ad375d04edaca9dc2fad775a23bf0"></a>
### `network`
```cpp
EspectreNetworkInfo espectre::EspectreDeviceInfo::network {}
```
Current link details.
<a id="structespectre_1_1_espectre_extension_route"></a>
## espectre::EspectreExtensionRoute
```cpp
#include <runtime/espectre_protocol.h>
```
```cpp
struct espectre::EspectreExtensionRoute
```
One frontend-owned route, shared by capability output and both transports.
<a id="structespectre_1_1_espectre_extension_route_1aab83e58cb053c7bb88f5c757f3ffdcb7"></a>
### `http_method`
```cpp
const char* espectre::EspectreExtensionRoute::http_method
```
HTTP method, such as `POST`.
<a id="structespectre_1_1_espectre_extension_route_1a11999df7cabf53bee4cd44e705f3b5ed"></a>
### `path`
```cpp
const char* espectre::EspectreExtensionRoute::path
```
Absolute path under `/espectre/v1`.
<a id="structespectre_1_1_espectre_extension_route_1acb880c342282379b5504f90d611dd6e6"></a>
### `name`
```cpp
const char* espectre::EspectreExtensionRoute::name
```
Resource or operation name in the `capabilities` catalog.
<a id="structespectre_1_1_espectre_extension_route_1a283adbd2404039858219bb25b22c219e"></a>
### `command`
```cpp
const char* espectre::EspectreExtensionRoute::command
```
Command name; must not collide with an SDK command.
<a id="structespectre_1_1_espectre_extension_route_1a63477d3373b59335ed35c7fc30d44de7"></a>
### `kind`
```cpp
EspectreApiRouteKind espectre::EspectreExtensionRoute::kind
```
<a id="structespectre_1_1_espectre_extension_route_1a6259d196f36470a17e7c8e9833c6d609"></a>
### `asynchronous`
```cpp
bool espectre::EspectreExtensionRoute::asynchronous {false}
```
Whether the operation completes after the response.
<a id="structespectre_1_1_espectre_extension_route_1a63cb47c8281f9d461f8c74c046a874af"></a>
### `mqtt`
```cpp
bool espectre::EspectreExtensionRoute::mqtt {false}
```
Whether the frontend command binding permits invocation over MQTT.
<a id="structespectre_1_1_espectre_extension_route_1a241fd946420c88d2acc33b131ca8fd17"></a>
### `allowed_during_raw_collection`
```cpp
bool espectre::EspectreExtensionRoute::allowed_during_raw_collection {false}
```
Whether the command may run while raw CSI collection is active.
<a id="structespectre_1_1_espectre_extension_route_1a6d826025d23f40a66dbe03639c4d4f02"></a>
### `validate`
```cpp
EspectreCommandValidator espectre::EspectreExtensionRoute::validate {nullptr}
```
Parameter validator.
Required.
<a id="structespectre_1_1_espectre_network_info"></a>
## espectre::EspectreNetworkInfo
```cpp
#include <runtime/espectre_protocol.h>
```
```cpp
struct espectre::EspectreNetworkInfo
```
Link details available to frontends.
Canonical MQTT info publishes only the channel.
<a id="structespectre_1_1_espectre_network_info_1a539c43609365b6dc97ca3a953545b8a5"></a>
### `ip_address`
```cpp
std::string espectre::EspectreNetworkInfo::ip_address
```
Dotted IPv4 address, or empty.
<a id="structespectre_1_1_espectre_network_info_1abd4271a4c76579a0d556462cadd32ccf"></a>
### `mac_address`
```cpp
std::string espectre::EspectreNetworkInfo::mac_address
```
Station MAC address, or empty.
<a id="structespectre_1_1_espectre_network_info_1afb3afd351ae9f6c2fe654e23557b2130"></a>
### `channel`
```cpp
uint8_t espectre::EspectreNetworkInfo::channel {0U}
```
Wi-Fi channel in use.
Zero when unknown.
<a id="structespectre_1_1_espectre_protocol_extension"></a>
## espectre::EspectreProtocolExtension
```cpp
#include <runtime/espectre_protocol.h>
```
```cpp
struct espectre::EspectreProtocolExtension
```
Immutable frontend additions.
Keep this object alive while adapters use it.
<a id="structespectre_1_1_espectre_protocol_extension_1a09ee85f8d1fe38009b808ff420b13476"></a>
### `routes`
```cpp
std::vector<EspectreExtensionRoute> espectre::EspectreProtocolExtension::routes
```
Extra routes and their commands.
<a id="structespectre_1_1_espectre_protocol_extension_1abcc84f7a49add2cd410f5a8d60de2b76"></a>
### `events`
```cpp
std::vector<std::string> espectre::EspectreProtocolExtension::events
```
Extra event names the application publishes.
<a id="structespectre_1_1_frontend_command_context"></a>
## espectre::FrontendCommandContext
```cpp
#include <runtime/frontend_command_engine.h>
```
```cpp
struct espectre::FrontendCommandContext
```
Where a command came from.
<a id="structespectre_1_1_frontend_command_context_1afa2f9a45ea6a720e082bbc48dedcc414"></a>
### `origin`
```cpp
FrontendCommandOrigin espectre::FrontendCommandContext::origin {FrontendCommandOrigin::DIRECT}
```
<a id="structespectre_1_1_frontend_command_context_1ab5e3b6101f580199bbf31688f2514d4e"></a>
### `connection_token`
```cpp
uint64_t espectre::FrontendCommandContext::connection_token {0U}
```
Opaque identity of the originating Direct connection; zero otherwise.
<a id="classespectre_1_1_frontend_command_engine"></a>
## espectre::FrontendCommandEngine
```cpp
#include <runtime/frontend_command_engine.h>
```
```cpp
class espectre::FrontendCommandEngine
```
Dispatches parsed protocol commands to frontend callbacks.
One engine serves every transport, so Direct HTTP, MQTT, and frontend surfaces apply the same capability checks and report the same result codes. The engine is stateless: frontends supply the capabilities and a callback for each kind of change they support. A command whose capability is not advertised, or whose callback is empty, is rejected as `unsupported`.
<a id="classespectre_1_1_frontend_command_engine_1a17c790151fd45182d2d020cd9d64019d"></a>
### `execute`
```cpp
FrontendCommandResult espectre::FrontendCommandEngine::execute(const EspectreCommand &command, const FrontendCommandContext &context, const FrontendCommandCapabilities &capabilities, FrontendReadPayloadCallback read_payload_callback, FrontendDeviceLabelCallback device_label_callback={}, FrontendThresholdCallback threshold_callback={}, FrontendMotionHitsCallback motion_hits_callback={}, FrontendTrafficGeneratorModeCallback traffic_generator_mode_callback={}, FrontendDetectorCallback detector_callback={}, FrontendRecalibrateCallback recalibrate_callback={}, FrontendWifiBssidCallback wifi_bssid_callback={}, FrontendMqttConfigCallback mqtt_config_callback={}, FrontendSensingControlCallback sensing_control_callback={}, FrontendSensingPreflightCallback sensing_preflight_callback={}) const
```
Execute a successfully parsed command.
Call a protocol parser first; this dispatcher checks capabilities and operational state, not parameters.
Read commands return the data from `read_payload_callback`. `update_sensing` first passes all its fields to `sensing_preflight_callback` and rejects the request as `invalid_params` if that fails, so nothing changes. It then applies the fields in order: detector, threshold, motion hits, traffic generator mode, then sensing state. A backend refusal after the preflight stops there; fields applied before it stay applied and are reported in [`FrontendCommandResult::changes`](#structespectre_1_1_frontend_command_result_1ac0e7393f21c05867f32f9678701a4fc6). Without a preflight callback, only capabilities are checked up front. Extension commands are not dispatched here; the application handles them.
<a id="structespectre_1_1_frontend_command_result"></a>
## espectre::FrontendCommandResult
```cpp
#include <runtime/frontend_command_engine.h>
```
```cpp
struct espectre::FrontendCommandResult
```
Outcome of [FrontendCommandEngine::execute()](#classespectre_1_1_frontend_command_engine_1a17c790151fd45182d2d020cd9d64019d), ready for [`espectre_command_result_payload()`](#namespaceespectre_1a23723f52835cb183d122bbaf8c5348f7).
<a id="structespectre_1_1_frontend_command_result_1a4b54953067c0b0fcd0b038c252ed18d3"></a>
### `handled`
```cpp
bool espectre::FrontendCommandResult::handled {false}
```
Always true for results returned by the engine.
<a id="structespectre_1_1_frontend_command_result_1a10179374b91551f82aa42c753ac91d4d"></a>
### `accepted`
```cpp
bool espectre::FrontendCommandResult::accepted {false}
```
Whether the command was applied or its data returned.
<a id="structespectre_1_1_frontend_command_result_1a35b941acfbc8f0a40cd71fc4444eaa2d"></a>
### `command`
```cpp
EspectreCommand espectre::FrontendCommandResult::command {}
```
The command that was executed.
<a id="structespectre_1_1_frontend_command_result_1a054a49799aafb67785fc8e45f08b14c8"></a>
### `code`
```cpp
std::string espectre::FrontendCommandResult::code {"internal_error"}
```
Stable result code: `ok`, `unsupported`, `forbidden`, `invalid_params`, `unavailable`, or `busy`.
<a id="structespectre_1_1_frontend_command_result_1ab145d66eabc6ed3afd21183d93aecb23"></a>
### `message`
```cpp
std::string espectre::FrontendCommandResult::message
```
Human-readable outcome.
<a id="structespectre_1_1_frontend_command_result_1a5fad97cea2c08b2568ecd4e6a10a1f9b"></a>
### `data_json`
```cpp
std::string espectre::FrontendCommandResult::data_json
```
JSON data returned by a read command; empty otherwise.
<a id="structespectre_1_1_frontend_command_result_1ac0e7393f21c05867f32f9678701a4fc6"></a>
### `changes`
```cpp
FrontendCommandChange espectre::FrontendCommandResult::changes {FrontendCommandChange::NONE}
```
Resources the command changed.
A rejected `update_sensing` still reports the fields applied before the rejection, so republish whenever this is not `NONE`, whether or not the command was accepted.
<a id="structespectre_1_1_frontend_device_config_defaults"></a>
## espectre::FrontendDeviceConfigDefaults
```cpp
#include <runtime/esp_idf/frontend_bootstrap_helpers.h>
```
```cpp
struct espectre::FrontendDeviceConfigDefaults
```
Build-time device settings used when nothing is saved in NVS.
The fields mirror [`EspectreDeviceConfig`](#structespectre_1_1_espectre_device_config); `nullptr` strings mean empty.
<a id="structespectre_1_1_frontend_device_config_defaults_1a659cf3e49fbec2b285fef4fe3189c312"></a>
### `device_label`
```cpp
const char* espectre::FrontendDeviceConfigDefaults::device_label {ESPECTRE_DEFAULT_DEVICE_LABEL}
```
<a id="structespectre_1_1_frontend_device_config_defaults_1a85e6cdbfc4f4af2a7500bbe9445a1c64"></a>
### `mqtt_scheme`
```cpp
const char* espectre::FrontendDeviceConfigDefaults::mqtt_scheme {""}
```
<a id="structespectre_1_1_frontend_device_config_defaults_1a0cd73628ab466d42f4ede69287d42baa"></a>
### `mqtt_host`
```cpp
const char* espectre::FrontendDeviceConfigDefaults::mqtt_host {""}
```
<a id="structespectre_1_1_frontend_device_config_defaults_1ad2fc4516ea752d9bdf04a988edd4455b"></a>
### `mqtt_port`
```cpp
uint16_t espectre::FrontendDeviceConfigDefaults::mqtt_port {0U}
```
<a id="structespectre_1_1_frontend_device_config_defaults_1ab2f2dfda15610082bab1c9ac3e032419"></a>
### `mqtt_username`
```cpp
const char* espectre::FrontendDeviceConfigDefaults::mqtt_username {""}
```
<a id="structespectre_1_1_frontend_device_config_defaults_1aa47a74274c8531654ba4df1df3f18ca3"></a>
### `mqtt_password`
```cpp
const char* espectre::FrontendDeviceConfigDefaults::mqtt_password {""}
```
<a id="structespectre_1_1_frontend_device_config_defaults_1a08565e041545e1d904857ee8a2326657"></a>
### `topic_prefix`
```cpp
const char* espectre::FrontendDeviceConfigDefaults::topic_prefix {ESPECTRE_TOPIC_PREFIX}
```
<a id="structespectre_1_1_frontend_device_config_defaults_1a1dcf1af494b14b5fde944157b30cf0ec"></a>
### `runtime_device_id`
```cpp
uint64_t espectre::FrontendDeviceConfigDefaults::runtime_device_id {0U}
```
Device identity to use; zero derives it with [derive\_runtime\_device\_id()](#namespaceespectre_1a34031a60d78bbb6306047b3540b4f905).
<a id="structespectre_1_1_frontend_ha_diagnostic_sensor"></a>
## espectre::FrontendHaDiagnosticSensor
```cpp
#include <runtime/esp_idf/frontend_ha_mqtt_helpers.h>
```
```cpp
struct espectre::FrontendHaDiagnosticSensor
```
One Home Assistant sensor fed by a diagnostic field.
<a id="structespectre_1_1_frontend_ha_diagnostic_sensor_1a80fae5ab7d6d680529e1660f032d4ec8"></a>
### `name`
```cpp
std::string espectre::FrontendHaDiagnosticSensor::name
```
Entity name shown in Home Assistant.
<a id="structespectre_1_1_frontend_ha_diagnostic_sensor_1a7ba7f5fbb9a271e618e1e69c670fdb72"></a>
### `key`
```cpp
std::string espectre::FrontendHaDiagnosticSensor::key
```
Diagnostic field the sensor reports.
<a id="structespectre_1_1_frontend_ha_diagnostic_sensor_1a99372960224bd99cdf6099536c7180ee"></a>
### `object_id`
```cpp
std::string espectre::FrontendHaDiagnosticSensor::object_id
```
Home Assistant object id.
<a id="structespectre_1_1_frontend_ha_diagnostic_sensor_1a525e99d2d157a616b7f33fa17a4d43b7"></a>
### `state_topic`
```cpp
std::string espectre::FrontendHaDiagnosticSensor::state_topic
```
Topic the frontend publishes this sensor's value to.
<a id="structespectre_1_1_frontend_ha_diagnostic_sensor_1a1e54481a565bb28da66564cc0a48575a"></a>
### `unit_of_measurement`
```cpp
const char* espectre::FrontendHaDiagnosticSensor::unit_of_measurement {nullptr}
```
Optional unit; `nullptr` omits it.
<a id="structespectre_1_1_frontend_ha_diagnostic_sensor_1a68c00ff8cadb583266de1caf36b5a266"></a>
### `icon`
```cpp
const char* espectre::FrontendHaDiagnosticSensor::icon {nullptr}
```
Optional `mdi:` icon; `nullptr` omits it.
<a id="structespectre_1_1_frontend_ha_diagnostic_sensor_1a84271971a0ad39ca08bf322ec9aacf9f"></a>
### `device_class`
```cpp
const char* espectre::FrontendHaDiagnosticSensor::device_class {nullptr}
```
Optional Home Assistant device class; `nullptr` omits it.
<a id="structespectre_1_1_frontend_ha_diagnostic_sensor_1a88db374adaa551c9be06b4ef2614bec8"></a>
### `state_class_measurement`
```cpp
bool espectre::FrontendHaDiagnosticSensor::state_class_measurement {true}
```
Declare `state_class: measurement`, so Home Assistant keeps statistics.
<a id="structespectre_1_1_frontend_ha_discovery_message"></a>
## espectre::FrontendHaDiscoveryMessage
```cpp
#include <runtime/esp_idf/frontend_ha_mqtt_helpers.h>
```
```cpp
struct espectre::FrontendHaDiscoveryMessage
```
One retained discovery message.
<a id="structespectre_1_1_frontend_ha_discovery_message_1a4e6b8493b03cc44a2bf674e83902cf22"></a>
### `topic`
```cpp
std::string espectre::FrontendHaDiscoveryMessage::topic
```
<a id="structespectre_1_1_frontend_ha_discovery_message_1abbf9846a07b76ef77dded5eff7fe2f9a"></a>
### `payload`
```cpp
std::string espectre::FrontendHaDiscoveryMessage::payload
```
Discovery JSON.
<a id="structespectre_1_1_frontend_ha_mqtt_settings"></a>
## espectre::FrontendHaMqttSettings
```cpp
#include <runtime/esp_idf/frontend_ha_mqtt_helpers.h>
```
```cpp
struct espectre::FrontendHaMqttSettings
```
Topics and entity ids for Home Assistant MQTT discovery.
[build\_frontend\_ha\_mqtt\_settings()](#namespaceespectre_1ad0ab3784ab4c2449af25b7fb4f8a80b6) fills every field from the device configuration; adjust fields before building the discovery messages.
<a id="structespectre_1_1_frontend_ha_mqtt_settings_1a6a46b306d5abd7cbe82652b88c607205"></a>
### `motion_state_topic`
```cpp
std::string espectre::FrontendHaMqttSettings::motion_state_topic
```
<a id="structespectre_1_1_frontend_ha_mqtt_settings_1a3e9bb24b6ad400338516faf8c35cec1d"></a>
### `movement_state_topic`
```cpp
std::string espectre::FrontendHaMqttSettings::movement_state_topic
```
<a id="structespectre_1_1_frontend_ha_mqtt_settings_1a3062c20e610a4ad68e7afe7e850eeaa2"></a>
### `threshold_state_topic`
```cpp
std::string espectre::FrontendHaMqttSettings::threshold_state_topic
```
<a id="structespectre_1_1_frontend_ha_mqtt_settings_1a18fbd90a2a3ed2797ce8186f897a0fb3"></a>
### `threshold_command_topic`
```cpp
std::string espectre::FrontendHaMqttSettings::threshold_command_topic
```
<a id="structespectre_1_1_frontend_ha_mqtt_settings_1acf6152f879910c7705e18a7608c1e5cb"></a>
### `motion_on_hits_state_topic`
```cpp
std::string espectre::FrontendHaMqttSettings::motion_on_hits_state_topic
```
<a id="structespectre_1_1_frontend_ha_mqtt_settings_1adf56175738267c11e5b760432603a681"></a>
### `motion_on_hits_command_topic`
```cpp
std::string espectre::FrontendHaMqttSettings::motion_on_hits_command_topic
```
<a id="structespectre_1_1_frontend_ha_mqtt_settings_1a6e05ea3194206028b4f93e5d8de0450e"></a>
### `motion_off_hits_state_topic`
```cpp
std::string espectre::FrontendHaMqttSettings::motion_off_hits_state_topic
```
<a id="structespectre_1_1_frontend_ha_mqtt_settings_1a26333e2e6f2475429d48a86be0373594"></a>
### `motion_off_hits_command_topic`
```cpp
std::string espectre::FrontendHaMqttSettings::motion_off_hits_command_topic
```
<a id="structespectre_1_1_frontend_ha_mqtt_settings_1a22d72ad7a8c2b4fd8904dcfa2418ef8f"></a>
### `calibrate_state_topic`
```cpp
std::string espectre::FrontendHaMqttSettings::calibrate_state_topic
```
<a id="structespectre_1_1_frontend_ha_mqtt_settings_1a14ac2de9442389a5861f906465276415"></a>
### `calibrate_command_topic`
```cpp
std::string espectre::FrontendHaMqttSettings::calibrate_command_topic
```
<a id="structespectre_1_1_frontend_ha_mqtt_settings_1a9cda7589d40fc3547e29c496d6e02997"></a>
### `detector_state_topic`
```cpp
std::string espectre::FrontendHaMqttSettings::detector_state_topic
```
<a id="structespectre_1_1_frontend_ha_mqtt_settings_1a9a985fb5bb45df15025428de5cf0bfbe"></a>
### `detector_command_topic`
```cpp
std::string espectre::FrontendHaMqttSettings::detector_command_topic
```
<a id="structespectre_1_1_frontend_ha_mqtt_settings_1a9e81fc2b48889395da591a07b413b9ef"></a>
### `traffic_generator_mode_state_topic`
```cpp
std::string espectre::FrontendHaMqttSettings::traffic_generator_mode_state_topic
```
<a id="structespectre_1_1_frontend_ha_mqtt_settings_1a5e2c007cec86c2dcb03bf49781dc3d99"></a>
### `traffic_generator_mode_command_topic`
```cpp
std::string espectre::FrontendHaMqttSettings::traffic_generator_mode_command_topic
```
<a id="structespectre_1_1_frontend_ha_mqtt_settings_1a1e97a2be49e37b392da23d3093eddfd5"></a>
### `diagnostics_command_topic`
```cpp
std::string espectre::FrontendHaMqttSettings::diagnostics_command_topic
```
<a id="structespectre_1_1_frontend_ha_mqtt_settings_1aebd7206ac2646bf74d76a78d9e8ed9ba"></a>
### `motion_object_id`
```cpp
std::string espectre::FrontendHaMqttSettings::motion_object_id
```
<a id="structespectre_1_1_frontend_ha_mqtt_settings_1a0773e6e2399eb64fa91338f1da547b49"></a>
### `movement_object_id`
```cpp
std::string espectre::FrontendHaMqttSettings::movement_object_id
```
<a id="structespectre_1_1_frontend_ha_mqtt_settings_1a99b35971b177319b3037efa2ec0c3488"></a>
### `threshold_object_id`
```cpp
std::string espectre::FrontendHaMqttSettings::threshold_object_id
```
<a id="structespectre_1_1_frontend_ha_mqtt_settings_1afa3ec3555092976c40b2216d58a377ca"></a>
### `motion_on_hits_object_id`
```cpp
std::string espectre::FrontendHaMqttSettings::motion_on_hits_object_id
```
<a id="structespectre_1_1_frontend_ha_mqtt_settings_1aac2915ea47c9dc2db666ae0abc668343"></a>
### `motion_off_hits_object_id`
```cpp
std::string espectre::FrontendHaMqttSettings::motion_off_hits_object_id
```
<a id="structespectre_1_1_frontend_ha_mqtt_settings_1a8ae34e66f2421743caf648499f1b1219"></a>
### `recalibrate_object_id`
```cpp
std::string espectre::FrontendHaMqttSettings::recalibrate_object_id
```
<a id="structespectre_1_1_frontend_ha_mqtt_settings_1a678649c91fad8ca213e0f25e0584ff4f"></a>
### `calibration_active_object_id`
```cpp
std::string espectre::FrontendHaMqttSettings::calibration_active_object_id
```
<a id="structespectre_1_1_frontend_ha_mqtt_settings_1a28772a882f61bba32dcc296ca2cf3c80"></a>
### `detector_object_id`
```cpp
std::string espectre::FrontendHaMqttSettings::detector_object_id
```
<a id="structespectre_1_1_frontend_ha_mqtt_settings_1aadd5e5d5490b416e8592d69c079da520"></a>
### `traffic_generator_mode_object_id`
```cpp
std::string espectre::FrontendHaMqttSettings::traffic_generator_mode_object_id
```
<a id="structespectre_1_1_frontend_ha_mqtt_settings_1a80c4edcf18fa2eef5e66d9b437fd533d"></a>
### `diagnostics_object_id`
```cpp
std::string espectre::FrontendHaMqttSettings::diagnostics_object_id
```
<a id="structespectre_1_1_frontend_ha_mqtt_settings_1a8d698ae0b479152a1541b2feee8c5b3e"></a>
### `discovery_prefix`
```cpp
std::string espectre::FrontendHaMqttSettings::discovery_prefix
```
Discovery root, from `CONFIG_ESPECTRE_HA_DISCOVERY_PREFIX`.
<a id="structespectre_1_1_frontend_ha_mqtt_settings_1a7fb79e719d7e2d266759eaea05872c96"></a>
### `birth_topic`
```cpp
std::string espectre::FrontendHaMqttSettings::birth_topic
```
Home Assistant birth topic; republish discovery when it announces `online`.
<a id="structespectre_1_1_frontend_ha_mqtt_settings_1afded0cf1d681651914d115c267433088"></a>
### `availability_topic`
```cpp
std::string espectre::FrontendHaMqttSettings::availability_topic
```
Topic whose payload reports availability; the `health` topic.
<a id="structespectre_1_1_frontend_ha_mqtt_settings_1a1eab8acce95aa4a8a473bbb28383c4d4"></a>
### `availability_template`
```cpp
std::string espectre::FrontendHaMqttSettings::availability_template
```
Template that turns the availability payload into `online` or `offline`.
<a id="structespectre_1_1_frontend_ha_mqtt_settings_1a5bf72ba04e894026945f7e412c9c410c"></a>
### `ha_object_prefix`
```cpp
std::string espectre::FrontendHaMqttSettings::ha_object_prefix
```
Prefix shared by every object id, derived from the frontend name and device id.
<a id="structespectre_1_1_frontend_ha_mqtt_settings_1a85a914412682eb7c3ff096355f7a40a7"></a>
### `diagnostic_sensors`
```cpp
std::vector<FrontendHaDiagnosticSensor> espectre::FrontendHaMqttSettings::diagnostic_sensors
```
Diagnostic sensors to announce.
<a id="structespectre_1_1_frontend_ha_mqtt_settings_1abf85200e68fefd3aa06ec76013271550"></a>
### `device_id`
```cpp
std::string espectre::FrontendHaMqttSettings::device_id
```
Device identity in the Home Assistant device registry.
<a id="structespectre_1_1_frontend_ha_mqtt_settings_1a5cf153b3ccf9a024f2d677ef7a9d892d"></a>
### `device_name`
```cpp
std::string espectre::FrontendHaMqttSettings::device_name
```
Device name in the Home Assistant device registry.
<a id="structespectre_1_1_frontend_ha_mqtt_settings_1a3293eeda4743499c6db7d62d3f4dece6"></a>
### `model`
```cpp
std::string espectre::FrontendHaMqttSettings::model
```
Device model in the Home Assistant device registry.
<a id="structespectre_1_1_frontend_wifi_station_options"></a>
## espectre::FrontendWifiStationOptions
```cpp
#include <runtime/esp_idf/frontend_bootstrap_helpers.h>
```
```cpp
struct espectre::FrontendWifiStationOptions
```
Station settings for [setup\_frontend\_wifi\_station()](#namespaceespectre_1a9c0cb264d4cfce2b1652a1da5e178fb3).
The credential and channel fields are the build-time defaults of [WifiProvisioningDefaults](#structespectre_1_1_wifi_provisioning_defaults); saved provisioning takes precedence.
<a id="structespectre_1_1_frontend_wifi_station_options_1a206bffdeb0c807a05829aef07201b18e"></a>
### `ssid`
```cpp
const char* espectre::FrontendWifiStationOptions::ssid {nullptr}
```
<a id="structespectre_1_1_frontend_wifi_station_options_1a29c8958337fe016cfaea779e71405d4e"></a>
### `password`
```cpp
const char* espectre::FrontendWifiStationOptions::password {nullptr}
```
<a id="structespectre_1_1_frontend_wifi_station_options_1a9acbb9d91ae575bb9f865f78ef76d4de"></a>
### `bssid`
```cpp
const char* espectre::FrontendWifiStationOptions::bssid {nullptr}
```
<a id="structespectre_1_1_frontend_wifi_station_options_1a38cbc5d9835a120fb95893d0f43e2448"></a>
### `configured_channel`
```cpp
int espectre::FrontendWifiStationOptions::configured_channel {0}
```
Channel hint; [`WIFI_CHANNEL_AUTO`](#namespaceespectre_1ab18ef5b016f2a45b3e57911383e7a528) for none.
<a id="structespectre_1_1_frontend_wifi_station_options_1aaea0f7e7c6dd4003c799294123f45692"></a>
### `max_retry`
```cpp
int espectre::FrontendWifiStationOptions::max_retry {8}
```
<a id="structespectre_1_1_frontend_wifi_station_options_1acfef20b31152a3bd68da54724e0961c4"></a>
### `manage_csi_lifecycle`
```cpp
bool espectre::FrontendWifiStationOptions::manage_csi_lifecycle {false}
```
Forwarded to [`StandaloneWifiConfig::manage_csi_lifecycle`](#structespectre_1_1_standalone_wifi_config_1a1fa7c525d96db4d9729b0bc3be689ce2).
<a id="structespectre_1_1_frontend_wifi_station_options_1ab768ec3b3ae37afbb890422e627e9e5d"></a>
### `start_manager`
```cpp
bool espectre::FrontendWifiStationOptions::start_manager {false}
```
Start the station after setting it up.
<a id="structespectre_1_1_frontend_wifi_station_options_1adc1b615bee32f339ac74c65f6db27683"></a>
### `change_callback`
```cpp
WifiProvisioningService::ChangeCallback espectre::FrontendWifiStationOptions::change_callback {}
```
Forwarded to [WifiProvisioningService::set\_change\_callback()](#classespectre_1_1_wifi_provisioning_service_1a3974e07bf87f9714e0733a0b0ac30477).
<a id="structespectre_1_1_frontend_wifi_station_options_1a84d42e71c8939635ed67ff8426c26ef6"></a>
### `connected_callback`
```cpp
standalone_wifi_callback_t espectre::FrontendWifiStationOptions::connected_callback {}
```
<a id="structespectre_1_1_frontend_wifi_station_options_1aeae790292be454b20bf674bdd829592c"></a>
### `disconnected_callback`
```cpp
standalone_wifi_callback_t espectre::FrontendWifiStationOptions::disconnected_callback {}
```
<a id="structespectre_1_1_frontend_wifi_station_options_1aaa6cfc09dd4e9d59b5c52de40f8332f6"></a>
### `band_policy`
```cpp
WifiBandPolicy espectre::FrontendWifiStationOptions::band_policy {WifiBandPolicy::BAND_2G}
```
<a id="classespectre_1_1_high_accuracy_detector"></a>
## espectre::HighAccuracyDetector
```cpp
#include <core/high_accuracy_detector.h>
```
```cpp
class espectre::HighAccuracyDetector : public espectre::BaseDetector
```
Neural motion detector, using the MLP weights exported by training.
Unlike [`LightweightDetector`](#classespectre_1_1_lightweight_detector) it does not calibrate to the room: it ships a fixed threshold learned at training time, so it performs best in environments the training corpus represents. Check the per-chip figures in the [performance report](<https://github.com/francescopace/espectre/blob/main/docs/performance/README.md>) before choosing it over Lightweight.
Same usage as [`LightweightDetector`](#classespectre_1_1_lightweight_detector) on the core-only path, and the same threading rules. The weights in `core/ml_weights.h` are generated; see [ML\_TRAINING.md](<https://github.com/francescopace/espectre/blob/main/docs/ML_TRAINING.md>) to retrain them.
[`espectre::BaseDetector`](#classespectre_1_1_base_detector)
<a id="classespectre_1_1_high_accuracy_detector_1a8abe924f8cfc5b950f03a81819660d50"></a>
### `HighAccuracyDetector`
```cpp
espectre::HighAccuracyDetector::HighAccuracyDetector(uint16_t window_size=DETECTOR_DEFAULT_WINDOW_SIZE, float threshold=HIGH_ACCURACY_DEFAULT_THRESHOLD, uint16_t lag=L1_DELTA_LAG)
```
Constructor.
**Parameters**
- `window_size`: Feature extraction window size in the inclusive range defined by DETECTOR\_MIN\_WINDOW\_SIZE and DETECTOR\_MAX\_WINDOW\_SIZE
- `threshold`: Motion detection threshold (0.0-1.0 on the ML probability scale)
- `lag`: Profile-displacement distance in packets. Production uses the nominal-rate default. Alternate values are for replay experiments and require retraining before deployment.
<a id="classespectre_1_1_high_accuracy_detector_1a419cca780bf04a8b49156eab81aba632"></a>
### `~HighAccuracyDetector`
```cpp
espectre::HighAccuracyDetector::~HighAccuracyDetector() override
```
<a id="classespectre_1_1_high_accuracy_detector_1aaa26e576e969f50a416ea9fa9be1f534"></a>
### `HighAccuracyDetector`
```cpp
espectre::HighAccuracyDetector::HighAccuracyDetector(HighAccuracyDetector &&other) noexcept
```
<a id="classespectre_1_1_high_accuracy_detector_1a753a343d584ca462f941244fa86704c5"></a>
### `operator=`
```cpp
HighAccuracyDetector & espectre::HighAccuracyDetector::operator=(HighAccuracyDetector &&other) noexcept
```
<a id="classespectre_1_1_high_accuracy_detector_1ad03f02184534d8d78022c4ef39bfe064"></a>
### `HighAccuracyDetector`
```cpp
espectre::HighAccuracyDetector::HighAccuracyDetector(const HighAccuracyDetector &)=delete
```
<a id="classespectre_1_1_high_accuracy_detector_1a88124904a2c79a845223d052c356d3f1"></a>
### `operator=`
```cpp
HighAccuracyDetector & espectre::HighAccuracyDetector::operator=(const HighAccuracyDetector &)=delete
```
<a id="classespectre_1_1_high_accuracy_detector_1a6b757cf36e76d564867142fbb7eed886"></a>
### `process_packet`
```cpp
void espectre::HighAccuracyDetector::process_packet(const int8_t *csi_data, size_t csi_len, const uint8_t *selected_subcarriers=nullptr, uint8_t num_subcarriers=0, int8_t rssi_dbm=INT8_MIN) override
```
Process one normalized, temporally admitted CSI packet.
Calculates spatial turbulence from CSI data, applies filtering, and stores in circular buffer.
**Parameters**
- `csi_data`: Normalized CSI data (I/Q interleaved)
- `csi_len`: Length of CSI data
- `selected_subcarriers`: Array of subcarrier indices
- `num_subcarriers`: Number of selected subcarriers
- `rssi_dbm`: Link RSSI for this packet, or INT8\_MIN when unknown
<a id="classespectre_1_1_high_accuracy_detector_1a346ad05afbe1ef410c4d66fb93b1ed82"></a>
### `advance_missing_slots`
```cpp
void espectre::HighAccuracyDetector::advance_missing_slots(uint32_t count) override
```
Advance packet-indexed feature rings for absent temporal slots.
<a id="classespectre_1_1_high_accuracy_detector_1ad2dc97f2244b7480e876aa2ec5434b09"></a>
### `update_state`
```cpp
void espectre::HighAccuracyDetector::update_state() override
```
Update state machine (call at the detector evaluation interval).
Subclasses implement their detection algorithm here.
<a id="classespectre_1_1_high_accuracy_detector_1ad74ad007107531f8d6256382723fdeea"></a>
### `clear_buffer`
```cpp
void espectre::HighAccuracyDetector::clear_buffer() override
```
Clear turbulence buffer (cold restart).
Virtual so detectors with additional state (e.g. L1-Delta profile rings) can extend the cold clear.
<a id="classespectre_1_1_high_accuracy_detector_1a2b06b097b5297dd0657135c35ed495ed"></a>
### `is_ready`
```cpp
bool espectre::HighAccuracyDetector::is_ready() const override
```
Check if detector is ready.
Ready once the window has filled and its valid slots reach the floor set by [set\_minimum\_valid\_samples()](#classespectre_1_1_base_detector_1a9732e34f845a2eb619ac9f42e1096353).
<a id="classespectre_1_1_high_accuracy_detector_1a5714b924b98643cec4011d1615aa9a42"></a>
### `is_valid`
```cpp
bool espectre::HighAccuracyDetector::is_valid() const override
```
Return whether all base detector working storage was allocated.
<a id="classespectre_1_1_high_accuracy_detector_1a05da3de784780af05d10273efdc079af"></a>
### `set_threshold`
```cpp
bool espectre::HighAccuracyDetector::set_threshold(float threshold) override
```
Set detection threshold.
**Parameters**
- `threshold`: New threshold value
**Returns:** true if value was accepted
<a id="classespectre_1_1_high_accuracy_detector_1aafe80e8f8559c570554a3d2712e68eca"></a>
### `get_threshold`
```cpp
float espectre::HighAccuracyDetector::get_threshold() const override
```
Get current threshold.
<a id="classespectre_1_1_high_accuracy_detector_1a6695e4d3a97f8387bda3f8ff6a227e81"></a>
### `get_name`
```cpp
const char * espectre::HighAccuracyDetector::get_name() const override
```
Get detector name for logging.
<a id="classespectre_1_1_high_accuracy_detector_1a1e1e180fb3242297ceb69bb55ad50a51"></a>
### `configure_hampel`
```cpp
void espectre::HighAccuracyDetector::configure_hampel(bool enabled, uint8_t window_size=HAMPEL_TURBULENCE_WINDOW_DEFAULT, float threshold=HAMPEL_TURBULENCE_THRESHOLD_DEFAULT) override
```
Configure Hampel filter.
**Parameters**
- `enabled`: Whether to enable the filter
- `window_size`: Window size (3-11)
- `threshold`: MAD multiplier threshold
<a id="classespectre_1_1_high_accuracy_detector_1a1924bfdb1e6ae3c85172b3189551f2fe"></a>
### `configure_lowpass`
```cpp
void espectre::HighAccuracyDetector::configure_lowpass(bool enabled, float cutoff_hz=LOWPASS_CUTOFF_DEFAULT) override
```
Configure low-pass filter.
**Parameters**
- `enabled`: Whether to enable the filter
- `cutoff_hz`: Cutoff frequency (5.0-20.0 Hz)
<a id="classespectre_1_1_i_csi_traffic_generator"></a>
## espectre::ICsiTrafficGenerator
```cpp
#include <runtime/csi_traffic_service.h>
```
```cpp
class espectre::ICsiTrafficGenerator
```
Internal traffic source that makes the access point answer the device.
[TrafficGeneratorManager](#classespectre_1_1_traffic_generator_manager) is the ESP-IDF implementation. Call every method from the owner task.
<a id="classespectre_1_1_i_csi_traffic_generator_1aa56d7c32d024963291509b76cd11da40"></a>
### `~ICsiTrafficGenerator`
```cpp
virtual espectre::ICsiTrafficGenerator::~ICsiTrafficGenerator()=default
```
<a id="classespectre_1_1_i_csi_traffic_generator_1a43ea91d3f4570aa0d281bae397c44ec8"></a>
### `init`
```cpp
virtual void espectre::ICsiTrafficGenerator::init(uint32_t target_pps, TrafficGeneratorMode mode)=0
```
Configure the send rate and mode while stopped.
<a id="classespectre_1_1_i_csi_traffic_generator_1aa91ad08e345f9f48335438c89990be27"></a>
### `start`
```cpp
virtual bool espectre::ICsiTrafficGenerator::start(uint32_t target_addr)=0
```
Start sending to an IPv4 address in network byte order; false on failure.
<a id="classespectre_1_1_i_csi_traffic_generator_1ae941653f3ec776a7b891486682ea053f"></a>
### `stop`
```cpp
virtual void espectre::ICsiTrafficGenerator::stop()=0
```
Signal the sender to stop.
[loop()](#classespectre_1_1_i_csi_traffic_generator_1a7e069a25ab8bf08f7fcd07e4855e86e2) releases it; this call does not block.
<a id="classespectre_1_1_i_csi_traffic_generator_1a7e069a25ab8bf08f7fcd07e4855e86e2"></a>
### `loop`
```cpp
virtual void espectre::ICsiTrafficGenerator::loop()=0
```
Advance periodic work from the owner task.
Called while stopped too, so an implementation can finish a [stop()](#classespectre_1_1_i_csi_traffic_generator_1ae941653f3ec776a7b891486682ea053f) that returned before its sender exited.
<a id="classespectre_1_1_i_csi_traffic_generator_1a4e085366eadb06c8e72a9e8b4d886ec2"></a>
### `hold_pending_restart`
```cpp
virtual void espectre::ICsiTrafficGenerator::hold_pending_restart(bool hold)
```
Keep a deferred start from launching inside [loop()](#classespectre_1_1_i_csi_traffic_generator_1a7e069a25ab8bf08f7fcd07e4855e86e2).
The owner sets this while it still has to disable CSI or touch the radio. [start()](#classespectre_1_1_i_csi_traffic_generator_1aa91ad08e345f9f48335438c89990be27) itself still launches once the previous sender has already exited.
**Parameters**
- `hold`: True to park the deferred start.
<a id="classespectre_1_1_i_csi_traffic_generator_1a199e6364991477c334ace5721c3b4b62"></a>
### `is_running`
```cpp
virtual bool espectre::ICsiTrafficGenerator::is_running() const =0
```
<a id="classespectre_1_1_i_csi_traffic_generator_1a13e508579ed21a7dd240a893d483fcd1"></a>
### `is_quiescent`
```cpp
virtual bool espectre::ICsiTrafficGenerator::is_quiescent() const
```
True when no sender is inside a send.
A deferred start can still be waiting.
<a id="classespectre_1_1_i_csi_traffic_generator_1a0ac0e1ffe0838a45c386d0beef1185b6"></a>
### `has_live_worker`
```cpp
virtual bool espectre::ICsiTrafficGenerator::has_live_worker() const
```
True after [start()](#classespectre_1_1_i_csi_traffic_generator_1aa91ad08e345f9f48335438c89990be27) has created a worker that [stop()](#classespectre_1_1_i_csi_traffic_generator_1ae941653f3ec776a7b891486682ea053f) has not signalled.
<a id="classespectre_1_1_i_csi_traffic_generator_1a1d9a989889f10b44356629f225c63af0"></a>
### `consume_start_failure`
```cpp
virtual bool espectre::ICsiTrafficGenerator::consume_start_failure()
```
True once, after a deferred launch fails.
Synchronous [start()](#classespectre_1_1_i_csi_traffic_generator_1aa91ad08e345f9f48335438c89990be27) does not set this.
<a id="classespectre_1_1_i_csi_traffic_generator_1a4d604b77c4be8fbcd2561f39dfa4e883"></a>
### `consume_stop_timeout`
```cpp
virtual bool espectre::ICsiTrafficGenerator::consume_stop_timeout()
```
True once, after a stopped sender has not exited within its grace period.
<a id="classespectre_1_1_i_csi_traffic_generator_1ae561e9b7aebda5148c1c62b97f9777d2"></a>
### `send_success_count`
```cpp
virtual uint32_t espectre::ICsiTrafficGenerator::send_success_count() const =0
```
Successful sends in the current session.
<a id="classespectre_1_1_i_csi_traffic_generator_1a92124965479b44d35b88a16a26d78775"></a>
### `icmp_identifier`
```cpp
virtual uint16_t espectre::ICsiTrafficGenerator::icmp_identifier() const =0
```
ICMP identifier used by ping traffic, so its replies can be recognized.
<a id="classespectre_1_1_i_csi_traffic_ingress"></a>
## espectre::ICsiTrafficIngress
```cpp
#include <runtime/csi_traffic_service.h>
```
```cpp
class espectre::ICsiTrafficIngress
```
Listener for traffic sent by another host in `EXTERNAL` mode.
Only datagrams whose payload matches the expected marker are counted and reported. Call every method from the owner task.
<a id="classespectre_1_1_i_csi_traffic_ingress_1a52abe6c059a0e7027b70c98f0f1d1ef5"></a>
### `~ICsiTrafficIngress`
```cpp
virtual espectre::ICsiTrafficIngress::~ICsiTrafficIngress()=default
```
<a id="classespectre_1_1_i_csi_traffic_ingress_1a032e74b603c7c77e9a0c089d37c92784"></a>
### `init`
```cpp
virtual void espectre::ICsiTrafficIngress::init(uint16_t port)=0
```
Set the UDP port to bind at the next [start()](#classespectre_1_1_i_csi_traffic_ingress_1af32d5cf7242053f8a1998dec716362fd).
<a id="classespectre_1_1_i_csi_traffic_ingress_1a4b1a7eafb45b592386a66fbeffcc5bc1"></a>
### `set_multicast_group`
```cpp
virtual void espectre::ICsiTrafficIngress::set_multicast_group(const char *group)=0
```
Set the multicast group to join, or `nullptr` for unicast only.
<a id="classespectre_1_1_i_csi_traffic_ingress_1a3d174084ec84ea73db71c60bee8b8f34"></a>
### `set_expected_payload`
```cpp
virtual void espectre::ICsiTrafficIngress::set_expected_payload(const uint8_t *payload, size_t len)=0
```
Set the payload a datagram must carry to be accepted.
<a id="classespectre_1_1_i_csi_traffic_ingress_1aa816a8caaec1016c7998756fd3031d45"></a>
### `set_packet_callback`
```cpp
virtual void espectre::ICsiTrafficIngress::set_packet_callback(csi_traffic_packet_callback_t callback, void *context=nullptr)=0
```
Register the per-packet callback; `context` is passed through unchanged.
<a id="classespectre_1_1_i_csi_traffic_ingress_1af32d5cf7242053f8a1998dec716362fd"></a>
### `start`
```cpp
virtual bool espectre::ICsiTrafficIngress::start()=0
```
Bind the socket and join the group; false on failure.
<a id="classespectre_1_1_i_csi_traffic_ingress_1af215abbbf80c1431220c5ab000fea810"></a>
### `stop`
```cpp
virtual void espectre::ICsiTrafficIngress::stop()=0
```
Close the socket.
<a id="classespectre_1_1_i_csi_traffic_ingress_1a5a6cc7046c6e4989caf2fa5ee3ac7c51"></a>
### `loop`
```cpp
virtual void espectre::ICsiTrafficIngress::loop()=0
```
Receive pending datagrams and deliver the callback.
<a id="classespectre_1_1_i_csi_traffic_ingress_1aa443f08dd27cedcc84d2c732e3d860f5"></a>
### `is_running`
```cpp
virtual bool espectre::ICsiTrafficIngress::is_running() const =0
```
<a id="classespectre_1_1_i_csi_traffic_ingress_1ac4cd5819ebc2847255bdfa5d9ecea39c"></a>
### `get_packets_received`
```cpp
virtual uint64_t espectre::ICsiTrafficIngress::get_packets_received() const =0
```
Accepted packets since [init()](#classespectre_1_1_i_csi_traffic_ingress_1a032e74b603c7c77e9a0c089d37c92784).
<a id="classespectre_1_1_i_csi_traffic_ingress_1aabedf208bf9ee9cd67baa5f03f4cc159"></a>
### `get_last_sender`
```cpp
virtual bool espectre::ICsiTrafficIngress::get_last_sender(UdpDatagramPeer *out_peer) const =0
```
Sender of the latest accepted packet; false before the first one.
<a id="classespectre_1_1_i_direct_http_service"></a>
## espectre::IDirectHttpService
```cpp
#include <runtime/direct_http_service.h>
```
```cpp
class espectre::IDirectHttpService
```
Local HTTP endpoints shared by ESPectre firmware frontends.
[`espectre::IDirectHttpService::DeferredRequestResult`](#structespectre_1_1_i_direct_http_service_1_1_deferred_request_result)
<a id="classespectre_1_1_i_direct_http_service_1a7d0434dbd3a5c12dffb28c2daffe5ec0"></a>
### `RequestHandler`
```cpp
using espectre::IDirectHttpService::RequestHandler = std::function<std::string(const DirectRequest &request)>
```
Answer a request synchronously with a canonical JSON response.
Runs from [loop()](#classespectre_1_1_i_direct_http_service_1a6f835ce9e9f17bd58c87b9b295f5a2c0).
<a id="classespectre_1_1_i_direct_http_service_1a40bce5f4a53bdd8391e97b2cb7bbdb29"></a>
### `ResponseSentCallback`
```cpp
using espectre::IDirectHttpService::ResponseSentCallback = std::function<void(bool sent)>
```
Reports whether the response reached the client.
<a id="classespectre_1_1_i_direct_http_service_1a01888012eaed141bfcf8cde8b25b36bf"></a>
### `DeferredRequestHandler`
```cpp
using espectre::IDirectHttpService::DeferredRequestHandler =
std::function<DeferredRequestResult(uint64_t request_token, const DirectRequest &request)>
```
Answer now or later; keep `request_token` to complete the request.
Runs from [loop()](#classespectre_1_1_i_direct_http_service_1a6f835ce9e9f17bd58c87b9b295f5a2c0).
<a id="classespectre_1_1_i_direct_http_service_1a79e0cf4b601a74148e34ac9269b2d301"></a>
### `ClientCountCallback`
```cpp
using espectre::IDirectHttpService::ClientCountCallback = std::function<void(size_t event_client_count)>
```
Reports the number of connected event stream clients after it changes.
<a id="classespectre_1_1_i_direct_http_service_1a586a3df77e489ea451bb53c0825736e2"></a>
### `RawSessionRequestedCallback`
```cpp
using espectre::IDirectHttpService::RawSessionRequestedCallback = std::function<bool(std::string *message)>
```
Open raw collection for `GET /csi`; return false with a reason to refuse it.
<a id="classespectre_1_1_i_direct_http_service_1af90d02bc26cb3c26b74f47858bfc898c"></a>
### `RawSessionStoppedCallback`
```cpp
using espectre::IDirectHttpService::RawSessionStoppedCallback = std::function<void(RawCsiStopReason reason)>
```
Reports why a raw session ended.
<a id="classespectre_1_1_i_direct_http_service_1a6942f8c8d9baa843bb95885b2d02e90f"></a>
### `~IDirectHttpService`
```cpp
virtual espectre::IDirectHttpService::~IDirectHttpService()=default
```
<a id="classespectre_1_1_i_direct_http_service_1a21bdc56c51f29cbfdec8545c8e52f705"></a>
### `setup`
```cpp
virtual bool espectre::IDirectHttpService::setup(const DirectHttpServiceConfig &config, RequestHandler request_handler, ClientCountCallback client_count_callback)=0
```
Configure and start the endpoint.
Safe to call again after shutdown.
<a id="classespectre_1_1_i_direct_http_service_1adb3a8a7bf1e9f08ce987142a1e7f9fce"></a>
### `setup_deferred`
```cpp
virtual bool espectre::IDirectHttpService::setup_deferred(const DirectHttpServiceConfig &config, DeferredRequestHandler request_handler, ClientCountCallback client_count_callback)
```
Configure a handler that may complete a request later.
The default preserves source compatibility for external transports that implement only synchronous Direct requests. A successful deferred handler must eventually call [complete\_deferred\_response()](#classespectre_1_1_i_direct_http_service_1a06fba7cb689b91f7be819faa83959575) with the opaque token.
<a id="classespectre_1_1_i_direct_http_service_1a06fba7cb689b91f7be819faa83959575"></a>
### `complete_deferred_response`
```cpp
virtual bool espectre::IDirectHttpService::complete_deferred_response(uint64_t request_token, std::string response)
```
Queue a deferred response only if the originating connection is live.
<a id="classespectre_1_1_i_direct_http_service_1a6f835ce9e9f17bd58c87b9b295f5a2c0"></a>
### `loop`
```cpp
virtual void espectre::IDirectHttpService::loop()=0
```
Pump deferred receive, dispatch, send work, and application callbacks from the frontend task.
Request, client-count, and raw-stop callbacks are never delivered from HTTP server or streaming worker tasks.
<a id="classespectre_1_1_i_direct_http_service_1ad8f2cf4aa8528504cfadfe34281e6e47"></a>
### `shutdown`
```cpp
virtual void espectre::IDirectHttpService::shutdown()=0
```
Stop accepting clients, close sockets, and release queued messages.
<a id="classespectre_1_1_i_direct_http_service_1af8e97ce6405baf11e9938a4040954ccd"></a>
### `running`
```cpp
virtual bool espectre::IDirectHttpService::running() const =0
```
True between a successful setup and [shutdown()](#classespectre_1_1_i_direct_http_service_1ad8f2cf4aa8528504cfadfe34281e6e47).
<a id="classespectre_1_1_i_direct_http_service_1aae1a9b281bfcbbccf9d66df82eb02e0f"></a>
### `event_client_count`
```cpp
virtual size_t espectre::IDirectHttpService::event_client_count() const =0
```
Connected event stream clients.
<a id="classespectre_1_1_i_direct_http_service_1aebcaa2d23b59c0ab5b59b19ad6ff8b80"></a>
### `publish_event`
```cpp
virtual bool espectre::IDirectHttpService::publish_event(const std::string &event_name, const std::string &data_json, bool replaceable_telemetry)=0
```
Queue a normalized event for every connected client.
Telemetry events may replace an older queued event with the same name. State transitions and command responses must never be replaced by telemetry. Returns false when no client can accept the event.
<a id="classespectre_1_1_i_direct_http_service_1ad9436229255cef3652b5ad01e50776ff"></a>
### `diagnostics`
```cpp
virtual DirectHttpServiceDiagnostics espectre::IDirectHttpService::diagnostics() const =0
```
Current counters.
<a id="classespectre_1_1_i_direct_http_service_1a16aa9eb2c01a18b2b866cf6fc00cd29b"></a>
### `set_raw_session_requested_callback`
```cpp
virtual void espectre::IDirectHttpService::set_raw_session_requested_callback(RawSessionRequestedCallback callback)
```
Register the frontend-task callback that opens collection for GET /csi.
<a id="classespectre_1_1_i_direct_http_service_1a21cb31f0636c6ac84554baa3532c9c5e"></a>
### `start_raw_session`
```cpp
virtual bool espectre::IDirectHttpService::start_raw_session(const RawCsiSessionConfig &config, RawSessionStoppedCallback stopped_callback)
```
Begin one owner-bound raw session on the service's binary endpoint.
<a id="classespectre_1_1_i_direct_http_service_1ae2917eb53be05f00272a68d65e57b14e"></a>
### `stop_raw_session`
```cpp
virtual bool espectre::IDirectHttpService::stop_raw_session(RawCsiStopReason reason)
```
Stop the active raw session and close its binary socket.
The stopped callback is delivered by [loop()](#classespectre_1_1_i_direct_http_service_1a6f835ce9e9f17bd58c87b9b295f5a2c0), or synchronously while [shutdown()](#classespectre_1_1_i_direct_http_service_1ad8f2cf4aa8528504cfadfe34281e6e47) completes on the owning frontend task.
<a id="classespectre_1_1_i_direct_http_service_1af860d2e8e4bf884954de06e137b4e288"></a>
### `offer_raw_packet`
```cpp
virtual bool espectre::IDirectHttpService::offer_raw_packet(const RawCsiPacketView &packet)
```
Copy one callback-scoped sample into the transport's bounded raw slots.
<a id="classespectre_1_1_i_direct_http_service_1a78821b4bf5721bea25c4b8d0e8c96a62"></a>
### `raw_diagnostics`
```cpp
virtual RawCsiSessionDiagnostics espectre::IDirectHttpService::raw_diagnostics() const
```
Counters of the current or last raw session; zeros when unsupported.
<a id="structespectre_1_1_i_direct_http_service_1_1_deferred_request_result"></a>
## espectre::IDirectHttpService::DeferredRequestResult
```cpp
#include <runtime/direct_http_service.h>
```
```cpp
struct espectre::IDirectHttpService::DeferredRequestResult
```
What a [DeferredRequestHandler](#classespectre_1_1_i_direct_http_service_1a01888012eaed141bfcf8cde8b25b36bf) decided for one request.
<a id="structespectre_1_1_i_direct_http_service_1_1_deferred_request_result_1a15136f0dc1f070fc1d4f92308833610a"></a>
### `deferred`
```cpp
bool espectre::IDirectHttpService::DeferredRequestResult::deferred {false}
```
True to answer later with [complete\_deferred\_response()](#classespectre_1_1_i_direct_http_service_1a06fba7cb689b91f7be819faa83959575); [`response`](#structespectre_1_1_i_direct_http_service_1_1_deferred_request_result_1a67b7adb4a29195f681c2c036f0b1062b) is then ignored.
<a id="structespectre_1_1_i_direct_http_service_1_1_deferred_request_result_1a67b7adb4a29195f681c2c036f0b1062b"></a>
### `response`
```cpp
std::string espectre::IDirectHttpService::DeferredRequestResult::response
```
Immediate response when [`deferred`](#structespectre_1_1_i_direct_http_service_1_1_deferred_request_result_1a15136f0dc1f070fc1d4f92308833610a) is false.
<a id="structespectre_1_1_i_direct_http_service_1_1_deferred_request_result_1a86fb9d9ffe614b43ad86ffe37c1b8ea6"></a>
### `response_sent_callback`
```cpp
ResponseSentCallback espectre::IDirectHttpService::DeferredRequestResult::response_sent_callback {}
```
Runs on the frontend task after the response send attempt completes.
<a id="classespectre_1_1_i_mqtt_transport"></a>
## espectre::IMqttTransport
```cpp
#include <runtime/mqtt_transport.h>
```
```cpp
class espectre::IMqttTransport
```
The MQTT client seam.
Implement it to carry ESPectre Protocol messages over an MQTT stack you already own, then hand the instance to a frontend. [`EspIdfMqttTransport`](#classespectre_1_1_esp_idf_mqtt_transport) ([`mqtt_transport_esp_idf.h`](#mqtt__transport__esp__idf_8h)) is the shipped implementation over `esp-mqtt`.
Topic layout and payload schemas live in [API.md](<https://github.com/francescopace/espectre/blob/main/docs/API.md>), and [`espectre_protocol.h`](#espectre__protocol_8h) builds the payloads, so an implementation only has to move bytes.
**Par:** Contract for implementers
- The transport is driven from the frontend's task: [`loop()`](#classespectre_1_1_i_mqtt_transport_1a002372527235e03bac5686a7ef9be0ab) is where you pump your client and deliver queued callbacks.
- Publishing while disconnected must fail cleanly rather than block.
- Registered subscriptions must survive a reconnect. Callers subscribe once and expect the broker subscription to be reissued on the next connect.
<a id="classespectre_1_1_i_mqtt_transport_1acc0dc393b8a4f5c5224c1ca0d05f1ac5"></a>
### `CommandCallback`
```cpp
using espectre::IMqttTransport::CommandCallback = std::function<void(const std::string &)>
```
Payload of a message on the device command topic.
<a id="classespectre_1_1_i_mqtt_transport_1abf12230069adc2e4a4133c576b1b8266"></a>
### `ConnectionCallback`
```cpp
using espectre::IMqttTransport::ConnectionCallback = std::function<void(bool connected)>
```
Broker connection state changed; the argument is the new state.
<a id="classespectre_1_1_i_mqtt_transport_1af45c762723f4ec009cafb30d82b89952"></a>
### `MessageCallback`
```cpp
using espectre::IMqttTransport::MessageCallback = std::function<void(const std::string &, const std::string &)>
```
Message on a topic registered through [`subscribe()`](#classespectre_1_1_i_mqtt_transport_1a114eb79f1af4599ae9648eb87ae89797): `(topic, payload)`.
<a id="classespectre_1_1_i_mqtt_transport_1ad0c7866dc6c5ba5cf0d358b66df50349"></a>
### `~IMqttTransport`
```cpp
virtual espectre::IMqttTransport::~IMqttTransport()=default
```
<a id="classespectre_1_1_i_mqtt_transport_1ac7f78bbd532a797bf6b53e26d005269c"></a>
### `setup`
```cpp
virtual bool espectre::IMqttTransport::setup(const EspectreDeviceConfig &config)=0
```
Configure and start connecting.
Asynchronous: true means the client started, not that it reached the broker. Wait for the connection callback before expecting publishes to land. Calling it again tears down the previous client and reconfigures.
**Returns:** false when the configuration cannot produce a client, such as an empty [`EspectreDeviceConfig::mqtt_host`](#structespectre_1_1_espectre_device_config_1a6bc7843ffc079108684b040e77b59c89).
<a id="classespectre_1_1_i_mqtt_transport_1a002372527235e03bac5686a7ef9be0ab"></a>
### `loop`
```cpp
virtual void espectre::IMqttTransport::loop()=0
```
Pump the client and dispatch callbacks.
Called from the frontend loop.
<a id="classespectre_1_1_i_mqtt_transport_1a367dda8b9a7cc32831c3fec442cd21bc"></a>
### `shutdown`
```cpp
virtual void espectre::IMqttTransport::shutdown()=0
```
Disconnect and release resources.
Safe to repeat.
<a id="classespectre_1_1_i_mqtt_transport_1aef7b264520bd820dd1475efbce2de5df"></a>
### `connected`
```cpp
virtual bool espectre::IMqttTransport::connected() const =0
```
True while the broker connection is established.
<a id="classespectre_1_1_i_mqtt_transport_1a9a10597cee927b981bd42922ad51cd4e"></a>
### `publish`
```cpp
virtual bool espectre::IMqttTransport::publish(const std::string &topic, const std::string &payload, bool retain)=0
```
Publish to an absolute topic.
**Parameters**
- `topic`: Full topic name, not a suffix.
- `payload`: Message body, copied before returning.
- `retain`: Ask the broker to retain the message, for state a late subscriber must still see, such as availability.
**Returns:** false when disconnected or the bounded publish queue rejects the message. Published at QoS 0, so true means queued locally, not delivered to the broker.
<a id="classespectre_1_1_i_mqtt_transport_1adfa1ecc1df9c7fc39fb07181193b6844"></a>
### `publish_suffix`
```cpp
virtual bool espectre::IMqttTransport::publish_suffix(const char *suffix, const std::string &payload, bool retain)=0
```
Publish under this device's protocol topic prefix.
The prefix comes from the [`EspectreDeviceConfig`](#structespectre_1_1_espectre_device_config) passed to [`setup()`](#classespectre_1_1_i_mqtt_transport_1ac7f78bbd532a797bf6b53e26d005269c), so callers pass only the trailing segment, for example `"motion"`.
<a id="classespectre_1_1_i_mqtt_transport_1a114eb79f1af4599ae9648eb87ae89797"></a>
### `subscribe`
```cpp
virtual bool espectre::IMqttTransport::subscribe(const std::string &topic, MessageCallback callback)=0
```
Register a topic and its handler.
Idempotent per topic: subscribing again replaces the handler. May be called before the connection is up; the subscription is issued on connect.
**Returns:** false for an empty topic or an empty callback.
<a id="classespectre_1_1_i_mqtt_transport_1a65414cdc22b80c2da4450e2d06d42868"></a>
### `set_command_callback`
```cpp
virtual void espectre::IMqttTransport::set_command_callback(CommandCallback callback)=0
```
Handler for the device command topic, which the transport subscribes itself.
<a id="classespectre_1_1_i_mqtt_transport_1a383063c67062b06bd8cf8f3da0a07edb"></a>
### `set_connection_callback`
```cpp
virtual void espectre::IMqttTransport::set_connection_callback(ConnectionCallback callback)=0
```
Handler for connection state changes, including reconnects.
<a id="classespectre_1_1_i_mqtt_transport_1ab54187eeae50e6ded380bb419d005a46"></a>
### `diagnostics`
```cpp
virtual MqttTransportDiagnostics espectre::IMqttTransport::diagnostics() const
```
Bounded outbound queue, drop, failure, and reconnect counters.
<a id="classespectre_1_1_i_peer_discovery_service"></a>
## espectre::IPeerDiscoveryService
```cpp
#include <runtime/peer_discovery.h>
```
```cpp
class espectre::IPeerDiscoveryService
```
Finds other ESPectre devices on the local network.
One search runs at a time. Call every method from the owner task.
<a id="classespectre_1_1_i_peer_discovery_service_1a1cf223ccf5d6d21bf17a9b87ffef8beb"></a>
### `Completion`
```cpp
using espectre::IPeerDiscoveryService::Completion = std::function<void(PeerDiscoverySnapshot snapshot)>
```
Receives the result of a search; delivered from [loop()](#classespectre_1_1_i_peer_discovery_service_1aa2a2d8fe5b6313de00d94094f618d009).
<a id="classespectre_1_1_i_peer_discovery_service_1a47af08903f6fbd96795f32a2da5d2ee1"></a>
### `~IPeerDiscoveryService`
```cpp
virtual espectre::IPeerDiscoveryService::~IPeerDiscoveryService()=default
```
<a id="classespectre_1_1_i_peer_discovery_service_1a8cee7d9b07243b4f198b202acf7e966e"></a>
### `set_local_candidate`
```cpp
virtual void espectre::IPeerDiscoveryService::set_local_candidate(PeerDiscoveryCandidate candidate)
```
Describe this device, so it appears in its own results.
<a id="classespectre_1_1_i_peer_discovery_service_1a9dd1f18dada5bfa92db388cb380c8169"></a>
### `set_wifi_ready`
```cpp
virtual void espectre::IPeerDiscoveryService::set_wifi_ready(bool ready)=0
```
Report whether the station has an IPv4 address; searches need one.
<a id="classespectre_1_1_i_peer_discovery_service_1ac0290e5614d7ba46e6747f8f9c8e76fd"></a>
### `ready`
```cpp
virtual bool espectre::IPeerDiscoveryService::ready() const =0
```
Whether a search can start now.
<a id="classespectre_1_1_i_peer_discovery_service_1a502f09da0fe65dd3b54377c43418b536"></a>
### `active`
```cpp
virtual bool espectre::IPeerDiscoveryService::active() const =0
```
Whether a search is running.
<a id="classespectre_1_1_i_peer_discovery_service_1a273a3530945f1215f9a75f18b83a56b7"></a>
### `start`
```cpp
virtual bool espectre::IPeerDiscoveryService::start(Completion completion)=0
```
Start a search; false when not ready or `completion` is empty.
<a id="classespectre_1_1_i_peer_discovery_service_1aa2a2d8fe5b6313de00d94094f618d009"></a>
### `loop`
```cpp
virtual void espectre::IPeerDiscoveryService::loop()=0
```
Collect results and deliver the completion when the search ends.
<a id="classespectre_1_1_i_peer_discovery_service_1a5a198f14c09be33a478887cdb09b213c"></a>
### `shutdown`
```cpp
virtual void espectre::IPeerDiscoveryService::shutdown()=0
```
Stop a running search without delivering its completion.
<a id="classespectre_1_1_i_runtime_listener"></a>
## espectre::IRuntimeListener
```cpp
#include <runtime/runtime_events.h>
```
```cpp
class espectre::IRuntimeListener
```
Everything the runtime tells your firmware.
Subclass it, override only what your product reacts to, and install it with `RuntimeFrontendController::setup(listener)`. Every callback has an empty default, so an integration that only cares about motion overrides one method.
**Par:** Threading and reentrancy
Callbacks are always delivered on the caller's task, never from an interrupt or the Wi-Fi driver:
- Sensing events (motion, readiness, periodic, live telemetry, calibration progress, and detector-driven threshold adaptation) originate in the CSI callback but are deferred through an internal mailbox and dispatched from `loop()`.
- Control-driven events (threshold writes, detector selection, and manual recalibration) fire inline on whichever task called the corresponding control method.
[`on_threshold_changed()`](#classespectre_1_1_i_runtime_listener_1a6c97b8ed80d39f723a1d244b178c93f2) covers every threshold source: a setter, a calibration result, or Lightweight settled-level recovery.
Keep callbacks bounded and non-blocking. Slow work delays the next `loop()` iteration and can fill the bounded CSI mailbox, causing incoming frames to be dropped. Queue network publication, NVS writes, and other potentially blocking work for another task. Calling back into the controller is allowed, with one exception noted on [`on_runtime_fault()`](#classespectre_1_1_i_runtime_listener_1ae566b842c3e051c1230fe922a834a70f).
**Par:** Snapshot lifetime
The `snapshot` reference is only valid for the duration of the call. Copy it if you need it later.
**Par:** Readiness
Snapshots are delivered during startup calibration as well. Gate anything user-visible on [`RuntimeSnapshot::ready_to_publish`](#structespectre_1_1_runtime_snapshot_1a3e917a2d24bbe00e55416b9ddf3bffcd) so you do not report motion from an uncalibrated detector.
<a id="classespectre_1_1_i_runtime_listener_1a005de2f93b412c0fa098cb89bf150035"></a>
### `~IRuntimeListener`
```cpp
virtual espectre::IRuntimeListener::~IRuntimeListener()=default
```
<a id="classespectre_1_1_i_runtime_listener_1ac791b4ec86d1cfcd3cbb3f4a87981d79"></a>
### `on_sensing_readiness_changed`
```cpp
virtual void espectre::IRuntimeListener::on_sensing_readiness_changed(const RuntimeSnapshot &snapshot)
```
Public sensing readiness changed, including warm-up and input expiry.
[RuntimeFrontendController](#classespectre_1_1_runtime_frontend_controller) emits this from loop(), after caching the current snapshot, and once from an explicit shutdown() when sensing was ready; the controller destructor does not call the listener. Publish the sensing resource on both availability transitions.
**Parameters**
- `snapshot`: Current sensing state, including public readiness.
<a id="classespectre_1_1_i_runtime_listener_1a3b0fd8a11331f19d48085ccb4e9623d8"></a>
### `on_motion_state_changed`
```cpp
virtual void espectre::IRuntimeListener::on_motion_state_changed(const RuntimeSnapshot &snapshot)
```
The debounced motion state changed.
Edge-triggered and already filtered by `motion_on_hits` / `motion_off_hits`, so this is the hook for occupancy, relays, and notifications.
It also fires with [`MotionState::IDLE`](#namespaceespectre_1a7d37681f3243ed6bdd97aee1ed776857aa5daf7f2ebbba4975d61dab1c40188c7) when the Wi-Fi link drops, and that call carries `ready_to_publish == false`. A frontend that gates on that flag leaves its last published value in place across a disconnect; if your product would rather fail open, handle the not-ready edge explicitly instead of returning early.
**Parameters**
- `snapshot`: Sensing state at the moment of the change.
<a id="classespectre_1_1_i_runtime_listener_1a2d3d588024e38fa5db5b9a2ac92f2706"></a>
### `on_periodic_update`
```cpp
virtual void espectre::IRuntimeListener::on_periodic_update(const RuntimeSnapshot &snapshot, uint32_t csi_accepted)
```
Heartbeat, emitted every fixed [`RUNTIME_HEARTBEAT_INTERVAL_MS`](#namespaceespectre_1adac330f75e60dcf8bbc56efa51cac931) milliseconds.
Use it for status logging and diagnostics sampling rather than sensing telemetry. Movement and canonical MQTT telemetry follow detector evaluation through [`on_live_telemetry()`](#classespectre_1_1_i_runtime_listener_1a2473b19c1324d186b11ba596000acde9).
**Parameters**
- `snapshot`: Current sensing state, including the metric and threshold.
- `csi_accepted`: CSI packets the detector processed since the previous heartbeat, after temporal admission. This is the achieved sensing rate, not the capture-validation count in [`RuntimeDiagnosticsSnapshot::Csi::accepted_total`](#structespectre_1_1_runtime_diagnostics_snapshot_1_1_csi_1a2d706255afa69bbfbc50492c82ffaa05).
<a id="classespectre_1_1_i_runtime_listener_1a6c97b8ed80d39f723a1d244b178c93f2"></a>
### `on_threshold_changed`
```cpp
virtual void espectre::IRuntimeListener::on_threshold_changed(const RuntimeSnapshot &snapshot)
```
The active threshold changed, from a control call, calibration, or detector-driven adaptation such as Lightweight settled-level recovery.
Refresh any threshold you mirror in a UI or a published entity. Live telemetry still carries the per-sample comparison value; this hook is the control-plane notification when that value itself has moved.
<a id="classespectre_1_1_i_runtime_listener_1a514dc3bb10087f78c374ba69265b7282"></a>
### `on_detector_changed`
```cpp
virtual void espectre::IRuntimeListener::on_detector_changed(const RuntimeSnapshot &snapshot)
```
The active detector changed.
Thresholds are per-detector, so [`on_threshold_changed()`](#classespectre_1_1_i_runtime_listener_1a6c97b8ed80d39f723a1d244b178c93f2) follows this one.
<a id="classespectre_1_1_i_runtime_listener_1a5d300e4e6a00a72a718f0c25aa181a34"></a>
### `on_calibration_started`
```cpp
virtual void espectre::IRuntimeListener::on_calibration_started(const RuntimeSnapshot &snapshot)
```
Startup calibration began; detection results are not valid yet.
Lightweight only. High Accuracy keeps a fixed threshold, so it skips this callback and reports [`on_calibration_finished()`](#classespectre_1_1_i_runtime_listener_1a27f8430a4a3b5b5dc6323765a2155e74) with `success` true at once.
<a id="classespectre_1_1_i_runtime_listener_1a27f8430a4a3b5b5dc6323765a2155e74"></a>
### `on_calibration_finished`
```cpp
virtual void espectre::IRuntimeListener::on_calibration_finished(const RuntimeSnapshot &snapshot, bool success)
```
Startup calibration finished.
The runtime releases completed threshold calibration resources before notifying the listener.
**Parameters**
- `snapshot`: Sensing state at completion, carrying the applied threshold.
- `success`: false when calibration was cancelled or could not settle on a threshold. The runtime keeps sensing with the threshold in force before this calibration, which after a failed startup calibration is the configured value. Treat this as a signal to surface, not a fatal error.
<a id="classespectre_1_1_i_runtime_listener_1a2473b19c1324d186b11ba596000acde9"></a>
### `on_live_telemetry`
```cpp
virtual void espectre::IRuntimeListener::on_live_telemetry(float movement, float threshold)
```
High-rate movement stream, one call per detector evaluation.
Frontends publish canonical telemetry and Movement Score from this hook. Considerably more frequent than [`on_periodic_update()`](#classespectre_1_1_i_runtime_listener_1a2d3d588024e38fa5db5b9a2ac92f2706); suppress it with `set_live_telemetry_enabled(false)` when nothing is watching.
**Parameters**
- `movement`: Current motion metric.
- `threshold`: Threshold it is compared against, on the same scale.
<a id="classespectre_1_1_i_runtime_listener_1ae566b842c3e051c1230fe922a834a70f"></a>
### `on_runtime_fault`
```cpp
virtual void espectre::IRuntimeListener::on_runtime_fault(const char *message)
```
A runtime-owned failure your firmware should surface.
**Parameters**
- `message`: Human-readable cause, valid only for this call.
Do not drive the runtime from here beyond `shutdown()`: the fault is reported from inside runtime work, and re-entering control paths from it is not supported.
<a id="classespectre_1_1_i_udp_datagram_socket"></a>
## espectre::IUdpDatagramSocket
```cpp
#include <runtime/udp_datagram_socket.h>
```
```cpp
class espectre::IUdpDatagramSocket
```
Non-blocking UDP socket, the platform seam behind the external traffic listener.
<a id="classespectre_1_1_i_udp_datagram_socket_1aef6091336756e15eaca69b6c8d9c2614"></a>
### `~IUdpDatagramSocket`
```cpp
virtual espectre::IUdpDatagramSocket::~IUdpDatagramSocket()=default
```
<a id="classespectre_1_1_i_udp_datagram_socket_1a0902f85514a6eb87058257f6e03664e4"></a>
### `open`
```cpp
virtual bool espectre::IUdpDatagramSocket::open(uint16_t port, const char *multicast_group)=0
```
Bind to `port` on every interface and join `multicast_group` unless it is `nullptr` or empty.
Returns false when either step fails.
<a id="classespectre_1_1_i_udp_datagram_socket_1a6de650bf037bab96cc3fb3abe4e332d2"></a>
### `close`
```cpp
virtual void espectre::IUdpDatagramSocket::close()=0
```
Close the socket.
Safe to repeat.
<a id="classespectre_1_1_i_udp_datagram_socket_1afb8cf45cdfbf8d5ef06a9a05474d754f"></a>
### `receive`
```cpp
virtual UdpReceiveResult espectre::IUdpDatagramSocket::receive(uint8_t *buffer, size_t buffer_len, size_t *received_len, UdpDatagramPeer *peer)=0
```
Receive one datagram into `buffer` without blocking.
<a id="structespectre_1_1_json_field_view"></a>
## espectre::JsonFieldView
```cpp
#include <runtime/protocol_json.h>
```
```cpp
struct espectre::JsonFieldView
```
Validated field whose raw JSON token remains in the caller-owned input.
<a id="structespectre_1_1_json_field_view_1a62caa94cc338b92850da051e8328c797"></a>
### `name`
```cpp
std::string espectre::JsonFieldView::name
```
Decoded field name.
<a id="structespectre_1_1_json_field_view_1aec7dff4b8b86809e57baf5a933757e35"></a>
### `type`
```cpp
JsonValueType espectre::JsonFieldView::type {JsonValueType::NULL_VALUE}
```
Kind of the referenced JSON token.
<a id="structespectre_1_1_json_field_view_1a922836069a9946b1a17a0ab6cb32e4ce"></a>
### `begin`
```cpp
size_t espectre::JsonFieldView::begin {0U}
```
Token offset relative to the parsed input range.
<a id="structespectre_1_1_json_field_view_1ad0218c3eb0b5b61915d3380de6105090"></a>
### `length`
```cpp
size_t espectre::JsonFieldView::length {0U}
```
Token size, including quotes and escapes for strings.
<a id="classespectre_1_1_json_input"></a>
## espectre::JsonInput
```cpp
#include <runtime/protocol_json.h>
```
```cpp
class espectre::JsonInput
```
Read-only JSON input that may span separately allocated buffers.
<a id="classespectre_1_1_json_input_1a768c8185680ba7ff5583c34929bbb2cd"></a>
### `~JsonInput`
```cpp
virtual espectre::JsonInput::~JsonInput()=default
```
<a id="classespectre_1_1_json_input_1a77bea6937bc2e2c2fc4b23e06e5d818e"></a>
### `size`
```cpp
virtual size_t espectre::JsonInput::size() const =0
```
Return the number of available bytes.
<a id="classespectre_1_1_json_input_1a192a1ed22238c3cd8ed7ee580eff86b0"></a>
### `operator[]`
```cpp
virtual char espectre::JsonInput::operator[](size_t offset) const =0
```
Read a byte at an offset strictly less than [size()](#classespectre_1_1_json_input_1a77bea6937bc2e2c2fc4b23e06e5d818e).
<a id="structespectre_1_1_json_object_field"></a>
## espectre::JsonObjectField
```cpp
#include <runtime/protocol_json.h>
```
```cpp
struct espectre::JsonObjectField
```
One field of a parsed JSON object, with its value copied.
<a id="structespectre_1_1_json_object_field_1a1af29f07260e57a269cd982209e583b0"></a>
### `name`
```cpp
std::string espectre::JsonObjectField::name
```
Decoded field name.
<a id="structespectre_1_1_json_object_field_1a507478e78e0f77113b1672953cd6094d"></a>
### `type`
```cpp
JsonValueType espectre::JsonObjectField::type {JsonValueType::NULL_VALUE}
```
<a id="structespectre_1_1_json_object_field_1a5dd50afd8d4656c599e9681d33a469f1"></a>
### `value`
```cpp
std::string espectre::JsonObjectField::value
```
Decoded contents for strings, or the exact JSON token for every other type.
<a id="classespectre_1_1_lightweight_detector"></a>
## espectre::LightweightDetector
```cpp
#include <core/lightweight_detector.h>
```
```cpp
class espectre::LightweightDetector : public espectre::BaseDetector
```
The default detector: self-calibrating, no training data required.
Fuses turbulence autocorrelation with robust spread from a five-bin aggregated turbulence stream, and adapts its threshold to the room during startup calibration. After that, a long quiet stretch can still lower the live threshold when the opening was noisier than the rest of the session. The full runtime emits [`IRuntimeListener::on_threshold_changed()`](#classespectre_1_1_i_runtime_listener_1a6c97b8ed80d39f723a1d244b178c93f2) for that drop; a core-only integration must re-read [`get_threshold()`](#classespectre_1_1_lightweight_detector_1a6ec5c610ed3a5f766ba026a86d3f3110) after [`update_state()`](#classespectre_1_1_lightweight_detector_1a2c115275c63b3e4f4032d5218b1743d1). Prefer it unless you have a reason to run [`HighAccuracyDetector`](#classespectre_1_1_high_accuracy_detector).
Most integrations never construct one: [`RuntimeConfig::detection_algorithm`](#structespectre_1_1_runtime_config_1a3d14cc007fe6107bd81c6c6da176327a) selects it and the runtime owns the lifecycle. Drive it directly only on the core-only path, where your firmware already captures CSI:
```cpp
espectre::LightweightDetector detector;
if (!detector.is_valid()) { return; }
// For each slot retained by your temporal sampler:
detector.advance_missing_slots(missing_slots_before_this_packet);
detector.set_packet_timestamp_us(packet_timestamp_us);
detector.process_packet(csi, csi_len, espectre::DEFAULT_SUBCARRIERS,
espectre::HT20_SELECTED_BAND_SIZE, rssi_dbm);
// on your evaluation cadence:
detector.update_state();
if (detector.is_ready() && detector.get_state() == espectre::MotionState::MOTION) { ... }
```
[`is_ready()`](#classespectre_1_1_lightweight_detector_1ae7316e1b71611a18a03ad52b18f03ee7) is false until the window fills; results before that are not meaningful. See `runtime/esp_idf/csi_pipeline.cpp` for the reference normalization, cadence, and hit filtering around these calls, and [ALGORITHMS.md](<https://github.com/francescopace/espectre/blob/main/docs/ALGORITHMS.md>) for the algorithm itself.
**Par:** Threading
Not thread-safe. [`process_packet()`](#classespectre_1_1_lightweight_detector_1ad98770bd6ca93a90cc4baca9b45b72ce) and [`update_state()`](#classespectre_1_1_lightweight_detector_1a2c115275c63b3e4f4032d5218b1743d1) must not run concurrently.
[`espectre::BaseDetector`](#classespectre_1_1_base_detector)
<a id="classespectre_1_1_lightweight_detector_1a7c69093cdce4f6390740e79d4ec21647"></a>
### `get_turb_autocorr`
```cpp
float espectre::LightweightDetector::get_turb_autocorr() const
```
Turbulence autocorrelation at the configured lag.
<a id="classespectre_1_1_lightweight_detector_1a79cc507df17c747f3340fdc600cce909"></a>
### `get_turb_iqr_over_mean_aggr`
```cpp
float espectre::LightweightDetector::get_turb_iqr_over_mean_aggr() const
```
Interquartile range over mean of the aggregated turbulence stream.
<a id="classespectre_1_1_lightweight_detector_1a9759c675e359c00c802e049339f5327d"></a>
### `get_logit`
```cpp
float espectre::LightweightDetector::get_logit() const
```
Logit of the motion probability that [get\_motion\_metric()](#classespectre_1_1_base_detector_1ab7ea59db54d734cc87815e0a7aebd972) reports.
<a id="classespectre_1_1_lightweight_detector_1a2827677c475727e751cd53c70f215c46"></a>
### `LightweightDetector`
```cpp
espectre::LightweightDetector::LightweightDetector(uint16_t window_size=DETECTOR_DEFAULT_WINDOW_SIZE, float threshold=LIGHTWEIGHT_DEFAULT_THRESHOLD, uint16_t autocorr_lag=1U)
```
Constructor.
**Parameters**
- `window_size`: Detector window in packets
- `threshold`: Motion probability threshold
- `autocorr_lag`: Turbulence autocorrelation distance in packets
Production uses the nominal-rate default. Alternate lags are exposed for replay experiments only: changing the feature offset requires validating the fitted coefficients before deployment. See [`core/detector_limits.h`](#detector__limits_8h).
<a id="classespectre_1_1_lightweight_detector_1a3a8e768134861844f23a49dd0ad1cc16"></a>
### `~LightweightDetector`
```cpp
espectre::LightweightDetector::~LightweightDetector() override=default
```
<a id="classespectre_1_1_lightweight_detector_1a4dee4a11dd008112747999be2537ed5f"></a>
### `LightweightDetector`
```cpp
espectre::LightweightDetector::LightweightDetector(LightweightDetector &&other) noexcept=default
```
<a id="classespectre_1_1_lightweight_detector_1ad56def16d1aac6ff2bf2ff937de4c75f"></a>
### `operator=`
```cpp
LightweightDetector & espectre::LightweightDetector::operator=(LightweightDetector &&other) noexcept=default
```
<a id="classespectre_1_1_lightweight_detector_1a943f38c526f8402d109d2aa28a41c8f4"></a>
### `LightweightDetector`
```cpp
espectre::LightweightDetector::LightweightDetector(const LightweightDetector &)=delete
```
<a id="classespectre_1_1_lightweight_detector_1ade8a697de335b7644e9c9d4d29934526"></a>
### `operator=`
```cpp
LightweightDetector & espectre::LightweightDetector::operator=(const LightweightDetector &)=delete
```
<a id="classespectre_1_1_lightweight_detector_1ad98770bd6ca93a90cc4baca9b45b72ce"></a>
### `process_packet`
```cpp
void espectre::LightweightDetector::process_packet(const int8_t *csi_data, size_t csi_len, const uint8_t *selected_subcarriers=nullptr, uint8_t num_subcarriers=0, int8_t rssi_dbm=INT8_MIN) override
```
Process one normalized, temporally admitted CSI packet.
Calculates spatial turbulence from CSI data, applies filtering, and stores in circular buffer.
**Parameters**
- `csi_data`: Normalized CSI data (I/Q interleaved)
- `csi_len`: Length of CSI data
- `selected_subcarriers`: Array of subcarrier indices
- `num_subcarriers`: Number of selected subcarriers
- `rssi_dbm`: Link RSSI for this packet, or INT8\_MIN when unknown
<a id="classespectre_1_1_lightweight_detector_1aa93ad761aa4e7111ed6b0e2e30496366"></a>
### `advance_missing_slots`
```cpp
void espectre::LightweightDetector::advance_missing_slots(uint32_t count) override
```
Advance packet-indexed feature rings for absent temporal slots.
<a id="classespectre_1_1_lightweight_detector_1a2c115275c63b3e4f4032d5218b1743d1"></a>
### `update_state`
```cpp
void espectre::LightweightDetector::update_state() override
```
Update state machine (call at the detector evaluation interval).
Subclasses implement their detection algorithm here.
<a id="classespectre_1_1_lightweight_detector_1aadbd176e74980d13d4560b36d55728d7"></a>
### `reset`
```cpp
void espectre::LightweightDetector::reset() override
```
Reset detector state.
Resets state machine but preserves buffer ("warm" restart).
<a id="classespectre_1_1_lightweight_detector_1ae3c4afa60d1448f142853b296c9c94eb"></a>
### `clear_buffer`
```cpp
void espectre::LightweightDetector::clear_buffer() override
```
Clear turbulence buffer (cold restart).
Virtual so detectors with additional state (e.g. L1-Delta profile rings) can extend the cold clear.
<a id="classespectre_1_1_lightweight_detector_1a593fe23304af8dcedea11856fc1c495b"></a>
### `configure_hampel`
```cpp
void espectre::LightweightDetector::configure_hampel(bool enabled, uint8_t window_size=HAMPEL_TURBULENCE_WINDOW_DEFAULT, float threshold=HAMPEL_TURBULENCE_THRESHOLD_DEFAULT) override
```
Configure Hampel filter.
**Parameters**
- `enabled`: Whether to enable the filter
- `window_size`: Window size (3-11)
- `threshold`: MAD multiplier threshold
<a id="classespectre_1_1_lightweight_detector_1a49437a685bbd6f18e6439e2d2cd1a650"></a>
### `configure_lowpass`
```cpp
void espectre::LightweightDetector::configure_lowpass(bool enabled, float cutoff_hz=LOWPASS_CUTOFF_DEFAULT) override
```
Configure low-pass filter.
**Parameters**
- `enabled`: Whether to enable the filter
- `cutoff_hz`: Cutoff frequency (5.0-20.0 Hz)
<a id="classespectre_1_1_lightweight_detector_1ae7316e1b71611a18a03ad52b18f03ee7"></a>
### `is_ready`
```cpp
bool espectre::LightweightDetector::is_ready() const override
```
Check if detector is ready.
Ready once the window has filled and its valid slots reach the floor set by [set\_minimum\_valid\_samples()](#classespectre_1_1_base_detector_1a9732e34f845a2eb619ac9f42e1096353).
<a id="classespectre_1_1_lightweight_detector_1a5313035ca79adb3270764b4f53021cdf"></a>
### `is_valid`
```cpp
bool espectre::LightweightDetector::is_valid() const override
```
Return whether all base detector working storage was allocated.
<a id="classespectre_1_1_lightweight_detector_1a03a94bf71221845a156b778aba9f2c4a"></a>
### `set_threshold`
```cpp
bool espectre::LightweightDetector::set_threshold(float threshold) override
```
Set detection threshold.
**Parameters**
- `threshold`: New threshold value
**Returns:** true if value was accepted
<a id="classespectre_1_1_lightweight_detector_1ab5359cd2f8ac714c018d6f0b11745ca1"></a>
### `set_adaptive_threshold`
```cpp
bool espectre::LightweightDetector::set_adaptive_threshold(float threshold) override
```
Apply a detector-specific startup-calibrated threshold.
<a id="classespectre_1_1_lightweight_detector_1a6ec5c610ed3a5f766ba026a86d3f3110"></a>
### `get_threshold`
```cpp
float espectre::LightweightDetector::get_threshold() const override
```
Get current threshold.
<a id="classespectre_1_1_lightweight_detector_1a9a64dac4614bdc6013375f59a15ecfe1"></a>
### `get_name`
```cpp
const char * espectre::LightweightDetector::get_name() const override
```
Get detector name for logging.
<a id="classespectre_1_1_lightweight_detector_1a7aa058c0d53152d81f5da9d1989fd141"></a>
### `get_startup_threshold_factor`
```cpp
float espectre::LightweightDetector::get_startup_threshold_factor() const override
```
Get the detector-specific automatic startup multiplier.
threshold = threshold\_metric x factor, where `threshold_metric` comes from the shared startup calibrator.
<a id="classespectre_1_1_lightweight_detector_1a4d060e026a59eb3c7c381992cf274b51"></a>
### `calibration_motion_ceiling`
```cpp
float espectre::LightweightDetector::calibration_motion_ceiling() const override
```
Motion metric above which a calibration evaluation counts as motion.
An evaluation above it restarts the calibration window. A recalibration under the setup of the last successful calibration also restarts above the live threshold when that is lower. The default, infinity, leaves calibration without an absolute reference.
<a id="classespectre_1_1_lightweight_detector_1a1cb63dff32578d0e76e5593057efec8b"></a>
### `startup_calibration_conclusive`
```cpp
bool espectre::LightweightDetector::startup_calibration_conclusive() const override
```
Whether the calibration evidence collected so far can set a threshold.
The runtime asks each time the calibration budget is spent. While the answer is false, the calibration continues in steps of half its initial budget, up to three times that budget. The default always concludes.
<a id="classespectre_1_1_lightweight_detector_1a5c3f2b65e433379face4641fb3398bb0"></a>
### `on_startup_calibration_begin`
```cpp
void espectre::LightweightDetector::on_startup_calibration_begin() override
```
Hook called immediately before startup calibration begins.
<a id="classespectre_1_1_lightweight_detector_1a3d0cb8a72ad26769ffddacc1db32b8ba"></a>
### `on_startup_calibration_complete`
```cpp
void espectre::LightweightDetector::on_startup_calibration_complete() override
```
Hook called when startup calibration completes successfully.
Detectors can freeze session-specific state here before the runtime performs its warm clear between calibration and steady-state detection.
<a id="classespectre_1_1_lightweight_detector_1ad1de55d8d9218f585284327b8931213d"></a>
### `on_startup_calibration_abandoned`
```cpp
void espectre::LightweightDetector::on_startup_calibration_abandoned() override
```
Hook called when a calibration ends without a result.
The runtime keeps the threshold in force before the calibration began. Detectors discard the evidence collected since [on\_startup\_calibration\_begin()](#classespectre_1_1_lightweight_detector_1a5c3f2b65e433379face4641fb3398bb0) and resume the adaptation they had, or start adapting the threshold in force if no calibration has completed.
<a id="structespectre_1_1_log_sink"></a>
## espectre::LogSink
```cpp
#include <core/espectre_log.h>
```
```cpp
struct espectre::LogSink
```
Frontend-owned logging callbacks.
ESPectre copies this value when it is registered but does not own [`context`](#structespectre_1_1_log_sink_1a0766bd86173c1c6da6bd67fecdd70e20). The context and callbacks must remain valid until the sink is cleared.
<a id="structespectre_1_1_log_sink_1a0766bd86173c1c6da6bd67fecdd70e20"></a>
### `context`
```cpp
void* espectre::LogSink::context {nullptr}
```
Opaque value passed to both callbacks.
May be `nullptr`.
<a id="structespectre_1_1_log_sink_1a308ac37737bd18dc082d8b9efef056f2"></a>
### `enabled`
```cpp
LogEnabledCallback espectre::LogSink::enabled {nullptr}
```
Required filter, asked before a message is formatted.
<a id="structespectre_1_1_log_sink_1a27a477296e13456e0557b6b55cf57185"></a>
### `write`
```cpp
LogWriteCallback espectre::LogSink::write {nullptr}
```
Required writer for messages that passed the filter.
<a id="classespectre_1_1_mdns_bootstrap_responder"></a>
## espectre::MdnsBootstrapResponder
```cpp
#include <runtime/esp_idf/mdns_bootstrap_responder.h>
```
```cpp
class espectre::MdnsBootstrapResponder
```
Answers the browser bootstrap names `espectre-devices-{nonce}.local` with this device's IPv4 address.
See [DISCOVERY.md](<https://github.com/francescopace/espectre/blob/main/docs/DISCOVERY.md#browser-bootstrap>) for the protocol. Queries reach it through a link-time wrapper around the ESP-IDF mDNS receive path, which the SDK component adds with the Direct source group. Only one responder can be set up at a time.
**Par:** Threading
Call [setup()](#classespectre_1_1_mdns_bootstrap_responder_1ab95bbcd82c6192e292f3f77658901262), [update()](#classespectre_1_1_mdns_bootstrap_responder_1ab785ffa19ea97dd9c4d05b5387959e06), [loop()](#classespectre_1_1_mdns_bootstrap_responder_1a05d87c09dc6a1ee0072639e7dc45e573), and [shutdown()](#classespectre_1_1_mdns_bootstrap_responder_1a6f5cfb8d78d6a2d0ca71ef60b3729478) from one owner task.
<a id="classespectre_1_1_mdns_bootstrap_responder_1a2b2f05c55613a24569190cb622829f7c"></a>
### `NONCE_HEX_LENGTH`
```cpp
constexpr size_t espectre::MdnsBootstrapResponder::NONCE_HEX_LENGTH = 24U
```
Length of the random nonce in a bootstrap name, in hexadecimal characters.
<a id="classespectre_1_1_mdns_bootstrap_responder_1a6c834267d8586769daacedbfc5581981"></a>
### `RESPONSE_TTL_SECONDS`
```cpp
constexpr uint32_t espectre::MdnsBootstrapResponder::RESPONSE_TTL_SECONDS = 10U
```
TTL of every answer.
<a id="classespectre_1_1_mdns_bootstrap_responder_1ad7c040408ec79f780ea13978cd007fa3"></a>
### `~MdnsBootstrapResponder`
```cpp
espectre::MdnsBootstrapResponder::~MdnsBootstrapResponder()
```
<a id="classespectre_1_1_mdns_bootstrap_responder_1ab95bbcd82c6192e292f3f77658901262"></a>
### `setup`
```cpp
bool espectre::MdnsBootstrapResponder::setup()
```
Register as the process-wide responder; false when another is active.
<a id="classespectre_1_1_mdns_bootstrap_responder_1ab785ffa19ea97dd9c4d05b5387959e06"></a>
### `update`
```cpp
bool espectre::MdnsBootstrapResponder::update(uint32_t ipv4_address)
```
Set the address to answer with, in network byte order; zero stops answering.
<a id="classespectre_1_1_mdns_bootstrap_responder_1a05d87c09dc6a1ee0072639e7dc45e573"></a>
### `loop`
```cpp
void espectre::MdnsBootstrapResponder::loop()
```
Send pending answers, at most a few per call and eight per second.
<a id="classespectre_1_1_mdns_bootstrap_responder_1a6f5cfb8d78d6a2d0ca71ef60b3729478"></a>
### `shutdown`
```cpp
void espectre::MdnsBootstrapResponder::shutdown()
```
Unregister and discard pending answers.
Safe to repeat.
<a id="classespectre_1_1_mdns_bootstrap_responder_1a19e169721cd9ef76e08250f05a009619"></a>
### `active`
```cpp
bool espectre::MdnsBootstrapResponder::active() const
```
Whether the responder is set up and has an address.
<a id="classespectre_1_1_mdns_bootstrap_responder_1a8e12a6a872421c51e02d49853dc64ea7"></a>
### `ingest_query`
```cpp
void espectre::MdnsBootstrapResponder::ingest_query(const uint8_t *packet, size_t length, size_t interface, uint32_t source_ipv4, uint16_t source_port)
```
Parse one received mDNS packet and queue answers for bootstrap names.
Called by the mDNS receive wrapper before the Espressif responder filters questions for host names it owns; firmware does not call it.
<a id="classespectre_1_1_mdns_discovery_service"></a>
## espectre::MdnsDiscoveryService
```cpp
#include <runtime/esp_idf/mdns_discovery_service.h>
```
```cpp
class espectre::MdnsDiscoveryService
```
Advertises one DNS-SD service on the Wi-Fi station interface.
Call [on\_wifi\_connected()](#classespectre_1_1_mdns_discovery_service_1a4756ee87d05459a8a95bb97062088c5b) and [on\_wifi\_disconnected()](#classespectre_1_1_mdns_discovery_service_1a90fffb53d97c2d76c5d1af84e3e5c681) from the firmware's connection callbacks so the service is announced after every reconnect.
**Par:** Threading
Call every method from one owner task.
<a id="classespectre_1_1_mdns_discovery_service_1a9bca4f5edf7810ea3426c21807da432d"></a>
### `setup`
```cpp
bool espectre::MdnsDiscoveryService::setup(const MdnsDiscoveryServiceConfig &config)
```
Replace any previous advertisement and add the configured service.
**Returns:** false for an incomplete configuration or when the responder rejects it. Resources acquired before the failure are released.
<a id="classespectre_1_1_mdns_discovery_service_1a8a4ead7333e20ee71e19fce8140fe287"></a>
### `update_txt`
```cpp
bool espectre::MdnsDiscoveryService::update_txt(const MdnsTxtRecords &txt_records)
```
Replace the TXT records; false before [setup()](#classespectre_1_1_mdns_discovery_service_1a9bca4f5edf7810ea3426c21807da432d) or when the responder rejects them.
<a id="classespectre_1_1_mdns_discovery_service_1a4756ee87d05459a8a95bb97062088c5b"></a>
### `on_wifi_connected`
```cpp
void espectre::MdnsDiscoveryService::on_wifi_connected()
```
Enable or announce the service on the station interface.
<a id="classespectre_1_1_mdns_discovery_service_1a90fffb53d97c2d76c5d1af84e3e5c681"></a>
### `on_wifi_disconnected`
```cpp
void espectre::MdnsDiscoveryService::on_wifi_disconnected()
```
Withdraw the station interface from an owned responder.
<a id="classespectre_1_1_mdns_discovery_service_1aea78330e76641592ac570c395273a9b4"></a>
### `shutdown`
```cpp
void espectre::MdnsDiscoveryService::shutdown()
```
Remove the service and free an owned responder.
Safe to repeat.
<a id="classespectre_1_1_mdns_discovery_service_1aa8896a8b2d043d58738b340d72dafb58"></a>
### `initialized`
```cpp
bool espectre::MdnsDiscoveryService::initialized() const
```
True between a successful [setup()](#classespectre_1_1_mdns_discovery_service_1a9bca4f5edf7810ea3426c21807da432d) and [shutdown()](#classespectre_1_1_mdns_discovery_service_1aea78330e76641592ac570c395273a9b4).
<a id="classespectre_1_1_mdns_discovery_service_1a5bc9235099cda7de927791866c0c9547"></a>
### `service_enabled`
```cpp
bool espectre::MdnsDiscoveryService::service_enabled() const
```
True while the service is announced on the station interface.
<a id="structespectre_1_1_mdns_discovery_service_config"></a>
## espectre::MdnsDiscoveryServiceConfig
```cpp
#include <runtime/esp_idf/mdns_discovery_service.h>
```
```cpp
struct espectre::MdnsDiscoveryServiceConfig
```
DNS-SD advertisement for [MdnsDiscoveryService](#classespectre_1_1_mdns_discovery_service).
See [DISCOVERY.md](<https://github.com/francescopace/espectre/blob/main/docs/DISCOVERY.md>) for the service type and TXT keys that ESPectre clients expect.
<a id="structespectre_1_1_mdns_discovery_service_config_1a1b122f1021e95de3f1668fcb67346cf9"></a>
### `hostname`
```cpp
std::string espectre::MdnsDiscoveryServiceConfig::hostname
```
Host label, up to 63 bytes.
Required with `OWN_RESPONDER`, optional otherwise.
<a id="structespectre_1_1_mdns_discovery_service_config_1a9c632f66f8b84dd2aabf6c5c75d46202"></a>
### `instance_name`
```cpp
std::string espectre::MdnsDiscoveryServiceConfig::instance_name
```
Human-readable service instance name.
Required.
<a id="structespectre_1_1_mdns_discovery_service_config_1a2b72aeb06aa4a27468f88314c1e1b8bd"></a>
### `service_type`
```cpp
std::string espectre::MdnsDiscoveryServiceConfig::service_type
```
Service type such as `_espectre`.
Required.
<a id="structespectre_1_1_mdns_discovery_service_config_1addcc38c93c25c34118c999bca3ec233a"></a>
### `service_protocol`
```cpp
std::string espectre::MdnsDiscoveryServiceConfig::service_protocol
```
Transport label such as `_tcp`.
Required.
<a id="structespectre_1_1_mdns_discovery_service_config_1a872e38c6f5141daa04bfa58db661efa7"></a>
### `port`
```cpp
uint16_t espectre::MdnsDiscoveryServiceConfig::port {0U}
```
Advertised port.
Required.
<a id="structespectre_1_1_mdns_discovery_service_config_1a046eb2615b1c2196f28367e02ebc87e9"></a>
### `txt_records`
```cpp
MdnsTxtRecords espectre::MdnsDiscoveryServiceConfig::txt_records
```
<a id="structespectre_1_1_mdns_discovery_service_config_1a43c7aa08b72548d6c707a2acef1b92b6"></a>
### `responder_mode`
```cpp
MdnsResponderMode espectre::MdnsDiscoveryServiceConfig::responder_mode {MdnsResponderMode::OWN_RESPONDER}
```
<a id="structespectre_1_1_mqtt_transport_diagnostics"></a>
## espectre::MqttTransportDiagnostics
```cpp
#include <runtime/mqtt_transport.h>
```
```cpp
struct espectre::MqttTransportDiagnostics
```
Publish queue and connection counters of an [IMqttTransport](#classespectre_1_1_i_mqtt_transport).
<a id="structespectre_1_1_mqtt_transport_diagnostics_1a57f23464d94bd6e89343fa67a9c5d891"></a>
### `queue_capacity`
```cpp
size_t espectre::MqttTransportDiagnostics::queue_capacity {0U}
```
Publishes the local queue can hold.
<a id="structespectre_1_1_mqtt_transport_diagnostics_1a25432ed4113bcf1ba97f39fe73777c9f"></a>
### `outbox_capacity_bytes`
```cpp
size_t espectre::MqttTransportDiagnostics::outbox_capacity_bytes {0U}
```
Byte limit of the MQTT client's outbox.
<a id="structespectre_1_1_mqtt_transport_diagnostics_1a1a9aedeafb50f0aeda3b56b3912661a5"></a>
### `queued_publishes`
```cpp
size_t espectre::MqttTransportDiagnostics::queued_publishes {0U}
```
Publishes waiting in the local queue.
<a id="structespectre_1_1_mqtt_transport_diagnostics_1a25bba45d97b4adeb25d61e3773829985"></a>
### `dropped_publishes`
```cpp
uint32_t espectre::MqttTransportDiagnostics::dropped_publishes {0U}
```
Publishes discarded because the queue was full or the client rejected them.
<a id="structespectre_1_1_mqtt_transport_diagnostics_1a8b6bd7d2dfaac1e23aea8ecf8898eca2"></a>
### `publish_failures`
```cpp
uint32_t espectre::MqttTransportDiagnostics::publish_failures {0U}
```
Attempts to hand a publish to the client that failed.
<a id="structespectre_1_1_mqtt_transport_diagnostics_1a6a8233be7136f4a79616df527108b258"></a>
### `reconnects`
```cpp
uint32_t espectre::MqttTransportDiagnostics::reconnects {0U}
```
Broker reconnections since setup.
<a id="structespectre_1_1_network_traffic_snapshot"></a>
## espectre::NetworkTrafficSnapshot
```cpp
#include <runtime/esp_idf/network_traffic.h>
```
```cpp
struct espectre::NetworkTrafficSnapshot
```
Default Wi-Fi station packet counters, each wrapping modulo 2^32.
<a id="structespectre_1_1_network_traffic_snapshot_1a16937fe01691e172c038508a58285216"></a>
### `tx_packets`
```cpp
uint32_t espectre::NetworkTrafficSnapshot::tx_packets
```
Packets accepted by the station driver, excluding failed sends.
<a id="structespectre_1_1_network_traffic_snapshot_1a3e228990f34b6352a94c654882c86ce1"></a>
### `rx_packets`
```cpp
uint32_t espectre::NetworkTrafficSnapshot::rx_packets
```
Packets delivered by the station driver, including later stack drops.
<a id="structespectre_1_1_peer_discovery_candidate"></a>
## espectre::PeerDiscoveryCandidate
```cpp
#include <runtime/peer_discovery.h>
```
```cpp
struct espectre::PeerDiscoveryCandidate
```
One ESPectre device found through DNS-SD, as advertised in its TXT record.
See [DISCOVERY.md](<https://github.com/francescopace/espectre/blob/main/docs/DISCOVERY.md>) for the meaning and format of each advertised key.
<a id="structespectre_1_1_peer_discovery_candidate_1a2d5778b7ef895ea38a0cfc176e28866e"></a>
### `instance`
```cpp
std::string espectre::PeerDiscoveryCandidate::instance
```
DNS-SD service instance name.
<a id="structespectre_1_1_peer_discovery_candidate_1ab89b27af773b55a3928fd8062ee2d86b"></a>
### `hostname`
```cpp
std::string espectre::PeerDiscoveryCandidate::hostname
```
mDNS host name.
<a id="structespectre_1_1_peer_discovery_candidate_1a0cb2d0eeab818141ddb73739215e56e8"></a>
### `device_id`
```cpp
std::string espectre::PeerDiscoveryCandidate::device_id
```
Canonical device id; devices are deduplicated by it.
<a id="structespectre_1_1_peer_discovery_candidate_1abad2df8531fd04b073e07f0cad38ad4a"></a>
### `name`
```cpp
std::string espectre::PeerDiscoveryCandidate::name
```
User-facing device name.
<a id="structespectre_1_1_peer_discovery_candidate_1acbb95beb16745ead3f6f278dbd62d03b"></a>
### `frontend`
```cpp
std::string espectre::PeerDiscoveryCandidate::frontend
```
<a id="structespectre_1_1_peer_discovery_candidate_1a8a1a8899c7557f2b1e0cdf9684792731"></a>
### `txt_version`
```cpp
std::string espectre::PeerDiscoveryCandidate::txt_version
```
TXT schema version, `txtvers`.
<a id="structespectre_1_1_peer_discovery_candidate_1a7d354f75bec29ca21378d5258cdf3b94"></a>
### `protocol_version`
```cpp
std::string espectre::PeerDiscoveryCandidate::protocol_version
```
[`ESPECTRE_PROTOCOL_VERSION`](#namespaceespectre_1a27be540efef19a111bae40cf08a98cfe) of the device.
<a id="structespectre_1_1_peer_discovery_candidate_1ac354bb8df10122355d7eabf1072be6c0"></a>
### `transport`
```cpp
std::string espectre::PeerDiscoveryCandidate::transport
```
Transport name, such as `http`.
<a id="structespectre_1_1_peer_discovery_candidate_1a7ed3aee56d18d0e3a23a9f0f25b178cd"></a>
### `path`
```cpp
std::string espectre::PeerDiscoveryCandidate::path
```
API base path, such as `/espectre/v1`.
<a id="structespectre_1_1_peer_discovery_candidate_1a1d45f9d1267ac44d120bf0d2c4266f03"></a>
### `firmware`
```cpp
std::string espectre::PeerDiscoveryCandidate::firmware
```
Application version.
<a id="structespectre_1_1_peer_discovery_candidate_1a20721debec00cbc2392fbbc87473bd3d"></a>
### `chip`
```cpp
std::string espectre::PeerDiscoveryCandidate::chip
```
<a id="structespectre_1_1_peer_discovery_candidate_1a571b201c3eefb9ff5df2704436a9cd3f"></a>
### `capabilities`
```cpp
std::string espectre::PeerDiscoveryCandidate::capabilities
```
Advertised capability summary.
<a id="structespectre_1_1_peer_discovery_candidate_1a340e803e81a292c10c0bd5a868abb6d3"></a>
### `port`
```cpp
uint16_t espectre::PeerDiscoveryCandidate::port {0U}
```
Service port.
<a id="structespectre_1_1_peer_discovery_candidate_1a4c4748768d568fcd2417c54669d0f28d"></a>
### `ipv4_addresses`
```cpp
std::vector<uint32_t> espectre::PeerDiscoveryCandidate::ipv4_addresses
```
IPv4 addresses in network byte order.
<a id="structespectre_1_1_peer_discovery_snapshot"></a>
## espectre::PeerDiscoverySnapshot
```cpp
#include <runtime/peer_discovery.h>
```
```cpp
struct espectre::PeerDiscoverySnapshot
```
Validated result of one discovery search.
<a id="structespectre_1_1_peer_discovery_snapshot_1a473a8af1eaf8d087b009d62ab3f551ba"></a>
### `elapsed_ms`
```cpp
uint32_t espectre::PeerDiscoverySnapshot::elapsed_ms {0U}
```
Search duration.
<a id="structespectre_1_1_peer_discovery_snapshot_1a2a6b95456424813636302cdc39624ca2"></a>
### `timed_out`
```cpp
bool espectre::PeerDiscoverySnapshot::timed_out {false}
```
Whether the search ended before it completed.
<a id="structespectre_1_1_peer_discovery_snapshot_1a79217af1072e21bb9c45b8c3a722f872"></a>
### `truncated`
```cpp
bool espectre::PeerDiscoverySnapshot::truncated {false}
```
Whether devices or addresses were dropped to respect the limits.
<a id="structespectre_1_1_peer_discovery_snapshot_1abd303c6912222a2338686f1a0c120b8e"></a>
### `rejected_results`
```cpp
size_t espectre::PeerDiscoverySnapshot::rejected_results {0U}
```
Results rejected as invalid, off-link, or conflicting with another device.
<a id="structespectre_1_1_peer_discovery_snapshot_1ae14eb3461048718dbadd944cc5b6bf03"></a>
### `devices`
```cpp
std::vector<PeerDiscoveryCandidate> espectre::PeerDiscoverySnapshot::devices
```
Accepted devices, sorted by device id.
<a id="classespectre_1_1_pending_event"></a>
## espectre::PendingEvent
```cpp
#include <runtime/pending_event.h>
```
```cpp
template <typename... Ts>
class espectre::PendingEvent
```
Single-slot mailbox carrying an event with an optional payload.
[post()](#classespectre_1_1_pending_event_1af79ae9ab56f40807b4bbff6b16bba1e0) records the event and overwrites any unconsumed payload, so events coalesce to the most recent one. [take()](#classespectre_1_1_pending_event_1ad03dda7136be67a473aea263aaa82bae) consumes at most one event per call. Single producer, single consumer.
Access is serialized with a lightweight critical section. On ESP-IDF this remains safe from both task and ISR context, including the CSI callback path. Host builds use a regular mutex with the same coalescing semantics.
<a id="classespectre_1_1_pending_event_1af79ae9ab56f40807b4bbff6b16bba1e0"></a>
### `post`
```cpp
void espectre::PendingEvent< Ts >::post(Ts... values)
```
Record an event, replacing any unconsumed one.
<a id="classespectre_1_1_pending_event_1ad03dda7136be67a473aea263aaa82bae"></a>
### `take`
```cpp
bool espectre::PendingEvent< Ts >::take(Ts &...out)
```
Consume the pending event into `out`; false, with `out` unchanged, when none is pending.
<a id="classespectre_1_1_pending_event_1aed0bf169385a4196d542dedec1ff35f5"></a>
### `clear`
```cpp
void espectre::PendingEvent< Ts >::clear()
```
Discard any pending event.
<a id="classespectre_1_1_pending_queue"></a>
## espectre::PendingQueue
```cpp
#include <runtime/pending_queue.h>
```
```cpp
template <typename T, size_t Capacity>
class espectre::PendingQueue
```
Fixed-capacity FIFO for callback-to-loop handoff.
[post()](#classespectre_1_1_pending_queue_1aa971a069073a9d16138ff75e5ccb2ad4) never allocates or blocks: it returns false when the queue is full. The consumer drains records with [take()](#classespectre_1_1_pending_queue_1aa9b530fa51f2b30d7a1688bf10d32d58) from its owning task. T must remain trivially copyable because ESP-IDF protects the short copy with a critical section that must not run constructors, destructors, or heap allocation.
<a id="classespectre_1_1_pending_queue_1aa971a069073a9d16138ff75e5ccb2ad4"></a>
### `post`
```cpp
bool espectre::PendingQueue< T, Capacity >::post(const T &value)
```
Append a record; false, without blocking, when the queue is full.
<a id="classespectre_1_1_pending_queue_1a7d3f4c1a69924ab5eb5bfec2e0c8baca"></a>
### `post_overwrite_oldest`
```cpp
bool espectre::PendingQueue< T, Capacity >::post_overwrite_oldest(const T &value)
```
Append a record, discarding the oldest record when the queue is full.
**Returns:** true when no record was discarded.
<a id="classespectre_1_1_pending_queue_1aa9b530fa51f2b30d7a1688bf10d32d58"></a>
### `take`
```cpp
bool espectre::PendingQueue< T, Capacity >::take(T &value)
```
Remove the oldest record into `value`; false when the queue is empty.
<a id="classespectre_1_1_pending_queue_1a38633383c3a20b1b53f82d8890e17525"></a>
### `clear`
```cpp
void espectre::PendingQueue< T, Capacity >::clear()
```
Discard every record.
<a id="classespectre_1_1_pending_queue_1adf95f881daf5bbf3376b5f34c5199276"></a>
### `size`
```cpp
size_t espectre::PendingQueue< T, Capacity >::size() const
```
Records currently queued.
<a id="structespectre_1_1_raw_csi_http_frame_prefix"></a>
## espectre::RawCsiHttpFramePrefix
```cpp
#include <runtime/raw_csi.h>
```
```cpp
struct espectre::RawCsiHttpFramePrefix
```
Little-endian prefix before every record on the binary stream.
A frame is this 60-byte prefix, a [`RawCsiRecordHeaderV8`](#structespectre_1_1_raw_csi_record_header_v8), and the CSI payload. The counters let a client detect loss without a side channel.
<a id="structespectre_1_1_raw_csi_http_frame_prefix_1aff63ce4fc7a4e08371da97d54cb746c5"></a>
### `magic`
```cpp
uint32_t espectre::RawCsiHttpFramePrefix::magic
```
[`ESPECTRE_RAW_CSI_RESPONSE_MAGIC`](#namespaceespectre_1ad78ee1950a9973d84c25e6b5e925aff4).
<a id="structespectre_1_1_raw_csi_http_frame_prefix_1ac4f5786b99681c4cad962c0f97dfafbf"></a>
### `version`
```cpp
uint8_t espectre::RawCsiHttpFramePrefix::version
```
[`ESPECTRE_RAW_CSI_PROTOCOL_VERSION`](#namespaceespectre_1a1571e2dbb44f5b5edacc83b4d1539ea9).
<a id="structespectre_1_1_raw_csi_http_frame_prefix_1a16b90d015a0fdb3b5fbc67ea5c925480"></a>
### `record_version`
```cpp
uint8_t espectre::RawCsiHttpFramePrefix::record_version
```
[`ESPECTRE_RAW_CSI_RECORD_VERSION`](#namespaceespectre_1a2c47aea6a64e9bbf1699a0066f9c437f).
<a id="structespectre_1_1_raw_csi_http_frame_prefix_1a4310fd9517fadbec9303fe3305c0a36d"></a>
### `header_len`
```cpp
uint16_t espectre::RawCsiHttpFramePrefix::header_len
```
Size of this prefix in bytes.
<a id="structespectre_1_1_raw_csi_http_frame_prefix_1a4519c8824b89b80a0fe4236319e2f840"></a>
### `session_id`
```cpp
uint8_t espectre::RawCsiHttpFramePrefix::session_id[ESPECTRE_RAW_CSI_SESSION_ID_BYTES][ESPECTRE_RAW_CSI_SESSION_ID_BYTES]
```
Session identifier, constant for the whole connection.
<a id="structespectre_1_1_raw_csi_http_frame_prefix_1a1aab45e916774b1d37733a135b6ad862"></a>
### `stream_sequence`
```cpp
uint64_t espectre::RawCsiHttpFramePrefix::stream_sequence
```
One-based sequence of packets offered to the stream, including dropped ones, so a gap shows how many were lost.
<a id="structespectre_1_1_raw_csi_http_frame_prefix_1ae2ce8f1c1b320fd785fa96cb84902e91"></a>
### `record_len`
```cpp
uint16_t espectre::RawCsiHttpFramePrefix::record_len
```
Size of the record header and payload that follow, in bytes.
<a id="structespectre_1_1_raw_csi_http_frame_prefix_1a1afdf43be2cc516e3a13302a17fa1d9e"></a>
### `flags`
```cpp
uint16_t espectre::RawCsiHttpFramePrefix::flags
```
Reserved; zero.
<a id="structespectre_1_1_raw_csi_http_frame_prefix_1aff647ce0eab14075108180bf3dabd939"></a>
### `fresh_record_total`
```cpp
uint64_t espectre::RawCsiHttpFramePrefix::fresh_record_total
```
Records sent in this session, including this one.
<a id="structespectre_1_1_raw_csi_http_frame_prefix_1abea7ebe4270089f9268e923847b02bf9"></a>
### `raw_drop_total`
```cpp
uint64_t espectre::RawCsiHttpFramePrefix::raw_drop_total
```
Records not sent: the queue was full, the packet was invalid, or its batch failed to send.
<a id="structespectre_1_1_raw_csi_http_frame_prefix_1ade022647201de886fa85623153e474fd"></a>
### `raw_send_backpressure_total`
```cpp
uint64_t espectre::RawCsiHttpFramePrefix::raw_send_backpressure_total
```
Batch sends the client did not accept.
<a id="structespectre_1_1_raw_csi_packet_view"></a>
## espectre::RawCsiPacketView
```cpp
#include <runtime/raw_csi.h>
```
```cpp
struct espectre::RawCsiPacketView
```
Callback-scoped view of one normalized raw CSI packet.
The struct and the bytes addressed by [`csi`](#structespectre_1_1_raw_csi_packet_view_1a518f5bc92cc9b0b4d2d8ac60cda60cb1) are valid only for the duration of the capture callback. Copy them before returning if another task needs the sample. The built-in capture pipeline supplies HT20\_CSI\_LEN bytes (64 complex subcarriers) after LLTF, HT, or VHT normalization. This normalized capture bound is independent of RAW\_CSI\_MAX\_PAYLOAD\_BYTES, the record-format limit.
<a id="structespectre_1_1_raw_csi_packet_view_1a518f5bc92cc9b0b4d2d8ac60cda60cb1"></a>
### `csi`
```cpp
const int8_t* espectre::RawCsiPacketView::csi {nullptr}
```
Interleaved I/Q bytes in the centered HT20 convention.
<a id="structespectre_1_1_raw_csi_packet_view_1a595517f6c85eedfe92c2bd0f3b27fdef"></a>
### `csi_len`
```cpp
uint16_t espectre::RawCsiPacketView::csi_len {0U}
```
Length of [`csi`](#structespectre_1_1_raw_csi_packet_view_1a518f5bc92cc9b0b4d2d8ac60cda60cb1) in bytes.
<a id="structespectre_1_1_raw_csi_packet_view_1ab750df6d53c73e68797581458488b832"></a>
### `captured_at_us`
```cpp
uint64_t espectre::RawCsiPacketView::captured_at_us {0U}
```
`esp_timer` time when the callback received the packet, in microseconds.
<a id="structespectre_1_1_raw_csi_packet_view_1a0961514d44a91e8922fb371098117fd2"></a>
### `wifi_rx_ts_us`
```cpp
uint32_t espectre::RawCsiPacketView::wifi_rx_ts_us {0U}
```
Wi-Fi driver receive timestamp, in microseconds.
Valid when [`record_flags`](#structespectre_1_1_raw_csi_packet_view_1a4550d70cf63fd67ecaaba4a96f7532aa) has [`RAW_CSI_FLAG_WIFI_RX_TS_VALID`](#namespaceespectre_1a967920764a50523f0ce8f7c5e36a3a21a4e720bd9bc21639dc5557441624cef2a). On the classic ESP32 it runs on a different clock than `esp_timer`.
<a id="structespectre_1_1_raw_csi_packet_view_1a4550d70cf63fd67ecaaba4a96f7532aa"></a>
### `record_flags`
```cpp
uint8_t espectre::RawCsiPacketView::record_flags {0U}
```
Bit set of [`RawCsiRecordFlags`](#namespaceespectre_1a967920764a50523f0ce8f7c5e36a3a21).
<a id="structespectre_1_1_raw_csi_packet_view_1af2ded4c9345b6b13f1136a1cc3d34f22"></a>
### `channel`
```cpp
uint8_t espectre::RawCsiPacketView::channel {0U}
```
Primary channel the packet arrived on.
<a id="structespectre_1_1_raw_csi_packet_view_1a6b31d1c641df6c888905d3d1d2a15bc4"></a>
### `rssi_dbm`
```cpp
int8_t espectre::RawCsiPacketView::rssi_dbm {0}
```
<a id="structespectre_1_1_raw_csi_packet_view_1a1c4362c1daa8093dccf22a2f20ef5529"></a>
### `noise_floor_dbm`
```cpp
int8_t espectre::RawCsiPacketView::noise_floor_dbm {0}
```
Noise floor as reported by the Wi-Fi driver.
<a id="structespectre_1_1_raw_csi_packet_view_1a66bf7a3613a973d694bed6c12e3b6948"></a>
### `phy_mode`
```cpp
RawCsiPhyMode espectre::RawCsiPacketView::phy_mode {RawCsiPhyMode::UNKNOWN}
```
<a id="structespectre_1_1_raw_csi_packet_view_1a94a64374b6cedf012a2a0dfc63edcc94"></a>
### `ltf_type`
```cpp
RawCsiLtfType espectre::RawCsiPacketView::ltf_type {RawCsiLtfType::UNKNOWN}
```
<a id="structespectre_1_1_raw_csi_packet_view_1a1df4e8233c12a8488b33f692f28ab34f"></a>
### `channel_width`
```cpp
RawCsiChannelWidth espectre::RawCsiPacketView::channel_width {RawCsiChannelWidth::UNKNOWN}
```
Always 20 MHz from the built-in pipeline.
<a id="structespectre_1_1_raw_csi_record_header_v8"></a>
## espectre::RawCsiRecordHeaderV8
```cpp
#include <runtime/csi_raw_record.h>
```
```cpp
struct espectre::RawCsiRecordHeaderV8
```
Little-endian, 64-byte header of one raw CSI record, followed by [`csi_len_bytes`](#structespectre_1_1_raw_csi_record_header_v8_1a023ae711e0a5af78d436ee6927e72a93) of interleaved I/Q payload.
Transport-neutral: Direct raw collection sends it after a [`RawCsiHttpFramePrefix`](#structespectre_1_1_raw_csi_http_frame_prefix). The capture fields mirror [`RawCsiPacketView`](#structespectre_1_1_raw_csi_packet_view).
<a id="structespectre_1_1_raw_csi_record_header_v8_1a2be7e3fe64a7ad696429405bc01eb145"></a>
### `magic`
```cpp
uint16_t espectre::RawCsiRecordHeaderV8::magic
```
`RAW_CSI_RECORD_MAGIC`.
<a id="structespectre_1_1_raw_csi_record_header_v8_1a63bfbc147266f17ce8e0ca11fbd4eecc"></a>
### `version`
```cpp
uint8_t espectre::RawCsiRecordHeaderV8::version
```
`RAW_CSI_RECORD_VERSION_V8`.
<a id="structespectre_1_1_raw_csi_record_header_v8_1a9600a4ab094c962b3551e1886523e9f8"></a>
### `header_len`
```cpp
uint8_t espectre::RawCsiRecordHeaderV8::header_len
```
Size of this header in bytes.
<a id="structespectre_1_1_raw_csi_record_header_v8_1a5f3a5c11eabed7999a830d818ec4904e"></a>
### `chip`
```cpp
uint8_t espectre::RawCsiRecordHeaderV8::chip
```
[`RawCsiChipType`](#namespaceespectre_1a83022e1a22fdb212c86c99fc85d8b22a) value.
<a id="structespectre_1_1_raw_csi_record_header_v8_1a7e2b9459ba67ad46bb4a93384b35beff"></a>
### `flags`
```cpp
uint8_t espectre::RawCsiRecordHeaderV8::flags
```
Bit set of [`RawCsiRecordFlags`](#namespaceespectre_1a967920764a50523f0ce8f7c5e36a3a21).
<a id="structespectre_1_1_raw_csi_record_header_v8_1aef74dacf16ba25a8ce3bde3d46b6979b"></a>
### `seq_num`
```cpp
uint32_t espectre::RawCsiRecordHeaderV8::seq_num
```
Stream sequence, saturated at `UINT32_MAX`.
<a id="structespectre_1_1_raw_csi_record_header_v8_1acd10191805ae0cc24b2cf50ce5b0ec86"></a>
### `num_subcarriers`
```cpp
uint16_t espectre::RawCsiRecordHeaderV8::num_subcarriers
```
Complex subcarriers in the payload: [`csi_len_bytes / 2`](#structespectre_1_1_raw_csi_record_header_v8_1a023ae711e0a5af78d436ee6927e72a93).
<a id="structespectre_1_1_raw_csi_record_header_v8_1a023ae711e0a5af78d436ee6927e72a93"></a>
### `csi_len_bytes`
```cpp
uint16_t espectre::RawCsiRecordHeaderV8::csi_len_bytes
```
Payload size in bytes, at most `RAW_CSI_MAX_PAYLOAD_BYTES`.
<a id="structespectre_1_1_raw_csi_record_header_v8_1ad9da0926689f413708e83d94e29aa3e9"></a>
### `device_id`
```cpp
uint64_t espectre::RawCsiRecordHeaderV8::device_id
```
<a id="structespectre_1_1_raw_csi_record_header_v8_1a2309743c2ab9d1ec26e9e3f7ff4c8881"></a>
### `device_ticks_us`
```cpp
uint64_t espectre::RawCsiRecordHeaderV8::device_ticks_us
```
Monotonic device time captured with the CSI sample, in microseconds.
<a id="structespectre_1_1_raw_csi_record_header_v8_1a79e1bfe6b2254f5be7cf4f4a40020877"></a>
### `wifi_rx_ts_us`
```cpp
uint32_t espectre::RawCsiRecordHeaderV8::wifi_rx_ts_us
```
See [`RawCsiPacketView::wifi_rx_ts_us`](#structespectre_1_1_raw_csi_packet_view_1a0961514d44a91e8922fb371098117fd2).
<a id="structespectre_1_1_raw_csi_record_header_v8_1acf55ce899c8d2cf518a15b4c0f59b705"></a>
### `wifi_rx_start_ts_ns`
```cpp
uint64_t espectre::RawCsiRecordHeaderV8::wifi_rx_start_ts_ns
```
Receive start time in nanoseconds, valid with [`RAW_CSI_FLAG_WIFI_RX_START_TS_NS_VALID`](#namespaceespectre_1a967920764a50523f0ce8f7c5e36a3a21ad3840b82f9a900c6c97204ff67f6b8be); the SDK writes zero.
<a id="structespectre_1_1_raw_csi_record_header_v8_1acc3237a83d4782265ec7256b0823e3f8"></a>
### `channel`
```cpp
uint8_t espectre::RawCsiRecordHeaderV8::channel
```
<a id="structespectre_1_1_raw_csi_record_header_v8_1ad954b162911a918cff26d75ef6e4d07d"></a>
### `rssi_dbm`
```cpp
int8_t espectre::RawCsiRecordHeaderV8::rssi_dbm
```
<a id="structespectre_1_1_raw_csi_record_header_v8_1a95e7928f62ae72588421ba826bd080cc"></a>
### `noise_floor_dbm`
```cpp
int8_t espectre::RawCsiRecordHeaderV8::noise_floor_dbm
```
<a id="structespectre_1_1_raw_csi_record_header_v8_1a2a0ceacb775707eb740176834364b33a"></a>
### `transport_backpressure_total`
```cpp
uint64_t espectre::RawCsiRecordHeaderV8::transport_backpressure_total
```
Copy of [`RawCsiHttpFramePrefix::raw_send_backpressure_total`](#structespectre_1_1_raw_csi_http_frame_prefix_1ade022647201de886fa85623153e474fd).
<a id="structespectre_1_1_raw_csi_record_header_v8_1a9bea32173dff7bc07a0537cf8f41acf9"></a>
### `fresh_record_total`
```cpp
uint32_t espectre::RawCsiRecordHeaderV8::fresh_record_total
```
Records sent including this one, saturated at `UINT32_MAX`.
<a id="structespectre_1_1_raw_csi_record_header_v8_1a994a6ea793326afe12c8ecfde222a7b3"></a>
### `request_accepted_total`
```cpp
uint32_t espectre::RawCsiRecordHeaderV8::request_accepted_total
```
Packets offered to the stream up to this one, saturated at `UINT32_MAX`.
<a id="structespectre_1_1_raw_csi_record_header_v8_1abd87cbb6fdffc6f3e26a0e9ed12725ad"></a>
### `phy_mode`
```cpp
uint8_t espectre::RawCsiRecordHeaderV8::phy_mode
```
[`RawCsiPhyMode`](#namespaceespectre_1a679285b0ae641ff6d1446f1a7cb6a363) value.
<a id="structespectre_1_1_raw_csi_record_header_v8_1a855dfc7a80986911adf5c337c2dea3e1"></a>
### `ltf_type`
```cpp
uint8_t espectre::RawCsiRecordHeaderV8::ltf_type
```
[`RawCsiLtfType`](#namespaceespectre_1a04fa1bf9323c3efd3ff9998892a32e9e) value.
<a id="structespectre_1_1_raw_csi_record_header_v8_1a1442437f89c541d25b34a6539d934916"></a>
### `channel_width`
```cpp
uint8_t espectre::RawCsiRecordHeaderV8::channel_width
```
[`RawCsiChannelWidth`](#namespaceespectre_1a74c31f33edc1dcd2760c4cf242d01c97) value.
<a id="structespectre_1_1_raw_csi_session_config"></a>
## espectre::RawCsiSessionConfig
```cpp
#include <runtime/raw_csi.h>
```
```cpp
struct espectre::RawCsiSessionConfig
```
Identity stamped on every record of one raw collection session.
<a id="structespectre_1_1_raw_csi_session_config_1a64034c747a85e38ec0b3e3393d87610d"></a>
### `session_id`
```cpp
uint8_t espectre::RawCsiSessionConfig::session_id[ESPECTRE_RAW_CSI_SESSION_ID_BYTES][ESPECTRE_RAW_CSI_SESSION_ID_BYTES] {}
```
Identifier echoed in every frame prefix.
<a id="structespectre_1_1_raw_csi_session_config_1a330ce1101930b0bc35e51a6dddfbeb89"></a>
### `device_id`
```cpp
uint64_t espectre::RawCsiSessionConfig::device_id {0U}
```
Device identity written to each record header.
<a id="structespectre_1_1_raw_csi_session_config_1a3b93ff18005d0b24237d29635cb7184d"></a>
### `chip`
```cpp
RawCsiChipType espectre::RawCsiSessionConfig::chip {RawCsiChipType::UNKNOWN}
```
Chip written to each record header.
<a id="classespectre_1_1_raw_csi_session_controller"></a>
## espectre::RawCsiSessionController
```cpp
#include <runtime/esp_idf/raw_csi_session_controller.h>
```
```cpp
class espectre::RawCsiSessionController
```
Connects a Direct raw session to the runtime's raw collection.
Once configured, a `GET /csi` request on the Direct service starts raw collection through the controller and streams every packet to the client; ending either side stops the other.
**Par:** Threading
Call every method from the task that owns the runtime and the service.
<a id="classespectre_1_1_raw_csi_session_controller_1ae9cf91a097cfb99ff2017f48b0175201"></a>
### `StoppedCallback`
```cpp
using espectre::RawCsiSessionController::StoppedCallback = std::function<void(RawCsiStopReason reason)>
```
Reports why the session ended, after the runtime left raw collection.
<a id="classespectre_1_1_raw_csi_session_controller_1abd15e43bf15014bdd32b80449dd791cb"></a>
### `StartedCallback`
```cpp
using espectre::RawCsiSessionController::StartedCallback = std::function<void()>
```
Reports that a session started.
<a id="classespectre_1_1_raw_csi_session_controller_1aad3fc3c7ed2079d4945e2a61054e42dc"></a>
### `configure`
```cpp
void espectre::RawCsiSessionController::configure(IDirectHttpService *service, RuntimeFrontendController *runtime, uint64_t device_id, std::string chip, StoppedCallback stopped_callback={}, StartedCallback started_callback={})
```
Bind the service and runtime, and register the `GET /csi` handler.
Neither object is owned; both must outlive the controller. `device_id` must be nonzero and `chip` is the `CONFIG_IDF_TARGET` name; both are stamped on every record.
<a id="classespectre_1_1_raw_csi_session_controller_1a1e7634c8a365a87f71f760acbc675f37"></a>
### `begin`
```cpp
bool espectre::RawCsiSessionController::begin(std::string *message=nullptr)
```
Start a session.
**Returns:** false, with a reason in `message`, when raw CSI is unavailable, a session is already active, or either side fails to start.
<a id="classespectre_1_1_raw_csi_session_controller_1a52e62ad8344a6e0ed58060f483fa0191"></a>
### `ensure_runtime_consistency`
```cpp
void espectre::RawCsiSessionController::ensure_runtime_consistency()
```
End the session if the runtime left raw collection on its own.
Call it from the loop.
<a id="classespectre_1_1_raw_csi_session_controller_1aedcad49435d24cd25e14fff9ee1b79ba"></a>
### `shutdown`
```cpp
void espectre::RawCsiSessionController::shutdown(RawCsiStopReason reason=RawCsiStopReason::SHUTDOWN)
```
End the active session, if any.
<a id="classespectre_1_1_raw_csi_session_controller_1a520a1ab907c02b461de790cd6342881e"></a>
### `active`
```cpp
bool espectre::RawCsiSessionController::active() const
```
Whether a session is active.
<a id="structespectre_1_1_raw_csi_session_diagnostics"></a>
## espectre::RawCsiSessionDiagnostics
```cpp
#include <runtime/raw_csi.h>
```
```cpp
struct espectre::RawCsiSessionDiagnostics
```
Counters of the current or last raw collection session.
<a id="structespectre_1_1_raw_csi_session_diagnostics_1a9d6559b9af3fe917d1d706cdfa9908fd"></a>
### `active`
```cpp
bool espectre::RawCsiSessionDiagnostics::active {false}
```
Whether a session is open.
<a id="structespectre_1_1_raw_csi_session_diagnostics_1a00dfeb74a7853d881d5daf28fe46d19a"></a>
### `binary_bound`
```cpp
bool espectre::RawCsiSessionDiagnostics::binary_bound {false}
```
Whether a client is attached to the binary stream.
<a id="structespectre_1_1_raw_csi_session_diagnostics_1af028b03fa5574f470cb775528e731902"></a>
### `raw_drop_total`
```cpp
uint64_t espectre::RawCsiSessionDiagnostics::raw_drop_total {0U}
```
See [`RawCsiHttpFramePrefix::raw_drop_total`](#structespectre_1_1_raw_csi_http_frame_prefix_1abea7ebe4270089f9268e923847b02bf9).
<a id="structespectre_1_1_raw_csi_session_diagnostics_1a949a317f2743710686258f4315cf8250"></a>
### `raw_send_backpressure_total`
```cpp
uint64_t espectre::RawCsiSessionDiagnostics::raw_send_backpressure_total {0U}
```
See [`RawCsiHttpFramePrefix::raw_send_backpressure_total`](#structespectre_1_1_raw_csi_http_frame_prefix_1ade022647201de886fa85623153e474fd).
<a id="structespectre_1_1_raw_csi_session_diagnostics_1a4c48a663c7d565f0b9fe478e218b76a3"></a>
### `fresh_record_total`
```cpp
uint64_t espectre::RawCsiSessionDiagnostics::fresh_record_total {0U}
```
See [`RawCsiHttpFramePrefix::fresh_record_total`](#structespectre_1_1_raw_csi_http_frame_prefix_1aff647ce0eab14075108180bf3dabd939).
<a id="structespectre_1_1_raw_csi_session_diagnostics_1af7f644fe02ab9bea2e3ba52d33a5bc59"></a>
### `stream_sequence`
```cpp
uint64_t espectre::RawCsiSessionDiagnostics::stream_sequence {0U}
```
Latest offered sequence; see [`RawCsiHttpFramePrefix::stream_sequence`](#structespectre_1_1_raw_csi_http_frame_prefix_1a1aab45e916774b1d37733a135b6ad862).
<a id="structespectre_1_1_runtime_capabilities"></a>
## espectre::RuntimeCapabilities
```cpp
#include <runtime/runtime_capabilities.h>
```
```cpp
struct espectre::RuntimeCapabilities
```
What a runtime actually offers its frontend.
Every flag defaults to false, so a runtime declares each capability explicitly. Protocol clients read these flags to learn which controls exist.
[`supports_live_telemetry`](#structespectre_1_1_runtime_capabilities_1a7c29851c92d3dce3570e44946c055948) describes the runtime side of the surface: whether it drives the live-telemetry callback at all.
<a id="structespectre_1_1_runtime_capabilities_1a73c517a443cb659c29fe03926926d7b6"></a>
### `supports_runtime_threshold_updates`
```cpp
bool espectre::RuntimeCapabilities::supports_runtime_threshold_updates {false}
```
`set_threshold()` is honored.
<a id="structespectre_1_1_runtime_capabilities_1a84d3b5bb447e02b9026bdb81f69db236"></a>
### `supports_runtime_motion_hits_updates`
```cpp
bool espectre::RuntimeCapabilities::supports_runtime_motion_hits_updates {false}
```
`set_motion_hits()` is honored; otherwise the controller refuses it.
<a id="structespectre_1_1_runtime_capabilities_1a8a74863f469d46c8a8441ef4e58c6b66"></a>
### `supports_runtime_detector_selection`
```cpp
bool espectre::RuntimeCapabilities::supports_runtime_detector_selection {false}
```
`set_detection_algorithm()` is honored.
Driven by [`RuntimeConfig::runtime_detector_selection_enabled`](#structespectre_1_1_runtime_config_1adb8b5784fab9a57ecc354c281b3cd799), since switching detectors also means persisting and restoring the choice.
<a id="structespectre_1_1_runtime_capabilities_1a1457a33557663be153d4472ac9192b20"></a>
### `supports_manual_recalibration`
```cpp
bool espectre::RuntimeCapabilities::supports_manual_recalibration {false}
```
`trigger_recalibration()` is honored; otherwise the controller refuses it.
<a id="structespectre_1_1_runtime_capabilities_1a7c29851c92d3dce3570e44946c055948"></a>
### `supports_live_telemetry`
```cpp
bool espectre::RuntimeCapabilities::supports_live_telemetry {false}
```
The runtime drives [`IRuntimeListener::on_live_telemetry()`](#classespectre_1_1_i_runtime_listener_1a2473b19c1324d186b11ba596000acde9) at all.
Use it for high-rate outputs such as a live movement score. Transport adapters decide how to forward live sensing.
<a id="structespectre_1_1_runtime_capabilities_1ab38fbc94f33d1f3dace27cca8e48f0c3"></a>
### `supports_extended_diagnostics`
```cpp
bool espectre::RuntimeCapabilities::supports_extended_diagnostics {false}
```
The runtime reports the extended fields used by diagnostics payloads.
<a id="structespectre_1_1_runtime_capabilities_1a9cb79d6a0f22efbcfecabc4d4747fedb"></a>
### `supports_traffic_control`
```cpp
bool espectre::RuntimeCapabilities::supports_traffic_control {false}
```
The runtime owns CSI traffic generation and can be asked to retune it.
<a id="structespectre_1_1_runtime_capabilities_1ae02edf210122c8ba729173b427c0dec2"></a>
### `supports_raw_csi`
```cpp
bool espectre::RuntimeCapabilities::supports_raw_csi {false}
```
The runtime can temporarily bypass sensing and expose normalized raw CSI.
<a id="structespectre_1_1_runtime_config"></a>
## espectre::RuntimeConfig
```cpp
#include <runtime/runtime_config.h>
```
```cpp
struct espectre::RuntimeConfig
```
Everything the runtime needs to know before `setup()`.
Every member is default-constructed to a supported production value, so [`RuntimeConfig{}`](#structespectre_1_1_runtime_config) is a working configuration for Lightweight Detection on internally generated traffic. Override only what your product changes.
Ranges are declared in [`runtime_sensing_schema.h`](#runtime__sensing__schema_8h) as `RUNTIME_<FIELD>_MIN` / `_MAX` / `_DEFAULT`, and the free functions in [`runtime_config_utils.h`](#runtime__config__utils_8h) validate against them. On ESP-IDF you can build this from menuconfig with [`make_runtime_sensing_config_from_kconfig()`](#namespaceespectre_1ab070877204ffb133b519d0b163420df6) instead of assigning fields by hand.
The config is copied into the runtime at `setup()`. Later edits to your own copy have no effect; use the [`RuntimeFrontendController`](#classespectre_1_1_runtime_frontend_controller) setters instead.
<a id="structespectre_1_1_runtime_config_1a8802e0c9228e203ce428e689604eed0a"></a>
### `wifi_band_policy`
```cpp
WifiBandPolicy espectre::RuntimeConfig::wifi_band_policy {WifiBandPolicy::AUTO}
```
Band available to the station while the runtime keeps the PHY at HT20.
The default, `AUTO`, uses every band the radio has, which means 2.4 GHz on single-band targets. `BAND_5G` requires dual-band silicon.
<a id="structespectre_1_1_runtime_config_1a11e3dabb6a3b11810eecd2cf0e082b35"></a>
### `csi_capture_policy`
```cpp
CsiCapturePolicy espectre::RuntimeConfig::csi_capture_policy {CsiCapturePolicy::AUTO}
```
Build-time CSI profile; AUTO resolves from chip, band, and the active traffic source.
No runtime setter.
<a id="structespectre_1_1_runtime_config_1a3d14cc007fe6107bd81c6c6da176327a"></a>
### `detection_algorithm`
```cpp
DetectionAlgorithm espectre::RuntimeConfig::detection_algorithm {DetectionAlgorithm::LIGHTWEIGHT}
```
Detection profile to run.
Lightweight self-calibrates; High Accuracy uses trained weights.
<a id="structespectre_1_1_runtime_config_1a4eaac5c4cc10b6d34f679ec1cb152671"></a>
### `threshold`
```cpp
float espectre::RuntimeConfig::threshold {RUNTIME_THRESHOLD_DEFAULT}
```
Motion probability threshold, on the same 0..1 scale as [`RuntimeSnapshot::movement_metric`](#structespectre_1_1_runtime_snapshot_1a6844aeb15178c5088d4564c5719361c7).
Lightweight Detection overwrites this during startup calibration, so the configured value only governs the pre-calibration window. High-Accuracy Detection keeps it as given.
<a id="structespectre_1_1_runtime_config_1af157afffd481dcc5a8eb9e2f64d281d0"></a>
### `window_size_ms`
```cpp
uint32_t espectre::RuntimeConfig::window_size_ms {RUNTIME_WINDOW_SIZE_MS_DEFAULT}
```
Detector window duration in milliseconds (1000..2000).
Runtimes resolve the duration to a fixed temporal grid from [`csi_target_pps`](#structespectre_1_1_runtime_config_1a0dbde3a8ad2fed884033fe0855153461); live arrival jitter never resizes the detector.
<a id="structespectre_1_1_runtime_config_1adb8b5784fab9a57ecc354c281b3cd799"></a>
### `runtime_detector_selection_enabled`
```cpp
bool espectre::RuntimeConfig::runtime_detector_selection_enabled {false}
```
Advertise runtime detector switching.
When true the runtime restores the persisted detector choice at `setup()` and sets [`RuntimeCapabilities::supports_runtime_detector_selection`](#structespectre_1_1_runtime_capabilities_1a8a74863f469d46c8a8441ef4e58c6b66). A persisted detector that differs from [`detection_algorithm`](#structespectre_1_1_runtime_config_1a3d14cc007fe6107bd81c6c6da176327a) also replaces [`threshold`](#structespectre_1_1_runtime_config_1a4eaac5c4cc10b6d34f679ec1cb152671) with that detector's default.
<a id="structespectre_1_1_runtime_config_1a0dbde3a8ad2fed884033fe0855153461"></a>
### `csi_target_pps`
```cpp
uint32_t espectre::RuntimeConfig::csi_target_pps {RUNTIME_CSI_TARGET_PPS_DEFAULT}
```
Target CSI sensing cadence, in packets per second.
This value is always positive and defines detector temporal slots as well as the target for managed traffic. [`traffic_generator_mode`](#structespectre_1_1_runtime_config_1aa7bf6c82465a049cfa6ca6fb3da7d134) alone selects who supplies traffic. The detector coefficients are fitted at 100 pps; see [ALGORITHMS.md](<https://github.com/francescopace/espectre/blob/main/docs/ALGORITHMS.md>) before moving far from it.
<a id="structespectre_1_1_runtime_config_1aa7bf6c82465a049cfa6ca6fb3da7d134"></a>
### `traffic_generator_mode`
```cpp
TrafficGeneratorMode espectre::RuntimeConfig::traffic_generator_mode {TrafficGeneratorMode::PING}
```
How the device gets CSI-bearing traffic: one of the internal generator modes, or `EXTERNAL` to listen for another host.
<a id="structespectre_1_1_runtime_config_1a3724c06056cbaa57995ec053a955403f"></a>
### `traffic_generator_target_ip`
```cpp
std::string espectre::RuntimeConfig::traffic_generator_target_ip
```
Unicast IPv4 destination for internal IP traffic; empty uses the Wi-Fi gateway.
Ignored by `wifi_raw`.
<a id="structespectre_1_1_runtime_config_1a351c09d60c62894a66d78bbcff516ba4"></a>
### `csi_traffic_udp_port`
```cpp
uint16_t espectre::RuntimeConfig::csi_traffic_udp_port {RUNTIME_CSI_TRAFFIC_UDP_PORT_DEFAULT}
```
UDP port used by the external CSI traffic mode.
<a id="structespectre_1_1_runtime_config_1a030014458960bd11b3848bba7f770d8e"></a>
### `csi_traffic_multicast_group`
```cpp
std::string espectre::RuntimeConfig::csi_traffic_multicast_group {RUNTIME_CSI_TRAFFIC_MULTICAST_GROUP_DEFAULT}
```
IPv4 multicast group joined by the UDP listener in `external`.
Empty disables the IGMP join. Unicast to the device IP still works.
<a id="structespectre_1_1_runtime_config_1a9ed14bbc7a7bbef728b2db39fc484553"></a>
### `device_id`
```cpp
uint64_t espectre::RuntimeConfig::device_id {0U}
```
Stable device identity used by the ESPectre Protocol and CSI streaming.
Assign [`derive_runtime_device_id()`](#namespaceespectre_1a34031a60d78bbb6306047b3540b4f905) to use the SDK's stable pseudonym from the Wi-Fi MAC. Zero is an unresolved sentinel; the controller does not replace it automatically.
<a id="structespectre_1_1_runtime_config_1ac210376be06dd066fcf78547733ee8af"></a>
### `evaluation_interval_ms`
```cpp
uint32_t espectre::RuntimeConfig::evaluation_interval_ms {RUNTIME_EVALUATION_INTERVAL_MS_DEFAULT}
```
Detector evaluation cadence in milliseconds.
<a id="structespectre_1_1_runtime_config_1a9ffb875a52b525060dc7996787d6fd3a"></a>
### `motion_on_hits`
```cpp
uint8_t espectre::RuntimeConfig::motion_on_hits {RUNTIME_MOTION_ON_HITS_DEFAULT}
```
Consecutive above-threshold evaluations before reporting motion (1..20).
<a id="structespectre_1_1_runtime_config_1a53ebfb156a2125c61fa675788784c301"></a>
### `motion_off_hits`
```cpp
uint8_t espectre::RuntimeConfig::motion_off_hits {RUNTIME_MOTION_OFF_HITS_DEFAULT}
```
Consecutive below-threshold evaluations before clearing motion (1..20).
<a id="structespectre_1_1_runtime_config_1a6b833d1269bc157a791dc100241087b7"></a>
### `lowpass_enabled`
```cpp
bool espectre::RuntimeConfig::lowpass_enabled {RUNTIME_LOWPASS_ENABLED_DEFAULT}
```
Enable the low-pass filter on the turbulence stream.
Off by default.
<a id="structespectre_1_1_runtime_config_1aa6a480f526a935faef46ee91c286ee5d"></a>
### `lowpass_cutoff`
```cpp
float espectre::RuntimeConfig::lowpass_cutoff {RUNTIME_LOWPASS_CUTOFF_DEFAULT}
```
Low-pass cutoff in Hz (5.0..20.0).
Ignored unless [`lowpass_enabled`](#structespectre_1_1_runtime_config_1a6b833d1269bc157a791dc100241087b7).
<a id="structespectre_1_1_runtime_config_1a36be148ebec6f2e07240cbd1c39e1ccb"></a>
### `hampel_enabled`
```cpp
bool espectre::RuntimeConfig::hampel_enabled {RUNTIME_HAMPEL_ENABLED_DEFAULT}
```
Enable Hampel outlier rejection on the turbulence stream.
On by default.
<a id="structespectre_1_1_runtime_config_1a034ce1a3a20c5509049fff9ba5e76c54"></a>
### `hampel_window`
```cpp
uint8_t espectre::RuntimeConfig::hampel_window {RUNTIME_HAMPEL_WINDOW_DEFAULT}
```
Hampel window in samples (3..11).
Ignored unless [`hampel_enabled`](#structespectre_1_1_runtime_config_1a36be148ebec6f2e07240cbd1c39e1ccb).
<a id="structespectre_1_1_runtime_config_1a36d865a656d4cd1856c709a340d3c63b"></a>
### `hampel_threshold`
```cpp
float espectre::RuntimeConfig::hampel_threshold {RUNTIME_HAMPEL_THRESHOLD_DEFAULT}
```
Hampel MAD multiplier (1.0..10.0).
Ignored unless [`hampel_enabled`](#structespectre_1_1_runtime_config_1a36be148ebec6f2e07240cbd1c39e1ccb).
<a id="structespectre_1_1_runtime_config_1a6e59c22554445734d3245bc0511757a4"></a>
### `wifi_scan_results_managed_externally`
```cpp
bool espectre::RuntimeConfig::wifi_scan_results_managed_externally {false}
```
The Wi-Fi stack consumes scan results, including CSI recovery scans.
Enable for stacks with autonomous scans, such as ESPHome. The runtime must not clear their driver result list, even after its own scan completes. Otherwise, independent scanners must wait until the SDK releases its scanner reservation after cleanup.
<a id="structespectre_1_1_runtime_config_1a246097b5af94d246329a089da27dd6f9"></a>
### `persist_runtime_overrides`
```cpp
bool espectre::RuntimeConfig::persist_runtime_overrides {true}
```
Remember runtime control changes across reboots.
When true, `setup()` restores the traffic generator mode and motion hits saved by earlier control calls, plus the detector when [`runtime_detector_selection_enabled`](#structespectre_1_1_runtime_config_1adb8b5784fab9a57ecc354c281b3cd799) is set, and those calls save their new values. Set it to false when your firmware owns configuration, for example from YAML or a cloud service: this config is then the only source of truth, and the runtime neither reads nor writes saved controls.
<a id="structespectre_1_1_runtime_control_update"></a>
## espectre::RuntimeControlUpdate
```cpp
#include <runtime/runtime_config_utils.h>
```
```cpp
struct espectre::RuntimeControlUpdate
```
A partial change to the live sensing controls.
Each `has_*` flag marks a field to change; the others keep their value. Validate the whole change before applying any field, so a request either applies completely or not at all.
<a id="structespectre_1_1_runtime_control_update_1a99a6c6a22ce08c61f57d090228475024"></a>
### `has_detection_algorithm`
```cpp
bool espectre::RuntimeControlUpdate::has_detection_algorithm {false}
```
<a id="structespectre_1_1_runtime_control_update_1a118cce94b78b4c30d0c72bcbe4524986"></a>
### `detection_algorithm`
```cpp
DetectionAlgorithm espectre::RuntimeControlUpdate::detection_algorithm {DetectionAlgorithm::LIGHTWEIGHT}
```
<a id="structespectre_1_1_runtime_control_update_1ae96d103c53d6cdd99e27eb351c36f51c"></a>
### `has_threshold`
```cpp
bool espectre::RuntimeControlUpdate::has_threshold {false}
```
<a id="structespectre_1_1_runtime_control_update_1af89fd90e55cdc213236631869ec0b310"></a>
### `threshold`
```cpp
float espectre::RuntimeControlUpdate::threshold {0.0f}
```
<a id="structespectre_1_1_runtime_control_update_1a7da412ee017c652b4dac4c53efc5e061"></a>
### `has_motion_hits`
```cpp
bool espectre::RuntimeControlUpdate::has_motion_hits {false}
```
<a id="structespectre_1_1_runtime_control_update_1a36c768e930c661ef52b0d94976b51e4f"></a>
### `motion_on_hits`
```cpp
uint8_t espectre::RuntimeControlUpdate::motion_on_hits {0U}
```
<a id="structespectre_1_1_runtime_control_update_1aa5a28dad01990c44ff99fd2aeb55aec0"></a>
### `motion_off_hits`
```cpp
uint8_t espectre::RuntimeControlUpdate::motion_off_hits {0U}
```
<a id="structespectre_1_1_runtime_control_update_1a2528ec9b8c78a5e81bc60afd1e5c9bf0"></a>
### `has_traffic_generator_mode`
```cpp
bool espectre::RuntimeControlUpdate::has_traffic_generator_mode {false}
```
<a id="structespectre_1_1_runtime_control_update_1a84401f569cf5386dac7115e7ea9e9cad"></a>
### `traffic_generator_mode`
```cpp
TrafficGeneratorMode espectre::RuntimeControlUpdate::traffic_generator_mode {TrafficGeneratorMode::PING}
```
<a id="structespectre_1_1_runtime_diagnostics_sample"></a>
## espectre::RuntimeDiagnosticsSample
```cpp
#include <runtime/runtime_diagnostics.h>
```
```cpp
struct espectre::RuntimeDiagnosticsSample
```
Rate and link diagnostics derived from cumulative runtime counters.
Produced by the runtime-owned [`RuntimeDiagnosticsSampler`](#classespectre_1_1_runtime_diagnostics_sampler). The rates are what the runtime's monotonic totals moved by between two periodic sensing updates, and every frontend reads the same latest sample.
A zero rate means the counter did not move over the interval, and the first sample after [`RuntimeDiagnosticsSampler::reset()`](#classespectre_1_1_runtime_diagnostics_sampler_1a255a7d6a981df30ffdce72d1b89495df) reports zero rates because it establishes the baseline. The link fields are carried through either way.
<a id="structespectre_1_1_runtime_diagnostics_sample_1a04f14702fc3d3c2ada6eaf0973d362db"></a>
### `generator_pps`
```cpp
float espectre::RuntimeDiagnosticsSample::generator_pps {0.0f}
```
Successful internal generator sends per second; zero in external mode.
<a id="structespectre_1_1_runtime_diagnostics_sample_1a3ff1ff0161be346bff367985d0721824"></a>
### `traffic_tx_pps`
```cpp
float espectre::RuntimeDiagnosticsSample::traffic_tx_pps {0.0f}
```
Station network packets per second accepted by the driver.
<a id="structespectre_1_1_runtime_diagnostics_sample_1a237c806beb2a88d33bb76877d6a07ce2"></a>
### `traffic_rx_pps`
```cpp
float espectre::RuntimeDiagnosticsSample::traffic_rx_pps {0.0f}
```
Station network packets per second delivered by the driver.
<a id="structespectre_1_1_runtime_diagnostics_sample_1a43ac7ee8b3dfdf6f3274d4e81dafcd16"></a>
### `csi_callback_pps`
```cpp
float espectre::RuntimeDiagnosticsSample::csi_callback_pps {0.0f}
```
Raw CSI callbacks per second, before any capture-level validation.
<a id="structespectre_1_1_runtime_diagnostics_sample_1a125500562a6bc3ad824cf696cae8c9a4"></a>
### `csi_accepted_pps`
```cpp
float espectre::RuntimeDiagnosticsSample::csi_accepted_pps {0.0f}
```
CSI packets per second accepted by capture validation.
<a id="structespectre_1_1_runtime_diagnostics_sample_1a701ee4b43a9b5f7a09a2f75a717e51ca"></a>
### `csi_admitted_pps`
```cpp
float espectre::RuntimeDiagnosticsSample::csi_admitted_pps {0.0f}
```
CSI packets per second admitted to the detector's temporal grid.
<a id="structespectre_1_1_runtime_diagnostics_sample_1a76312bc2c4556eaf7bfa17a577d38dc9"></a>
### `csi_filtered_pps`
```cpp
float espectre::RuntimeDiagnosticsSample::csi_filtered_pps {0.0f}
```
CSI packets per second rejected by capture-level validation.
<a id="structespectre_1_1_runtime_diagnostics_sample_1aabbfd5e2dba6cd01ee3063247f02e314"></a>
### `csi_hw_error_pps`
```cpp
float espectre::RuntimeDiagnosticsSample::csi_hw_error_pps {0.0f}
```
Hardware-quality rejections per second, with one reason per rejected callback.
<a id="structespectre_1_1_runtime_diagnostics_sample_1a4ef885c63bffa884bea39ae6a52785af"></a>
### `csi_pending_frame_drop_pps`
```cpp
float espectre::RuntimeDiagnosticsSample::csi_pending_frame_drop_pps {0.0f}
```
Valid CSI callbacks per second dropped because the pending queue was full.
<a id="structespectre_1_1_runtime_diagnostics_sample_1a3027d157b651e64d5b50e08b0a88357c"></a>
### `csi_missing_slots_pps`
```cpp
float espectre::RuntimeDiagnosticsSample::csi_missing_slots_pps {0.0f}
```
Missing detector slots per second.
<a id="structespectre_1_1_runtime_diagnostics_sample_1aba879cef28a0cc1d02aa752f3bb09819"></a>
### `csi_excess_pps`
```cpp
float espectre::RuntimeDiagnosticsSample::csi_excess_pps {0.0f}
```
Same-slot excess drops per second.
<a id="structespectre_1_1_runtime_diagnostics_sample_1a205207163e1676ca349806e25ca91107"></a>
### `csi_stale_pps`
```cpp
float espectre::RuntimeDiagnosticsSample::csi_stale_pps {0.0f}
```
Stale temporal drops per second.
<a id="structespectre_1_1_runtime_diagnostics_sample_1a4351f6e1c87593f9c38fd5ae30657141"></a>
### `csi_out_of_order_pps`
```cpp
float espectre::RuntimeDiagnosticsSample::csi_out_of_order_pps {0.0f}
```
Out-of-order temporal drops per second.
<a id="structespectre_1_1_runtime_diagnostics_sample_1a7cecc77e01848e3f2978a5814ec1568a"></a>
### `csi_occupancy_ratio`
```cpp
float espectre::RuntimeDiagnosticsSample::csi_occupancy_ratio {0.0f}
```
Valid-slot occupancy of the active temporal detector window.
<a id="structespectre_1_1_runtime_diagnostics_sample_1abac2acdc8b1e74cbde558ef87578c5fe"></a>
### `wifi_rssi_dbm`
```cpp
int8_t espectre::RuntimeDiagnosticsSample::wifi_rssi_dbm {INT8_MIN}
```
RSSI of the current association.
`INT8_MIN` when unavailable.
<a id="structespectre_1_1_runtime_diagnostics_sample_1a0dbd610d4f5bf12a6467446a19a98ecd"></a>
### `wifi_channel`
```cpp
uint8_t espectre::RuntimeDiagnosticsSample::wifi_channel {0U}
```
Primary channel of the current association.
Zero when unavailable.
<a id="classespectre_1_1_runtime_diagnostics_sampler"></a>
## espectre::RuntimeDiagnosticsSampler
```cpp
#include <runtime/runtime_diagnostics.h>
```
```cpp
class espectre::RuntimeDiagnosticsSampler
```
Converts cumulative diagnostics into rates over the interval between reads.
Call [`reset()`](#classespectre_1_1_runtime_diagnostics_sampler_1a255a7d6a981df30ffdce72d1b89495df) when the owning runtime starts. Counter resets are treated as a new epoch, so rearming a traffic source cannot underflow a rate. Station network counters wrap modulo 2^32 and are never reset by sensing restarts.
```cpp
// once, after controller.setup() succeeds:
sampler.reset(controller.diagnostics(), now_ms);
// on the runtime's existing sensing heartbeat:
latest = sampler.sample(controller.diagnostics(), now_ms);
```
**Par:** Threading
Not synchronized, and it holds the previous read. Sample it from the task that owns the runtime.
<a id="classespectre_1_1_runtime_diagnostics_sampler_1a255a7d6a981df30ffdce72d1b89495df"></a>
### `reset`
```cpp
void espectre::RuntimeDiagnosticsSampler::reset(const RuntimeDiagnosticsSnapshot &snapshot, uint32_t now_ms)
```
Establish the baseline the next [`sample()`](#classespectre_1_1_runtime_diagnostics_sampler_1aa63e9035ae799879686273cfab48e0bb) measures against.
**Parameters**
- `snapshot`: Current cumulative counters.
- `now_ms`: Monotonic frontend clock, in milliseconds.
<a id="classespectre_1_1_runtime_diagnostics_sampler_1aa63e9035ae799879686273cfab48e0bb"></a>
### `sample`
```cpp
RuntimeDiagnosticsSample espectre::RuntimeDiagnosticsSampler::sample(const RuntimeDiagnosticsSnapshot &snapshot, uint32_t now_ms)
```
Derive rates since the previous read and adopt this one as the baseline.
The caller owns the window. Call it from an existing periodic sensing update, so diagnostics do not add a timer.
**Parameters**
- `snapshot`: Current cumulative counters.
- `now_ms`: Monotonic frontend clock, in milliseconds.
**Returns:** Rates over the elapsed interval. The link fields are always carried through; the rates are zero when there is no baseline yet or no time has elapsed.
<a id="structespectre_1_1_runtime_diagnostics_snapshot"></a>
## espectre::RuntimeDiagnosticsSnapshot
```cpp
#include <runtime/runtime_snapshot.h>
```
```cpp
struct espectre::RuntimeDiagnosticsSnapshot
```
Low-frequency counters and radio state used by optional diagnostic surfaces.
This deliberately stays separate from [`RuntimeSnapshot`](#structespectre_1_1_runtime_snapshot): sensing snapshots travel through the hot callback path, while frontends query diagnostics when they already handle a periodic sensing update.
Counters are cumulative and monotonic within a session; pass them through [`RuntimeDiagnosticsSampler`](#classespectre_1_1_runtime_diagnostics_sampler) to turn them into rates.
[`espectre::RuntimeDiagnosticsSnapshot::Link`](#structespectre_1_1_runtime_diagnostics_snapshot_1_1_link)
[`espectre::RuntimeDiagnosticsSnapshot::Traffic`](#structespectre_1_1_runtime_diagnostics_snapshot_1_1_traffic)
[`espectre::RuntimeDiagnosticsSnapshot::Csi`](#structespectre_1_1_runtime_diagnostics_snapshot_1_1_csi)
[`espectre::RuntimeDiagnosticsSnapshot::Platform`](#structespectre_1_1_runtime_diagnostics_snapshot_1_1_platform)
[`espectre::RuntimeDiagnosticsSnapshot::Performance`](#structespectre_1_1_runtime_diagnostics_snapshot_1_1_performance)
<a id="structespectre_1_1_runtime_diagnostics_snapshot_1aae60e81b8c408a1174e63cead0ba2c0f"></a>
### `link`
```cpp
Link espectre::RuntimeDiagnosticsSnapshot::link {}
```
Current Wi-Fi association.
<a id="structespectre_1_1_runtime_diagnostics_snapshot_1a0b12d908b3a5ffa2660e3c49cf80a7e0"></a>
### `traffic`
```cpp
Traffic espectre::RuntimeDiagnosticsSnapshot::traffic {}
```
Internal generator and station traffic counters.
<a id="structespectre_1_1_runtime_diagnostics_snapshot_1a2fa751d4c3ef9aa007a0bca99c4d2d45"></a>
### `csi`
```cpp
Csi espectre::RuntimeDiagnosticsSnapshot::csi {}
```
CSI capture, validation, and temporal admission counters.
<a id="structespectre_1_1_runtime_diagnostics_snapshot_1ae8d47c360ab2051a6e9365bbbf81059b"></a>
### `platform`
```cpp
Platform espectre::RuntimeDiagnosticsSnapshot::platform {}
```
Heap and CPU state.
<a id="structespectre_1_1_runtime_diagnostics_snapshot_1aeb1c046aad8ee83978aaeaa3e07ac0ea"></a>
### `performance`
```cpp
Performance espectre::RuntimeDiagnosticsSnapshot::performance {}
```
Runtime loop and detector timing over the latest complete window.
<a id="structespectre_1_1_runtime_diagnostics_snapshot_1_1_csi"></a>
## espectre::RuntimeDiagnosticsSnapshot::Csi
```cpp
#include <runtime/runtime_snapshot.h>
```
```cpp
struct espectre::RuntimeDiagnosticsSnapshot::Csi
```
CSI capture, validation, and temporal admission counters.
<a id="structespectre_1_1_runtime_diagnostics_snapshot_1_1_csi_1a58a56d6df14be2d45414409bbc433ac1"></a>
### `callbacks_total`
```cpp
uint64_t espectre::RuntimeDiagnosticsSnapshot::Csi::callbacks_total {0U}
```
Raw invocations of the ESP-IDF CSI callback.
<a id="structespectre_1_1_runtime_diagnostics_snapshot_1_1_csi_1a1cbb35d95f27648bcd49a3c54ca840ff"></a>
### `provenance_rejected_total`
```cpp
uint64_t espectre::RuntimeDiagnosticsSnapshot::Csi::provenance_rejected_total {0U}
```
CSI callbacks rejected because their packet provenance did not match.
<a id="structespectre_1_1_runtime_diagnostics_snapshot_1_1_csi_1a2d706255afa69bbfbc50492c82ffaa05"></a>
### `accepted_total`
```cpp
uint64_t espectre::RuntimeDiagnosticsSnapshot::Csi::accepted_total {0U}
```
CSI packets accepted by capture validation, before temporal admission.
<a id="structespectre_1_1_runtime_diagnostics_snapshot_1_1_csi_1a22041c8f2a777dc9d8babb576b85016a"></a>
### `admitted_total`
```cpp
uint64_t espectre::RuntimeDiagnosticsSnapshot::Csi::admitted_total {0U}
```
CSI packets admitted to the detector's temporal grid.
<a id="structespectre_1_1_runtime_diagnostics_snapshot_1_1_csi_1aa753669ebf30516781cb6766fb7b0007"></a>
### `filtered_total`
```cpp
uint64_t espectre::RuntimeDiagnosticsSnapshot::Csi::filtered_total {0U}
```
CSI packets rejected by capture-level validation.
<a id="structespectre_1_1_runtime_diagnostics_snapshot_1_1_csi_1a7d5e0e121d2baf902fc706c6f719ae00"></a>
### `rx_error_total`
```cpp
uint64_t espectre::RuntimeDiagnosticsSnapshot::Csi::rx_error_total {0U}
```
Packets rejected because the receiver reported an error.
<a id="structespectre_1_1_runtime_diagnostics_snapshot_1_1_csi_1a13b993e522bc083a7162b6247023e9aa"></a>
### `rx_end_error_total`
```cpp
uint64_t espectre::RuntimeDiagnosticsSnapshot::Csi::rx_end_error_total {0U}
```
Packets rejected because reception ended with an error (HE-capable chips).
<a id="structespectre_1_1_runtime_diagnostics_snapshot_1_1_csi_1abbdc69cf02f596025fd472175db5186a"></a>
### `invalid_estimate_total`
```cpp
uint64_t espectre::RuntimeDiagnosticsSnapshot::Csi::invalid_estimate_total {0U}
```
Packets rejected because the hardware CSI estimate was invalid (HE-capable chips).
<a id="structespectre_1_1_runtime_diagnostics_snapshot_1_1_csi_1a7cf3507ad16a2660f684dfa8db078c49"></a>
### `invalid_first_word_total`
```cpp
uint64_t espectre::RuntimeDiagnosticsSnapshot::Csi::invalid_first_word_total {0U}
```
Packets rejected because hardware-invalid source pairs affect live or unknown tones.
<a id="structespectre_1_1_runtime_diagnostics_snapshot_1_1_csi_1ac06c37456ffb2adb026bf1dfd18ffa1c"></a>
### `sanitized_first_word_total`
```cpp
uint64_t espectre::RuntimeDiagnosticsSnapshot::Csi::sanitized_first_word_total {0U}
```
Frames whose hardware-invalid guard pairs were zeroed without changing live tones.
<a id="structespectre_1_1_runtime_diagnostics_snapshot_1_1_csi_1afaa97ed007c7026468d177902b99408a"></a>
### `pending_frame_drops_total`
```cpp
uint64_t espectre::RuntimeDiagnosticsSnapshot::Csi::pending_frame_drops_total {0U}
```
Valid CSI callbacks dropped because the callback-to-runtime queue was full.
<a id="structespectre_1_1_runtime_diagnostics_snapshot_1_1_csi_1adae60ebb0af559c8634279ef9af52b4f"></a>
### `missing_slots_total`
```cpp
uint64_t espectre::RuntimeDiagnosticsSnapshot::Csi::missing_slots_total {0U}
```
Empty temporal detector slots observed before admitted packets.
<a id="structespectre_1_1_runtime_diagnostics_snapshot_1_1_csi_1ae29ae900d52ecc9c1e43ba26d578d006"></a>
### `excess_total`
```cpp
uint64_t espectre::RuntimeDiagnosticsSnapshot::Csi::excess_total {0U}
```
Valid packets dropped because their temporal slot was already occupied.
<a id="structespectre_1_1_runtime_diagnostics_snapshot_1_1_csi_1a90b777c93f1ef9eda9a00191038852ed"></a>
### `stale_total`
```cpp
uint64_t espectre::RuntimeDiagnosticsSnapshot::Csi::stale_total {0U}
```
Packets rejected because processing began after the active window.
<a id="structespectre_1_1_runtime_diagnostics_snapshot_1_1_csi_1a92c99b3151375b5708c389a876c94d1e"></a>
### `out_of_order_total`
```cpp
uint64_t espectre::RuntimeDiagnosticsSnapshot::Csi::out_of_order_total {0U}
```
Packets rejected because their timestamp moved backwards.
<a id="structespectre_1_1_runtime_diagnostics_snapshot_1_1_csi_1a9a1403a602d99acf261ccac34b2f9e71"></a>
### `occupancy_slots`
```cpp
uint32_t espectre::RuntimeDiagnosticsSnapshot::Csi::occupancy_slots {0U}
```
Valid slots in the current detector window.
<a id="structespectre_1_1_runtime_diagnostics_snapshot_1_1_csi_1aa85ca8f568eac8fe6f1c87895fb47d8d"></a>
### `window_slots`
```cpp
uint32_t espectre::RuntimeDiagnosticsSnapshot::Csi::window_slots {0U}
```
Total slots in the configured detector window.
<a id="structespectre_1_1_runtime_diagnostics_snapshot_1_1_csi_1aa6dc6c023a87726abf7926a87f53889f"></a>
### `pending_frames`
```cpp
uint32_t espectre::RuntimeDiagnosticsSnapshot::Csi::pending_frames {0U}
```
Frames currently waiting in the callback-to-runtime queue.
<a id="structespectre_1_1_runtime_diagnostics_snapshot_1_1_csi_1a6de7b75234ada4b441e716c322c7c13d"></a>
### `pending_frame_capacity`
```cpp
uint32_t espectre::RuntimeDiagnosticsSnapshot::Csi::pending_frame_capacity {0U}
```
Fixed capacity of the callback-to-runtime queue.
<a id="structespectre_1_1_runtime_diagnostics_snapshot_1_1_link"></a>
## espectre::RuntimeDiagnosticsSnapshot::Link
```cpp
#include <runtime/runtime_snapshot.h>
```
```cpp
struct espectre::RuntimeDiagnosticsSnapshot::Link
```
Current Wi-Fi association.
<a id="structespectre_1_1_runtime_diagnostics_snapshot_1_1_link_1a1a0c4b19033b8d8c50c601df279f3d2a"></a>
### `rssi_dbm`
```cpp
int8_t espectre::RuntimeDiagnosticsSnapshot::Link::rssi_dbm {INT8_MIN}
```
RSSI of the current Wi-Fi association.
`INT8_MIN` when unavailable.
<a id="structespectre_1_1_runtime_diagnostics_snapshot_1_1_link_1a34c1718530e3b312aa608e8e2841f0db"></a>
### `channel`
```cpp
uint8_t espectre::RuntimeDiagnosticsSnapshot::Link::channel {0U}
```
Primary channel of the current Wi-Fi association.
Zero when unavailable.
<a id="structespectre_1_1_runtime_diagnostics_snapshot_1_1_performance"></a>
## espectre::RuntimeDiagnosticsSnapshot::Performance
```cpp
#include <runtime/runtime_snapshot.h>
```
```cpp
struct espectre::RuntimeDiagnosticsSnapshot::Performance
```
Runtime loop and detector timing over the latest complete window.
<a id="structespectre_1_1_runtime_diagnostics_snapshot_1_1_performance_1aa174c35c42de7575833c9ef3d05ad883"></a>
### `window_ready`
```cpp
bool espectre::RuntimeDiagnosticsSnapshot::Performance::window_ready {false}
```
True after the first complete performance aggregation window.
<a id="structespectre_1_1_runtime_diagnostics_snapshot_1_1_performance_1afb7e2a4327e2523913a0792e7e94ee7d"></a>
### `window_duration_us`
```cpp
uint32_t espectre::RuntimeDiagnosticsSnapshot::Performance::window_duration_us {0U}
```
Duration of the latest complete performance window, in microseconds.
<a id="structespectre_1_1_runtime_diagnostics_snapshot_1_1_performance_1a00524727f0a68bed1c8fc44c8071257e"></a>
### `runtime_load_percent`
```cpp
float espectre::RuntimeDiagnosticsSnapshot::Performance::runtime_load_percent {0.0f}
```
Share of the window spent inside the ESPectre runtime loop.
<a id="structespectre_1_1_runtime_diagnostics_snapshot_1_1_performance_1ad0a936672ea767895399572ad6c190b5"></a>
### `loop_samples`
```cpp
uint32_t espectre::RuntimeDiagnosticsSnapshot::Performance::loop_samples {0U}
```
Runtime loop iterations measured in the latest complete window.
<a id="structespectre_1_1_runtime_diagnostics_snapshot_1_1_performance_1acbe4b4683543f3d6ebc125d73e3b9cd6"></a>
### `loop_average_us`
```cpp
uint32_t espectre::RuntimeDiagnosticsSnapshot::Performance::loop_average_us {0U}
```
Mean runtime loop duration in the latest complete window.
<a id="structespectre_1_1_runtime_diagnostics_snapshot_1_1_performance_1a434abf9882bccb3678a59585c8987bf2"></a>
### `loop_maximum_us`
```cpp
uint32_t espectre::RuntimeDiagnosticsSnapshot::Performance::loop_maximum_us {0U}
```
Maximum runtime loop duration in the latest complete window.
<a id="structespectre_1_1_runtime_diagnostics_snapshot_1_1_performance_1a44dfe9047ddcb0a5c1b668e0ea135086"></a>
### `detection_timing_supported`
```cpp
bool espectre::RuntimeDiagnosticsSnapshot::Performance::detection_timing_supported {false}
```
Whether this runtime executes a detector and reports its timing.
<a id="structespectre_1_1_runtime_diagnostics_snapshot_1_1_performance_1a79dc17a478708a848658fc0c74a803e1"></a>
### `detection_samples`
```cpp
uint32_t espectre::RuntimeDiagnosticsSnapshot::Performance::detection_samples {0U}
```
Detector evaluations measured in the latest complete window.
<a id="structespectre_1_1_runtime_diagnostics_snapshot_1_1_performance_1aaaab7a8d0a0d930811d8f1254e8257d0"></a>
### `detection_sum_us`
```cpp
uint64_t espectre::RuntimeDiagnosticsSnapshot::Performance::detection_sum_us {0U}
```
Total detector evaluation time in the latest complete window.
<a id="structespectre_1_1_runtime_diagnostics_snapshot_1_1_performance_1ab5bb43775ff08de32876ba8f82327d29"></a>
### `detection_average_us`
```cpp
uint32_t espectre::RuntimeDiagnosticsSnapshot::Performance::detection_average_us {0U}
```
Mean detector evaluation time in the latest complete window.
<a id="structespectre_1_1_runtime_diagnostics_snapshot_1_1_performance_1aaf6c543bea5fe51e5117e19e486a289d"></a>
### `detection_minimum_us`
```cpp
uint32_t espectre::RuntimeDiagnosticsSnapshot::Performance::detection_minimum_us {0U}
```
Minimum detector evaluation time in the latest complete window.
<a id="structespectre_1_1_runtime_diagnostics_snapshot_1_1_performance_1abb6db305844c66eb70cf0a38fbf82c76"></a>
### `detection_maximum_us`
```cpp
uint32_t espectre::RuntimeDiagnosticsSnapshot::Performance::detection_maximum_us {0U}
```
Maximum detector evaluation time in the latest complete window.
<a id="structespectre_1_1_runtime_diagnostics_snapshot_1_1_platform"></a>
## espectre::RuntimeDiagnosticsSnapshot::Platform
```cpp
#include <runtime/runtime_snapshot.h>
```
```cpp
struct espectre::RuntimeDiagnosticsSnapshot::Platform
```
Heap and CPU state.
<a id="structespectre_1_1_runtime_diagnostics_snapshot_1_1_platform_1a50bdee8f9d007d0cd733c4940b9e23d4"></a>
### `free_memory_bytes`
```cpp
uint32_t espectre::RuntimeDiagnosticsSnapshot::Platform::free_memory_bytes {0U}
```
Current free heap in bytes.
Zero when unavailable.
<a id="structespectre_1_1_runtime_diagnostics_snapshot_1_1_platform_1af9023a09884bcfadd8cb73a5e6dbcc46"></a>
### `minimum_free_memory_bytes`
```cpp
uint32_t espectre::RuntimeDiagnosticsSnapshot::Platform::minimum_free_memory_bytes {0U}
```
Minimum free heap observed since boot, in bytes.
Zero when unavailable.
<a id="structespectre_1_1_runtime_diagnostics_snapshot_1_1_platform_1a3875ebe1ddc2d3b398816b3dab407839"></a>
### `largest_free_memory_block_bytes`
```cpp
uint32_t espectre::RuntimeDiagnosticsSnapshot::Platform::largest_free_memory_block_bytes {0U}
```
Largest currently allocatable heap block, in bytes.
Zero when unavailable.
<a id="structespectre_1_1_runtime_diagnostics_snapshot_1_1_platform_1a6504e771d1e7bece46e85f1bf68ca58c"></a>
### `cpu_frequency_mhz`
```cpp
uint32_t espectre::RuntimeDiagnosticsSnapshot::Platform::cpu_frequency_mhz {0U}
```
Resolved CPU frequency in MHz.
Zero when unavailable.
<a id="structespectre_1_1_runtime_diagnostics_snapshot_1_1_traffic"></a>
## espectre::RuntimeDiagnosticsSnapshot::Traffic
```cpp
#include <runtime/runtime_snapshot.h>
```
```cpp
struct espectre::RuntimeDiagnosticsSnapshot::Traffic
```
Internal generator and station traffic counters.
<a id="structespectre_1_1_runtime_diagnostics_snapshot_1_1_traffic_1a66992dc066c497b395cf4548a680389a"></a>
### `generator_packets_total`
```cpp
uint32_t espectre::RuntimeDiagnosticsSnapshot::Traffic::generator_packets_total {0U}
```
Successful internal generator sends; zero with external traffic ownership.
<a id="structespectre_1_1_runtime_diagnostics_snapshot_1_1_traffic_1a0d0a858a800c10c473eff07c22bfb2d1"></a>
### `tx_packets_total`
```cpp
uint32_t espectre::RuntimeDiagnosticsSnapshot::Traffic::tx_packets_total {0U}
```
Station packets accepted by the network driver; wraps modulo 2^32.
<a id="structespectre_1_1_runtime_diagnostics_snapshot_1_1_traffic_1ae0298f5b6b52bda34b53b7ef5c140248"></a>
### `rx_packets_total`
```cpp
uint32_t espectre::RuntimeDiagnosticsSnapshot::Traffic::rx_packets_total {0U}
```
Station packets delivered by the network driver; wraps modulo 2^32.
<a id="classespectre_1_1_runtime_direct_http_bridge"></a>
## espectre::RuntimeDirectHttpBridge
```cpp
#include <runtime/esp_idf/runtime_direct_http_bridge.h>
```
```cpp
class espectre::RuntimeDirectHttpBridge
```
Exposes the common runtime controls over the versioned Direct HTTP API.
Frontends retain ownership of their runtime and transport. The optional callback lets an adapter republish frontend-native entities after a Direct mutation, for example ESPHome number and select entities.
<a id="classespectre_1_1_runtime_direct_http_bridge_1a08b3b850fdc2a6fa96b6f77f00e381c6"></a>
### `ConfigChangedCallback`
```cpp
using espectre::RuntimeDirectHttpBridge::ConfigChangedCallback = std::function<void()>
```
Called after a Direct request changed configuration.
<a id="classespectre_1_1_runtime_direct_http_bridge_1a11186d3fd85075cfa76082d3dcc2089f"></a>
### `setup`
```cpp
bool espectre::RuntimeDirectHttpBridge::setup(IDirectHttpService *service, RuntimeFrontendController *runtime, const RuntimeDirectHttpBridgeConfig &config, ConfigChangedCallback config_changed={})
```
Start `service` for the first-party portals and route its requests to `runtime`.
Neither is owned; both must outlive the bridge.
<a id="classespectre_1_1_runtime_direct_http_bridge_1a14f48cfe088fdc4d9e3b4983630d8840"></a>
### `loop`
```cpp
void espectre::RuntimeDirectHttpBridge::loop()
```
Pump the service, raw collection, and peer discovery.
Call it from the owner loop.
<a id="classespectre_1_1_runtime_direct_http_bridge_1a3b7ed14517fe314ad124e7eaac7f2647"></a>
### `shutdown`
```cpp
void espectre::RuntimeDirectHttpBridge::shutdown()
```
Stop raw collection, peer discovery, and the service.
<a id="classespectre_1_1_runtime_direct_http_bridge_1a41168a884b23afcfaa6207b4232eaac4"></a>
### `running`
```cpp
bool espectre::RuntimeDirectHttpBridge::running() const
```
Whether the service is running.
<a id="classespectre_1_1_runtime_direct_http_bridge_1a3d62c7c02fe9edc2f9fdd446a6ff28ff"></a>
### `event_client_count`
```cpp
size_t espectre::RuntimeDirectHttpBridge::event_client_count() const
```
Connected event stream clients.
<a id="classespectre_1_1_runtime_direct_http_bridge_1a2860a623e4969bcd4e6ab0a40162027c"></a>
### `publish_event`
```cpp
bool espectre::RuntimeDirectHttpBridge::publish_event(const char *event_name, const std::string &data_json, bool replaceable_telemetry=false)
```
Publish an event to event stream clients; see [IDirectHttpService::publish\_event()](#classespectre_1_1_i_direct_http_service_1aebcaa2d23b59c0ab5b59b19ad6ff8b80).
<a id="classespectre_1_1_runtime_direct_http_bridge_1ac737e2da4c867bcf341f3bfeb22d59bf"></a>
### `publish_motion`
```cpp
bool espectre::RuntimeDirectHttpBridge::publish_motion(const RuntimeSnapshot &snapshot)
```
Publish replaceable `motion` telemetry; false without clients.
<a id="classespectre_1_1_runtime_direct_http_bridge_1ad59141bad149054a36f26958a9d3c1d7"></a>
### `publish_changes`
```cpp
bool espectre::RuntimeDirectHttpBridge::publish_changes(FrontendCommandChange changes)
```
Republish the resources named in `changes` to event stream clients.
<a id="structespectre_1_1_runtime_direct_http_bridge_config"></a>
## espectre::RuntimeDirectHttpBridgeConfig
```cpp
#include <runtime/esp_idf/runtime_direct_http_bridge.h>
```
```cpp
struct espectre::RuntimeDirectHttpBridgeConfig
```
What [RuntimeDirectHttpBridge](#classespectre_1_1_runtime_direct_http_bridge) reports about the device, and the optional hooks that extend its surface.
Every callback runs on the owner task.
<a id="structespectre_1_1_runtime_direct_http_bridge_config_1a98a38f7328ca6e75524eaa76ae061b4c"></a>
### `frontend`
```cpp
std::string espectre::RuntimeDirectHttpBridgeConfig::frontend
```
Frontend name, for example `native`.
<a id="structespectre_1_1_runtime_direct_http_bridge_config_1aad0a4b9509731f7d97ddd668a73fc4a7"></a>
### `device_name`
```cpp
std::string espectre::RuntimeDirectHttpBridgeConfig::device_name
```
Display name used when no label is set.
<a id="structespectre_1_1_runtime_direct_http_bridge_config_1a6d04303fb7d2db4b0f06c58cabf02a75"></a>
### `hostname`
```cpp
std::string espectre::RuntimeDirectHttpBridgeConfig::hostname
```
mDNS host name advertised to peers.
<a id="structespectre_1_1_runtime_direct_http_bridge_config_1ac3bbaf6e0368a05bf57f6d51e6a199ac"></a>
### `firmware_version`
```cpp
std::string espectre::RuntimeDirectHttpBridgeConfig::firmware_version
```
Application version.
<a id="structespectre_1_1_runtime_direct_http_bridge_config_1ae9f04c562da67f6e9fd70129f7e70309"></a>
### `chip`
```cpp
std::string espectre::RuntimeDirectHttpBridgeConfig::chip
```
Chip target, normally `CONFIG_IDF_TARGET`.
<a id="structespectre_1_1_runtime_direct_http_bridge_config_1af7b33835649bf55581e73e0fc93df7ad"></a>
### `device_id`
```cpp
uint64_t espectre::RuntimeDirectHttpBridgeConfig::device_id {0U}
```
Device identity; must be nonzero for raw collection.
<a id="structespectre_1_1_runtime_direct_http_bridge_config_1a0d722df897a745d3c48282f3a5badd7f"></a>
### `port`
```cpp
uint16_t espectre::RuntimeDirectHttpBridgeConfig::port {ESPECTRE_DIRECT_HTTP_PORT}
```
<a id="structespectre_1_1_runtime_direct_http_bridge_config_1a16bfff616ea05aa8a9086a31aa8d8dc6"></a>
### `raw_csi`
```cpp
bool espectre::RuntimeDirectHttpBridgeConfig::raw_csi {false}
```
Offer raw collection when the runtime supports it.
<a id="structespectre_1_1_runtime_direct_http_bridge_config_1a357de25db9703b755cf566d95730092c"></a>
### `allow_missing_origin`
```cpp
bool espectre::RuntimeDirectHttpBridgeConfig::allow_missing_origin {false}
```
See [`DirectHttpServiceConfig::allow_missing_origin`](#structespectre_1_1_direct_http_service_config_1af076038c08cbdbb6811eb2b09db08762).
<a id="structespectre_1_1_runtime_direct_http_bridge_config_1a157215245d7518fe4483f056a278f798"></a>
### `device_label_getter`
```cpp
std::function<std::string()> espectre::RuntimeDirectHttpBridgeConfig::device_label_getter
```
Current user-facing label; omitted, [`device_name`](#structespectre_1_1_runtime_direct_http_bridge_config_1aad0a4b9509731f7d97ddd668a73fc4a7) is used.
<a id="structespectre_1_1_runtime_direct_http_bridge_config_1ab41b1bc76a6dc3eb78f6bcae2cc7c88e"></a>
### `device_label_setter`
```cpp
FrontendDeviceLabelCallback espectre::RuntimeDirectHttpBridgeConfig::device_label_setter
```
Apply `update_device`; omitted, the command is not advertised.
<a id="structespectre_1_1_runtime_direct_http_bridge_config_1a1de58ab64ec772200f6bf159a6b0bb67"></a>
### `wifi_snapshot_getter`
```cpp
std::function<DirectWifiSnapshot()> espectre::RuntimeDirectHttpBridgeConfig::wifi_snapshot_getter
```
Station snapshot for the `wifi` resource; omitted, [read\_direct\_wifi\_snapshot()](#namespaceespectre_1ad4c7901011b5435695529f5f5a01e8bf) is used.
<a id="structespectre_1_1_runtime_direct_http_bridge_config_1ae284c51c72571be70a3a6d89aebf4c34"></a>
### `peer_discovery`
```cpp
IPeerDiscoveryService* espectre::RuntimeDirectHttpBridgeConfig::peer_discovery {nullptr}
```
Peer discovery for the `devices` resource; not owned.
Omitted, it is not advertised.
<a id="structespectre_1_1_runtime_direct_http_bridge_config_1acab815a09347ea06d6f08d711c7cc284"></a>
### `diagnostics_sample_getter`
```cpp
std::function<const RuntimeDiagnosticsSample *()> espectre::RuntimeDirectHttpBridgeConfig::diagnostics_sample_getter
```
Rate diagnostics, normally [`RuntimeFrontendController::diagnostics_sample()`](#classespectre_1_1_runtime_frontend_controller_1a9fe6055dcea10b65dc4e07a5855d38a9).
<a id="structespectre_1_1_runtime_direct_http_bridge_config_1a650302f6eeae5abd967d3ada89ff72fc"></a>
### `runtime_events`
```cpp
const RuntimeEventMailbox* espectre::RuntimeDirectHttpBridgeConfig::runtime_events {nullptr}
```
Mailbox whose drop counter is reported in diagnostics; not owned.
<a id="structespectre_1_1_runtime_direct_http_bridge_config_1a8930371a045d3abd60310248a304df6b"></a>
### `wifi_bssid_pin_setter`
```cpp
std::function<bool(const std::string &bssid, bool force, std::string *message)> espectre::RuntimeDirectHttpBridgeConfig::wifi_bssid_pin_setter
```
Apply or clear, for an empty BSSID, the station pin.
A frontend that provides it owns the complete live-apply and persistence transaction, for example through [WifiBssidPinService](#classespectre_1_1_wifi_bssid_pin_service). Omitted, the pin is applied to the current station session only.
<a id="structespectre_1_1_runtime_direct_http_bridge_config_1a8870d38f405961f6c2f95f7a2dd2317a"></a>
### `wifi_bssid_pin_preflight`
```cpp
std::function<bool(std::string *message)> espectre::RuntimeDirectHttpBridgeConfig::wifi_bssid_pin_preflight
```
Refuse a pin change before it starts; return false with a reason.
<a id="structespectre_1_1_runtime_direct_http_bridge_config_1ab1411fd0f73a5d394dbfa1c3eb3cae34"></a>
### `loop_time_ms_getter`
```cpp
std::function<float()> espectre::RuntimeDirectHttpBridgeConfig::loop_time_ms_getter {}
```
Latest complete frontend loop duration in milliseconds; omitted callbacks yield null.
<a id="classespectre_1_1_runtime_event_mailbox"></a>
## espectre::RuntimeEventMailbox
```cpp
#include <runtime/runtime_event_mailbox.h>
```
```cpp
class espectre::RuntimeEventMailbox
```
Fixed-memory handoff from runtime listener callbacks to a frontend loop.
Motion-state changes retain FIFO ordering. If their bounded queue fills, posting keeps the newest state by discarding the oldest unconsumed state and reports the loss to the caller. Live telemetry is replaceable by design, so repeated posts coalesce to the newest snapshot.
All operations serialize their short value copies and are safe to call from different tasks. Drain the mailbox from one owning frontend task. This class is not intended for raw CSI callbacks or other ISR/driver contexts.
The mailbox never allocates and never invokes frontend code. The frontend remains responsible for publication, transport policy, and error handling.
<a id="classespectre_1_1_runtime_event_mailbox_1aa261f423c540d7b25a634e026893c9d2"></a>
### `kMotionStateCapacity`
```cpp
constexpr size_t espectre::RuntimeEventMailbox::kMotionStateCapacity = 4U
```
Maximum number of ordered motion-state changes retained.
<a id="classespectre_1_1_runtime_event_mailbox_1a210fe73397d29832b8437e54284b2b3a"></a>
### `RuntimeEventMailbox`
```cpp
espectre::RuntimeEventMailbox::RuntimeEventMailbox()=default
```
Construct an empty mailbox.
<a id="classespectre_1_1_runtime_event_mailbox_1acac8ca0bfe508013021819de3c513496"></a>
### `RuntimeEventMailbox`
```cpp
espectre::RuntimeEventMailbox::RuntimeEventMailbox(const RuntimeEventMailbox &)=delete
```
Mailboxes own synchronization state and cannot be copied.
<a id="classespectre_1_1_runtime_event_mailbox_1a27c244ca2820533e76bb5d84389deccc"></a>
### `operator=`
```cpp
RuntimeEventMailbox & espectre::RuntimeEventMailbox::operator=(const RuntimeEventMailbox &)=delete
```
Mailboxes own synchronization state and cannot be assigned.
<a id="classespectre_1_1_runtime_event_mailbox_1aa1e5bdcc75d829bd1bb7a0436d5f6f3c"></a>
### `post_motion_state`
```cpp
bool espectre::RuntimeEventMailbox::post_motion_state(const RuntimeSnapshot &snapshot)
```
Append a motion-state snapshot for ordered delivery.
When the queue is full, the oldest unconsumed snapshot is discarded so the eventual consumer still observes the newest state.
**Parameters**
- `snapshot`: Runtime state captured by `on_motion_state_changed()`.
**Returns:** `true` when every queued state was retained, or `false` when the oldest state had to be discarded.
<a id="classespectre_1_1_runtime_event_mailbox_1af2f3ac8fa1590beec480fbd97a5b1c5c"></a>
### `take_motion_state`
```cpp
bool espectre::RuntimeEventMailbox::take_motion_state(RuntimeSnapshot &snapshot)
```
Consume the oldest pending motion-state snapshot.
**Parameters**
- `snapshot`: Receives the snapshot when one is pending and remains unchanged otherwise.
**Returns:** `true` when a snapshot was consumed.
<a id="classespectre_1_1_runtime_event_mailbox_1add3140e9171121d8e525a71c74c8506d"></a>
### `post_live_telemetry`
```cpp
void espectre::RuntimeEventMailbox::post_live_telemetry(const RuntimeSnapshot &snapshot)
```
Store the newest replaceable live-telemetry snapshot.
**Parameters**
- `snapshot`: Runtime state with the callback's movement and threshold.
<a id="classespectre_1_1_runtime_event_mailbox_1a6f186ff4189a415c534c9192ecd8138f"></a>
### `take_live_telemetry`
```cpp
bool espectre::RuntimeEventMailbox::take_live_telemetry(RuntimeSnapshot &snapshot)
```
Consume the newest pending live-telemetry snapshot.
**Parameters**
- `snapshot`: Receives the snapshot when one is pending and remains unchanged otherwise.
**Returns:** `true` when a snapshot was consumed.
<a id="classespectre_1_1_runtime_event_mailbox_1aa70fbc51557b6a20ff80885a75b02fa8"></a>
### `post_threshold`
```cpp
void espectre::RuntimeEventMailbox::post_threshold(float threshold)
```
Store the newest replaceable threshold update.
<a id="classespectre_1_1_runtime_event_mailbox_1a6287a832d6ca1af858b56f1587ffea90"></a>
### `take_threshold`
```cpp
bool espectre::RuntimeEventMailbox::take_threshold(float &threshold)
```
Consume the newest pending threshold update.
<a id="classespectre_1_1_runtime_event_mailbox_1ad9a7a83373f51ddca801cf66653ab72b"></a>
### `motion_state_drops_total`
```cpp
uint32_t espectre::RuntimeEventMailbox::motion_state_drops_total() const
```
Cumulative ordered motion events discarded since construction.
<a id="classespectre_1_1_runtime_event_mailbox_1af50f6976e3f6cf006e62ea4863207d7f"></a>
### `clear`
```cpp
void espectre::RuntimeEventMailbox::clear()
```
Discard every unconsumed runtime event.
<a id="classespectre_1_1_runtime_frontend_controller"></a>
## espectre::RuntimeFrontendController
```cpp
#include <runtime/esp_idf/runtime_frontend_controller.h>
```
```cpp
class espectre::RuntimeFrontendController : private espectre::IRuntimeListener
```
The recommended entry point for firmware embedding ESPectre.
It owns the sensing runtime, caches the latest snapshot and discovered capabilities, and validates control calls before they reach the backend.
```cpp
class ProductFrontend : public espectre::IRuntimeListener {
public:
bool setup() {
espectre::RuntimeConfig config;
config.detection_algorithm = espectre::DetectionAlgorithm::LIGHTWEIGHT;
runtime_.set_config(config);
return runtime_.setup(this);
}
void loop() { runtime_.loop(); }
void on_motion_state_changed(const espectre::RuntimeSnapshot &snapshot) override {
if (snapshot.ready_to_publish) publish(snapshot.motion_state);
}
private:
espectre::RuntimeFrontendController runtime_;
};
```
**Par:** Lifecycle
[`set_config()`](#classespectre_1_1_runtime_frontend_controller_1a6bc5d2dea03c406e822c0fc917e54840) -> `setup(listener)` -> [`loop()`](#classespectre_1_1_runtime_frontend_controller_1aa66c6b1a1a453f9ef9b4dfd27768c6f1) repeatedly -> [`shutdown()`](#classespectre_1_1_runtime_frontend_controller_1a676b16e92ff6025de8fdc400d2344215). The controller is reusable after [`shutdown()`](#classespectre_1_1_runtime_frontend_controller_1a676b16e92ff6025de8fdc400d2344215): configuration survives, and [`set_config()`](#classespectre_1_1_runtime_frontend_controller_1a6bc5d2dea03c406e822c0fc917e54840) becomes effective again.
**Par:** Threading
Carries no internal locking. Run [`setup()`](#classespectre_1_1_runtime_frontend_controller_1a4e448eb22ec37407f04ca7de09ee1153), [`loop()`](#classespectre_1_1_runtime_frontend_controller_1aa66c6b1a1a453f9ef9b4dfd27768c6f1), and [`shutdown()`](#classespectre_1_1_runtime_frontend_controller_1a676b16e92ff6025de8fdc400d2344215) on one task. See [`espectre_sdk.h`](#espectre__sdk_8h) for the full contract, including where listener callbacks land and how to handle controls driven from a transport callback.
**Par:** Control calls before setup
The setters work before [`setup()`](#classespectre_1_1_runtime_frontend_controller_1a4e448eb22ec37407f04ca7de09ee1153) and simply update the pending configuration, so a frontend can accept provisioning commands during boot without special-casing the ordering.
[`espectre::IRuntimeListener`](#classespectre_1_1_i_runtime_listener)
<a id="classespectre_1_1_runtime_frontend_controller_1ae54006efe65854689a9f22a5e2d19486"></a>
### `RuntimeFrontendController`
```cpp
espectre::RuntimeFrontendController::RuntimeFrontendController()
```
<a id="classespectre_1_1_runtime_frontend_controller_1ac4cb2c38604472e5a91773d63e4f86e9"></a>
### `~RuntimeFrontendController`
```cpp
espectre::RuntimeFrontendController::~RuntimeFrontendController() override
```
Shut the runtime down on scope exit without listener callbacks.
Call [`shutdown()`](#classespectre_1_1_runtime_frontend_controller_1a676b16e92ff6025de8fdc400d2344215) explicitly to receive the final readiness edge. This waits until a traffic generator worker still inside a socket call has exited, so destroy the controller outside a watched loop task.
<a id="classespectre_1_1_runtime_frontend_controller_1a6bc5d2dea03c406e822c0fc917e54840"></a>
### `set_config`
```cpp
void espectre::RuntimeFrontendController::set_config(const RuntimeConfig &config)
```
Stage the configuration used by the next [`setup()`](#classespectre_1_1_runtime_frontend_controller_1a4e448eb22ec37407f04ca7de09ee1153).
Ignored once setup has started, so reconfiguring a running runtime means [`shutdown()`](#classespectre_1_1_runtime_frontend_controller_1a676b16e92ff6025de8fdc400d2344215) first, or the setters for the fields that support live changes.
<a id="classespectre_1_1_runtime_frontend_controller_1a0c93736a1d6dc29e8bd4bfb03bffa25a"></a>
### `config`
```cpp
RuntimeConfig & espectre::RuntimeFrontendController::config()
```
Mutable access to the staged configuration.
Provided so a frontend can adjust individual fields before [`setup()`](#classespectre_1_1_runtime_frontend_controller_1a4e448eb22ec37407f04ca7de09ee1153) without rebuilding the whole struct. After a successful setup it reflects the backend's effective configuration, including persisted overrides. Writing to it after setup stages the next setup only; live controls continue to validate against the active configuration.
<a id="classespectre_1_1_runtime_frontend_controller_1a835cf53e8614e7b7dac7b2b5f5ac31e3"></a>
### `config`
```cpp
const RuntimeConfig & espectre::RuntimeFrontendController::config() const
```
Read-only view of the staged or last effective configuration.
<a id="classespectre_1_1_runtime_frontend_controller_1abe9fba2fd299106438728026bc018888"></a>
### `snapshot`
```cpp
const RuntimeSnapshot & espectre::RuntimeFrontendController::snapshot() const
```
Latest known snapshot, without querying the backend.
Refreshed automatically at [`setup()`](#classespectre_1_1_runtime_frontend_controller_1a4e448eb22ec37407f04ca7de09ee1153), by control calls, and before every listener callback is forwarded to your frontend. Use the cached snapshot for on-demand reads such as answering a status query; use the listener callbacks to react to change.
<a id="classespectre_1_1_runtime_frontend_controller_1a9fe6055dcea10b65dc4e07a5855d38a9"></a>
### `diagnostics_sample`
```cpp
const RuntimeDiagnosticsSample * espectre::RuntimeFrontendController::diagnostics_sample() const
```
Latest one-second diagnostics: traffic and CSI rates plus the current link.
The recommended way to read diagnostics. The sample is owned by the runtime and shared by every reader. Returns `nullptr` before [`setup()`](#classespectre_1_1_runtime_frontend_controller_1a4e448eb22ec37407f04ca7de09ee1153).
<a id="classespectre_1_1_runtime_frontend_controller_1a621291d366aa0d0f47748724927c8a75"></a>
### `diagnostics`
```cpp
RuntimeDiagnosticsSnapshot espectre::RuntimeFrontendController::diagnostics() const
```
Advanced: cumulative counters behind [`diagnostics_sample()`](#classespectre_1_1_runtime_frontend_controller_1a9fe6055dcea10b65dc4e07a5855d38a9).
Use it for totals, or with [`RuntimeDiagnosticsSampler`](#classespectre_1_1_runtime_diagnostics_sampler) for a custom sampling interval. Unlike [`snapshot()`](#classespectre_1_1_runtime_frontend_controller_1abe9fba2fd299106438728026bc018888), this queries the backend on every call, so invoke it from an existing periodic sensing callback, not from the hot loop. Returns a zeroed snapshot before [`setup()`](#classespectre_1_1_runtime_frontend_controller_1a4e448eb22ec37407f04ca7de09ee1153).
<a id="classespectre_1_1_runtime_frontend_controller_1a7dc5dd34287ce0af14346d436e15e8ef"></a>
### `capabilities`
```cpp
const RuntimeCapabilities & espectre::RuntimeFrontendController::capabilities() const
```
What the active backend supports.
Meaningful only after [`setup()`](#classespectre_1_1_runtime_frontend_controller_1a4e448eb22ec37407f04ca7de09ee1153).
Gate your product surface on it rather than hardcoding: the controller already refuses capability-gated calls, and this is how you avoid exposing a control the runtime will reject.
<a id="classespectre_1_1_runtime_frontend_controller_1a2fa537d3e5ba87c01bcd42f2fabab0ea"></a>
### `subcarriers`
```cpp
const SelectedSubcarriers & espectre::RuntimeFrontendController::subcarriers() const
```
Subcarrier indices the detector measures on.
Fixed for this SDK version.
<a id="classespectre_1_1_runtime_frontend_controller_1a93a43bbf7657e0681fd870504b2da3bf"></a>
### `is_setup_complete`
```cpp
bool espectre::RuntimeFrontendController::is_setup_complete() const
```
True between a successful [`setup()`](#classespectre_1_1_runtime_frontend_controller_1a4e448eb22ec37407f04ca7de09ee1153) and the next [`shutdown()`](#classespectre_1_1_runtime_frontend_controller_1a676b16e92ff6025de8fdc400d2344215).
<a id="classespectre_1_1_runtime_frontend_controller_1a4e448eb22ec37407f04ca7de09ee1153"></a>
### `setup`
```cpp
bool espectre::RuntimeFrontendController::setup(IRuntimeListener *listener)
```
Create the backend, apply the configuration, and start sensing.
Calling it twice is a no-op that returns true.
**Parameters**
- `listener`: Event sink, or `nullptr` for none. Not owned; it must outlive the controller.
**Returns:** false when the backend cannot start or its bounded working storage cannot be allocated. On failure the backend is dropped and the controller stays un-setup, so it is safe to fix the config and retry.
<a id="classespectre_1_1_runtime_frontend_controller_1aa66c6b1a1a453f9ef9b4dfd27768c6f1"></a>
### `loop`
```cpp
void espectre::RuntimeFrontendController::loop()
```
Advance runtime work and deliver pending listener callbacks.
Call it continuously from your loop task. Safe before setup; after [shutdown()](#classespectre_1_1_runtime_frontend_controller_1a676b16e92ff6025de8fdc400d2344215) it only reaps a traffic worker that outlived the backend.
<a id="classespectre_1_1_runtime_frontend_controller_1a676b16e92ff6025de8fdc400d2344215"></a>
### `shutdown`
```cpp
void espectre::RuntimeFrontendController::shutdown()
```
Stop sensing and release the backend.
Safe before setup and to repeat.
Does not wait for the traffic generator worker, so it is safe from the loop task. A later [setup()](#classespectre_1_1_runtime_frontend_controller_1a4e448eb22ec37407f04ca7de09ee1153) starts traffic once that worker has exited.
<a id="classespectre_1_1_runtime_frontend_controller_1abcf381fd02a5b47f239f61680f79a773"></a>
### `set_services_armed`
```cpp
void espectre::RuntimeFrontendController::set_services_armed(bool armed)
```
Gate runtime-owned services without tearing the runtime down.
Sticky: the value is remembered and reapplied to the backend created by a later [`setup()`](#classespectre_1_1_runtime_frontend_controller_1a4e448eb22ec37407f04ca7de09ee1153). Use it to stay silent until commissioning completes, or to pause CSI without dropping Wi-Fi. During raw collection the requested value is staged and applied when collection stops, because changing sensing services cannot interrupt the capture callback in place.
<a id="classespectre_1_1_runtime_frontend_controller_1ae334cb483e672900ac987aba31d073f0"></a>
### `set_live_telemetry_enabled`
```cpp
void espectre::RuntimeFrontendController::set_live_telemetry_enabled(bool enabled)
```
Enable or suppress [`IRuntimeListener::on_live_telemetry()`](#classespectre_1_1_i_runtime_listener_1a2473b19c1324d186b11ba596000acde9).
Also sticky.
<a id="classespectre_1_1_runtime_frontend_controller_1a72ce3c88bf076a26033c2ff796e91db7"></a>
### `services_armed`
```cpp
bool espectre::RuntimeFrontendController::services_armed() const
```
Current armed state, including before setup.
<a id="classespectre_1_1_runtime_frontend_controller_1a71cb508021e76d51c49bae135c19d64a"></a>
### `traffic_allows_radio_work`
```cpp
bool espectre::RuntimeFrontendController::traffic_allows_radio_work() const
```
False while a traffic stop or its CSI disable is in progress, including after [shutdown()](#classespectre_1_1_runtime_frontend_controller_1a676b16e92ff6025de8fdc400d2344215) until that worker has left its send.
True before setup.
<a id="classespectre_1_1_runtime_frontend_controller_1a72525a0e3c0f3781fccfe8ff6a7a5fae"></a>
### `hold_pending_traffic_restart`
```cpp
void espectre::RuntimeFrontendController::hold_pending_traffic_restart(bool hold)
```
Keep a deferred traffic restart parked while a radio reconfigure is waiting.
**Parameters**
- `hold`: True while a station reconfigure or scan has not touched the driver yet.
<a id="classespectre_1_1_runtime_frontend_controller_1aa34bdedcf70f7a13dc90c91929123eec"></a>
### `quiesce`
```cpp
void espectre::RuntimeFrontendController::quiesce()
```
Temporarily quiet the runtime without releasing its backend or configuration.
Disables live telemetry and sensing services, and stops active raw collection. Restore the desired service and telemetry gates explicitly when resuming.
<a id="classespectre_1_1_runtime_frontend_controller_1a74108feda3b239de79e7f74e1d0a286f"></a>
### `set_threshold`
```cpp
bool espectre::RuntimeFrontendController::set_threshold(float threshold)
```
Set the motion threshold, validating it against the active detector.
**Parameters**
- `threshold`: Value on the 0..1 metric scale.
**Returns:** false when out of range, or when the backend refuses it. Before setup the value is staged and returns true.
<a id="classespectre_1_1_runtime_frontend_controller_1a297134ef51750ae4de0f1f4e9865ed9b"></a>
### `set_motion_hits`
```cpp
bool espectre::RuntimeFrontendController::set_motion_hits(uint8_t motion_on_hits, uint8_t motion_off_hits)
```
Set the hit filter.
**Parameters**
- `motion_on_hits`: Consecutive above-threshold evaluations to report motion (1..20). Higher trades latency for fewer false positives.
- `motion_off_hits`: Consecutive below-threshold evaluations to clear it (1..20).
**Returns:** false when either value is out of range, or when the runtime is up and does not advertise [`RuntimeCapabilities::supports_runtime_motion_hits_updates`](#structespectre_1_1_runtime_capabilities_1a84d3b5bb447e02b9026bdb81f69db236).
<a id="classespectre_1_1_runtime_frontend_controller_1a6b064a59cfbc88f56cebdcc53fa32aee"></a>
### `set_traffic_generator_mode`
```cpp
bool espectre::RuntimeFrontendController::set_traffic_generator_mode(TrafficGeneratorMode mode)
```
Change how the device gets CSI traffic: one of the internal generator modes, or [`TrafficGeneratorMode::EXTERNAL`](#namespaceespectre_1a41663f63d8455701e3a3d8e2ee838aa5a3932d629fb5e2be9d09b3a4485b3cc9d) to listen for another host.
**Returns:** false when the mode is invalid or unsupported on this target, or when the runtime is up and does not advertise [`RuntimeCapabilities::supports_traffic_control`](#structespectre_1_1_runtime_capabilities_1a9cb79d6a0f22efbcfecabc4d4747fedb).
<a id="classespectre_1_1_runtime_frontend_controller_1af1f0ea0d5537893247c360366a9abc08"></a>
### `set_detection_algorithm`
```cpp
bool espectre::RuntimeFrontendController::set_detection_algorithm(DetectionAlgorithm algorithm)
```
Switch detector while running.
The threshold follows the detector: the controller adopts the new detector's threshold rather than carrying the old value across scales.
**Returns:** false for an unknown algorithm, or when the runtime is up and does not advertise [`RuntimeCapabilities::supports_runtime_detector_selection`](#structespectre_1_1_runtime_capabilities_1a8a74863f469d46c8a8441ef4e58c6b66).
<a id="classespectre_1_1_runtime_frontend_controller_1a4022d8f2e85a66c50222aac5d0cbd4f3"></a>
### `validate_control_update`
```cpp
bool espectre::RuntimeFrontendController::validate_control_update(const RuntimeControlUpdate &update, std::string *message=nullptr) const
```
Check a combined change before applying any of it.
Applies `update` to a copy of the active configuration and validates the result, so a threshold is checked against the detector the same update selects, and a traffic generator mode against this chip and the CSI capture policy. Once the runtime is up, it also rejects fields whose capability is not advertised and any change during raw collection. Call it before the individual setters to apply a request completely or not at all; a setter can still fail afterwards when the backend refuses, for example on an allocation or NVS failure.
**Parameters**
- `update`: Fields to change.
- `message`: Receives the reason on failure. May be `nullptr`.
**Returns:** true when every setter in `update` is expected to succeed.
<a id="classespectre_1_1_runtime_frontend_controller_1a2607dfb2e9eb34c51fe780e4d036548a"></a>
### `trigger_recalibration`
```cpp
bool espectre::RuntimeFrontendController::trigger_recalibration()
```
Restart startup calibration.
**Returns:** false before setup, or when the backend does not advertise [`RuntimeCapabilities::supports_manual_recalibration`](#structespectre_1_1_runtime_capabilities_1a1457a33557663be153d4472ac9192b20). Success only means calibration started; the outcome arrives through [`IRuntimeListener::on_calibration_finished()`](#classespectre_1_1_i_runtime_listener_1a27f8430a4a3b5b5dc6323765a2155e74).
<a id="classespectre_1_1_runtime_frontend_controller_1a4cdb8ac518bf507346f83b88cec6009e"></a>
### `is_calibrating`
```cpp
bool espectre::RuntimeFrontendController::is_calibrating() const
```
True while the backend is calibrating.
False before setup.
<a id="classespectre_1_1_runtime_frontend_controller_1a471ae93254ac292e6808dd04bddb4277"></a>
### `start_raw_collection`
```cpp
bool espectre::RuntimeFrontendController::start_raw_collection(raw_csi_packet_callback_t callback, void *context)
```
Enter transient raw collection through the active sensing backend.
The callback runs synchronously in the Wi-Fi CSI capture context, not from [`loop()`](#classespectre_1_1_runtime_frontend_controller_1aa66c6b1a1a453f9ef9b4dfd27768c6f1). It must remain bounded, non-blocking, and allocation-free. Copy any bytes needed after the callback returns; the packet view and its CSI buffer expire with the call. See [`raw_csi_packet_callback_t`](#namespaceespectre_1a7b0352147eec65c1f73a9d8714c4596d) for the return convention.
**Parameters**
- `callback`: Capture-context packet consumer. Must not be `nullptr`.
- `context`: Opaque caller-owned value passed to every callback. The caller must keep it valid until collection stops.
**Returns:** false before setup, without raw-CSI capability, with no Wi-Fi link, or when another transient operation is active.
<a id="classespectre_1_1_runtime_frontend_controller_1afe421ca5c348fe22cfa49461a24ecca0"></a>
### `stop_raw_collection`
```cpp
bool espectre::RuntimeFrontendController::stop_raw_collection(RawCsiStopReason reason=RawCsiStopReason::REQUESTED)
```
Leave transient raw collection and restore the prior armed state.
<a id="classespectre_1_1_runtime_frontend_controller_1ab81dbd7ee21318fd03015731064dc2df"></a>
### `operation_state`
```cpp
RuntimeOperationState espectre::RuntimeFrontendController::operation_state() const
```
Current transient backend operation.
<a id="structespectre_1_1_runtime_snapshot"></a>
## espectre::RuntimeSnapshot
```cpp
#include <runtime/runtime_snapshot.h>
```
```cpp
struct espectre::RuntimeSnapshot
```
A consistent view of the sensing state at one instant.
Passed to every [`IRuntimeListener`](#classespectre_1_1_i_runtime_listener) callback and returned by [`RuntimeFrontendController::snapshot()`](#classespectre_1_1_runtime_frontend_controller_1abe9fba2fd299106438728026bc018888). It is a plain value type: copy it freely, and copy it if you need it past the callback that delivered it.
Read [`ready_to_publish`](#structespectre_1_1_runtime_snapshot_1a3e917a2d24bbe00e55416b9ddf3bffcd) before anything else. The runtime keeps emitting snapshots while it calibrates, and [`motion_state`](#structespectre_1_1_runtime_snapshot_1a39dbe81761f12a45799c1845d8d8f8af) is not meaningful until that flag is true.
<a id="structespectre_1_1_runtime_snapshot_1a39dbe81761f12a45799c1845d8d8f8af"></a>
### `motion_state`
```cpp
MotionState espectre::RuntimeSnapshot::motion_state {MotionState::IDLE}
```
Debounced motion state, after the `motion_on_hits` / `motion_off_hits` filter.
<a id="structespectre_1_1_runtime_snapshot_1a6844aeb15178c5088d4564c5719361c7"></a>
### `movement_metric`
```cpp
float espectre::RuntimeSnapshot::movement_metric {0.0f}
```
Current motion metric, on a 0..1 probability scale for both detectors.
Comparable to [`threshold`](#structespectre_1_1_runtime_snapshot_1ad26aab6b3715a69403a257668c6699c3), but not comparable across detectors: Lightweight and High Accuracy produce the number differently even though the scale matches.
<a id="structespectre_1_1_runtime_snapshot_1ad26aab6b3715a69403a257668c6699c3"></a>
### `threshold`
```cpp
float espectre::RuntimeSnapshot::threshold {RUNTIME_THRESHOLD_DEFAULT}
```
Threshold [`movement_metric`](#structespectre_1_1_runtime_snapshot_1a6844aeb15178c5088d4564c5719361c7) is compared against, on the same scale.
<a id="structespectre_1_1_runtime_snapshot_1a60ac8110de78ba7af0de788667e3702b"></a>
### `link_rssi_dbm`
```cpp
int8_t espectre::RuntimeSnapshot::link_rssi_dbm {INT8_MIN}
```
RSSI of the packets behind this metric.
`INT8_MIN` when unknown.
<a id="structespectre_1_1_runtime_snapshot_1a3b92bf25fed1f8f66d22ead1af2b7585"></a>
### `link_channel`
```cpp
uint8_t espectre::RuntimeSnapshot::link_channel {0}
```
Wi-Fi channel those packets arrived on.
Zero when unknown.
<a id="structespectre_1_1_runtime_snapshot_1a5d52ce9114fd4a374f93d26f6d6a4ab6"></a>
### `csi_capture_profile`
```cpp
CsiCaptureProfile espectre::RuntimeSnapshot::csi_capture_profile {CsiCaptureProfile::HT20}
```
Automatically selected CSI training-field and 20 MHz PHY profile.
<a id="structespectre_1_1_runtime_snapshot_1a83dbe442c55df68823a88b7270f3e5ab"></a>
### `calibrating`
```cpp
bool espectre::RuntimeSnapshot::calibrating {false}
```
Startup calibration is running; detection results are not valid yet.
<a id="structespectre_1_1_runtime_snapshot_1a334eddad66b0f849390574e3fef45400"></a>
### `calibration_packets`
```cpp
uint32_t espectre::RuntimeSnapshot::calibration_packets {0}
```
Packets observed by the current Lightweight startup calibrator.
Zero when calibration is not running. It returns to zero when motion restarts the calibration.
<a id="structespectre_1_1_runtime_snapshot_1a6c8c6bffd0f2903d6dd8b0dd656d30ee"></a>
### `calibration_target_packets`
```cpp
uint16_t espectre::RuntimeSnapshot::calibration_target_packets {0}
```
Packet budget for the current Lightweight startup calibrator.
Zero when calibration is not running. It grows in steps while the detector needs more evidence, up to three times its starting value.
<a id="structespectre_1_1_runtime_snapshot_1a3e917a2d24bbe00e55416b9ddf3bffcd"></a>
### `ready_to_publish`
```cpp
bool espectre::RuntimeSnapshot::ready_to_publish {false}
```
The runtime is calibrated, linked, and its output is safe to act on.
Gate every user-visible publication on this. It goes false again when the Wi-Fi link drops, while calibrating, and when detector input is one window old. Window coverage under the valid-slot floor clears it only after it lasts one detector window.
<a id="structespectre_1_1_runtime_snapshot_1a347d4e5da325362a17fa2d227fe3b900"></a>
### `startup_threshold`
```cpp
float espectre::RuntimeSnapshot::startup_threshold {0.0f}
```
Threshold startup calibration settled on.
Zero before it completes.
<a id="structespectre_1_1_runtime_snapshot_1a8839c547761d0f0f42121d48f48e34ee"></a>
### `detector_name`
```cpp
const char* espectre::RuntimeSnapshot::detector_name {"unknown"}
```
Active detector label: `"lightweight"` or `"high_accuracy"`.
Always a static string literal, so it stays valid for the process, but the pointer changes when the detector changes. [`parse_detection_algorithm()`](#namespaceespectre_1a58cce43945e826bdfe8db0e85cd5732c) turns it back into a [`DetectionAlgorithm`](#namespaceespectre_1ae6098340c58c0355e67beaa092880c6b). Note these are the protocol names, not [`BaseDetector::get_name()`](#classespectre_1_1_base_detector_1af1a3b2c9adb5ad7b550acfd7230a1503), which is capitalized for logs.
<a id="structespectre_1_1_standalone_wifi_access_point"></a>
## espectre::StandaloneWifiAccessPoint
```cpp
#include <runtime/esp_idf/standalone_wifi_service.h>
```
```cpp
struct espectre::StandaloneWifiAccessPoint
```
One access point reported by [StandaloneWifiService::request\_scan()](#classespectre_1_1_standalone_wifi_service_1a69941cd23b980c89c46985b87fddbbb1).
<a id="structespectre_1_1_standalone_wifi_access_point_1a4e5b5f856bdc024db112112b3278ef5d"></a>
### `ssid`
```cpp
std::string espectre::StandaloneWifiAccessPoint::ssid
```
<a id="structespectre_1_1_standalone_wifi_access_point_1a74bdab16629ec51c89eb5ca38affe56b"></a>
### `bssid`
```cpp
std::string espectre::StandaloneWifiAccessPoint::bssid
```
Upper-case, colon-separated MAC address.
<a id="structespectre_1_1_standalone_wifi_access_point_1a524b7b539a7ad9cb317565f80d956536"></a>
### `rssi_dbm`
```cpp
int8_t espectre::StandaloneWifiAccessPoint::rssi_dbm {0}
```
<a id="structespectre_1_1_standalone_wifi_access_point_1a2ea237c462588011a59460cc6da2bfb9"></a>
### `channel`
```cpp
uint8_t espectre::StandaloneWifiAccessPoint::channel {0U}
```
Primary channel.
<a id="structespectre_1_1_standalone_wifi_config"></a>
## espectre::StandaloneWifiConfig
```cpp
#include <runtime/esp_idf/standalone_wifi_service.h>
```
```cpp
struct espectre::StandaloneWifiConfig
```
Station settings for [StandaloneWifiService](#classespectre_1_1_standalone_wifi_service).
The strings are borrowed, null-terminated values. Keep them alive until shutdown or until update\_station\_config() replaces them.
<a id="structespectre_1_1_standalone_wifi_config_1a49bc4d2503cf2b54dc855c65e99ffd32"></a>
### `ssid`
```cpp
const char* espectre::StandaloneWifiConfig::ssid {""}
```
Network name, up to 32 bytes.
Empty leaves the station idle.
<a id="structespectre_1_1_standalone_wifi_config_1a957f816303c0875d685350c4d20e8604"></a>
### `password`
```cpp
const char* espectre::StandaloneWifiConfig::password {""}
```
Passphrase, up to 64 bytes.
Empty for open networks.
<a id="structespectre_1_1_standalone_wifi_config_1a66f2ee63c5333f92f34868c8b05bebac"></a>
### `bssid`
```cpp
const char* espectre::StandaloneWifiConfig::bssid {""}
```
Optional access point to pin, as `AA:BB:CC:DD:EE:FF`.
Empty lets the driver pick the strongest access point with this SSID.
<a id="structespectre_1_1_standalone_wifi_config_1a89507eb952f0bdbc814370e7d4735914"></a>
### `channel`
```cpp
uint8_t espectre::StandaloneWifiConfig::channel {0U}
```
Optional channel hint; [`WIFI_CHANNEL_AUTO`](#namespaceespectre_1ab18ef5b016f2a45b3e57911383e7a528) (0) scans every allowed channel.
<a id="structespectre_1_1_standalone_wifi_config_1a0dc87d4cf1fc77af1596e504cf0a1153"></a>
### `max_retry`
```cpp
int espectre::StandaloneWifiConfig::max_retry {8}
```
Immediate retries per burst; exhausted bursts restart after 30 seconds.
Zero skips immediate retries.
<a id="structespectre_1_1_standalone_wifi_config_1a1fa7c525d96db4d9729b0bc3be689ce2"></a>
### `manage_csi_lifecycle`
```cpp
bool espectre::StandaloneWifiConfig::manage_csi_lifecycle {false}
```
Register the [WiFiLifecycleManager](#classespectre_1_1_wi_fi_lifecycle_manager) handlers in this service.
Leave it false when [`RuntimeFrontendController`](#classespectre_1_1_runtime_frontend_controller) runs, because the runtime registers its own. Set it only when this service alone applies the CSI radio policy and delivers connection callbacks.
<a id="structespectre_1_1_standalone_wifi_config_1acefebff0c192715fe326af1e85878f66"></a>
### `band_policy`
```cpp
WifiBandPolicy espectre::StandaloneWifiConfig::band_policy {WifiBandPolicy::BAND_2G}
```
Band the station may use.
Fixed for the life of one setup().
<a id="structespectre_1_1_standalone_wifi_info"></a>
## espectre::StandaloneWifiInfo
```cpp
#include <runtime/esp_idf/standalone_wifi_service.h>
```
```cpp
struct espectre::StandaloneWifiInfo
```
Station state reported by [StandaloneWifiService::get\_info()](#classespectre_1_1_standalone_wifi_service_1a72c20691db34234a5984ac316b304141).
<a id="structespectre_1_1_standalone_wifi_info_1a7da10e8f5c15eee10602ee65e0b1fb4e"></a>
### `connected`
```cpp
bool espectre::StandaloneWifiInfo::connected {false}
```
True while associated with a cached IPv4 address.
<a id="structespectre_1_1_standalone_wifi_info_1ab82b00cba6e171807a274106a6129a17"></a>
### `ip_address`
```cpp
char espectre::StandaloneWifiInfo::ip_address[16][16] {}
```
Dotted IPv4 address, or empty without one.
<a id="structespectre_1_1_standalone_wifi_info_1ae54e242d978be13305357da7cdabfd77"></a>
### `mac_address`
```cpp
char espectre::StandaloneWifiInfo::mac_address[18][18] {}
```
Upper-case, colon-separated station MAC address.
<a id="structespectre_1_1_standalone_wifi_info_1a57fbee42754f9a27fac1a8f8e236f25e"></a>
### `channel`
```cpp
uint8_t espectre::StandaloneWifiInfo::channel {0U}
```
Primary channel of the association, or zero.
<a id="classespectre_1_1_standalone_wifi_service"></a>
## espectre::StandaloneWifiService
```cpp
#include <runtime/esp_idf/standalone_wifi_service.h>
```
```cpp
class espectre::StandaloneWifiService
```
Owns the ESP-IDF Wi-Fi station for firmware without its own Wi-Fi stack.
The service creates the station netif and driver, connects, retries in bounded bursts, and reports connection changes. Firmware that already owns Wi-Fi, such as ESPHome, does not use it.
```cpp
espectre::StandaloneWifiConfig wifi;
wifi.ssid = ssid;
wifi.password = password;
ESP_ERROR_CHECK(service.setup(wifi, on_connected, on_disconnected));
ESP_ERROR_CHECK(service.start());
// from the owner task's loop:
service.loop();
```
**Par:** Threading
Call every method from one owner task. Wi-Fi and IP events are queued by the event handlers, and callbacks run from [loop()](#classespectre_1_1_standalone_wifi_service_1ad1e165e7f0eb286a2c1b68b573cee60c).
<a id="classespectre_1_1_standalone_wifi_service_1aef1b01da7ccaa70fa30c5a0622a8322f"></a>
### `~StandaloneWifiService`
```cpp
espectre::StandaloneWifiService::~StandaloneWifiService()
```
Release the station driver, netif, and registered handlers.
<a id="classespectre_1_1_standalone_wifi_service_1af6031ac873d13c5c31203be7a7b24db4"></a>
### `setup`
```cpp
esp_err_t espectre::StandaloneWifiService::setup(const StandaloneWifiConfig &config, standalone_wifi_callback_t connected_cb={}, standalone_wifi_callback_t disconnected_cb={})
```
Own a new station driver and netif; the application must not already own them.
Requires initialized NVS. The default event loop is created if needed and remains available after shutdown. Credentials are borrowed; SSIDs up to 32 bytes and passwords up to 64 bytes are preserved without truncation. Failure releases acquired resources so setup can be retried. Calling setup while active returns ESP\_ERR\_INVALID\_STATE. Use one owner task for all methods; callbacks run from [loop()](#classespectre_1_1_standalone_wifi_service_1ad1e165e7f0eb286a2c1b68b573cee60c).
<a id="classespectre_1_1_standalone_wifi_service_1a533d0f1dec909d9ce1580c3d23395d07"></a>
### `start`
```cpp
esp_err_t espectre::StandaloneWifiService::start()
```
Start the station driver after [setup()](#classespectre_1_1_standalone_wifi_service_1af6031ac873d13c5c31203be7a7b24db4).
Connection proceeds asynchronously; the connected callback reports the IPv4 address. Returns `ESP_ERR_INVALID_STATE` before [setup()](#classespectre_1_1_standalone_wifi_service_1af6031ac873d13c5c31203be7a7b24db4).
<a id="classespectre_1_1_standalone_wifi_service_1ab8f6a62aafef564c0f4cd1ac1686ce4d"></a>
### `update_station_config`
```cpp
esp_err_t espectre::StandaloneWifiService::update_station_config(const StandaloneWifiConfig &config)
```
Replace the station settings while the service is set up.
An active connection is dropped and re-established with the new settings. While the radio-work callback returns false, that driver call waits for [`loop()`](#classespectre_1_1_standalone_wifi_service_1ad1e165e7f0eb286a2c1b68b573cee60c). Returns `ESP_ERR_INVALID_ARG` for oversized credentials, a negative retry count, or an unusable channel, and `ESP_ERR_INVALID_STATE` before [setup()](#classespectre_1_1_standalone_wifi_service_1af6031ac873d13c5c31203be7a7b24db4), while another reconfiguration is pending, or for a different band policy.
<a id="classespectre_1_1_standalone_wifi_service_1a979258a56118e7d03734582f652bc64a"></a>
### `set_radio_work_ready_callback`
```cpp
void espectre::StandaloneWifiService::set_radio_work_ready_callback(std::function< bool()> callback)
```
Defer a station reconfigure or scan while this returns false.
The native frontend returns false while a traffic stop, or the CSI disable that follows it, is in progress, so the driver is not reconfigured under an in-flight frame. An empty callback keeps the driver call immediate.
**Parameters**
- `callback`: Returns true when radio work may start. Empty disables deferral.
<a id="classespectre_1_1_standalone_wifi_service_1ab51464d5ce0bd11482f15d9498169a70"></a>
### `has_deferred_radio_work`
```cpp
bool espectre::StandaloneWifiService::has_deferred_radio_work() const
```
True while a reconfigure or scan is waiting for traffic to leave the radio.
<a id="classespectre_1_1_standalone_wifi_service_1a69941cd23b980c89c46985b87fddbbb1"></a>
### `request_scan`
```cpp
esp_err_t espectre::StandaloneWifiService::request_scan(standalone_wifi_scan_callback_t callback)
```
Scan every allowed channel for the configured SSID and report its bounded snapshot from [loop()](#classespectre_1_1_standalone_wifi_service_1ad1e165e7f0eb286a2c1b68b573cee60c).
<a id="classespectre_1_1_standalone_wifi_service_1ad1e165e7f0eb286a2c1b68b573cee60c"></a>
### `loop`
```cpp
void espectre::StandaloneWifiService::loop()
```
Deliver queued Wi-Fi events and callbacks, and drive reconnection.
<a id="classespectre_1_1_standalone_wifi_service_1a72c20691db34234a5984ac316b304141"></a>
### `get_info`
```cpp
bool espectre::StandaloneWifiService::get_info(StandaloneWifiInfo *info) const
```
Read the station MAC address and, while connected, its IPv4 address and channel.
Uses the cached address instead of querying an unassociated driver. Returns false for a null `info` or when nothing is known yet.
<a id="classespectre_1_1_standalone_wifi_service_1a1d8ca8218dc20f1007034de43983693d"></a>
### `shutdown`
```cpp
void espectre::StandaloneWifiService::shutdown()
```
Stop and release owned Wi-Fi resources.
Safe to repeat; setup can be called again.
<a id="structespectre_1_1_stored_wifi_config"></a>
## espectre::StoredWifiConfig
```cpp
#include <runtime/esp_idf/device_config_store.h>
```
```cpp
struct espectre::StoredWifiConfig
```
Wi-Fi station settings as persisted in NVS.
<a id="structespectre_1_1_stored_wifi_config_1a0962ca8aab4664861378f9a32e7bfbd8"></a>
### `ssid`
```cpp
std::string espectre::StoredWifiConfig::ssid
```
<a id="structespectre_1_1_stored_wifi_config_1a526e922f19f013af34d8340b7593bd4a"></a>
### `password`
```cpp
std::string espectre::StoredWifiConfig::password
```
<a id="structespectre_1_1_stored_wifi_config_1a6916305746a8f7b1a6583a48dc68da1a"></a>
### `bssid`
```cpp
std::string espectre::StoredWifiConfig::bssid
```
Optional pinned access point, as `AA:BB:CC:DD:EE:FF`; empty when unpinned.
<a id="structespectre_1_1_stored_wifi_config_1a6b11dd58df8efc4cf26dd01d1484734a"></a>
### `channel`
```cpp
uint8_t espectre::StoredWifiConfig::channel {0U}
```
Optional channel hint; zero means automatic.
<a id="structespectre_1_1_stored_wifi_config_1a59c1d0e8d1a9a1029eec2de177568353"></a>
### `band_policy`
```cpp
WifiBandPolicy espectre::StoredWifiConfig::band_policy {WifiBandPolicy::BAND_2G}
```
<a id="structespectre_1_1_stored_wifi_config_1a936af3c1785f5eed84182c66457a3ee9"></a>
### `has_saved_band_policy`
```cpp
bool espectre::StoredWifiConfig::has_saved_band_policy {false}
```
Whether [`band_policy`](#structespectre_1_1_stored_wifi_config_1a59c1d0e8d1a9a1029eec2de177568353) came from NVS rather than a build default.
<a id="structespectre_1_1_stored_wifi_config_1af2972a09f2650d2f0dc172e6990bb1d4"></a>
### `has_saved_config`
```cpp
bool espectre::StoredWifiConfig::has_saved_config {false}
```
Whether these settings came from NVS rather than build defaults.
<a id="classespectre_1_1_temporal_csi_sampler"></a>
## espectre::TemporalCsiSampler
```cpp
#include <core/temporal_csi_sampler.h>
```
```cpp
class espectre::TemporalCsiSampler
```
Admit timestamped CSI packets onto the production fixed-time grid.
The sampler retains at most one candidate per target-rate slot, preserves missing slots, rejects invalid timestamp progress, and reports when a gap requires detector history to be cleared. A core-only integration should apply its admission result before forwarding CSI to a detector.
The sampler stores timing and slot state, not CSI payloads. The caller keeps the currently selected payload. When [admit()](#classespectre_1_1_temporal_csi_sampler_1a1791e9ab49629b200e9273ae61ebd4aa) commits a prior slot, consume that retained payload before replacing it when [selected\_current()](#classespectre_1_1_temporal_csi_sampler_1ae1ec9c3c8e6f8989c600bab39e628c93) is true.
Not thread-safe. Construct, configure, admit, and read it from the task that owns the custom capture pipeline. Construction and [configure()](#classespectre_1_1_temporal_csi_sampler_1af439a77c9ee2831f65801d359ca6a995) use non-throwing storage allocation; check [is\_valid()](#classespectre_1_1_temporal_csi_sampler_1a6815a334d670439cd680f2bd156095d5) after construction and the [configure()](#classespectre_1_1_temporal_csi_sampler_1af439a77c9ee2831f65801d359ca6a995) result before consuming packets. The sampler is movable and intentionally non-copyable because the slot window owns live temporal state.
<a id="classespectre_1_1_temporal_csi_sampler_1a8b8dae0e5fe5148b924e66af47cab22a"></a>
### `target_pps`
```cpp
uint32_t espectre::TemporalCsiSampler::target_pps() const
```
<a id="classespectre_1_1_temporal_csi_sampler_1a2b931007fb93c841a71fa7d23a463d62"></a>
### `window_size_ms`
```cpp
uint32_t espectre::TemporalCsiSampler::window_size_ms() const
```
<a id="classespectre_1_1_temporal_csi_sampler_1ae2c7518168da096d5fa018b095b9bfb1"></a>
### `window_slots`
```cpp
uint32_t espectre::TemporalCsiSampler::window_slots() const
```
Slots in one window: [`target_pps`](#classespectre_1_1_temporal_csi_sampler_1a8b8dae0e5fe5148b924e66af47cab22a) times the window duration, rounded up.
<a id="classespectre_1_1_temporal_csi_sampler_1a7a3d5d2332ffa7d8a9f05704f412e5a7"></a>
### `minimum_valid_slots`
```cpp
uint32_t espectre::TemporalCsiSampler::minimum_valid_slots() const
```
Occupied slots a window needs to be ready.
<a id="classespectre_1_1_temporal_csi_sampler_1a5e631296ec639219dfc7c91eb8cc2928"></a>
### `minimum_sample_spacing_us`
```cpp
uint32_t espectre::TemporalCsiSampler::minimum_sample_spacing_us() const
```
Smallest time between two committed candidates, in microseconds.
<a id="classespectre_1_1_temporal_csi_sampler_1a193d03754a56bc4e09d2604a41aed345"></a>
### `occupancy_slots`
```cpp
uint32_t espectre::TemporalCsiSampler::occupancy_slots() const
```
Slots in the current window that hold a committed sample.
<a id="classespectre_1_1_temporal_csi_sampler_1adcc84addf47197494916c3f57884daf8"></a>
### `occupancy_ratio`
```cpp
float espectre::TemporalCsiSampler::occupancy_ratio() const
```
[occupancy\_slots()](#classespectre_1_1_temporal_csi_sampler_1a193d03754a56bc4e09d2604a41aed345) divided by [window\_slots()](#classespectre_1_1_temporal_csi_sampler_1ae2c7518168da096d5fa018b095b9bfb1).
<a id="classespectre_1_1_temporal_csi_sampler_1a7fcea0bff326d0a049d9c9bb48eb265c"></a>
### `is_ready`
```cpp
bool espectre::TemporalCsiSampler::is_ready() const
```
Whether the window spans all its slots and meets the occupancy floor.
<a id="classespectre_1_1_temporal_csi_sampler_1afe7474e33d824553b2d33323597dc48a"></a>
### `accepted`
```cpp
bool espectre::TemporalCsiSampler::accepted() const
```
Whether the call committed the retained payload; same as the return value.
<a id="classespectre_1_1_temporal_csi_sampler_1ae1ec9c3c8e6f8989c600bab39e628c93"></a>
### `selected_current`
```cpp
bool espectre::TemporalCsiSampler::selected_current() const
```
Whether the current packet became the retained candidate; store its payload.
<a id="classespectre_1_1_temporal_csi_sampler_1ab936c9db7ed7a1c0716272b7c2993933"></a>
### `has_pending_candidate`
```cpp
bool espectre::TemporalCsiSampler::has_pending_candidate() const
```
Whether a candidate is retained and not yet committed.
<a id="classespectre_1_1_temporal_csi_sampler_1a8cacc760d7b7599cc2233bde30c7350e"></a>
### `reset_required`
```cpp
bool espectre::TemporalCsiSampler::reset_required() const
```
Whether the committed payload is the first after a gap; clear detector history before it.
<a id="classespectre_1_1_temporal_csi_sampler_1ac21e227f4e489f3586f13577a18ccc66"></a>
### `gap_reset_required`
```cpp
bool espectre::TemporalCsiSampler::gap_reset_required() const
```
Whether this packet followed a gap of at least one window; clear detector history.
<a id="classespectre_1_1_temporal_csi_sampler_1ace42717de24f9c381c0c85a728bcf069"></a>
### `current_slot`
```cpp
uint64_t espectre::TemporalCsiSampler::current_slot() const
```
Grid slot of the latest committed payload, counted from the timestamp epoch.
<a id="classespectre_1_1_temporal_csi_sampler_1a32402864d8caa2f17d149cfe95b2caab"></a>
### `slots_advanced`
```cpp
uint64_t espectre::TemporalCsiSampler::slots_advanced() const
```
Slots between the previous committed payload and this one.
<a id="classespectre_1_1_temporal_csi_sampler_1a8956697103963cddff22fa05626053cc"></a>
### `missing_slots_before`
```cpp
uint64_t espectre::TemporalCsiSampler::missing_slots_before() const
```
Empty slots before the committed payload; pass to [`BaseDetector::advance_missing_slots()`](#classespectre_1_1_base_detector_1a5e047ba665b25faf9e5088df58302f50).
<a id="classespectre_1_1_temporal_csi_sampler_1a6af061429ee800be178ae81db2141e6f"></a>
### `accepted_packets`
```cpp
uint64_t espectre::TemporalCsiSampler::accepted_packets() const
```
Payloads committed to the grid.
<a id="classespectre_1_1_temporal_csi_sampler_1a95f0c153916f097cdcae970f0a5fe322"></a>
### `excess_packets`
```cpp
uint64_t espectre::TemporalCsiSampler::excess_packets() const
```
Packets not kept because their slot already had a better candidate or they came too soon.
<a id="classespectre_1_1_temporal_csi_sampler_1a49794045bc9b78765549614cfa82b6b2"></a>
### `out_of_order_packets`
```cpp
uint64_t espectre::TemporalCsiSampler::out_of_order_packets() const
```
Packets whose timestamp moved backwards.
<a id="classespectre_1_1_temporal_csi_sampler_1ad73b99e1810a1e83292075ec34e34409"></a>
### `stale_packets`
```cpp
uint64_t espectre::TemporalCsiSampler::stale_packets() const
```
Packets older than one window when processed; needs `now_us`.
<a id="classespectre_1_1_temporal_csi_sampler_1a91fdaedfdbc09d6f74a4fec4d37544ae"></a>
### `missing_slots`
```cpp
uint64_t espectre::TemporalCsiSampler::missing_slots() const
```
Empty slots skipped between committed payloads.
<a id="classespectre_1_1_temporal_csi_sampler_1a223fef3f5d5c971137c31cb937aef12e"></a>
### `TemporalCsiSampler`
```cpp
explicit espectre::TemporalCsiSampler::TemporalCsiSampler(uint32_t target_pps=100U, uint32_t window_size_ms=1000U)
```
Construct a sampler for the requested target rate and window duration.
<a id="classespectre_1_1_temporal_csi_sampler_1ae08dd76f204e50fa60c43c628a2bbbf2"></a>
### `TemporalCsiSampler`
```cpp
espectre::TemporalCsiSampler::TemporalCsiSampler(TemporalCsiSampler &&) noexcept=default
```
<a id="classespectre_1_1_temporal_csi_sampler_1ae0fdbbaa165cbd540a6cceae7ccee675"></a>
### `operator=`
```cpp
TemporalCsiSampler & espectre::TemporalCsiSampler::operator=(TemporalCsiSampler &&) noexcept=default
```
<a id="classespectre_1_1_temporal_csi_sampler_1a7ddc81d12caa7fc7ef9be73eb83db54d"></a>
### `TemporalCsiSampler`
```cpp
espectre::TemporalCsiSampler::TemporalCsiSampler(const TemporalCsiSampler &)=delete
```
<a id="classespectre_1_1_temporal_csi_sampler_1af4d593a870758620ec7674408e19dcd7"></a>
### `operator=`
```cpp
TemporalCsiSampler & espectre::TemporalCsiSampler::operator=(const TemporalCsiSampler &)=delete
```
<a id="classespectre_1_1_temporal_csi_sampler_1af439a77c9ee2831f65801d359ca6a995"></a>
### `configure`
```cpp
bool espectre::TemporalCsiSampler::configure(uint32_t target_pps, uint32_t window_size_ms)
```
Reconfigure the grid and clear its timestamp epoch and window state.
<a id="classespectre_1_1_temporal_csi_sampler_1a6815a334d670439cd680f2bd156095d5"></a>
### `is_valid`
```cpp
bool espectre::TemporalCsiSampler::is_valid() const
```
Return whether the active slot window owns complete storage.
<a id="classespectre_1_1_temporal_csi_sampler_1a2f519ceeb7c1948c6380e13db258376f"></a>
### `reset`
```cpp
void espectre::TemporalCsiSampler::reset()
```
Clear the timestamp epoch, window state, and lifetime counters.
<a id="classespectre_1_1_temporal_csi_sampler_1a711c178e7646d3e21cd7263c4f9fdfb0"></a>
### `clear_history`
```cpp
void espectre::TemporalCsiSampler::clear_history()
```
Clear the window and timestamp grid while retaining lifetime counters.
<a id="classespectre_1_1_temporal_csi_sampler_1ad40635b15a773affa083090355b87ee7"></a>
### `clear_window_preserving_phase`
```cpp
void espectre::TemporalCsiSampler::clear_window_preserving_phase()
```
Clear admitted window data while retaining the active timestamp grid.
<a id="classespectre_1_1_temporal_csi_sampler_1a1791e9ab49629b200e9273ae61ebd4aa"></a>
### `admit`
```cpp
bool espectre::TemporalCsiSampler::admit(uint32_t timestamp_us, bool has_timestamp=true, uint32_t now_us=0U, bool has_now=false)
```
Observe one candidate and report whether the retained payload was committed.
`now_us` is optional processing time on the same unsigned 32-bit clock as `timestamp_us`. Omit it when the clocks differ, including classic ESP32 Wi-Fi RX timestamps versus `esp_timer`.
<a id="classespectre_1_1_temporal_csi_sampler_1a20e40f1dff05429d21aa8a98adc1f45d"></a>
### `flush`
```cpp
bool espectre::TemporalCsiSampler::flush()
```
Commit the retained payload when the input stream ends.
<a id="classespectre_1_1_traffic_generator_manager"></a>
## espectre::TrafficGeneratorManager
```cpp
#include <runtime/esp_idf/traffic_generator_manager.h>
```
```cpp
class espectre::TrafficGeneratorManager : public espectre::ICsiTrafficGenerator
```
Paced ESP-IDF traffic generator with a firmware-owned lifecycle.
[`espectre::ICsiTrafficGenerator`](#classespectre_1_1_i_csi_traffic_generator)
<a id="classespectre_1_1_traffic_generator_manager_1addf9baba77d7e7a4c96768ada90da8d2"></a>
### `~TrafficGeneratorManager`
```cpp
espectre::TrafficGeneratorManager::~TrafficGeneratorManager() override
```
Stop the worker and wait until it exits, however long its socket call takes.
Destroy the generator outside a watched loop, or keep it for the device's lifetime.
<a id="classespectre_1_1_traffic_generator_manager_1a1611ff5acf3063285af5e79a256d4bbb"></a>
### `init`
```cpp
void espectre::TrafficGeneratorManager::init(uint32_t target_pps, TrafficGeneratorMode mode=TrafficGeneratorMode::PING) override
```
Configure the send rate and backend while stopped.
<a id="classespectre_1_1_traffic_generator_manager_1a04d7c96a83f8cbf0a6244fcbe129619d"></a>
### `start`
```cpp
bool espectre::TrafficGeneratorManager::start(uint32_t target_addr) override
```
Start sending to an IPv4 address in network byte order; WIFI\_RAW ignores the address.
<a id="classespectre_1_1_traffic_generator_manager_1a71b888ef51013730d88e5d1c2554679f"></a>
### `loop`
```cpp
void espectre::TrafficGeneratorManager::loop() override
```
Finish a pending stop or restart, and report a stalled generator, from the owner task.
<a id="classespectre_1_1_traffic_generator_manager_1af5c7a6638c9d90e5d4aa289444cc9604"></a>
### `stop`
```cpp
void espectre::TrafficGeneratorManager::stop() override
```
Signal the worker to exit and return without waiting for it.
<a id="classespectre_1_1_traffic_generator_manager_1a4b211fd9a717d3ff60ccb9f3e89a089f"></a>
### `hold_pending_restart`
```cpp
void espectre::TrafficGeneratorManager::hold_pending_restart(bool hold) override
```
Keep [loop()](#classespectre_1_1_traffic_generator_manager_1a71b888ef51013730d88e5d1c2554679f) from launching a deferred start while the owner still owns the radio.
<a id="classespectre_1_1_traffic_generator_manager_1aeb69bab1ad47e746c35ec76e879ffded"></a>
### `is_running`
```cpp
bool espectre::TrafficGeneratorManager::is_running() const override
```
Whether the worker runs or a deferred start is waiting to launch it.
<a id="classespectre_1_1_traffic_generator_manager_1ab4dedbdc24158c68ab56bf863a7c3693"></a>
### `is_quiescent`
```cpp
bool espectre::TrafficGeneratorManager::is_quiescent() const override
```
True when the worker has left its send, even if [loop()](#classespectre_1_1_traffic_generator_manager_1a71b888ef51013730d88e5d1c2554679f) has not reaped it yet.
<a id="classespectre_1_1_traffic_generator_manager_1ad08e5650c576a5a2b39657cf8485e9bd"></a>
### `has_live_worker`
```cpp
bool espectre::TrafficGeneratorManager::has_live_worker() const override
```
True when [start()](#classespectre_1_1_traffic_generator_manager_1a04d7c96a83f8cbf0a6244fcbe129619d) has a worker that [stop()](#classespectre_1_1_traffic_generator_manager_1af5c7a6638c9d90e5d4aa289444cc9604) has not signalled.
<a id="classespectre_1_1_traffic_generator_manager_1ae9bb3a5d3e3aa4e9787bdfa2242694ec"></a>
### `consume_start_failure`
```cpp
bool espectre::TrafficGeneratorManager::consume_start_failure() override
```
True once, after [loop()](#classespectre_1_1_traffic_generator_manager_1a71b888ef51013730d88e5d1c2554679f) fails to launch a deferred start.
<a id="classespectre_1_1_traffic_generator_manager_1a996c873a2bbb3d5484b6ed93d5e132a3"></a>
### `consume_stop_timeout`
```cpp
bool espectre::TrafficGeneratorManager::consume_stop_timeout() override
```
True once, after a stopped worker has not exited within 30 s.
An unread timeout is dropped when that worker exits.
<a id="classespectre_1_1_traffic_generator_manager_1ae96bf40e87baf67b98c77e937e40f6ef"></a>
### `pause`
```cpp
void espectre::TrafficGeneratorManager::pause()
```
Suspend sends without destroying the worker.
<a id="classespectre_1_1_traffic_generator_manager_1ac36d125fc2307d4f6122a9146ebb82e4"></a>
### `resume`
```cpp
void espectre::TrafficGeneratorManager::resume()
```
Resume sends after [pause()](#classespectre_1_1_traffic_generator_manager_1ae96bf40e87baf67b98c77e937e40f6ef).
<a id="classespectre_1_1_traffic_generator_manager_1a829a2dbcac0ab4de35c0cd92e0681116"></a>
### `is_paused`
```cpp
bool espectre::TrafficGeneratorManager::is_paused() const
```
<a id="classespectre_1_1_traffic_generator_manager_1a94c6aa4e46b66482054d438b157938bd"></a>
### `target_rate_pps`
```cpp
uint32_t espectre::TrafficGeneratorManager::target_rate_pps() const
```
Rate requested by [init()](#classespectre_1_1_traffic_generator_manager_1a1611ff5acf3063285af5e79a256d4bbb), in packets per second.
<a id="classespectre_1_1_traffic_generator_manager_1af37515bc464d44eac94d82db9b8e23c6"></a>
### `current_rate_pps`
```cpp
uint32_t espectre::TrafficGeneratorManager::current_rate_pps() const
```
Send rate used by the worker, in packets per second.
<a id="classespectre_1_1_traffic_generator_manager_1a05a24eb916d7ef9b4bb71999b08c8da4"></a>
### `send_success_count`
```cpp
uint32_t espectre::TrafficGeneratorManager::send_success_count() const override
```
Number of successful sends in the current session.
<a id="classespectre_1_1_traffic_generator_manager_1a234d3ce12e136fa717fb88979287c78e"></a>
### `send_error_count`
```cpp
uint32_t espectre::TrafficGeneratorManager::send_error_count() const
```
Number of failed sends in the current session.
<a id="classespectre_1_1_traffic_generator_manager_1ace20abf21cf500964cc91747c7423830"></a>
### `icmp_identifier`
```cpp
uint16_t espectre::TrafficGeneratorManager::icmp_identifier() const override
```
ICMP identifier used to recognize this generator's ping replies.
<a id="structespectre_1_1_udp_datagram_peer"></a>
## espectre::UdpDatagramPeer
```cpp
#include <runtime/udp_datagram_socket.h>
```
```cpp
struct espectre::UdpDatagramPeer
```
Sender of a UDP datagram.
Both fields use host byte order.
<a id="structespectre_1_1_udp_datagram_peer_1a8ad9fa7d60974939dd76d1a1eedc4c2d"></a>
### `ipv4_addr`
```cpp
uint32_t espectre::UdpDatagramPeer::ipv4_addr {0U}
```
<a id="structespectre_1_1_udp_datagram_peer_1aed7273d785b3417c4c2bdaa70bccc9be"></a>
### `port`
```cpp
uint16_t espectre::UdpDatagramPeer::port {0U}
```
<a id="classespectre_1_1_wi_fi_lifecycle_manager"></a>
## espectre::WiFiLifecycleManager
```cpp
#include <runtime/esp_idf/wifi_lifecycle.h>
```
```cpp
class espectre::WiFiLifecycleManager
```
Turns Wi-Fi and IP events into connect and disconnect callbacks.
The runtime starts and stops CSI capture, traffic, and calibration from those callbacks. The station TX rate policy is applied before the connected callbacks, whether sensing uses an internal generator or external traffic.
The STA-start handler applies the short radio policy synchronously, before association. Connect/disconnect callbacks run from [process\_pending\_events()](#classespectre_1_1_wi_fi_lifecycle_manager_1adc7ad4c05118e53e0767d4123f374517), which the runtime must call from its loop task. This keeps service startup and log formatting off the small default event loop task (sys\_evt) stack.
<a id="classespectre_1_1_wi_fi_lifecycle_manager_1a812e0a4f46c766d812658185aa933761"></a>
### `register_handlers`
```cpp
esp_err_t espectre::WiFiLifecycleManager::register_handlers(wifi_connected_callback_t connected_cb, wifi_disconnected_callback_t disconnected_cb, WifiBandPolicy band_policy=WifiBandPolicy::BAND_2G)
```
Register Wi-Fi event handlers.
**Parameters**
- `connected_cb`: Callback when Wi-Fi obtains or retains an IPv4 configuration; receives the address, netmask, and gateway after GOT\_IP or reassociation
- `disconnected_cb`: Callback when Wi-Fi disconnects
- `band_policy`: Station band policy used while applying connection settings
**Returns:** ESP\_OK on success. If the default station already has an IPv4 address, its current state is queued for [process\_pending\_events()](#classespectre_1_1_wi_fi_lifecycle_manager_1adc7ad4c05118e53e0767d4123f374517).
<a id="classespectre_1_1_wi_fi_lifecycle_manager_1ae130fbbcc4833a424e4ad4488143c338"></a>
### `unregister_handlers`
```cpp
void espectre::WiFiLifecycleManager::unregister_handlers()
```
Unregister Wi-Fi event handlers.
<a id="classespectre_1_1_wi_fi_lifecycle_manager_1adc7ad4c05118e53e0767d4123f374517"></a>
### `process_pending_events`
```cpp
esp_err_t espectre::WiFiLifecycleManager::process_pending_events()
```
Invoke the registered callbacks for events recorded by the handlers.
Must be called periodically from the runtime loop task. Events are processed in the same order in which the ESP event loop recorded them.
<a id="classespectre_1_1_wi_fi_lifecycle_manager_1a38826e392159833222339361036f6c26"></a>
### `refresh_csi_receive_path`
```cpp
esp_err_t espectre::WiFiLifecycleManager::refresh_csi_receive_path(wifi_csi_rx_refresh_callback_t callback, bool manage_scan_results=true)
```
Attempt an asynchronous scan on the associated channel to recover a silent CSI receive path.
Requires a current association with a nonzero channel. Busy drivers and unconsumed scan results return ESP\_ERR\_INVALID\_STATE. Completion, including a 30-second timeout, runs from [process\_pending\_events()](#classespectre_1_1_wi_fi_lifecycle_manager_1adc7ad4c05118e53e0767d4123f374517). Promiscuous mode stays disabled. With manage\_scan\_results enabled, callers must keep independent scanners idle until [csi\_receive\_path\_refresh\_active()](#classespectre_1_1_wi_fi_lifecycle_manager_1a6f3a5e218edd6ad77719ba2911947312) becomes false. Disable it when the Wi-Fi stack consumes all scan results; cleanup then leaves the driver's result list entirely to that stack.
<a id="classespectre_1_1_wi_fi_lifecycle_manager_1a1fe9bba1e6dd8c26acf37503fc3e80cc"></a>
### `cancel_csi_receive_path_refresh`
```cpp
void espectre::WiFiLifecycleManager::cancel_csi_receive_path_refresh()
```
Cancel an in-flight CSI receive-path refresh.
Late scan completion events are invalidated and cannot invoke the canceled callback.
<a id="classespectre_1_1_wi_fi_lifecycle_manager_1a6f3a5e218edd6ad77719ba2911947312"></a>
### `csi_receive_path_refresh_active`
```cpp
static bool espectre::WiFiLifecycleManager::csi_receive_path_refresh_active()
```
Whether an SDK CSI refresh owns the scanner, including pending cleanup.
<a id="classespectre_1_1_wi_fi_lifecycle_manager_1a731bac4db6341b9069145f34197c4044"></a>
### `apply_started_csi_policy`
```cpp
static esp_err_t espectre::WiFiLifecycleManager::apply_started_csi_policy(WifiBandPolicy band_policy=WifiBandPolicy::BAND_2G)
```
Apply the short CSI radio policy that must run after WIFI\_EVENT\_STA\_START and before association.
Safe to call more than once; later calls are no-ops once protocol, bandwidth, and power-save already match.
<a id="classespectre_1_1_wi_fi_lifecycle_manager_1a9dc55a7bc08ab9e6c4a0dd9c315c52e7"></a>
### `reinitialize_stopped_station_driver`
```cpp
static esp_err_t espectre::WiFiLifecycleManager::reinitialize_stopped_station_driver(wifi_storage_t storage=WIFI_STORAGE_RAM)
```
Reinitialize an already-stopped station driver and restore the invariants required by every CSI frontend.
The caller remains responsible for applying its station configuration and starting the driver.
<a id="classespectre_1_1_wifi_bssid_pin_service"></a>
## espectre::WifiBssidPinService
```cpp
#include <runtime/esp_idf/wifi_bssid_pin_service.h>
```
```cpp
class espectre::WifiBssidPinService
```
Persists an access point pin for the provisioned SSID and applies it with verification and rollback.
For firmware whose Wi-Fi stack owns the credentials, such as Matter commissioning. The service stores only the SSID and BSSID pair in NVS. A pin takes effect through `apply_callback`, is saved after the station reconnects to that access point with an IPv4 address, and is rolled back when that does not happen within `candidate_timeout_ms`. At boot, a stored pin for the current SSID is reapplied when the station associates elsewhere.
**Par:** Threading
Call every method from one owner task, and call [loop()](#classespectre_1_1_wifi_bssid_pin_service_1a9ffdc9e9947edb8d41fd79f60c3afddd) from its loop.
<a id="classespectre_1_1_wifi_bssid_pin_service_1a4401cef436ec422e0f47bedc102832a0"></a>
### `setup`
```cpp
esp_err_t espectre::WifiBssidPinService::setup(WifiBssidPinServiceConfig config)
```
Install the hooks and load the stored pin.
**Returns:** `ESP_ERR_INVALID_ARG` when a required hook is missing or the timeout is zero, or the NVS error that prevented loading.
<a id="classespectre_1_1_wifi_bssid_pin_service_1a22c79734f4160237420aeb468627ca1b"></a>
### `request_update`
```cpp
bool espectre::WifiBssidPinService::request_update(const std::string &bssid, std::string *message, bool force=false)
```
Stage a pin update.
An empty BSSID clears the current override.
Pinning the access point already in use is saved directly unless `force` is set.
**Returns:** false before [setup()](#classespectre_1_1_wifi_bssid_pin_service_1a4401cef436ec422e0f47bedc102832a0), while another change is in progress, for a malformed BSSID, or without a provisioned SSID. `message` receives the outcome.
<a id="classespectre_1_1_wifi_bssid_pin_service_1aa335fdf5103c23d6baad549e4279ea37"></a>
### `notify_station_changed`
```cpp
void espectre::WifiBssidPinService::notify_station_changed()
```
Schedule a station snapshot refresh after a Wi-Fi or IP event.
<a id="classespectre_1_1_wifi_bssid_pin_service_1a9ffdc9e9947edb8d41fd79f60c3afddd"></a>
### `loop`
```cpp
void espectre::WifiBssidPinService::loop()
```
Advance verification, rollback, and boot-time enforcement.
<a id="classespectre_1_1_wifi_bssid_pin_service_1af64af02c4ef7cd53cd586b0d6f1969b1"></a>
### `apply_state`
```cpp
WifiBssidPinApplyState espectre::WifiBssidPinService::apply_state() const
```
<a id="classespectre_1_1_wifi_bssid_pin_service_1acc0f42e341b2b5eee23c4eafebc50527"></a>
### `apply_message`
```cpp
const std::string & espectre::WifiBssidPinService::apply_message() const
```
Human-readable detail for [apply\_state()](#classespectre_1_1_wifi_bssid_pin_service_1af64af02c4ef7cd53cd586b0d6f1969b1).
<a id="classespectre_1_1_wifi_bssid_pin_service_1accd04bb7d2f92f873918389af209e283"></a>
### `stored_ssid`
```cpp
const std::string & espectre::WifiBssidPinService::stored_ssid() const
```
SSID the stored pin belongs to; empty without a pin.
<a id="classespectre_1_1_wifi_bssid_pin_service_1a73cf4b9405976db503875edf9fac3280"></a>
### `stored_bssid`
```cpp
const std::string & espectre::WifiBssidPinService::stored_bssid() const
```
Stored pin; empty without one.
<a id="classespectre_1_1_wifi_bssid_pin_service_1aa97db1ae127786e2db9204a8ba0bdbc3"></a>
### `apply_pending`
```cpp
bool espectre::WifiBssidPinService::apply_pending() const
```
True while a change is `VERIFYING` or `ROLLING_BACK`.
<a id="structespectre_1_1_wifi_bssid_pin_service_config"></a>
## espectre::WifiBssidPinServiceConfig
```cpp
#include <runtime/esp_idf/wifi_bssid_pin_service.h>
```
```cpp
struct espectre::WifiBssidPinServiceConfig
```
Hooks that connect [WifiBssidPinService](#classespectre_1_1_wifi_bssid_pin_service) to the firmware's Wi-Fi stack.
<a id="structespectre_1_1_wifi_bssid_pin_service_config_1a43cf641913174835573ac08ef3b4d420"></a>
### `ApplyCallback`
```cpp
using espectre::WifiBssidPinServiceConfig::ApplyCallback = std::function<bool(const std::string &bssid,
std::string *message,
bool *station_transition_started)>
```
Apply a BSSID pin to the station, or clear it for an empty `bssid`.
Return false when the pin cannot be applied, with a reason in `message`. Set `*station_transition_started` when the failure happened after the station began reconnecting, so the service waits for the previous configuration to come back. The pointer is `nullptr` during rollback.
<a id="structespectre_1_1_wifi_bssid_pin_service_config_1a307fa876d73c4361b58844f74a319044"></a>
### `StationStateGetter`
```cpp
using espectre::WifiBssidPinServiceConfig::StationStateGetter = std::function<WifiBssidPinStationState()>
```
Read the current station state.
<a id="structespectre_1_1_wifi_bssid_pin_service_config_1aa9165f343c1ff8b0386a6aac8649ff84"></a>
### `ChangeCallback`
```cpp
using espectre::WifiBssidPinServiceConfig::ChangeCallback = std::function<void()>
```
Notification without arguments, delivered on the owner task.
<a id="structespectre_1_1_wifi_bssid_pin_service_config_1a3a678d1e92866b879c0a6fed14c0a0d1"></a>
### `apply_callback`
```cpp
ApplyCallback espectre::WifiBssidPinServiceConfig::apply_callback
```
Required.
<a id="structespectre_1_1_wifi_bssid_pin_service_config_1a7dcbfda84aa709b87ab638c4c9b11257"></a>
### `station_state_getter`
```cpp
StationStateGetter espectre::WifiBssidPinServiceConfig::station_state_getter
```
Required.
<a id="structespectre_1_1_wifi_bssid_pin_service_config_1ab6a059f017598440ed5f032098163e05"></a>
### `prepare_callback`
```cpp
ChangeCallback espectre::WifiBssidPinServiceConfig::prepare_callback
```
Optional; runs before the station is reconfigured, for example to quiesce sensing.
<a id="structespectre_1_1_wifi_bssid_pin_service_config_1afecd3ee11a65e73e94ba868fe1849696"></a>
### `resume_callback`
```cpp
ChangeCallback espectre::WifiBssidPinServiceConfig::resume_callback
```
Optional; runs when a change ends, except in `RECOVERY_REQUIRED`.
<a id="structespectre_1_1_wifi_bssid_pin_service_config_1a997a6e6e9b0d3f9ae139b8b14c1f2383"></a>
### `candidate_timeout_ms`
```cpp
uint32_t espectre::WifiBssidPinServiceConfig::candidate_timeout_ms {60000U}
```
Time allowed for the station to verify a pin, and again for a rollback.
Must be nonzero.
<a id="structespectre_1_1_wifi_bssid_pin_station_state"></a>
## espectre::WifiBssidPinStationState
```cpp
#include <runtime/esp_idf/wifi_bssid_pin_service.h>
```
```cpp
struct espectre::WifiBssidPinStationState
```
Station state as reported by the firmware's Wi-Fi stack.
<a id="structespectre_1_1_wifi_bssid_pin_station_state_1a77a4ce1f6e06efd30575a0522e4c0b14"></a>
### `configured`
```cpp
bool espectre::WifiBssidPinStationState::configured {false}
```
Whether the station has credentials.
<a id="structespectre_1_1_wifi_bssid_pin_station_state_1a6dcf90c72c8d65cd7bcafef65ea5111f"></a>
### `connected`
```cpp
bool espectre::WifiBssidPinStationState::connected {false}
```
Whether the station is associated.
<a id="structespectre_1_1_wifi_bssid_pin_station_state_1ab3cb0d1e67769e8b613f2e33ea0991ad"></a>
### `has_ipv4`
```cpp
bool espectre::WifiBssidPinStationState::has_ipv4 {false}
```
Whether the station holds an IPv4 address.
<a id="structespectre_1_1_wifi_bssid_pin_station_state_1ab9820051700cf3b76fa5deff4234bab5"></a>
### `ssid`
```cpp
std::string espectre::WifiBssidPinStationState::ssid
```
Provisioned network name.
<a id="structespectre_1_1_wifi_bssid_pin_station_state_1a6a7257e881fe796a509c6a9c6ed0ae67"></a>
### `bssid`
```cpp
std::string espectre::WifiBssidPinStationState::bssid
```
Current access point, as upper-case `AA:BB:CC:DD:EE:FF`.
<a id="structespectre_1_1_wifi_provisioning_defaults"></a>
## espectre::WifiProvisioningDefaults
```cpp
#include <runtime/esp_idf/wifi_provisioning_service.h>
```
```cpp
struct espectre::WifiProvisioningDefaults
```
Build-time station settings used when nothing is saved in NVS.
The strings are copied by load\_or\_set\_defaults(); `nullptr` means empty.
<a id="structespectre_1_1_wifi_provisioning_defaults_1a3a22055cc0538d86ff249966a20b1e92"></a>
### `ssid`
```cpp
const char* espectre::WifiProvisioningDefaults::ssid {nullptr}
```
<a id="structespectre_1_1_wifi_provisioning_defaults_1a707b4a5359b3c35e8dc9d7e80480148b"></a>
### `password`
```cpp
const char* espectre::WifiProvisioningDefaults::password {nullptr}
```
<a id="structespectre_1_1_wifi_provisioning_defaults_1a83ebf67e6dad57074c647376bb5ae8e8"></a>
### `bssid`
```cpp
const char* espectre::WifiProvisioningDefaults::bssid {nullptr}
```
Optional access point to pin, as `AA:BB:CC:DD:EE:FF`.
<a id="structespectre_1_1_wifi_provisioning_defaults_1a35539b167d170151e209d5143a358384"></a>
### `channel`
```cpp
uint8_t espectre::WifiProvisioningDefaults::channel {0U}
```
Optional channel hint; [`WIFI_CHANNEL_AUTO`](#namespaceespectre_1ab18ef5b016f2a45b3e57911383e7a528) (0) scans every allowed channel.
<a id="structespectre_1_1_wifi_provisioning_defaults_1ae3233820bf084e6f88f7bf85dad3ea8f"></a>
### `max_retry`
```cpp
int espectre::WifiProvisioningDefaults::max_retry {8}
```
Forwarded to [`StandaloneWifiConfig::max_retry`](#structespectre_1_1_standalone_wifi_config_1a0dc87d4cf1fc77af1596e504cf0a1153).
<a id="structespectre_1_1_wifi_provisioning_defaults_1aa1abbc62d0564095be5d628db8f093ad"></a>
### `manage_csi_lifecycle`
```cpp
bool espectre::WifiProvisioningDefaults::manage_csi_lifecycle {false}
```
Forwarded to [`StandaloneWifiConfig::manage_csi_lifecycle`](#structespectre_1_1_standalone_wifi_config_1a1fa7c525d96db4d9729b0bc3be689ce2).
<a id="structespectre_1_1_wifi_provisioning_defaults_1ab55754dfbbfe2c004275d70cd749f735"></a>
### `band_policy`
```cpp
WifiBandPolicy espectre::WifiProvisioningDefaults::band_policy {WifiBandPolicy::BAND_2G}
```
Band policy used when no saved policy exists or the saved one is unsupported.
<a id="structespectre_1_1_wifi_provisioning_defaults_1aa473c6cdb212af5a5ae41b8bcdd4458d"></a>
### `candidate_timeout_ms`
```cpp
uint32_t espectre::WifiProvisioningDefaults::candidate_timeout_ms {30000U}
```
Time allowed for a staged candidate to associate and obtain an address, and again for the rollback that follows a failure.
<a id="classespectre_1_1_wifi_provisioning_service"></a>
## espectre::WifiProvisioningService
```cpp
#include <runtime/esp_idf/wifi_provisioning_service.h>
```
```cpp
class espectre::WifiProvisioningService
```
Stores Wi-Fi credentials and applies changes with verification and rollback.
New credentials are staged as a candidate in NVS, applied through [StandaloneWifiService](#classespectre_1_1_standalone_wifi_service), and saved as the station configuration only after the station associates and obtains an address. A candidate that does not connect within [`WifiProvisioningDefaults::candidate_timeout_ms`](#structespectre_1_1_wifi_provisioning_defaults_1aa473c6cdb212af5a5ae41b8bcdd4458d) is rolled back to the last-known-good settings. A candidate interrupted by a reboot resumes verification at the next [load\_or\_set\_defaults()](#classespectre_1_1_wifi_provisioning_service_1a83780a13c9467f636d6df89e02b7d327).
**Par:** Threading
Call every method from the task that owns the [StandaloneWifiService](#classespectre_1_1_standalone_wifi_service), and call [loop()](#classespectre_1_1_wifi_provisioning_service_1a8b8c00c288e12539a262cf41d4760c72) from that task's loop. Callbacks run on that task.
<a id="classespectre_1_1_wifi_provisioning_service_1a783569a1db3ddc367f220380b3d394e0"></a>
### `ChangeCallback`
```cpp
using espectre::WifiProvisioningService::ChangeCallback = std::function<void()>
```
Notification without arguments, delivered on the owner task.
<a id="classespectre_1_1_wifi_provisioning_service_1a00ae7a5deaa2fbf70206a118bd63e32f"></a>
### `WifiProvisioningService`
```cpp
explicit espectre::WifiProvisioningService::WifiProvisioningService(StandaloneWifiService *wifi_manager)
```
Bind the service to the station it configures.
Not owned; it must outlive this service.
<a id="classespectre_1_1_wifi_provisioning_service_1a3974e07bf87f9714e0733a0b0ac30477"></a>
### `set_change_callback`
```cpp
void espectre::WifiProvisioningService::set_change_callback(ChangeCallback callback)
```
Called whenever the configuration, apply state, or scan results change.
<a id="classespectre_1_1_wifi_provisioning_service_1a74cc326ce0bdeb9da7ed6fa8e3c63237"></a>
### `set_reconfigure_callbacks`
```cpp
void espectre::WifiProvisioningService::set_reconfigure_callbacks(ChangeCallback prepare_callback, ChangeCallback resume_callback)
```
Bracket every live station reconfiguration.
`prepare_callback` runs before the station is reconfigured, for example to quiesce sensing, and `resume_callback` runs after the station reconnects or the reconfiguration fails.
<a id="classespectre_1_1_wifi_provisioning_service_1a19f93cc32488b559cfc50d8bf4798c2d"></a>
### `set_scan_callbacks`
```cpp
void espectre::WifiProvisioningService::set_scan_callbacks(ChangeCallback prepare_callback, ChangeCallback resume_callback)
```
Bracket every access point scan, like [set\_reconfigure\_callbacks()](#classespectre_1_1_wifi_provisioning_service_1a74cc326ce0bdeb9da7ed6fa8e3c63237).
<a id="classespectre_1_1_wifi_provisioning_service_1aa9ed3ddf8930c9c917e849dde72718c9"></a>
### `set_apply_completed_callback`
```cpp
void espectre::WifiProvisioningService::set_apply_completed_callback(ChangeCallback callback)
```
Called when a staged change ends as `APPLIED` or `ROLLED_BACK`.
<a id="classespectre_1_1_wifi_provisioning_service_1a83780a13c9467f636d6df89e02b7d327"></a>
### `load_or_set_defaults`
```cpp
esp_err_t espectre::WifiProvisioningService::load_or_set_defaults(const WifiProvisioningDefaults &defaults)
```
Load the saved configuration, or adopt `defaults` when nothing is saved.
An unsupported saved band policy falls back to the default, and a channel that does not match the band becomes automatic. A pending candidate left by a reboot resumes in `VERIFYING`. Load errors fall back to the defaults and are reported by [last\_load\_result()](#classespectre_1_1_wifi_provisioning_service_1abf46e703d2106f21c5583050a3d8a66b); the call itself returns `ESP_OK`.
<a id="classespectre_1_1_wifi_provisioning_service_1a16a9ec64e656c3de1c1db41742892481"></a>
### `setup_station`
```cpp
esp_err_t espectre::WifiProvisioningService::setup_station(const WifiProvisioningDefaults &defaults, standalone_wifi_callback_t connected_cb={}, standalone_wifi_callback_t disconnected_cb={})
```
Load the configuration and set up the bound [StandaloneWifiService](#classespectre_1_1_standalone_wifi_service) with it.
The connected callback runs after the service has checked a pending candidate. Call [StandaloneWifiService::start()](#classespectre_1_1_standalone_wifi_service_1a533d0f1dec909d9ce1580c3d23395d07) afterwards.
**Returns:** `ESP_ERR_INVALID_STATE` without a bound station, otherwise the result of [StandaloneWifiService::setup()](#classespectre_1_1_standalone_wifi_service_1af6031ac873d13c5c31203be7a7b24db4).
<a id="classespectre_1_1_wifi_provisioning_service_1a1dbc037cfb93993188c2b7db33183a1a"></a>
### `handle_command`
```cpp
bool espectre::WifiProvisioningService::handle_command(const std::string &command, std::string *message)
```
Run a provisioning command: `SET_WIFI_BSSID:bssid=<mac>[&force=true]` or `CLEAR_WIFI`.
`SET_WIFI_BSSID` pins an access point of the provisioned SSID, taking its channel from the latest scan; an empty `bssid` removes the pin. Pinning the access point already in use is saved directly unless `force` is set. `CLEAR_WIFI` erases the saved and pending configuration and leaves the station unprovisioned.
**Returns:** false for an unknown or malformed command, or while another change or scan is in progress. `message` receives the outcome.
<a id="classespectre_1_1_wifi_provisioning_service_1aba5fb367940e5c866a4ae62ed0753dd2"></a>
### `request_access_point_scan`
```cpp
bool espectre::WifiProvisioningService::request_access_point_scan(std::string *message)
```
Start an asynchronous scan; results are limited to the provisioned SSID.
<a id="classespectre_1_1_wifi_provisioning_service_1a56081293fee4af1ea5c849d0ce43b43d"></a>
### `begin_serial_provisioning`
```cpp
bool espectre::WifiProvisioningService::begin_serial_provisioning(const std::string &ssid, const std::string &password, std::string *message)
```
Stage credentials received through the standard Improv Serial RPC.
<a id="classespectre_1_1_wifi_provisioning_service_1a8b8c00c288e12539a262cf41d4760c72"></a>
### `loop`
```cpp
void espectre::WifiProvisioningService::loop()
```
Advance candidate verification and bounded rollback after Wi-Fi events.
<a id="classespectre_1_1_wifi_provisioning_service_1a79c35f784213d4c5ec03db18158e2aec"></a>
### `apply_live`
```cpp
bool espectre::WifiProvisioningService::apply_live(std::string *message)
```
Reapply the current configuration to the station without verification.
**Returns:** false when the station rejects the configuration; `message` receives the outcome.
<a id="classespectre_1_1_wifi_provisioning_service_1a966219c8a620bb247e791797f6685c0d"></a>
### `config`
```cpp
const StoredWifiConfig & espectre::WifiProvisioningService::config() const
```
Configuration the station currently uses, including its password.
<a id="classespectre_1_1_wifi_provisioning_service_1aa4bdfeaf9f64a161badbfad96051caf5"></a>
### `password_set`
```cpp
bool espectre::WifiProvisioningService::password_set() const
```
Whether a password is configured, for display without exposing it.
<a id="classespectre_1_1_wifi_provisioning_service_1abf46e703d2106f21c5583050a3d8a66b"></a>
### `last_load_result`
```cpp
esp_err_t espectre::WifiProvisioningService::last_load_result() const
```
Result of the last NVS load; not `ESP_OK` when defaults replaced unreadable data.
<a id="classespectre_1_1_wifi_provisioning_service_1aa2477794505d74aedc6e2869800d48a7"></a>
### `apply_state`
```cpp
WifiProvisioningApplyState espectre::WifiProvisioningService::apply_state() const
```
<a id="classespectre_1_1_wifi_provisioning_service_1a3fd2939db9ab7ad2430888b02517894e"></a>
### `apply_message`
```cpp
const std::string & espectre::WifiProvisioningService::apply_message() const
```
Human-readable detail for [apply\_state()](#classespectre_1_1_wifi_provisioning_service_1aa2477794505d74aedc6e2869800d48a7).
<a id="classespectre_1_1_wifi_provisioning_service_1a2bfc4c97846f8b70f24d3ed25bc25a8c"></a>
### `apply_pending`
```cpp
bool espectre::WifiProvisioningService::apply_pending() const
```
True while a change is `VERIFYING` or `ROLLING_BACK`.
<a id="classespectre_1_1_wifi_provisioning_service_1a7d349ff6069f83f6f732092975e94a46"></a>
### `scan_pending`
```cpp
bool espectre::WifiProvisioningService::scan_pending() const
```
True while an access point scan runs.
<a id="classespectre_1_1_wifi_provisioning_service_1a32582a8a2a634e845bf09eca86f55522"></a>
### `access_points`
```cpp
const std::vector< StandaloneWifiAccessPoint > & espectre::WifiProvisioningService::access_points() const
```
Access points of the provisioned SSID from the latest scan, strongest first.
<a id="classespectre_1_1_wifi_provisioning_service_1acfc4a3b903d45ff9e465dfaed1991b88"></a>
### `scan_message`
```cpp
const std::string & espectre::WifiProvisioningService::scan_message() const
```
Human-readable outcome of the latest scan.
<a id="structespectre__diagnostic__field__t"></a>
## espectre\_diagnostic\_field\_t
```cpp
#include <runtime/diagnostic_fields.h>
```
```cpp
struct espectre_diagnostic_field_t
```
One field of the diagnostic catalog.
<a id="structespectre__diagnostic__field__t_1a408388c99ede059fe9ba5d59144b843f"></a>
### `name`
```cpp
const char* espectre_diagnostic_field_t::name
```
Dotted field path, such as `raw_csi.raw_drop_total`.
<a id="structespectre__diagnostic__field__t_1a72e7dedd3d33f32ac6c053ac2f68022f"></a>
### `type`
```cpp
const char* espectre_diagnostic_field_t::type
```
JSON type: `integer`, `number`, or `boolean`.
<a id="structespectre__diagnostic__field__t_1abe5eaa83e5e4261fbffdec2ee05d346b"></a>
### `unit`
```cpp
const char* espectre_diagnostic_field_t::unit
```
Unit such as `ms`, `pps`, or `count`; empty for flags.
<a id="structespectre__diagnostic__field__t_1a96265d791a592d8cb009930e8f495761"></a>
### `profiles`
```cpp
unsigned espectre_diagnostic_field_t::profiles
```
Bit set of `ESPECTRE_DIAGNOSTIC_PROFILE_*` values.
<a id="base__detector_8h"></a>
## base\_detector.h
```cpp
#include <cstddef>
```
```cpp
#include <cstdint>
```
```cpp
#include <algorithm>
```
```cpp
#include <limits>
```
```cpp
#include <detector_types.h>
```
```cpp
#include <detector_limits.h>
```
```cpp
#include <filters.h>
```
```cpp
#include <utils.h>
```
[`espectre::BaseDetector`](#classespectre_1_1_base_detector)
[`espectre`](#namespaceespectre)
<a id="csi__capture__profile_8h"></a>
## csi\_capture\_profile.h
```cpp
#include <cstdint>
```
[`espectre`](#namespaceespectre)
<a id="csi__format_8h"></a>
## csi\_format.h
```cpp
#include <array>
```
```cpp
#include <cmath>
```
```cpp
#include <cstddef>
```
```cpp
#include <cstdint>
```
```cpp
#include <cstring>
```
```cpp
#include <csi_types.h>
```
```cpp
#include <utils.h>
```
[`espectre`](#namespaceespectre)
<a id="csi__raw__record_8h"></a>
## csi\_raw\_record.h
```cpp
#include <cstddef>
```
```cpp
#include <cstdint>
```
[`espectre::RawCsiRecordHeaderV8`](#structespectre_1_1_raw_csi_record_header_v8)
[`espectre`](#namespaceespectre)
<a id="csi__traffic__service_8h"></a>
## csi\_traffic\_service.h
```cpp
#include <cstddef>
```
```cpp
#include <cstdint>
```
```cpp
#include <string>
```
```cpp
#include <runtime_config.h>
```
```cpp
#include <udp_datagram_socket.h>
```
[`espectre::CsiTrafficServiceConfig`](#structespectre_1_1_csi_traffic_service_config)
[`espectre::ICsiTrafficGenerator`](#classespectre_1_1_i_csi_traffic_generator)
[`espectre::ICsiTrafficIngress`](#classespectre_1_1_i_csi_traffic_ingress)
[`espectre::CsiTrafficService`](#classespectre_1_1_csi_traffic_service)
[`espectre`](#namespaceespectre)
<a id="csi__types_8h"></a>
## csi\_types.h
```cpp
#include <array>
```
```cpp
#include <cstdint>
```
[`espectre`](#namespaceespectre)
<a id="detector__limits_8h"></a>
## detector\_limits.h
```cpp
#include <cstdint>
```
[`espectre`](#namespaceespectre)
<a id="detector__types_8h"></a>
## detector\_types.h
[`espectre`](#namespaceespectre)
<a id="device__config__store_8h"></a>
## device\_config\_store.h
```cpp
#include <cstdint>
```
```cpp
#include <string>
```
```cpp
#include <esp_err.h>
```
```cpp
#include <runtime/espectre_protocol.h>
```
```cpp
#include <runtime/runtime_config.h>
```
[`espectre::StoredWifiConfig`](#structespectre_1_1_stored_wifi_config)
[`espectre`](#namespaceespectre)
<a id="device__identity_8h"></a>
## device\_identity.h
```cpp
#include <cstdint>
```
```cpp
#include <string>
```
[`espectre`](#namespaceespectre)
<a id="diagnostic__fields_8h"></a>
## diagnostic\_fields.h
C-compatible metadata for the canonical device diagnostic catalog.
Profiles are bitmasks of the `ESPECTRE_DIAGNOSTIC_PROFILE_*` constants. Dotted field names select leaves while protocol responses retain their nested objects.
[`espectre_diagnostic_field_t`](#structespectre__diagnostic__field__t)
<a id="diagnostic__fields_8h_1aab4accacf85c5d9df1fe8881d3e90aa1"></a>
### `ESPECTRE_DIAGNOSTIC_FIELD_COUNT`
```cpp
#define ESPECTRE_DIAGNOSTIC_FIELD_COUNT (sizeof(espectre_diagnostic_fields) / sizeof(espectre_diagnostic_fields[0]))
```
Number of entries in `espectre_diagnostic_fields`.
<a id="diagnostic__fields_8h_1a32337afdea5d0f80b050b58e9cd0c170"></a>
### `@021375134171037300010122103026273353367327044052`
```cpp
enum @021375134171037300010122103026273353367327044052
```
Frontend profiles a diagnostic field belongs to.
<a id="diagnostic__fields_8h_1a32337afdea5d0f80b050b58e9cd0c170a12caf91251d0643715d941988a7380d1"></a>
`ESPECTRE_DIAGNOSTIC_PROFILE_NATIVE = 1U`
Native firmware.
<a id="diagnostic__fields_8h_1a32337afdea5d0f80b050b58e9cd0c170a088e89a650c801504bb1c06428ab20e2"></a>
`ESPECTRE_DIAGNOSTIC_PROFILE_BRIDGE = 2U`
Shared Direct HTTP bridge, used by ESPHome.
<a id="diagnostic__fields_8h_1a32337afdea5d0f80b050b58e9cd0c170aa71d2243c1354b5c2c7acbf988471854"></a>
`ESPECTRE_DIAGNOSTIC_PROFILE_MICRO = 4U`
Micro-ESPectre.
<a id="diagnostic__fields_8h_1a32337afdea5d0f80b050b58e9cd0c170aa8a9f4128bd81cbed4061ddd8698e9d7"></a>
`ESPECTRE_DIAGNOSTIC_PROFILE_ALL = 7U`
Every frontend.
<a id="diagnostic__fields_8h_1a08e8682b5949c9c4654abaabbf7bc6bc"></a>
### `espectre_diagnostic_fields`
```cpp
const espectre_diagnostic_field_t espectre_diagnostic_fields[][]
```
Canonical diagnostic fields; filter by profile before exposing a catalog.
<a id="direct__http__protocol_8h"></a>
## direct\_http\_protocol.h
```cpp
#include <cstddef>
```
```cpp
#include <cstdint>
```
```cpp
#include <string>
```
```cpp
#include <espectre_protocol.h>
```
[`espectre::DirectRequest`](#structespectre_1_1_direct_request)
[`espectre`](#namespaceespectre)
<a id="direct__http__service_8h"></a>
## direct\_http\_service.h
```cpp
#include <cstddef>
```
```cpp
#include <cstdint>
```
```cpp
#include <functional>
```
```cpp
#include <string>
```
```cpp
#include <vector>
```
```cpp
#include <direct_http_protocol.h>
```
```cpp
#include <raw_csi.h>
```
[`espectre::DirectHttpServiceConfig`](#structespectre_1_1_direct_http_service_config)
[`espectre::DirectHttpServiceDiagnostics`](#structespectre_1_1_direct_http_service_diagnostics)
[`espectre::IDirectHttpService`](#classespectre_1_1_i_direct_http_service)
[`espectre::IDirectHttpService::DeferredRequestResult`](#structespectre_1_1_i_direct_http_service_1_1_deferred_request_result)
[`espectre`](#namespaceespectre)
<a id="direct__http__service__esp__idf_8h"></a>
## direct\_http\_service\_esp\_idf.h
```cpp
#include <array>
```
```cpp
#include <atomic>
```
```cpp
#include <deque>
```
```cpp
#include <memory>
```
```cpp
#include <string>
```
```cpp
#include <vector>
```
```cpp
#include <esp_err.h>
```
```cpp
#include <freertos/FreeRTOS.h>
```
```cpp
#include <freertos/semphr.h>
```
```cpp
#include <freertos/task.h>
```
```cpp
#include <core/csi_types.h>
```
```cpp
#include <runtime/direct_http_service.h>
```
```cpp
#include <runtime/pending_event.h>
```
[`espectre::EspIdfDirectHttpService`](#classespectre_1_1_esp_idf_direct_http_service)
[`espectre`](#namespaceespectre)
<a id="direct__wifi__snapshot__esp__idf_8h"></a>
## direct\_wifi\_snapshot\_esp\_idf.h
```cpp
#include <cstdint>
```
```cpp
#include <string>
```
[`espectre::DirectWifiSnapshot`](#structespectre_1_1_direct_wifi_snapshot)
[`espectre`](#namespaceespectre)
<a id="espectre__banner_8h"></a>
## espectre\_banner.h
[`espectre`](#namespaceespectre)
<a id="espectre__core__sdk_8h"></a>
## espectre\_core\_sdk.h
```cpp
#include <runtime/espectre_sdk_version.h>
```
```cpp
#include <core/espectre_log.h>
```
```cpp
#include <core/base_detector.h>
```
```cpp
#include <core/csi_format.h>
```
```cpp
#include <core/csi_types.h>
```
```cpp
#include <core/detector_limits.h>
```
```cpp
#include <core/detector_types.h>
```
```cpp
#include <core/filter_config.h>
```
```cpp
#include <core/high_accuracy_detector.h>
```
```cpp
#include <core/lightweight_detector.h>
```
```cpp
#include <core/temporal_csi_sampler.h>
```
Core-only detector API for custom CSI capture integrations.
Prefer [`espectre_sdk.h`](#espectre__sdk_8h) and `RuntimeFrontendController` when ESPectre should own CSI capture, temporal admission, calibration, and event delivery. Include this facade only when the embedding firmware already implements those parts.
<a id="espectre__log_8h"></a>
## espectre\_log.h
```cpp
#include <cstdarg>
```
```cpp
#include <cstdint>
```
[`espectre::LogSink`](#structespectre_1_1_log_sink)
[`espectre`](#namespaceespectre)
<a id="espectre__log_8h_1a2452a301ac5b137469ae614b74ee149c"></a>
### `ESPECTRE_LOG_AT_LEVEL`
```cpp
#define ESPECTRE_LOG_AT_LEVEL(level, tag, format, ...) do { \
const char *const espectre_log_tag__ = (tag); \
if (::espectre::log_enabled((level), espectre_log_tag__)) { \
::espectre::detail::log_printf((level), espectre_log_tag__, __LINE__, (format), \
##__VA_ARGS__); \
} \
} while (false)
```
Log at an explicit `LogLevel`.
<a id="espectre__log_8h_1ab36e1f3068305cde3db4c480d2fa875d"></a>
### `ESPECTRE_LOGE`
```cpp
#define ESPECTRE_LOGE(tag, format, ...) ESPECTRE_LOG_AT_LEVEL(::espectre::LogLevel::ERROR, tag, format, ##__VA_ARGS__)
```
Log at `LogLevel::ERROR`.
<a id="espectre__log_8h_1a68a060eeeeafdb7b959a76e2333e58a8"></a>
### `ESPECTRE_LOGW`
```cpp
#define ESPECTRE_LOGW(tag, format, ...) ESPECTRE_LOG_AT_LEVEL(::espectre::LogLevel::WARNING, tag, format, ##__VA_ARGS__)
```
Log at `LogLevel::WARNING`.
<a id="espectre__log_8h_1a7d3ba0708ef9dd2a162c694d70648dd6"></a>
### `ESPECTRE_LOGI`
```cpp
#define ESPECTRE_LOGI(tag, format, ...) ESPECTRE_LOG_AT_LEVEL(::espectre::LogLevel::INFO, tag, format, ##__VA_ARGS__)
```
Log at `LogLevel::INFO`.
<a id="espectre__log_8h_1acd3d41a27469c25aa5a01f0f28859b10"></a>
### `ESPECTRE_LOGD`
```cpp
#define ESPECTRE_LOGD(tag, format, ...) ESPECTRE_LOG_AT_LEVEL(::espectre::LogLevel::DEBUG, tag, format, ##__VA_ARGS__)
```
Log at `LogLevel::DEBUG`.
<a id="espectre__log_8h_1a2f6d5220e8d4a419bec05dbaaebfcc25"></a>
### `ESPECTRE_LOGV`
```cpp
#define ESPECTRE_LOGV(tag, format, ...) ESPECTRE_LOG_AT_LEVEL(::espectre::LogLevel::VERBOSE, tag, format, ##__VA_ARGS__)
```
Log at `LogLevel::VERBOSE`.
<a id="espectre__mqtt__sdk_8h"></a>
## espectre\_mqtt\_sdk.h
```cpp
#include <espectre_protocol_sdk.h>
```
```cpp
#include <runtime/esp_idf/mqtt_transport_esp_idf.h>
```
Opt-in ESP-IDF implementation of the public MQTT transport contract.
Requires ESP-IDF's mqtt component and ESPECTRE\_RUNTIME\_ESP\_IDF\_MQTT\_SOURCES (or CONFIG\_ESPECTRE\_SDK\_ENABLE\_MQTT). The integrating firmware owns the transport object and drives its lifecycle. Other services do not require this facade or the MQTT stack.
<a id="espectre__protocol_8h"></a>
## espectre\_protocol.h
```cpp
#include <array>
```
```cpp
#include <cstddef>
```
```cpp
#include <cstdint>
```
```cpp
#include <string>
```
```cpp
#include <vector>
```
```cpp
#include <runtime_snapshot.h>
```
```cpp
#include <protocol_json.h>
```
Wire types and payload builders for the ESPectre Protocol.
The protocol is the contract between a device and whatever consumes it: MQTT topics, Direct HTTP messages, JSON payloads, and frontend extensions. It is specified in [API.md](<https://github.com/francescopace/espectre/blob/main/docs/API.md>); this header is the C++ view of that specification.
Use it whenever your integration should stay interoperable with the shipped clients — the CLI, Home Assistant discovery, and the web portal all speak it. The builders take a `RuntimeSnapshot` and return a serialized payload, so your transport only moves bytes and never formats them.
The parsers never throw: they validate and report failure through an out parameter. On failure the command parsers reset their output, keeping at most the identifiers needed for the result payload. The device configuration parsers leave their output unchanged.
[`espectre::EspectreApiRoute`](#structespectre_1_1_espectre_api_route)
[`espectre::EspectreApiEventDescriptor`](#structespectre_1_1_espectre_api_event_descriptor)
[`espectre::EspectreExtensionRoute`](#structespectre_1_1_espectre_extension_route)
[`espectre::EspectreProtocolExtension`](#structespectre_1_1_espectre_protocol_extension)
[`espectre::EspectreCapabilityProfile`](#structespectre_1_1_espectre_capability_profile)
[`espectre::EspectreDeviceConfig`](#structespectre_1_1_espectre_device_config)
[`espectre::EspectreNetworkInfo`](#structespectre_1_1_espectre_network_info)
[`espectre::EspectreDeviceInfo`](#structespectre_1_1_espectre_device_info)
[`espectre::EspectreCommand`](#structespectre_1_1_espectre_command)
[`espectre`](#namespaceespectre)
<a id="espectre__protocol__sdk_8h"></a>
## espectre\_protocol\_sdk.h
```cpp
#include <espectre_sdk.h>
```
```cpp
#include <runtime/diagnostic_fields.h>
```
```cpp
#include <runtime/direct_http_protocol.h>
```
```cpp
#include <runtime/direct_http_service.h>
```
```cpp
#include <runtime/espectre_protocol.h>
```
```cpp
#include <runtime/mqtt_transport.h>
```
```cpp
#include <runtime/protocol_json.h>
```
```cpp
#include <runtime/runtime_diagnostics_protocol.h>
```
The ESPectre Protocol: messages, JSON, diagnostics, and transports.
Includes the sensing SDK plus the canonical protocol messages, their JSON form, the diagnostic field catalog, and the Direct HTTP and MQTT transport contracts you implement to reach your own transports. Include it only when your firmware speaks the ESPectre Protocol; the services and MQTT facades include it for you.
<a id="espectre__sdk_8h"></a>
## espectre\_sdk.h
```cpp
#include <runtime/espectre_sdk_version.h>
```
```cpp
#include <core/espectre_log.h>
```
```cpp
#include <runtime/csi_capture_profile.h>
```
```cpp
#include <runtime/runtime_capabilities.h>
```
```cpp
#include <runtime/runtime_config_utils.h>
```
```cpp
#include <runtime/runtime_diagnostics.h>
```
```cpp
#include <runtime/runtime_events.h>
```
```cpp
#include <runtime/runtime_config.h>
```
```cpp
#include <runtime/csi_raw_record.h>
```
```cpp
#include <runtime/raw_csi.h>
```
```cpp
#include <runtime/runtime_sensing_schema.h>
```
```cpp
#include <runtime/runtime_snapshot.h>
```
```cpp
#include <runtime/esp_idf/device_identity.h>
```
```cpp
#include <runtime/esp_idf/runtime_frontend_controller.h>
```
```cpp
#include <runtime/esp_idf/runtime_sensing_kconfig.h>
```
The public ESPectre integration surface, in one include.
ESPectre turns ordinary Wi-Fi traffic into a motion signal: it captures Channel State Information from the radio, extracts features, and reports a debounced motion state. This header is the supported entry point for firmware that embeds the sensing engine in its own application.
```cpp
#include "espectre_sdk.h"
class ProductFrontend : public espectre::IRuntimeListener {
public:
bool setup() {
espectre::RuntimeConfig config; // documented defaults, ready to use
runtime_.set_config(config);
return runtime_.setup(this);
}
void loop() { runtime_.loop(); }
void on_motion_state_changed(const espectre::RuntimeSnapshot &snapshot) override {
if (!snapshot.ready_to_publish) return;
publish(snapshot.motion_state == espectre::MotionState::MOTION);
}
private:
espectre::RuntimeFrontendController runtime_;
};
```
<a id="espectre__sdk_8h_1sdk_paths"></a>
### Two integration paths
- **Full runtime (recommended).** Your firmware owns boot, provisioning, networking, OTA, and the product surface. ESPectre owns Wi-Fi CSI capture, calibration, detection, and eventing behind [`espectre::RuntimeFrontendController`](#classespectre_1_1_runtime_frontend_controller) and [`espectre::IRuntimeListener`](#classespectre_1_1_i_runtime_listener). Requires ESP-IDF >= 5.5.3.
- **Core-only.** Your firmware already captures CSI. Include [`espectre_core_sdk.h`](#espectre__core__sdk_8h) and drive [`espectre::LightweightDetector`](#classespectre_1_1_lightweight_detector) or [`espectre::HighAccuracyDetector`](#classespectre_1_1_high_accuracy_detector) directly. `runtime/esp_idf/csi_pipeline.cpp` is the reference for normalization, evaluation cadence, and hit filtering.
<a id="espectre__sdk_8h_1sdk_threading"></a>
### Threading contract
The control surface is single-owner. Internal bounded mailboxes protect callback-to-loop handoff, but they do not make control calls thread-safe.
- Run `setup()`, `loop()`, and `shutdown()` on one task. These are the calls that build and tear down runtime state, and they are not safe to race.
- Every `IRuntimeListener` callback is delivered on the caller's task: from `loop()` for sensing events, or inline on the task that invoked a control method. Work raised in the Wi-Fi CSI callback is deferred through an internal mailbox first, so no listener callback runs in interrupt or Wi-Fi driver context.
- Keep callbacks bounded and non-blocking. Slow work delays `loop()` and can fill the bounded CSI mailbox, dropping incoming frames. Queue network I/O, NVS writes, and other blocking work for another task.
- Call the controller setters only from the owner task. Queue commands received by network callbacks and apply them from that task's loop.
- Do not drive the controller from inside `on_runtime_fault()` beyond `shutdown()`.
- Raw CSI packet callbacks are the deliberate exception to listener delivery: they run synchronously in Wi-Fi capture context. Keep them bounded, non-blocking, and allocation-free; see `raw_csi_packet_callback_t`.
<a id="espectre__sdk_8h_1sdk_versioning"></a>
### Versioning
[`ESPECTRE_SDK_VERSION_STRING`](#espectre__sdk__version_8h_1a63ca6448380d44c069980a49a9584c74) and [`ESPECTRE_SDK_VERSION_AT_LEAST()`](#espectre__sdk__version_8h_1a84f438434c7a7b020e175e84ae3ca6e8) identify the SDK sources you compiled against. See [`runtime/espectre_sdk_version.h`](#espectre__sdk__version_8h) for how that differs from your firmware version.
<a id="espectre__sdk_8h_1sdk_stability"></a>
### Stability tiers
Everything reachable from this header is the stable runtime surface and follows the SDK version contract. The opt-in [`espectre_core_sdk.h`](#espectre__core__sdk_8h) facade is the lower-level detector extension. The opt-in [`espectre_protocol_sdk.h`](#espectre__protocol__sdk_8h) facade adds the protocol and transport contracts. The optional services and MQTT facades expose supported ESP-IDF integration contracts. Headers included only as implementation dependencies can change in any release. See [Versioning](#sdk_integration_1integration_versioning) for the exact guarantees.
<a id="espectre__sdk_8h_1sdk_licensing"></a>
### Licensing
ESPectre is dual-licensed: GPLv3, or a separately offered commercial license for proprietary firmware. See `LICENSING.md`.
<a id="espectre__sdk__version_8h"></a>
## espectre\_sdk\_version.h
Compile-time identity of the ESPectre SDK sources you compiled against.
This is the version of the *SDK*, not of your firmware. The two are deliberately separate:
- [`ESPECTRE_SDK_VERSION_STRING`](#espectre__sdk__version_8h_1a63ca6448380d44c069980a49a9584c74) is baked in at compile time and identifies the ESPectre sources in your build. Use it in diagnostics, bug reports, and to guard code against SDK releases.
- The *application* version is supplied to the runtime by the frontend or integrator. In an integration it is your product's version, not ESPectre's.
Published SDK bundles stamp their identity into this header. Integrators can supply all four version macros at compile time to override the package. The SDK does not inspect Git, environment variables, or firmware metadata. Missing or incomplete metadata defaults to 0.0.0, meaning an unknown SDK version. Its numeric macros are zero, so checks for newer releases are false.
[`espectre`](#namespaceespectre)
<a id="espectre__sdk__version_8h_1a1c56ebb77dae087ea795df71afe1b36a"></a>
### `ESPECTRE_SDK_VERSION_MAJOR`
```cpp
#define ESPECTRE_SDK_VERSION_MAJOR 3
```
Major component of the SDK version; zero when unknown.
<a id="espectre__sdk__version_8h_1ab49f9a44dcd3be82d3b3e742d9334c23"></a>
### `ESPECTRE_SDK_VERSION_MINOR`
```cpp
#define ESPECTRE_SDK_VERSION_MINOR 0
```
Minor component of the SDK version; zero when unknown.
<a id="espectre__sdk__version_8h_1a74f3ae0b42f726bf3302abae42655339"></a>
### `ESPECTRE_SDK_VERSION_PATCH`
```cpp
#define ESPECTRE_SDK_VERSION_PATCH 0
```
Patch component of the SDK version; zero when unknown.
<a id="espectre__sdk__version_8h_1a63ca6448380d44c069980a49a9584c74"></a>
### `ESPECTRE_SDK_VERSION_STRING`
```cpp
#define ESPECTRE_SDK_VERSION_STRING "3.0.0-rc3"
```
SDK version as a string literal, such as `"3.0.0"`; `"0.0.0"` when unknown.
<a id="espectre__sdk__version_8h_1addabd247bcb8243d35a37657c029571b"></a>
### `ESPECTRE_SDK_VERSION_NUMBER`
```cpp
#define ESPECTRE_SDK_VERSION_NUMBER ((ESPECTRE_SDK_VERSION_MAJOR * 10000) + (ESPECTRE_SDK_VERSION_MINOR * 100) + ESPECTRE_SDK_VERSION_PATCH)
```
Legacy packed numeric identity for the SDK version, as `MMmmpp`.
Example: `3.0.0` becomes `30000`. Retained for compatibility and compact telemetry; do not use it for ordering because components are not limited to two digits. Use [`ESPECTRE_SDK_VERSION_AT_LEAST()`](#espectre__sdk__version_8h_1a84f438434c7a7b020e175e84ae3ca6e8) for feature guards.
<a id="espectre__sdk__version_8h_1a84f438434c7a7b020e175e84ae3ca6e8"></a>
### `ESPECTRE_SDK_VERSION_AT_LEAST`
```cpp
#define ESPECTRE_SDK_VERSION_AT_LEAST(major, minor, patch) ((ESPECTRE_SDK_VERSION_MAJOR > (major)) || \
(ESPECTRE_SDK_VERSION_MAJOR == (major) && \
(ESPECTRE_SDK_VERSION_MINOR > (minor) || \
(ESPECTRE_SDK_VERSION_MINOR == (minor) && \
ESPECTRE_SDK_VERSION_PATCH >= (patch)))))
```
Compile-time feature guard.
Use it to keep one integration compiling against several SDK releases:
```cpp
#if ESPECTRE_SDK_VERSION_AT_LEAST(3, 1, 0)
// Use an API introduced in 3.1.0.
#else
// Keep the equivalent behavior for earlier SDK releases.
#endif
```
<a id="espectre__services__sdk_8h"></a>
## espectre\_services\_sdk.h
```cpp
#include <espectre_protocol_sdk.h>
```
```cpp
#include <runtime/esp_idf/device_config_store.h>
```
```cpp
#include <runtime/esp_idf/direct_http_service_esp_idf.h>
```
```cpp
#include <runtime/esp_idf/direct_wifi_snapshot_esp_idf.h>
```
```cpp
#include <runtime/esp_idf/frontend_bootstrap_helpers.h>
```
```cpp
#include <runtime/esp_idf/frontend_ha_mqtt_helpers.h>
```
```cpp
#include <runtime/esp_idf/frontend_mqtt_helpers.h>
```
```cpp
#include <runtime/esp_idf/mdns_bootstrap_responder.h>
```
```cpp
#include <runtime/esp_idf/mdns_discovery_service.h>
```
```cpp
#include <runtime/esp_idf/network_traffic.h>
```
```cpp
#include <runtime/esp_idf/nvs_helpers.h>
```
```cpp
#include <runtime/esp_idf/peer_discovery_service_esp_idf.h>
```
```cpp
#include <runtime/esp_idf/raw_csi_session_controller.h>
```
```cpp
#include <runtime/esp_idf/runtime_direct_http_bridge.h>
```
```cpp
#include <runtime/esp_idf/standalone_wifi_service.h>
```
```cpp
#include <runtime/esp_idf/task_scheduling_config.h>
```
```cpp
#include <runtime/esp_idf/traffic_generator_manager.h>
```
```cpp
#include <runtime/esp_idf/wifi_band_helpers.h>
```
```cpp
#include <runtime/esp_idf/wifi_bssid_pin_service.h>
```
```cpp
#include <runtime/esp_idf/wifi_lifecycle.h>
```
```cpp
#include <runtime/esp_idf/wifi_provisioning_service.h>
```
```cpp
#include <runtime/csi_traffic_service.h>
```
```cpp
#include <runtime/espectre_banner.h>
```
```cpp
#include <runtime/frontend_command_engine.h>
```
```cpp
#include <runtime/peer_discovery.h>
```
```cpp
#include <runtime/pending_event.h>
```
```cpp
#include <runtime/pending_queue.h>
```
```cpp
#include <runtime/runtime_event_mailbox.h>
```
```cpp
#include <runtime/runtime_time.h>
```
```cpp
#include <runtime/udp_datagram_socket.h>
```
Optional services for firmware integrating the ESPectre runtime.
Includes the sensing SDK and the supported command, transport, discovery, provisioning, and bootstrap services. Compile only the capability source groups that your firmware uses; including this facade does not enable them. Requires the ESP-IDF platform headers and declared component dependencies. Firmware owns networking, service lifetime, task policy, and the allocation of each service object.
<a id="filter__config_8h"></a>
## filter\_config.h
```cpp
#include <cstdint>
```
[`espectre`](#namespaceespectre)
<a id="frontend__bootstrap__helpers_8h"></a>
## frontend\_bootstrap\_helpers.h
```cpp
#include <cstdint>
```
```cpp
#include <device_identity.h>
```
```cpp
#include <esp_err.h>
```
```cpp
#include <runtime/espectre_protocol.h>
```
```cpp
#include <standalone_wifi_service.h>
```
```cpp
#include <wifi_provisioning_service.h>
```
[`espectre::FrontendDeviceConfigDefaults`](#structespectre_1_1_frontend_device_config_defaults)
[`espectre::FrontendWifiStationOptions`](#structespectre_1_1_frontend_wifi_station_options)
[`espectre`](#namespaceespectre)
<a id="frontend__command__engine_8h"></a>
## frontend\_command\_engine.h
```cpp
#include <cstdint>
```
```cpp
#include <functional>
```
```cpp
#include <string>
```
```cpp
#include <espectre_protocol.h>
```
```cpp
#include <runtime_config_utils.h>
```
[`espectre::FrontendCommandContext`](#structespectre_1_1_frontend_command_context)
[`espectre::FrontendCommandResult`](#structespectre_1_1_frontend_command_result)
[`espectre::FrontendCommandEngine`](#classespectre_1_1_frontend_command_engine)
[`espectre`](#namespaceespectre)
<a id="frontend__ha__mqtt__helpers_8h"></a>
## frontend\_ha\_mqtt\_helpers.h
```cpp
#include <string>
```
```cpp
#include <vector>
```
```cpp
#include <runtime/espectre_protocol.h>
```
[`espectre::FrontendHaDiagnosticSensor`](#structespectre_1_1_frontend_ha_diagnostic_sensor)
[`espectre::FrontendHaMqttSettings`](#structespectre_1_1_frontend_ha_mqtt_settings)
[`espectre::FrontendHaDiscoveryMessage`](#structespectre_1_1_frontend_ha_discovery_message)
[`espectre`](#namespaceespectre)
<a id="frontend__mqtt__helpers_8h"></a>
## frontend\_mqtt\_helpers.h
```cpp
#include <cstdint>
```
```cpp
#include <functional>
```
```cpp
#include <string>
```
```cpp
#include <runtime/frontend_command_engine.h>
```
```cpp
#include <runtime/mqtt_transport.h>
```
[`espectre`](#namespaceespectre)
<a id="high__accuracy__detector_8h"></a>
## high\_accuracy\_detector.h
```cpp
#include <base_detector.h>
```
```cpp
#include <csi_format.h>
```
```cpp
#include <csi_features.h>
```
```cpp
#include <filtered_turbulence_ring.h>
```
```cpp
#include <l1_delta_tracker.h>
```
```cpp
#include <ml_feature_trackers.h>
```
```cpp
#include <cstdint>
```
```cpp
#include <cstddef>
```
[`espectre::HighAccuracyDetector`](#classespectre_1_1_high_accuracy_detector)
[`espectre`](#namespaceespectre)
<a id="lightweight__detector_8h"></a>
## lightweight\_detector.h
```cpp
#include <base_detector.h>
```
```cpp
#include <csi_format.h>
```
```cpp
#include <csi_features.h>
```
```cpp
#include <filtered_turbulence_ring.h>
```
```cpp
#include <cstddef>
```
```cpp
#include <cstdint>
```
```cpp
#include <memory>
```
[`espectre::LightweightDetector`](#classespectre_1_1_lightweight_detector)
[`espectre`](#namespaceespectre)
<a id="mdns__bootstrap__responder_8h"></a>
## mdns\_bootstrap\_responder.h
```cpp
#include <array>
```
```cpp
#include <atomic>
```
```cpp
#include <cstddef>
```
```cpp
#include <cstdint>
```
[`espectre::MdnsBootstrapResponder`](#classespectre_1_1_mdns_bootstrap_responder)
[`espectre`](#namespaceespectre)
<a id="mdns__discovery__service_8h"></a>
## mdns\_discovery\_service.h
```cpp
#include <cstdint>
```
```cpp
#include <string>
```
```cpp
#include <utility>
```
```cpp
#include <vector>
```
[`espectre::MdnsDiscoveryServiceConfig`](#structespectre_1_1_mdns_discovery_service_config)
[`espectre::MdnsDiscoveryService`](#classespectre_1_1_mdns_discovery_service)
[`espectre`](#namespaceespectre)
<a id="mqtt__payload__assembler_8h"></a>
## mqtt\_payload\_assembler.h
```cpp
#include <array>
```
```cpp
#include <cstddef>
```
```cpp
#include <cstring>
```
```cpp
#include <string_view>
```
```cpp
#include <espectre_protocol.h>
```
[`espectre`](#namespaceespectre)
<a id="mqtt__transport_8h"></a>
## mqtt\_transport.h
```cpp
#include <cstddef>
```
```cpp
#include <cstdint>
```
```cpp
#include <functional>
```
```cpp
#include <string>
```
```cpp
#include <espectre_protocol.h>
```
[`espectre::MqttTransportDiagnostics`](#structespectre_1_1_mqtt_transport_diagnostics)
[`espectre::IMqttTransport`](#classespectre_1_1_i_mqtt_transport)
[`espectre`](#namespaceespectre)
<a id="mqtt__transport__esp__idf_8h"></a>
## mqtt\_transport\_esp\_idf.h
```cpp
#include <array>
```
```cpp
#include <atomic>
```
```cpp
#include <deque>
```
```cpp
#include <memory>
```
```cpp
#include <string>
```
```cpp
#include <vector>
```
```cpp
#include <runtime/mqtt_transport.h>
```
```cpp
#include <runtime/mqtt_payload_assembler.h>
```
```cpp
#include <runtime/pending_event.h>
```
```cpp
#include <runtime/pending_queue.h>
```
```cpp
#include <mqtt_client.h>
```
[`espectre::EspIdfMqttTransport`](#classespectre_1_1_esp_idf_mqtt_transport)
[`espectre`](#namespaceespectre)
<a id="network__traffic_8h"></a>
## network\_traffic.h
```cpp
#include <cstdint>
```
```cpp
#include <esp_err.h>
```
[`espectre::NetworkTrafficSnapshot`](#structespectre_1_1_network_traffic_snapshot)
[`espectre`](#namespaceespectre)
<a id="nvs__helpers_8h"></a>
## nvs\_helpers.h
```cpp
#include <esp_err.h>
```
[`espectre`](#namespaceespectre)
<a id="peer__discovery_8h"></a>
## peer\_discovery.h
```cpp
#include <cstddef>
```
```cpp
#include <cstdint>
```
```cpp
#include <functional>
```
```cpp
#include <string>
```
```cpp
#include <vector>
```
[`espectre::PeerDiscoveryCandidate`](#structespectre_1_1_peer_discovery_candidate)
[`espectre::PeerDiscoverySnapshot`](#structespectre_1_1_peer_discovery_snapshot)
[`espectre::IPeerDiscoveryService`](#classespectre_1_1_i_peer_discovery_service)
[`espectre`](#namespaceespectre)
<a id="peer__discovery__service__esp__idf_8h"></a>
## peer\_discovery\_service\_esp\_idf.h
```cpp
#include <runtime/peer_discovery.h>
```
[`espectre::EspIdfPeerDiscoveryService`](#classespectre_1_1_esp_idf_peer_discovery_service)
[`espectre`](#namespaceespectre)
<a id="pending__event_8h"></a>
## pending\_event.h
```cpp
#include <cstddef>
```
```cpp
#include <mutex>
```
```cpp
#include <freertos/FreeRTOS.h>
```
```cpp
#include <freertos/portmacro.h>
```
```cpp
#include <tuple>
```
```cpp
#include <utility>
```
[`espectre::PendingEvent`](#classespectre_1_1_pending_event)
[`espectre`](#namespaceespectre)
<a id="pending__queue_8h"></a>
## pending\_queue.h
```cpp
#include <array>
```
```cpp
#include <cstddef>
```
```cpp
#include <mutex>
```
```cpp
#include <type_traits>
```
```cpp
#include <pending_event.h>
```
[`espectre::PendingQueue`](#classespectre_1_1_pending_queue)
[`espectre`](#namespaceespectre)
<a id="protocol__json_8h"></a>
## protocol\_json.h
```cpp
#include <cstdint>
```
```cpp
#include <string>
```
```cpp
#include <utility>
```
```cpp
#include <vector>
```
[`espectre::JsonObjectField`](#structespectre_1_1_json_object_field)
[`espectre::JsonInput`](#classespectre_1_1_json_input)
[`espectre::JsonFieldView`](#structespectre_1_1_json_field_view)
[`espectre`](#namespaceespectre)
<a id="raw__csi_8h"></a>
## raw\_csi.h
```cpp
#include <cstddef>
```
```cpp
#include <cstdint>
```
```cpp
#include <csi_raw_record.h>
```
[`espectre::RawCsiPacketView`](#structespectre_1_1_raw_csi_packet_view)
[`espectre::RawCsiHttpFramePrefix`](#structespectre_1_1_raw_csi_http_frame_prefix)
[`espectre::RawCsiSessionConfig`](#structespectre_1_1_raw_csi_session_config)
[`espectre::RawCsiSessionDiagnostics`](#structespectre_1_1_raw_csi_session_diagnostics)
[`espectre`](#namespaceespectre)
<a id="raw__csi__session__controller_8h"></a>
## raw\_csi\_session\_controller.h
```cpp
#include <cstdint>
```
```cpp
#include <functional>
```
```cpp
#include <string>
```
```cpp
#include <runtime/direct_http_service.h>
```
```cpp
#include <runtime_frontend_controller.h>
```
[`espectre::RawCsiSessionController`](#classespectre_1_1_raw_csi_session_controller)
[`espectre`](#namespaceespectre)
<a id="runtime__capabilities_8h"></a>
## runtime\_capabilities.h
[`espectre::RuntimeCapabilities`](#structespectre_1_1_runtime_capabilities)
[`espectre`](#namespaceespectre)
<a id="runtime__config_8h"></a>
## runtime\_config.h
```cpp
#include <cstdint>
```
```cpp
#include <string>
```
```cpp
#include <csi_capture_profile.h>
```
```cpp
#include <runtime_sensing_schema.h>
```
Runtime configuration handed to `RuntimeFrontendController`.
[`espectre::RuntimeConfig`](#structespectre_1_1_runtime_config)
[`espectre`](#namespaceespectre)
<a id="runtime__config__utils_8h"></a>
## runtime\_config\_utils.h
```cpp
#include <runtime_config.h>
```
```cpp
#include <runtime_snapshot.h>
```
[`espectre::RuntimeControlUpdate`](#structespectre_1_1_runtime_control_update)
[`espectre`](#namespaceespectre)
<a id="runtime__diagnostics_8h"></a>
## runtime\_diagnostics.h
```cpp
#include <cstdint>
```
```cpp
#include <runtime_snapshot.h>
```
[`espectre::RuntimeDiagnosticsSample`](#structespectre_1_1_runtime_diagnostics_sample)
[`espectre::RuntimeDiagnosticsSampler`](#classespectre_1_1_runtime_diagnostics_sampler)
[`espectre`](#namespaceespectre)
<a id="runtime__diagnostics__protocol_8h"></a>
## runtime\_diagnostics\_protocol.h
```cpp
#include <functional>
```
```cpp
#include <string>
```
```cpp
#include <vector>
```
```cpp
#include <diagnostic_fields.h>
```
```cpp
#include <runtime_diagnostics.h>
```
```cpp
#include <runtime_snapshot.h>
```
Diagnostic field selection and JSON serialization for protocol responses.
[`espectre`](#namespaceespectre)
<a id="runtime__direct__http__bridge_8h"></a>
## runtime\_direct\_http\_bridge.h
```cpp
#include <cstdint>
```
```cpp
#include <functional>
```
```cpp
#include <string>
```
```cpp
#include <runtime/direct_http_service.h>
```
```cpp
#include <direct_wifi_snapshot_esp_idf.h>
```
```cpp
#include <runtime/frontend_command_engine.h>
```
```cpp
#include <runtime/peer_discovery.h>
```
```cpp
#include <raw_csi_session_controller.h>
```
```cpp
#include <runtime/runtime_diagnostics.h>
```
```cpp
#include <runtime/runtime_event_mailbox.h>
```
```cpp
#include <runtime_frontend_controller.h>
```
```cpp
#include <atomic>
```
[`espectre::RuntimeDirectHttpBridgeConfig`](#structespectre_1_1_runtime_direct_http_bridge_config)
[`espectre::RuntimeDirectHttpBridge`](#classespectre_1_1_runtime_direct_http_bridge)
[`espectre`](#namespaceespectre)
<a id="runtime__event__mailbox_8h"></a>
## runtime\_event\_mailbox.h
```cpp
#include <array>
```
```cpp
#include <cstddef>
```
```cpp
#include <cstdint>
```
```cpp
#include <mutex>
```
```cpp
#include <type_traits>
```
```cpp
#include <freertos/FreeRTOS.h>
```
```cpp
#include <freertos/portmacro.h>
```
```cpp
#include <runtime_snapshot.h>
```
[`espectre::RuntimeEventMailbox`](#classespectre_1_1_runtime_event_mailbox)
[`espectre`](#namespaceespectre)
<a id="runtime__events_8h"></a>
## runtime\_events.h
```cpp
#include <cstdint>
```
```cpp
#include <runtime_snapshot.h>
```
[`espectre::IRuntimeListener`](#classespectre_1_1_i_runtime_listener)
[`espectre`](#namespaceespectre)
<a id="runtime__frontend__controller_8h"></a>
## runtime\_frontend\_controller.h
```cpp
#include <memory>
```
```cpp
#include <string>
```
```cpp
#include <core/csi_types.h>
```
```cpp
#include <runtime/raw_csi.h>
```
```cpp
#include <runtime/runtime_capabilities.h>
```
```cpp
#include <runtime/runtime_events.h>
```
```cpp
#include <runtime/runtime_config.h>
```
```cpp
#include <runtime/runtime_config_utils.h>
```
```cpp
#include <runtime/runtime_snapshot.h>
```
[`espectre::RuntimeFrontendController`](#classespectre_1_1_runtime_frontend_controller)
[`espectre`](#namespaceespectre)
<a id="runtime__sensing__kconfig_8h"></a>
## runtime\_sensing\_kconfig.h
```cpp
#include <runtime/runtime_config.h>
```
[`espectre`](#namespaceespectre)
<a id="runtime__sensing__schema_8h"></a>
## runtime\_sensing\_schema.h
```cpp
#include <cstddef>
```
```cpp
#include <cstdint>
```
```cpp
#include <core/detector_limits.h>
```
```cpp
#include <core/detector_types.h>
```
```cpp
#include <core/filter_config.h>
```
The schema behind `RuntimeConfig`: enums, defaults, and valid ranges.
This is the single source of truth for what a sensing configuration may contain. Every tunable is declared as a `RUNTIME_<FIELD>_DEFAULT` plus, where a range applies, `_MIN` and `_MAX`. Read them instead of hardcoding limits, so a UI, a provisioning flow, or a config parser stays correct across SDK releases.
[`espectre`](#namespaceespectre)
<a id="runtime__snapshot_8h"></a>
## runtime\_snapshot.h
```cpp
#include <cstdint>
```
```cpp
#include <csi_capture_profile.h>
```
```cpp
#include <core/csi_types.h>
```
```cpp
#include <core/detector_types.h>
```
```cpp
#include <runtime_sensing_schema.h>
```
[`espectre::RuntimeDiagnosticsSnapshot`](#structespectre_1_1_runtime_diagnostics_snapshot)
[`espectre::RuntimeDiagnosticsSnapshot::Link`](#structespectre_1_1_runtime_diagnostics_snapshot_1_1_link)
[`espectre::RuntimeDiagnosticsSnapshot::Traffic`](#structespectre_1_1_runtime_diagnostics_snapshot_1_1_traffic)
[`espectre::RuntimeDiagnosticsSnapshot::Csi`](#structespectre_1_1_runtime_diagnostics_snapshot_1_1_csi)
[`espectre::RuntimeDiagnosticsSnapshot::Platform`](#structespectre_1_1_runtime_diagnostics_snapshot_1_1_platform)
[`espectre::RuntimeDiagnosticsSnapshot::Performance`](#structespectre_1_1_runtime_diagnostics_snapshot_1_1_performance)
[`espectre::RuntimeSnapshot`](#structespectre_1_1_runtime_snapshot)
[`espectre`](#namespaceespectre)
<a id="runtime__time_8h"></a>
## runtime\_time.h
```cpp
#include <cstdint>
```
[`espectre`](#namespaceespectre)
<a id="standalone__wifi__service_8h"></a>
## standalone\_wifi\_service.h
```cpp
#include <atomic>
```
```cpp
#include <cstdint>
```
```cpp
#include <functional>
```
```cpp
#include <string>
```
```cpp
#include <vector>
```
```cpp
#include <esp_err.h>
```
```cpp
#include <esp_event.h>
```
```cpp
#include <runtime/pending_queue.h>
```
```cpp
#include <wifi_lifecycle.h>
```
[`espectre::StandaloneWifiAccessPoint`](#structespectre_1_1_standalone_wifi_access_point)
[`espectre::StandaloneWifiConfig`](#structespectre_1_1_standalone_wifi_config)
[`espectre::StandaloneWifiInfo`](#structespectre_1_1_standalone_wifi_info)
[`espectre::StandaloneWifiService`](#classespectre_1_1_standalone_wifi_service)
[`espectre`](#namespaceespectre)
<a id="task__scheduling__config_8h"></a>
## task\_scheduling\_config.h
```cpp
#include <cstdint>
```
[`espectre`](#namespaceespectre)
[`espectre::task_scheduling`](#namespaceespectre_1_1task__scheduling)
<a id="task__scheduling__config_8h_1a1c07ae2423b6566d454316bfd9a8dcfa"></a>
### `CONFIG_ESPECTRE_DIRECT_HTTPD_TASK_PRIORITY`
```cpp
#define CONFIG_ESPECTRE_DIRECT_HTTPD_TASK_PRIORITY 1
```
Default Direct HTTP server priority when the SDK Kconfig is not sourced.
<a id="task__scheduling__config_8h_1ab21ce3fdcc4837c2a0aecb8b3b58ca04"></a>
### `CONFIG_ESPECTRE_DIRECT_WORKER_TASK_PRIORITY`
```cpp
#define CONFIG_ESPECTRE_DIRECT_WORKER_TASK_PRIORITY 2
```
Default Direct response and event worker priority when the SDK Kconfig is not sourced.
<a id="task__scheduling__config_8h_1ac541f938b4a9aee9eb3e7edc08296acd"></a>
### `CONFIG_ESPECTRE_RAW_WORKER_TASK_PRIORITY`
```cpp
#define CONFIG_ESPECTRE_RAW_WORKER_TASK_PRIORITY 3
```
Default raw CSI delivery worker priority when the SDK Kconfig is not sourced.
<a id="task__scheduling__config_8h_1a89bc52af94882fc610139f6ac25a80c8"></a>
### `CONFIG_ESPECTRE_TRAFFIC_TASK_PRIORITY`
```cpp
#define CONFIG_ESPECTRE_TRAFFIC_TASK_PRIORITY 1
```
Default managed traffic generator priority when the SDK Kconfig is not sourced.
<a id="temporal__csi__sampler_8h"></a>
## temporal\_csi\_sampler.h
```cpp
#include <cstdint>
```
```cpp
#include <memory>
```
[`espectre::TemporalCsiSampler`](#classespectre_1_1_temporal_csi_sampler)
[`espectre`](#namespaceespectre)
<a id="traffic__generator__manager_8h"></a>
## traffic\_generator\_manager.h
```cpp
#include <atomic>
```
```cpp
#include <cstddef>
```
```cpp
#include <cstdint>
```
```cpp
#include <sys/types.h>
```
```cpp
#include <freertos/FreeRTOS.h>
```
```cpp
#include <freertos/task.h>
```
```cpp
#include <runtime/csi_traffic_service.h>
```
ESP-IDF managed traffic for firmware that owns its CSI capture path.
Link ESPECTRE\_RUNTIME\_ESP\_IDF\_TRAFFIC\_SOURCES and its ESP-IDF dependencies. The firmware owns the object and calls stop() before tearing down Wi-Fi. Call lifecycle and control methods from one owner task.
stop() only signals the worker and wakes it from a pacing wait, so it never blocks the owner loop. Keep calling loop() after stop(): it reaps the worker once that worker has suspended after leaving its send. Deleting it while it may be inside lwIP, or while vTaskSuspend is still running on another core, can leave the stack locked or corrupt the scheduler. A worker that has not exited within 2 s is logged, and loop() keeps waiting; after 30 s, consume\_stop\_timeout() is true once. If that worker exits before the flag is read, the timeout is dropped. The radio is free to reconfigure once is\_quiescent() is true. Destroying the generator waits until its worker has exited, so keep one generator alive across sensing restarts. A start() made while the previous worker is still exiting returns true and launches the new worker from a later loop(), unless hold\_pending\_restart() is set. If that launch fails, consume\_start\_failure() is true and is\_running() turns false.
[`espectre::TrafficGeneratorManager`](#classespectre_1_1_traffic_generator_manager)
[`espectre`](#namespaceespectre)
<a id="udp__datagram__socket_8h"></a>
## udp\_datagram\_socket.h
```cpp
#include <cstddef>
```
```cpp
#include <cstdint>
```
[`espectre::UdpDatagramPeer`](#structespectre_1_1_udp_datagram_peer)
[`espectre::IUdpDatagramSocket`](#classespectre_1_1_i_udp_datagram_socket)
[`espectre`](#namespaceespectre)
<a id="wifi__band__helpers_8h"></a>
## wifi\_band\_helpers.h
```cpp
#include <sdkconfig.h>
```
```cpp
#include <runtime/runtime_config.h>
```
[`espectre`](#namespaceespectre)
<a id="wifi__band__helpers_8h_1ae6a8d194706e2fb61b9b2eca0485388e"></a>
### `ESPECTRE_WIFI_DUAL_BAND`
```cpp
#define ESPECTRE_WIFI_DUAL_BAND 0
```
1 when the target radio supports 5 GHz, otherwise 0.
<a id="wifi__bssid__pin__service_8h"></a>
## wifi\_bssid\_pin\_service.h
```cpp
#include <cstdint>
```
```cpp
#include <functional>
```
```cpp
#include <string>
```
```cpp
#include <esp_err.h>
```
[`espectre::WifiBssidPinStationState`](#structespectre_1_1_wifi_bssid_pin_station_state)
[`espectre::WifiBssidPinServiceConfig`](#structespectre_1_1_wifi_bssid_pin_service_config)
[`espectre::WifiBssidPinService`](#classespectre_1_1_wifi_bssid_pin_service)
[`espectre`](#namespaceespectre)
<a id="wifi__lifecycle_8h"></a>
## wifi\_lifecycle.h
```cpp
#include <atomic>
```
```cpp
#include <cstdint>
```
```cpp
#include <esp_event.h>
```
```cpp
#include <esp_err.h>
```
```cpp
#include <esp_netif.h>
```
```cpp
#include <esp_wifi.h>
```
```cpp
#include <functional>
```
```cpp
#include <runtime/pending_queue.h>
```
```cpp
#include <runtime/runtime_config.h>
```
[`espectre::WiFiLifecycleManager`](#classespectre_1_1_wi_fi_lifecycle_manager)
[`espectre`](#namespaceespectre)
<a id="wifi__provisioning__service_8h"></a>
## wifi\_provisioning\_service.h
```cpp
#include <cstdint>
```
```cpp
#include <functional>
```
```cpp
#include <string>
```
```cpp
#include <device_config_store.h>
```
```cpp
#include <esp_err.h>
```
```cpp
#include <standalone_wifi_service.h>
```
[`espectre::WifiProvisioningDefaults`](#structespectre_1_1_wifi_provisioning_defaults)
[`espectre::WifiProvisioningService`](#classespectre_1_1_wifi_provisioning_service)
[`espectre`](#namespaceespectre)
idf.py add-dependency "francescopace/espectre^3.0.0-rc3"