Skip to content

v3.1.0 - Matter controller compatibility and external traffic sources

Latest

Choose a tag to compare

@github-actions github-actions released this 01 Nov 20:53

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.
  • ./espectre collect --detector high_accuracy works again (#203).
  • ./espectre devices finds 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 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 (#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_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.