You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
v3.1.0 - Matter controller compatibility and external traffic sources
#213
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_raw can send its Null Data frames to another sensor in external mode, 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_spacing setting for congested channels.
Sensing and CSI
wifi_raw is stable on supported chips. It is not available on ESP32-C6; see compatibility limits.
traffic_generator_target_mac sets the wifi_raw destination. The default, auto, follows the associated AP across reconnects and BSSID pin changes. A unicast MAC sends direct MCS0 Null Data to another sensor in external mode 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.
external mode 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.
external mode 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 collect are unchanged.
csi_sample_spacing sets how close admitted CSI packets can be. half_slot, the default, keeps them at least half a slot apart; distinct needs only distinct timestamps. On congested channels where packets arrive in back-to-back pairs, distinct lets 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 external mode 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.
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 a SerialNumber derived from the chip's base MAC.
Occupancy Sensing adds HoldTime and HoldTimeLimits; 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_cert and fctry without 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-generator runs 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 for amd64 and arm64.
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 ([FEATURE] wifi_raw as an option in the App #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 ([BUG] Home Assistant app handling of error messages #193). A Packet spacing column switches devices between half_slot and distinct, 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 deepmerge and 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:
RuntimeFrontendController adds set_traffic_generator_target_mac() and set_csi_sample_spacing(). RuntimeConfig, RuntimeControlUpdate, and RuntimeCapabilities gain matching fields, with validation and name helpers; see the API reference.
ICsiTrafficGenerator::set_target_mac() has a default implementation that accepts only auto.
FrontendCommandEngine::execute() takes the destination and spacing callbacks as optional trailing parameters. build_frontend_ha_discovery_message() and build_frontend_ha_discovery_messages() take supports_csi_sample_spacing the same way.
TemporalCsiSampler takes the spacing rule as an optional third constructor argument and adds set_spacing() and spacing(). 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() and PeerDiscoveryCandidate::mac_address expose the discovery MAC.
Direct accepts espressif/mdns 1.12 to 1.14 instead of exactly 1.12.0, so it resolves alongside ESPHome's mDNS 1.14.0.
RuntimeConfigError and EspectreDirectMethod gain two values each.
Devices advertise features.traffic_generator_target_mac and features.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 switch statements on RuntimeConfigError and EspectreDirectMethod.
New fields sit in the middle of RuntimeConfig, EspectreDeviceInfo, EspectreCommand, and FrontendHaMqttSettings. Positional brace initialization must follow the new order; designated initializers and member assignment are unaffected.
A custom ICsiTrafficGenerator must implement set_target_mac() to use a unicast wifi_raw destination. Without it, raw traffic to that destination does not start.
Scripts that call the Home Assistant app's /api/action must send mode instead of action.
Update both devices of a wifi_raw pair: 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.
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
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
wifi_rawcan send its Null Data frames to another sensor inexternalmode, which measures them directly. See the two-device placement guide.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.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
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../espectre collect --detector high_accuracyworks again ([BUG] ESP32-S3 N32R16V: occupancy stuck at ~50% in all traffic modes (Native 3.0.0) #203)../espectre devicesfinds devices on another VLAN behind an mDNS proxy, such as the UniFi gateway's ([BUG] CLI device discovery fails across VLANs with UniFi mDNS proxy (legacy-unicast replies not relayed) #205).set_config()result, and answers ping on the multicast group.Matter
SoftwareVersion, which grows with each release; it was 0. It also reports aSerialNumberderived from the chip's base MAC.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.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.wifi_rawas an option in the App #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 ([BUG] Home Assistant app handling of error messages #193). A Packet spacing column switches devices betweenhalf_slotanddistinct, and Traffic type selects ping or UDP.deepmergeand its unpatched advisory (GHSA-gcqx-w48m-w2h4).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.WrappingTimestampOrder, which holds the RX clock wrap rule.read_direct_station_mac_address()andPeerDiscoveryCandidate::mac_addressexpose the discovery MAC.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.features.traffic_generator_target_macandfeatures.csi_sample_spacing. Direct and MQTT share validation, state, and persistence for both settings.Upgrading from 3.0.0
switchstatements onRuntimeConfigErrorandEspectreDirectMethod.RuntimeConfig,EspectreDeviceInfo,EspectreCommand, andFrontendHaMqttSettings. Positional brace initialization must follow the new order; designated initializers and member assignment are unaffected.ICsiTrafficGeneratormust implementset_target_mac()to use a unicastwifi_rawdestination. Without it, raw traffic to that destination does not start./api/actionmust sendmodeinstead ofaction.wifi_rawpair: 3.0.0 receivers ignore direct Null Data.CONFIG_LWIP_MULTICAST_PING=y; see the recommended project configuration.This discussion was created from the release v3.1.0 - Matter controller compatibility and external traffic sources.
All reactions