The Proximity Ranging cluster enables the configuration of proximity ranging sessions and reporting of proximity ranging data between Matter devices using various technologies (BLE Beacon RSSI, Bluetooth Channel Sounding, Wi-Fi USD, UWB).
This directory contains a code-driven C++ implementation of the Matter Proximity Ranging cluster server (cluster ID 0x0433). The implementation follows the DefaultServerCluster pattern with a Config + Builder API for feature configuration and CodegenIntegration for ZAP-based deployments. All technology-specific runtime operations are delegated to a ProximityRangingDriver set via SetDriver().
The cluster handles:
The application is responsible for:
Config builders)ProximityRangingDriver interface for runtime behavior┌─────────────────────────────────────────────────────────────┐
│ ProximityRangingCluster (SDK, per-endpoint) │
│ - ReadAttribute, InvokeCommand, Events │
│ - SetDriver(ProximityRangingDriver *) │
└──────────────────────────┬──────────────────────────────────┘
│ ProximityRangingDriver interface
┌──────────────────────────▼──────────────────────────────────┐
│ DefaultProximityRangingDriver (example, per-endpoint) │
│ - Routes to RangingTechnologyController │
│ - Forwards callbacks to cluster │
└──────────────────────────┬──────────────────────────────────┘
│ RangingTechnologyController::Listener
┌──────────────────────────▼──────────────────────────────────┐
│ RangingTechnologyController (example, shared) │
│ - Routes sessions to adapters by technology │
│ - Multi-listener support for multiple endpoints │
└──────────┬────────────────────────────────┬─────────────────┘
│ │
┌──────────▼───────────┐ ┌──────────────▼─────────────────┐
│ BleRssiRangingAdapter│ │ (Future: WiFi/UWB adapters) │
│ - Encode/Decode │ │ │
│ - Platform subclass│ │ │
└──────────────────────┘ └────────────────────────────────┘
The cluster supports the following optional features, configured at construction time via Config::WithFeatures():
Feature::kWiFiUsdProximityDetection — enables ranging based on Wi-Fi USD and the WiFiDevIK attribute.Feature::kBluetoothChannelSounding — enables ranging based on Bluetooth Channel Sounding and the BLTDevIK, BLTCSSecurityLevel, and BLTCSModeCapability attributes.Feature::kBleBeaconRssi — enables ranging based on BLE Beacon RSSI and the BLEDeviceId attribute.Feature::kUwbRanging — enables ranging based on UWB.WithFeatures() sets the feature bits and marks the mandatory associated attributes as present. At least one feature must be enabled.
The cluster uses CodegenIntegration.cpp to bridge between ZAP-generated endpoint configuration and the code-driven cluster. The framework calls MatterProximityRangingClusterInitCallback which registers the cluster via LazyRegisteredServerCluster. The bridge reads the feature map from ember attribute storage and passes it directly to Config::WithFeatures():
// Inside CodegenIntegration.cpp — CreateRegistration() ProximityRangingCluster::Config config(endpointId); config.WithFeatures(BitMask<Feature>(featureMap)); gServers[idx].Create(config);
The application then calls FindClusterOnEndpoint() to get the cluster instance and set the driver:
#include <app/clusters/proximity-ranging-server/CodegenIntegration.h> auto * cluster = ProximityRanging::FindClusterOnEndpoint(endpointId); if (cluster != nullptr) { cluster->SetDriver(&myDriver); }
The all-devices-app demonstrates the recommended integration pattern where platform-specific code owns the ranging infrastructure.
The cluster is constructed with a Config that declares supported features. In the CodeDriven path, the application iterates its adapters to build the feature mask, then passes it to Config::WithFeatures():
BitMask<ProximityRanging::Feature> features; for (auto * adapter : adapters) { switch (adapter->GetTechnology()) { case RangingTechEnum::kBluetoothChannelSounding: features.Set(Feature::kBluetoothChannelSounding); break; case RangingTechEnum::kWiFiRoundTripTimeRanging: case RangingTechEnum::kWiFiNextGenerationRanging: features.Set(Feature::kWiFiUsdProximityDetection); break; case RangingTechEnum::kBLEBeaconRSSIRanging: features.Set(Feature::kBleBeaconRssi); break; default: break; } } mCluster.Create(endpoint, ProximityRanging::ProximityRangingCluster::Config().WithFeatures(features)); mCluster.Cluster().SetDriver(&myDriver);
Each platform (POSIX, ESP32) has a DeviceFactoryPlatformOverride that owns the controller, driver, and adapter as statics:
// DeviceFactoryPlatformOverride.cpp namespace { using namespace chip::app::Clusters::ProximityRanging; DarwinBleRssiRangingAdapter sBleAdapter; RangingTechnologyController sRangingController; DefaultProximityRangingDriver sRangingDriver{ sRangingController }; } // namespace void RegisterDeviceFactoryOverrides(TimerDelegate & timerDelegate, PersistentStorageDelegate * storageDelegate) { sBleAdapter.Init(storageDelegate); sRangingController.RegisterAdapter(sBleAdapter); DeviceFactory::GetInstance().RegisterCreator("proximity-ranger", [&timerDelegate]() { return std::make_unique<ProximityRangerDevice>(ProximityRangerDevice::Context{ .timerDelegate = timerDelegate, .driver = sRangingDriver, }); }); }
Platform adapters inherit from BleRssiRangingAdapter (which provides encode/decode and technology identification) and implement session management:
class DarwinBleRssiRangingAdapter : public PosixBleRssiRangingAdapter { public: ResultCodeEnum StartSession(uint8_t sessionId, const StartRangingRequest::DecodableType & request) override { AddSession(sessionId); // Start platform BLE advertising/scanning return ResultCodeEnum::kAccepted; } CHIP_ERROR StopSession(uint8_t sessionId) override { VerifyOrReturnError(RemoveSession(sessionId), CHIP_ERROR_NOT_FOUND); // Stop platform BLE if no sessions remain return CHIP_NO_ERROR; } };
The DefaultProximityRangingDriver connects to the controller via AddListener/RemoveListener:
Init(): Stores the cluster callback, adds itself as a controller listenerShutdown(): Removes itself as a listener, nulls the callbackThe controller and adapters are static objects with app lifetime. The controller's destruction calls StopAllSessions() on all adapters during program exit.
| Method | Description |
|---|---|
Init(callback) | Store callback, register as listener |
Shutdown() | Remove as listener, null callback |
HandleStartRanging() | Start a ranging session (synchronous) |
HandleStopRanging() | Stop a ranging session (synchronous) |
GetRangingCapabilities() | Encode the list of supported capabilities |
GetActiveSessionIds() | Return active session IDs (for session ID generation) |
GetBleRbcConfig() | Return BleRbcConfig (optional, BLERBC feature) |
GetWiFiUsdConfig() | Return WiFiUsdConfig (optional, WFUSDPD feature) |
GetBltcsConfig() | Return BltcsConfig (optional, BLTCS feature) |
Adapters can notify the cluster when attributes change (e.g., BLE Device ID rotation). The notification chain is:
Adapter: mCallback->OnAttributeChanged(BLEDeviceID::Id)
→ Controller: broadcasts to all listeners
→ Driver: mCallback->OnAttributeChanged(attributeId)
→ Cluster: NotifyAttributeChanged(attributeId) → subscription reports
StartRangingRequest and StopRangingRequest are handled synchronously:
Client Cluster Driver/Controller/Adapter │ │ │ ├─ StartRangingRequest ──►│ │ │ ├─ GenerateSessionId() ────►│ (GetActiveSessionIds) │ ├─ HandleStartRanging() ───►│ │ │◄── ResultCodeEnum ────────┤ │◄─ StartRangingResponse ─┤ │
Callback::OnMeasurementData().Callback::OnSessionStopped().The BleRssiRangingAdapter provides static encode/decode methods for the proximity ranging BLE advertisement payload (ChipBLEProximityRangingIdentificationInfo, 21 bytes):
BleRssiRangingAdapter::EncodeBeaconPayload(bleDeviceId, msgCounter, txPower, sessionKey, outPayload); BleRssiRangingAdapter::DecodeBeaconPayload(payload, candidateId, sessionKey);
The BLE Device ID is obfuscated in the beacon using HMAC (not yet implemented; currently encoded in plain form).
The BleRssiRangingAdapter::Init(PersistentStorageDelegate *) loads or generates the BLE Device ID and persists it under key "g/pr/bledevid". This ensures the device maintains a stable identity across reboots.
Multiple endpoints can share a single RangingTechnologyController and adapter set. Each endpoint has its own or can share the DefaultProximityRangingDriver which registers as a listener on the shared controller. All listeners receive session events and attribute change notifications.