ESPectre 3.1 makes Matter sensors work with more controllers and adds new ways to feed a sensor with traffic: another ESPectre device, multicast ping, or a standalone Docker service. It adds to the 3.0 API and SDK; the few changes existing code needs are listed under Upgrading from 3.0.0.
Highlights
- Matter sensors are validated with Google Home, Apple Home, and Home Assistant on ESP32-S3: commissioning, occupancy updates, and an automation trigger. See Matter controller compatibility.
- Two-device sensing:
wifi_rawcan send its Null Data frames to another sensor inexternalmode, which measures them directly. See the two-device placement guide. - Multicast ping is the new recommended external source. See external sources.
- A Docker image runs the traffic generator with a web UI, without Home Assistant OS. See the Docker image guide.
- New
csi_sample_spacingsetting for congested channels.
Sensing and CSI
wifi_rawis stable on supported chips. It is not available on ESP32-C6; see compatibility limits.traffic_generator_target_macsets thewifi_rawdestination. The default,auto, follows the associated AP across reconnects and BSSID pin changes. A unicast MAC sends direct MCS0 Null Data to another sensor inexternalmode on the same channel: HT20 on 2.4 GHz, and VHT20 on C5 at 5 GHz. The sender keeps LLTF sensing. Set it in ESPHome YAML,CONFIG_ESPECTRE_TRAFFIC_GENERATOR_TARGET_MAC, the SDK,update_sensing, or Monitor → Advanced sensing settings; see traffic destination.- Discovery includes the optional station
mac_address. The Monitor's Destination MAC menu offers Automatic (AP) and the sensors it finds, and keeps a configured destination that is not found. externalmode accepts direct non-QoS Null Data and unencrypted unicast ESP-NOW v1/v2 frames, subject to the usual CSI quality and capture-profile checks. Promiscuous mode stays off. A third-party Null Data sender at MCS0 must set HT20 bandwidth and a wildcard BSSID, and append two zero padding bytes; see external sources. ESP32-C6 receives valid HT20 CSI from padded Null Data and unicast ESP-NOW. See the hardware validation summary.externalmode accepts ICMP Echo Requests on the configured multicast group, and the firmware answers them. That reply is the uplink UDP markers lack: without it, an empty room can show motion. The generator script, the Home Assistant app, and the Docker image can send Echo Requests to device addresses or to the group. The script and the app keep UDP as the default, so existing setups and./espectre collectare unchanged.csi_sample_spacingsets how close admitted CSI packets can be.half_slot, the default, keeps them at least half a slot apart;distinctneeds only distinct timestamps. On congested channels where packets arrive in back-to-back pairs,distinctlets the earlier packet fill the free slot before it. It applies to every traffic source. Set it in ESPHome YAML, the CSI Packet Spacing select in Home Assistant,CONFIG_ESPECTRE_CSI_SAMPLE_SPACING_DISTINCT, the SDK,update_sensing, or Monitor → Advanced sensing settings. Micro-ESPectre accepts the same rule.
Fixes
- CSI admission no longer stalls after a long silence. The 32-bit Wi-Fi RX clock wraps every 71.6 minutes, so after more than 35.8 minutes without CSI, for example in
externalmode with no sender, new packets were rejected for up to 36 more minutes. Sensing now resumes about two seconds after traffic returns, also in Micro-ESPectre. - CSI occupancy drops to 0% once no CSI has arrived for one detector window, in diagnostics, the periodic log, and the Home Assistant CSI Temporal Occupancy entity. Before, a device whose traffic stopped kept its last value.
- A closed or slow USB Serial/JTAG monitor no longer stalls sensing: the console drops whole log lines instead of waiting, and retries Improv responses. ESP32-C6 is no longer flooded by USB interrupts.
- Monitor Demo mode applies the motion-on and motion-off reading counts to state changes and chart highlighting, and keeps these settings across tools.
./espectre collect --detector high_accuracyworks again (#203)../espectre devicesfinds devices on another VLAN behind an mDNS proxy, such as the UniFi gateway's (#205).- The SDK Wi-Fi example waits for traffic to leave the radio before it changes the station or scans, checks the
set_config()result, and answers ping on the multicast group.
Matter
- Basic Information reports a real
SoftwareVersion, which grows with each release; it was 0. It also reports aSerialNumberderived from the chip's base MAC. - Occupancy Sensing adds
HoldTimeandHoldTimeLimits; without them, Google Home showed the sensor offline. Occupancy still clears 1 second after the detector reports idle. A controller can set up to 300 seconds, kept across reboots. - Test Event Triggers, which esp-matter enabled with a public key, are off.
- Product builds can read onboarding data, the DAC, and the serial number from factory partitions. The partition table reserves
esp_secure_certandfctrywithout moving existing partitions, so updates keep fabrics and onboarding codes. See building a certified product and Google Home with community images.
Tools and integrations
ghcr.io/francescopace/espectre-traffic-generatorruns the external traffic generator next to Home Assistant Container or without Home Assistant. Its web UI, protected by a sign-in token, sets the same options as the Home Assistant app, starts and stops traffic, and shows the send rate, send errors, and ping replies. It finds devices by mDNS or IPv4 address, shows their traffic diagnostics, and changes their traffic source and CSI sample spacing over Direct HTTP, one device or several at once. It sends ping to the multicast group by default. Images are published foramd64andarm64.- Home Assistant app 0.4.0: a Traffic source picker replaces the External and Internal buttons and lists every source the device offers, also for bulk changes (#191); Previous internal source keeps the old Internal behavior. After a bulk change, only failed or unconfirmed devices stay selected, so one click retries them (#193). A Packet spacing column switches devices between
half_slotanddistinct, and Traffic type selects ping or UDP. - The performance report lists selection and holdout separately, adds time-based coverage, raw and filtered recall, and per-recording quiet alarm rates, and hashes the model files. New model exports record their training data and settings.
- The website's USB installer is built with esbuild instead of Rollup, which drops
deepmergeand its unpatched advisory (GHSA-gcqx-w48m-w2h4). - Official firmware builds use ESPHome 2026.10.0, ESP-IDF 5.5.6, and MicroPython 1.29.0. ESPHome configurations still require 2026.7.0 or later.
SDK
The additions are source-compatible, except as listed under Upgrading from 3.0.0:
RuntimeFrontendControlleraddsset_traffic_generator_target_mac()andset_csi_sample_spacing().RuntimeConfig,RuntimeControlUpdate, andRuntimeCapabilitiesgain matching fields, with validation and name helpers; see the API reference.ICsiTrafficGenerator::set_target_mac()has a default implementation that accepts onlyauto.FrontendCommandEngine::execute()takes the destination and spacing callbacks as optional trailing parameters.build_frontend_ha_discovery_message()andbuild_frontend_ha_discovery_messages()takesupports_csi_sample_spacingthe same way.TemporalCsiSamplertakes the spacing rule as an optional third constructor argument and addsset_spacing()andspacing().temporal_minimum_sample_spacing_us()has an overload with the rule.- The core SDK adds
WrappingTimestampOrder, which holds the RX clock wrap rule. read_direct_station_mac_address()andPeerDiscoveryCandidate::mac_addressexpose the discovery MAC.- Direct accepts
espressif/mdns1.12 to 1.14 instead of exactly 1.12.0, so it resolves alongside ESPHome's mDNS 1.14.0. RuntimeConfigErrorandEspectreDirectMethodgain two values each.- Devices advertise
features.traffic_generator_target_macandfeatures.csi_sample_spacing. Direct and MQTT share validation, state, and persistence for both settings.
Upgrading from 3.0.0
- Add the new cases to exhaustive
switchstatements onRuntimeConfigErrorandEspectreDirectMethod. - New fields sit in the middle of
RuntimeConfig,EspectreDeviceInfo,EspectreCommand, andFrontendHaMqttSettings. Positional brace initialization must follow the new order; designated initializers and member assignment are unaffected. - A custom
ICsiTrafficGeneratormust implementset_target_mac()to use a unicastwifi_rawdestination. Without it, raw traffic to that destination does not start. - Scripts that call the Home Assistant app's
/api/actionmust sendmodeinstead ofaction. - Update both devices of a
wifi_rawpair: 3.0.0 receivers ignore direct Null Data. - If an external UDP source shows motion in an empty room, switch it to ping.
- SDK firmware that should answer ping on the multicast group needs
CONFIG_LWIP_MULTICAST_PING=y; see the recommended project configuration.