From 48a03630b329d7e5d55d8f1efde5f25e69d18d39 Mon Sep 17 00:00:00 2001
From: Andrei Litvin <andy314@gmail.com>
Date: Tue, 6 Aug 2024 16:48:19 -0400
Subject: [PATCH 01/41] Add extra attributes to the bridged device basic info
 structures, remove nonsense comments

---
 .../src/BridgedDeviceManager.cpp              | 52 +++++++++++++------
 1 file changed, 37 insertions(+), 15 deletions(-)

diff --git a/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDeviceManager.cpp b/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDeviceManager.cpp
index 170b39cd2c94e2..f6f43ea6edd796 100644
--- a/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDeviceManager.cpp
+++ b/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDeviceManager.cpp
@@ -45,8 +45,13 @@ using namespace chip::app::Clusters;
 
 namespace {
 
-constexpr uint8_t kMaxRetries = 10;
-constexpr int kNodeLabelSize  = 32;
+constexpr uint8_t kMaxRetries      = 10;
+constexpr int kNodeLabelSize       = 32;
+constexpr int kUniqueIdSize        = 32;
+constexpr int kVendorNameSize      = 32;
+constexpr int kProductNameSize     = 32;
+constexpr int kHardwareVersionSize = 32;
+constexpr int kSoftwareVersionSize = 32;
 
 // Current ZCL implementation of Struct uses a max-size array of 254 bytes
 constexpr int kDescriptorAttributeArraySize = 254;
@@ -76,27 +81,44 @@ constexpr int kDescriptorAttributeArraySize = 254;
 //   - Bridged Device Basic Information
 //   - Administrator Commissioning
 
+// clang-format off
 // Declare Descriptor cluster attributes
 DECLARE_DYNAMIC_ATTRIBUTE_LIST_BEGIN(descriptorAttrs)
-DECLARE_DYNAMIC_ATTRIBUTE(Descriptor::Attributes::DeviceTypeList::Id, ARRAY, kDescriptorAttributeArraySize, 0), /* device list */
-    DECLARE_DYNAMIC_ATTRIBUTE(Descriptor::Attributes::ServerList::Id, ARRAY, kDescriptorAttributeArraySize, 0), /* server list */
-    DECLARE_DYNAMIC_ATTRIBUTE(Descriptor::Attributes::ClientList::Id, ARRAY, kDescriptorAttributeArraySize, 0), /* client list */
-    DECLARE_DYNAMIC_ATTRIBUTE(Descriptor::Attributes::PartsList::Id, ARRAY, kDescriptorAttributeArraySize, 0),  /* parts list */
-    DECLARE_DYNAMIC_ATTRIBUTE_LIST_END();
+  DECLARE_DYNAMIC_ATTRIBUTE(Descriptor::Attributes::DeviceTypeList::Id, ARRAY, kDescriptorAttributeArraySize, 0), /* device list */
+  DECLARE_DYNAMIC_ATTRIBUTE(Descriptor::Attributes::ServerList::Id, ARRAY, kDescriptorAttributeArraySize, 0), /* server list */
+  DECLARE_DYNAMIC_ATTRIBUTE(Descriptor::Attributes::ClientList::Id, ARRAY, kDescriptorAttributeArraySize, 0), /* client list */
+  DECLARE_DYNAMIC_ATTRIBUTE(Descriptor::Attributes::PartsList::Id, ARRAY, kDescriptorAttributeArraySize, 0),  /* parts list */
+DECLARE_DYNAMIC_ATTRIBUTE_LIST_END();
 
 // Declare Bridged Device Basic Information cluster attributes
 DECLARE_DYNAMIC_ATTRIBUTE_LIST_BEGIN(bridgedDeviceBasicAttrs)
-DECLARE_DYNAMIC_ATTRIBUTE(BridgedDeviceBasicInformation::Attributes::NodeLabel::Id, CHAR_STRING, kNodeLabelSize, 0), /* NodeLabel */
-    DECLARE_DYNAMIC_ATTRIBUTE(BridgedDeviceBasicInformation::Attributes::Reachable::Id, BOOLEAN, 1, 0),              /* Reachable */
-    DECLARE_DYNAMIC_ATTRIBUTE(BridgedDeviceBasicInformation::Attributes::FeatureMap::Id, BITMAP32, 4, 0), /* feature map */
-    DECLARE_DYNAMIC_ATTRIBUTE_LIST_END();
+  // The attributes below are MANDATORY in the Bridged Device Information Cluster
+  DECLARE_DYNAMIC_ATTRIBUTE(BridgedDeviceBasicInformation::Attributes::Reachable::Id, BOOLEAN, 1, 0),
+  DECLARE_DYNAMIC_ATTRIBUTE(BridgedDeviceBasicInformation::Attributes::UniqueID::Id, CHAR_STRING, kUniqueIdSize, 0),
+  DECLARE_DYNAMIC_ATTRIBUTE(BridgedDeviceBasicInformation::Attributes::FeatureMap::Id, BITMAP32, 4, 0),
+
+  // The attributes below are OPTIONAL in the bridged device, however they are MANDATORY in the BasicInformation cluster
+  // so they can always be provided if desired
+  DECLARE_DYNAMIC_ATTRIBUTE(BridgedDeviceBasicInformation::Attributes::VendorName::Id, CHAR_STRING, kVendorNameSize, 0),
+  DECLARE_DYNAMIC_ATTRIBUTE(BridgedDeviceBasicInformation::Attributes::VendorID::Id, INT16U, 2, 0),
+  DECLARE_DYNAMIC_ATTRIBUTE(BridgedDeviceBasicInformation::Attributes::ProductName::Id, CHAR_STRING, kProductNameSize, 0),
+  DECLARE_DYNAMIC_ATTRIBUTE(BridgedDeviceBasicInformation::Attributes::ProductID::Id, INT16U, 2, 0),
+  DECLARE_DYNAMIC_ATTRIBUTE(BridgedDeviceBasicInformation::Attributes::NodeLabel::Id, CHAR_STRING, kNodeLabelSize, 0),
+  DECLARE_DYNAMIC_ATTRIBUTE(BridgedDeviceBasicInformation::Attributes::HardwareVersion::Id, INT16U, 2, 0),
+  DECLARE_DYNAMIC_ATTRIBUTE(BridgedDeviceBasicInformation::Attributes::HardwareVersionString::Id, CHAR_STRING,
+                            kHardwareVersionSize, 0),
+  DECLARE_DYNAMIC_ATTRIBUTE(BridgedDeviceBasicInformation::Attributes::SoftwareVersion::Id, INT16U, 2, 0),
+  DECLARE_DYNAMIC_ATTRIBUTE(BridgedDeviceBasicInformation::Attributes::SoftwareVersionString::Id, CHAR_STRING,
+                            kSoftwareVersionSize, 0),
+DECLARE_DYNAMIC_ATTRIBUTE_LIST_END();
 
 // Declare Administrator Commissioning cluster attributes
 DECLARE_DYNAMIC_ATTRIBUTE_LIST_BEGIN(AdministratorCommissioningAttrs)
-DECLARE_DYNAMIC_ATTRIBUTE(AdministratorCommissioning::Attributes::WindowStatus::Id, ENUM8, 1, 0),              /* NodeLabel */
-    DECLARE_DYNAMIC_ATTRIBUTE(AdministratorCommissioning::Attributes::AdminFabricIndex::Id, FABRIC_IDX, 1, 0), /* Reachable */
-    DECLARE_DYNAMIC_ATTRIBUTE(AdministratorCommissioning::Attributes::AdminVendorId::Id, VENDOR_ID, 2, 0),     /* Reachable */
-    DECLARE_DYNAMIC_ATTRIBUTE_LIST_END();
+  DECLARE_DYNAMIC_ATTRIBUTE(AdministratorCommissioning::Attributes::WindowStatus::Id, ENUM8, 1, 0),
+  DECLARE_DYNAMIC_ATTRIBUTE(AdministratorCommissioning::Attributes::AdminFabricIndex::Id, FABRIC_IDX, 1, 0),
+  DECLARE_DYNAMIC_ATTRIBUTE(AdministratorCommissioning::Attributes::AdminVendorId::Id, VENDOR_ID, 2, 0),
+DECLARE_DYNAMIC_ATTRIBUTE_LIST_END();
+// clang-format on
 
 constexpr CommandId administratorCommissioningCommands[] = {
     app::Clusters::AdministratorCommissioning::Commands::OpenCommissioningWindow::Id,

From c37cd56e3a9dad5f8daad39b09a8de00771aa26b Mon Sep 17 00:00:00 2001
From: Andrei Litvin <andy314@gmail.com>
Date: Wed, 7 Aug 2024 08:37:08 -0400
Subject: [PATCH 02/41] Make use of AAI for BridgedDeviceBasicInformation
 cluster

---
 .../fabric-bridge-common/BUILD.gn             |  3 +-
 .../BridgedDeviceBasicInformationImpl.h       | 32 +++++++
 .../src/BridgedDeviceBasicInformationImpl.cpp | 78 ++++++++++++++++
 .../fabric-bridge-common/src/ZCLCallbacks.cpp | 91 -------------------
 examples/fabric-bridge-app/linux/main.cpp     |  4 +
 5 files changed, 116 insertions(+), 92 deletions(-)
 create mode 100644 examples/fabric-bridge-app/fabric-bridge-common/include/BridgedDeviceBasicInformationImpl.h
 create mode 100644 examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDeviceBasicInformationImpl.cpp
 delete mode 100644 examples/fabric-bridge-app/fabric-bridge-common/src/ZCLCallbacks.cpp

diff --git a/examples/fabric-bridge-app/fabric-bridge-common/BUILD.gn b/examples/fabric-bridge-app/fabric-bridge-common/BUILD.gn
index 10cb48c31c584e..855bb48f77a53e 100644
--- a/examples/fabric-bridge-app/fabric-bridge-common/BUILD.gn
+++ b/examples/fabric-bridge-app/fabric-bridge-common/BUILD.gn
@@ -29,12 +29,13 @@ source_set("fabric-bridge-lib") {
   public_configs = [ ":config" ]
 
   sources = [
+    "include/BridgedDeviceBasicInformationImpl.h",
     "include/BridgedDevice.h",
     "include/BridgedDeviceManager.h",
     "include/CHIPProjectAppConfig.h",
+    "src/BridgedDeviceBasicInformationImpl.cpp",
     "src/BridgedDevice.cpp",
     "src/BridgedDeviceManager.cpp",
-    "src/ZCLCallbacks.cpp",
   ]
 
   deps = [
diff --git a/examples/fabric-bridge-app/fabric-bridge-common/include/BridgedDeviceBasicInformationImpl.h b/examples/fabric-bridge-app/fabric-bridge-common/include/BridgedDeviceBasicInformationImpl.h
new file mode 100644
index 00000000000000..23403438ab2be8
--- /dev/null
+++ b/examples/fabric-bridge-app/fabric-bridge-common/include/BridgedDeviceBasicInformationImpl.h
@@ -0,0 +1,32 @@
+/*
+ *    Copyright (c) 2024 Project CHIP Authors
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+#pragma once
+
+#include <app-common/zap-generated/ids/Clusters.h>
+#include <app/AttributeAccessInterface.h>
+
+class BridgedDeviceBasicInformationImpl : public chip::app::AttributeAccessInterface
+{
+public:
+    BridgedDeviceBasicInformationImpl() :
+        chip::app::AttributeAccessInterface(chip::NullOptional /* endpointId */,
+                                            chip::app::Clusters::BridgedDeviceBasicInformation::Id)
+    {}
+
+    // AttributeAccessInterface implementation
+    CHIP_ERROR Read(const chip::app::ConcreteReadAttributePath & path, chip::app::AttributeValueEncoder & encoder) override;
+    CHIP_ERROR Write(const chip::app::ConcreteDataAttributePath & path, chip::app::AttributeValueDecoder & decoder) override;
+};
diff --git a/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDeviceBasicInformationImpl.cpp b/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDeviceBasicInformationImpl.cpp
new file mode 100644
index 00000000000000..cf35230dc1e155
--- /dev/null
+++ b/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDeviceBasicInformationImpl.cpp
@@ -0,0 +1,78 @@
+/*
+ *    Copyright (c) 2024 Project CHIP Authors
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+#include "BridgedDeviceBasicInformationImpl.h"
+
+#include "BridgedDeviceManager.h"
+
+#include <app-common/zap-generated/cluster-objects.h>
+#include <app-common/zap-generated/ids/Attributes.h>
+#include <app-common/zap-generated/ids/Clusters.h>
+
+#include <app/AttributeAccessInterfaceRegistry.h>
+
+static constexpr unsigned kBridgedDeviceBasicInformationClusterRevision = 2;
+static constexpr unsigned kBridgedDeviceBasicInformationFeatureMap      = 0;
+
+using namespace ::chip;
+using namespace ::chip::app;
+using namespace ::chip::app::Clusters;
+
+CHIP_ERROR BridgedDeviceBasicInformationImpl::Read(const ConcreteReadAttributePath & path, AttributeValueEncoder & encoder)
+{
+    // Registration is done for the bridged device basic information only
+    VerifyOrDie(path.mClusterId == app::Clusters::BridgedDeviceBasicInformation::Id);
+
+    BridgedDevice * dev = BridgeDeviceMgr().GetDevice(path.mEndpointId);
+    VerifyOrReturnError(dev != nullptr, CHIP_ERROR_NOT_FOUND);
+
+    switch (path.mAttributeId)
+    {
+    case BasicInformation::Attributes::Reachable::Id:
+        encoder.Encode(dev->IsReachable());
+        break;
+    case BasicInformation::Attributes::NodeLabel::Id:
+        encoder.Encode(CharSpan::fromCharString(dev->GetName()));
+        break;
+    case BasicInformation::Attributes::ClusterRevision::Id:
+        encoder.Encode(kBridgedDeviceBasicInformationClusterRevision);
+        break;
+    case BasicInformation::Attributes::FeatureMap::Id:
+        encoder.Encode(kBridgedDeviceBasicInformationFeatureMap);
+        break;
+    default:
+        return CHIP_ERROR_INVALID_ARGUMENT;
+    }
+    return CHIP_NO_ERROR;
+}
+
+CHIP_ERROR BridgedDeviceBasicInformationImpl::Write(const ConcreteDataAttributePath & path, AttributeValueDecoder & decoder)
+{
+    VerifyOrDie(path.mClusterId == app::Clusters::BridgedDeviceBasicInformation::Id);
+
+    BridgedDevice * dev = BridgeDeviceMgr().GetDevice(path.mEndpointId);
+    VerifyOrReturnError(dev != nullptr, CHIP_ERROR_NOT_FOUND);
+
+    if (!dev->IsReachable())
+    {
+        return CHIP_ERROR_NOT_CONNECTED;
+    }
+
+    ChipLogProgress(NotSpecified, "Bridged device basic information attempt to write attribute: ep=%d", path.mAttributeId);
+
+    // nothing writable right now ...
+
+    return CHIP_ERROR_INVALID_ARGUMENT;
+}
diff --git a/examples/fabric-bridge-app/fabric-bridge-common/src/ZCLCallbacks.cpp b/examples/fabric-bridge-app/fabric-bridge-common/src/ZCLCallbacks.cpp
deleted file mode 100644
index 9a0467be4e27e8..00000000000000
--- a/examples/fabric-bridge-app/fabric-bridge-common/src/ZCLCallbacks.cpp
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- *
- *    Copyright (c) 2024 Project CHIP Authors
- *
- *    Licensed under the Apache License, Version 2.0 (the "License");
- *    you may not use this file except in compliance with the License.
- *    You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- *    Unless required by applicable law or agreed to in writing, software
- *    distributed under the License is distributed on an "AS IS" BASIS,
- *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *    See the License for the specific language governing permissions and
- *    limitations under the License.
- */
-
-#include "BridgedDeviceManager.h"
-
-#include <app-common/zap-generated/cluster-objects.h>
-#include <app-common/zap-generated/ids/Attributes.h>
-#include <app-common/zap-generated/ids/Clusters.h>
-#include <lib/support/ZclString.h>
-
-using namespace ::chip;
-using namespace ::chip::app::Clusters;
-
-#define ZCL_DESCRIPTOR_CLUSTER_REVISION (1u)
-#define ZCL_BRIDGED_DEVICE_BASIC_INFORMATION_CLUSTER_REVISION (2u)
-#define ZCL_BRIDGED_DEVICE_BASIC_INFORMATION_FEATURE_MAP (0u)
-
-// External attribute read callback function
-Protocols::InteractionModel::Status emberAfExternalAttributeReadCallback(EndpointId endpoint, ClusterId clusterId,
-                                                                         const EmberAfAttributeMetadata * attributeMetadata,
-                                                                         uint8_t * buffer, uint16_t maxReadLength)
-{
-    AttributeId attributeId = attributeMetadata->attributeId;
-
-    BridgedDevice * dev = BridgeDeviceMgr().GetDevice(endpoint);
-    if (dev != nullptr && clusterId == app::Clusters::BridgedDeviceBasicInformation::Id)
-    {
-        using namespace app::Clusters::BridgedDeviceBasicInformation::Attributes;
-        ChipLogProgress(NotSpecified, "HandleReadBridgedDeviceBasicAttribute: attrId=%d, maxReadLength=%d", attributeId,
-                        maxReadLength);
-
-        if ((attributeId == Reachable::Id) && (maxReadLength == 1))
-        {
-            *buffer = dev->IsReachable() ? 1 : 0;
-        }
-        else if ((attributeId == NodeLabel::Id) && (maxReadLength == 32))
-        {
-            MutableByteSpan zclNameSpan(buffer, maxReadLength);
-            MakeZclCharString(zclNameSpan, dev->GetName());
-        }
-        else if ((attributeId == ClusterRevision::Id) && (maxReadLength == 2))
-        {
-            uint16_t rev = ZCL_BRIDGED_DEVICE_BASIC_INFORMATION_CLUSTER_REVISION;
-            memcpy(buffer, &rev, sizeof(rev));
-        }
-        else if ((attributeId == FeatureMap::Id) && (maxReadLength == 4))
-        {
-            uint32_t featureMap = ZCL_BRIDGED_DEVICE_BASIC_INFORMATION_FEATURE_MAP;
-            memcpy(buffer, &featureMap, sizeof(featureMap));
-        }
-        else
-        {
-            return Protocols::InteractionModel::Status::Failure;
-        }
-        return Protocols::InteractionModel::Status::Success;
-    }
-
-    return Protocols::InteractionModel::Status::Failure;
-}
-
-// External attribute write callback function
-Protocols::InteractionModel::Status emberAfExternalAttributeWriteCallback(EndpointId endpoint, ClusterId clusterId,
-                                                                          const EmberAfAttributeMetadata * attributeMetadata,
-                                                                          uint8_t * buffer)
-{
-    uint16_t endpointIndex                  = emberAfGetDynamicIndexFromEndpoint(endpoint);
-    Protocols::InteractionModel::Status ret = Protocols::InteractionModel::Status::Failure;
-
-    BridgedDevice * dev = BridgeDeviceMgr().GetDevice(endpointIndex);
-    if (dev != nullptr && dev->IsReachable())
-    {
-        ChipLogProgress(NotSpecified, "emberAfExternalAttributeWriteCallback: ep=%d, clusterId=%d", endpoint, clusterId);
-        ret = Protocols::InteractionModel::Status::Success;
-    }
-
-    return ret;
-}
diff --git a/examples/fabric-bridge-app/linux/main.cpp b/examples/fabric-bridge-app/linux/main.cpp
index c708b256727520..24ad4aa9a1690c 100644
--- a/examples/fabric-bridge-app/linux/main.cpp
+++ b/examples/fabric-bridge-app/linux/main.cpp
@@ -19,6 +19,7 @@
 #include <AppMain.h>
 
 #include "BridgedDevice.h"
+#include "BridgedDeviceBasicInformationImpl.h"
 #include "BridgedDeviceManager.h"
 #include "CommissionableInit.h"
 
@@ -48,6 +49,8 @@ constexpr uint16_t kPollIntervalMs = 100;
 constexpr uint16_t kRetryIntervalS = 3;
 #endif
 
+BridgedDeviceBasicInformationImpl gBridgedDeviceBasicInformationAttributes;
+
 bool KeyboardHit()
 {
     int bytesWaiting;
@@ -175,6 +178,7 @@ void ApplicationInit()
     ChipLogDetail(NotSpecified, "Fabric-Bridge: ApplicationInit()");
 
     CommandHandlerInterfaceRegistry::RegisterCommandHandler(&gAdministratorCommissioningCommandHandler);
+    registerAttributeAccessOverride(&gBridgedDeviceBasicInformationAttributes);
 
 #if defined(PW_RPC_FABRIC_BRIDGE_SERVICE) && PW_RPC_FABRIC_BRIDGE_SERVICE
     InitRpcServer(kFabricBridgeServerPort);

From 530691d30c1b5948350275d06bfb73e8081bf81d Mon Sep 17 00:00:00 2001
From: "Restyled.io" <commits@restyled.io>
Date: Wed, 7 Aug 2024 12:40:00 +0000
Subject: [PATCH 03/41] Restyled by gn

---
 examples/fabric-bridge-app/fabric-bridge-common/BUILD.gn | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/examples/fabric-bridge-app/fabric-bridge-common/BUILD.gn b/examples/fabric-bridge-app/fabric-bridge-common/BUILD.gn
index 855bb48f77a53e..60bf58115e416f 100644
--- a/examples/fabric-bridge-app/fabric-bridge-common/BUILD.gn
+++ b/examples/fabric-bridge-app/fabric-bridge-common/BUILD.gn
@@ -29,12 +29,12 @@ source_set("fabric-bridge-lib") {
   public_configs = [ ":config" ]
 
   sources = [
-    "include/BridgedDeviceBasicInformationImpl.h",
     "include/BridgedDevice.h",
+    "include/BridgedDeviceBasicInformationImpl.h",
     "include/BridgedDeviceManager.h",
     "include/CHIPProjectAppConfig.h",
-    "src/BridgedDeviceBasicInformationImpl.cpp",
     "src/BridgedDevice.cpp",
+    "src/BridgedDeviceBasicInformationImpl.cpp",
     "src/BridgedDeviceManager.cpp",
   ]
 

From a7240c827c3f45901cf940b652b9749b3a790b8a Mon Sep 17 00:00:00 2001
From: Andrei Litvin <andy314@gmail.com>
Date: Wed, 7 Aug 2024 08:55:04 -0400
Subject: [PATCH 04/41] Fix sizes for software version

---
 .../fabric-bridge-common/src/BridgedDeviceManager.cpp           | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDeviceManager.cpp b/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDeviceManager.cpp
index f6f43ea6edd796..7e78baa7ded548 100644
--- a/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDeviceManager.cpp
+++ b/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDeviceManager.cpp
@@ -107,7 +107,7 @@ DECLARE_DYNAMIC_ATTRIBUTE_LIST_BEGIN(bridgedDeviceBasicAttrs)
   DECLARE_DYNAMIC_ATTRIBUTE(BridgedDeviceBasicInformation::Attributes::HardwareVersion::Id, INT16U, 2, 0),
   DECLARE_DYNAMIC_ATTRIBUTE(BridgedDeviceBasicInformation::Attributes::HardwareVersionString::Id, CHAR_STRING,
                             kHardwareVersionSize, 0),
-  DECLARE_DYNAMIC_ATTRIBUTE(BridgedDeviceBasicInformation::Attributes::SoftwareVersion::Id, INT16U, 2, 0),
+  DECLARE_DYNAMIC_ATTRIBUTE(BridgedDeviceBasicInformation::Attributes::SoftwareVersion::Id, INT32U, 4, 0),
   DECLARE_DYNAMIC_ATTRIBUTE(BridgedDeviceBasicInformation::Attributes::SoftwareVersionString::Id, CHAR_STRING,
                             kSoftwareVersionSize, 0),
 DECLARE_DYNAMIC_ATTRIBUTE_LIST_END();

From eb9585402efa3f8e59cfac662d5aae352e45f1f8 Mon Sep 17 00:00:00 2001
From: Andrei Litvin <andy314@gmail.com>
Date: Wed, 7 Aug 2024 08:55:48 -0400
Subject: [PATCH 05/41] Update the synchronized device proto to have more data
 in it

---
 examples/common/pigweed/BUILD.gn                      |  1 +
 .../pigweed/protos/fabric_bridge_service.options      |  6 ++++++
 .../common/pigweed/protos/fabric_bridge_service.proto | 11 +++++++++++
 3 files changed, 18 insertions(+)
 create mode 100644 examples/common/pigweed/protos/fabric_bridge_service.options

diff --git a/examples/common/pigweed/BUILD.gn b/examples/common/pigweed/BUILD.gn
index 6252f86e637890..a7b7d97da32ba6 100644
--- a/examples/common/pigweed/BUILD.gn
+++ b/examples/common/pigweed/BUILD.gn
@@ -90,6 +90,7 @@ pw_proto_library("fabric_admin_service") {
 
 pw_proto_library("fabric_bridge_service") {
   sources = [ "protos/fabric_bridge_service.proto" ]
+  inputs = [ "protos/fabric_bridge_service.options" ]
   deps = [ "$dir_pw_protobuf:common_protos" ]
   strip_prefix = "protos"
   prefix = "fabric_bridge_service"
diff --git a/examples/common/pigweed/protos/fabric_bridge_service.options b/examples/common/pigweed/protos/fabric_bridge_service.options
new file mode 100644
index 00000000000000..d5ad57e57d6447
--- /dev/null
+++ b/examples/common/pigweed/protos/fabric_bridge_service.options
@@ -0,0 +1,6 @@
+chip.rpc.SynchronizedDevice.unique_id max_size:32
+chip.rpc.SynchronizedDevice.vendor_name max_size:32
+chip.rpc.SynchronizedDevice.product_name max_size:32
+chip.rpc.SynchronizedDevice.node_label max_size:32
+chip.rpc.SynchronizedDevice.hardware_version_string max_size:32
+chip.rpc.SynchronizedDevice.software_version_string max_size:32
diff --git a/examples/common/pigweed/protos/fabric_bridge_service.proto b/examples/common/pigweed/protos/fabric_bridge_service.proto
index 10e5ccf888583d..120bfdb88ccfcc 100644
--- a/examples/common/pigweed/protos/fabric_bridge_service.proto
+++ b/examples/common/pigweed/protos/fabric_bridge_service.proto
@@ -7,6 +7,17 @@ package chip.rpc;
 // Define the message for a synchronized end device with necessary fields
 message SynchronizedDevice {
   uint64 node_id = 1;
+
+  string unique_id = 2;
+  string vendor_name = 3;
+  uint32 vendor_id = 4;
+  string product_name = 5;
+  uint32 product_id = 6;
+  string node_label = 7;
+  uint32 hardware_version = 8;
+  string hardware_version_string = 9;
+  uint32 software_version = 10;
+  string software_version_string = 11;
 }
 
 service FabricBridge {

From 1356b1f44fd1652436979b682412b55cfa87aae6 Mon Sep 17 00:00:00 2001
From: Andrei Litvin <andy314@gmail.com>
Date: Wed, 7 Aug 2024 09:10:04 -0400
Subject: [PATCH 06/41] Switch to unique ptr in the registry, making sure
 memory management works (fixed memory leak on remove device)

---
 .../include/BridgedDeviceManager.h            |  9 ++-
 .../src/BridgedDeviceManager.cpp              | 76 +++++++++----------
 .../fabric-bridge-app/linux/RpcServer.cpp     |  7 +-
 3 files changed, 45 insertions(+), 47 deletions(-)

diff --git a/examples/fabric-bridge-app/fabric-bridge-common/include/BridgedDeviceManager.h b/examples/fabric-bridge-app/fabric-bridge-common/include/BridgedDeviceManager.h
index 8411ec656f9803..134ab308f000b2 100644
--- a/examples/fabric-bridge-app/fabric-bridge-common/include/BridgedDeviceManager.h
+++ b/examples/fabric-bridge-app/fabric-bridge-common/include/BridgedDeviceManager.h
@@ -22,6 +22,8 @@
 
 #include "BridgedDevice.h"
 
+#include <memory>
+
 class BridgedDeviceManager
 {
 public:
@@ -45,9 +47,10 @@ class BridgedDeviceManager
      *
      * @param dev A pointer to the device to be added.
      * @param parentEndpointId The parent endpoint ID. Defaults to an invalid endpoint ID.
-     * @return int The index of the dynamic endpoint if successful, -1 otherwise.
+     * @return int The index of the dynamic endpoint if successful, nullopt otherwise
      */
-    int AddDeviceEndpoint(BridgedDevice * dev, chip::EndpointId parentEndpointId = chip::kInvalidEndpointId);
+    std::optional<unsigned> AddDeviceEndpoint(std::unique_ptr<BridgedDevice> dev,
+                                              chip::EndpointId parentEndpointId = chip::kInvalidEndpointId);
 
     /**
      * @brief Removes a device from a dynamic endpoint.
@@ -104,7 +107,7 @@ class BridgedDeviceManager
 
     chip::EndpointId mCurrentEndpointId;
     chip::EndpointId mFirstDynamicEndpointId;
-    BridgedDevice * mDevices[CHIP_DEVICE_CONFIG_DYNAMIC_ENDPOINT_COUNT + 1];
+    std::unique_ptr<BridgedDevice> mDevices[CHIP_DEVICE_CONFIG_DYNAMIC_ENDPOINT_COUNT + 1];
 };
 
 /**
diff --git a/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDeviceManager.cpp b/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDeviceManager.cpp
index f6f43ea6edd796..4ad555dbdd886a 100644
--- a/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDeviceManager.cpp
+++ b/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDeviceManager.cpp
@@ -33,6 +33,7 @@
 #include <lib/support/ZclString.h>
 
 #include <cstdio>
+#include <optional>
 #include <string>
 
 using namespace chip;
@@ -147,60 +148,55 @@ BridgedDeviceManager BridgedDeviceManager::sInstance;
 
 void BridgedDeviceManager::Init()
 {
-    memset(mDevices, 0, sizeof(mDevices));
     mFirstDynamicEndpointId = static_cast<chip::EndpointId>(
         static_cast<int>(emberAfEndpointFromIndex(static_cast<uint16_t>(emberAfFixedEndpointCount() - 1))) + 1);
     mCurrentEndpointId = mFirstDynamicEndpointId;
 }
 
-int BridgedDeviceManager::AddDeviceEndpoint(BridgedDevice * dev, chip::EndpointId parentEndpointId)
+std::optional<unsigned> BridgedDeviceManager::AddDeviceEndpoint(std::unique_ptr<BridgedDevice> dev,
+                                                                chip::EndpointId parentEndpointId)
 {
-    uint8_t index                                              = 0;
     EmberAfEndpointType * ep                                   = &sBridgedNodeEndpoint;
     const chip::Span<const EmberAfDeviceType> & deviceTypeList = Span<const EmberAfDeviceType>(sBridgedDeviceTypes);
     const chip::Span<chip::DataVersion> & dataVersionStorage   = Span<DataVersion>(sBridgedNodeDataVersions);
 
-    while (index < CHIP_DEVICE_CONFIG_DYNAMIC_ENDPOINT_COUNT)
+    for (unsigned index = 0; index < CHIP_DEVICE_CONFIG_DYNAMIC_ENDPOINT_COUNT; index++)
     {
-        if (nullptr == mDevices[index])
+        if (mDevices[index])
+        {
+            continue;
+        }
+
+        for (int retryCount = 0; retryCount < kMaxRetries; retryCount++)
         {
-            mDevices[index] = dev;
-            CHIP_ERROR err;
-            int retryCount = 0;
-            while (retryCount < kMaxRetries)
+            DeviceLayer::StackLock lock;
+            dev->SetEndpointId(mCurrentEndpointId);
+            dev->SetParentEndpointId(parentEndpointId);
+            CHIP_ERROR err =
+                emberAfSetDynamicEndpoint(index, mCurrentEndpointId, ep, dataVersionStorage, deviceTypeList, parentEndpointId);
+            if (err == CHIP_NO_ERROR)
             {
-                DeviceLayer::StackLock lock;
-                dev->SetEndpointId(mCurrentEndpointId);
-                dev->SetParentEndpointId(parentEndpointId);
-                err =
-                    emberAfSetDynamicEndpoint(index, mCurrentEndpointId, ep, dataVersionStorage, deviceTypeList, parentEndpointId);
-                if (err == CHIP_NO_ERROR)
-                {
-                    ChipLogProgress(NotSpecified,
-                                    "Added device with nodeId=0x" ChipLogFormatX64 " to dynamic endpoint %d (index=%d)",
-                                    ChipLogValueX64(dev->GetNodeId()), mCurrentEndpointId, index);
-                    return index;
-                }
-                if (err != CHIP_ERROR_ENDPOINT_EXISTS)
-                {
-                    mDevices[index] = nullptr;
-                    return -1; // Return error as endpoint addition failed due to an error other than endpoint already exists
-                }
-                // Increment the endpoint ID and handle wrap condition
-                if (++mCurrentEndpointId < mFirstDynamicEndpointId)
-                {
-                    mCurrentEndpointId = mFirstDynamicEndpointId;
-                }
-                retryCount++;
+                ChipLogProgress(NotSpecified, "Added device with nodeId=0x" ChipLogFormatX64 " to dynamic endpoint %d (index=%d)",
+                                ChipLogValueX64(dev->GetNodeId()), mCurrentEndpointId, index);
+                mDevices[index] = std::move(dev);
+                return index;
+            }
+            if (err != CHIP_ERROR_ENDPOINT_EXISTS)
+            {
+                return std::nullopt; // Return error as endpoint addition failed due to an error other than endpoint already exists
+            }
+            // Increment the endpoint ID and handle wrap condition
+            if (++mCurrentEndpointId < mFirstDynamicEndpointId)
+            {
+                mCurrentEndpointId = mFirstDynamicEndpointId;
             }
-            ChipLogError(NotSpecified, "Failed to add dynamic endpoint after %d retries", kMaxRetries);
-            mDevices[index] = nullptr;
-            return -1; // Return error as all retries are exhausted
         }
-        index++;
+        ChipLogError(NotSpecified, "Failed to add dynamic endpoint after %d retries", kMaxRetries);
+        return std::nullopt; // Return error as all retries are exhausted
     }
+
     ChipLogProgress(NotSpecified, "Failed to add dynamic endpoint: No endpoints available!");
-    return -1;
+    return std::nullopt;
 }
 
 int BridgedDeviceManager::RemoveDeviceEndpoint(BridgedDevice * dev)
@@ -208,7 +204,7 @@ int BridgedDeviceManager::RemoveDeviceEndpoint(BridgedDevice * dev)
     uint8_t index = 0;
     while (index < CHIP_DEVICE_CONFIG_DYNAMIC_ENDPOINT_COUNT)
     {
-        if (mDevices[index] == dev)
+        if (mDevices[index].get() == dev)
         {
             DeviceLayer::StackLock lock;
             // Silence complaints about unused ep when progress logging
@@ -229,7 +225,7 @@ BridgedDevice * BridgedDeviceManager::GetDevice(chip::EndpointId endpointId) con
     {
         if (mDevices[index] && mDevices[index]->GetEndpointId() == endpointId)
         {
-            return mDevices[index];
+            return mDevices[index].get();
         }
     }
     return nullptr;
@@ -241,7 +237,7 @@ BridgedDevice * BridgedDeviceManager::GetDeviceByNodeId(chip::NodeId nodeId) con
     {
         if (mDevices[index] && mDevices[index]->GetNodeId() == nodeId)
         {
-            return mDevices[index];
+            return mDevices[index].get();
         }
     }
     return nullptr;
diff --git a/examples/fabric-bridge-app/linux/RpcServer.cpp b/examples/fabric-bridge-app/linux/RpcServer.cpp
index 76fe8f84653d39..20730c3f98071b 100644
--- a/examples/fabric-bridge-app/linux/RpcServer.cpp
+++ b/examples/fabric-bridge-app/linux/RpcServer.cpp
@@ -51,13 +51,12 @@ pw::Status FabricBridge::AddSynchronizedDevice(const chip_rpc_SynchronizedDevice
     NodeId nodeId = request.node_id;
     ChipLogProgress(NotSpecified, "Received AddSynchronizedDevice: " ChipLogFormatX64, ChipLogValueX64(nodeId));
 
-    BridgedDevice * device = new BridgedDevice(nodeId);
+    auto device = std::make_unique<BridgedDevice>(nodeId);
     device->SetReachable(true);
 
-    int result = BridgeDeviceMgr().AddDeviceEndpoint(device, 1);
-    if (result == -1)
+    auto result = BridgeDeviceMgr().AddDeviceEndpoint(std::move(device), 1 /* parentEndpointId */);
+    if (!result.has_value())
     {
-        delete device;
         ChipLogError(NotSpecified, "Failed to add device with nodeId=0x" ChipLogFormatX64, ChipLogValueX64(nodeId));
         return pw::Status::Unknown();
     }

From 3d063059db6499bfbf87f7259ce087298d5fef57 Mon Sep 17 00:00:00 2001
From: Andrei Litvin <andy314@gmail.com>
Date: Wed, 7 Aug 2024 09:12:18 -0400
Subject: [PATCH 07/41] Use more std::optional

---
 .../fabric-bridge-common/include/BridgedDeviceManager.h     | 2 +-
 .../fabric-bridge-common/src/BridgedDeviceManager.cpp       | 6 +++---
 examples/fabric-bridge-app/linux/RpcServer.cpp              | 4 ++--
 3 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/examples/fabric-bridge-app/fabric-bridge-common/include/BridgedDeviceManager.h b/examples/fabric-bridge-app/fabric-bridge-common/include/BridgedDeviceManager.h
index 134ab308f000b2..6c2829a8a4bb38 100644
--- a/examples/fabric-bridge-app/fabric-bridge-common/include/BridgedDeviceManager.h
+++ b/examples/fabric-bridge-app/fabric-bridge-common/include/BridgedDeviceManager.h
@@ -98,7 +98,7 @@ class BridgedDeviceManager
      * @param nodeId The NodeId of the device to be removed.
      * @return int The index of the removed dynamic endpoint if successful, -1 otherwise.
      */
-    int RemoveDeviceByNodeId(chip::NodeId nodeId);
+    std::optional<unsigned> RemoveDeviceByNodeId(chip::NodeId nodeId);
 
 private:
     friend BridgedDeviceManager & BridgeDeviceMgr();
diff --git a/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDeviceManager.cpp b/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDeviceManager.cpp
index 4ad555dbdd886a..10b6055b3d635b 100644
--- a/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDeviceManager.cpp
+++ b/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDeviceManager.cpp
@@ -243,9 +243,9 @@ BridgedDevice * BridgedDeviceManager::GetDeviceByNodeId(chip::NodeId nodeId) con
     return nullptr;
 }
 
-int BridgedDeviceManager::RemoveDeviceByNodeId(chip::NodeId nodeId)
+std::optional<unsigned> BridgedDeviceManager::RemoveDeviceByNodeId(chip::NodeId nodeId)
 {
-    for (uint8_t index = 0; index < CHIP_DEVICE_CONFIG_DYNAMIC_ENDPOINT_COUNT; ++index)
+    for (unsigned index = 0; index < CHIP_DEVICE_CONFIG_DYNAMIC_ENDPOINT_COUNT; ++index)
     {
         if (mDevices[index] && mDevices[index]->GetNodeId() == nodeId)
         {
@@ -257,5 +257,5 @@ int BridgedDeviceManager::RemoveDeviceByNodeId(chip::NodeId nodeId)
             return index;
         }
     }
-    return -1;
+    return std::nullopt;
 }
diff --git a/examples/fabric-bridge-app/linux/RpcServer.cpp b/examples/fabric-bridge-app/linux/RpcServer.cpp
index 20730c3f98071b..b04ec3b3c35187 100644
--- a/examples/fabric-bridge-app/linux/RpcServer.cpp
+++ b/examples/fabric-bridge-app/linux/RpcServer.cpp
@@ -69,8 +69,8 @@ pw::Status FabricBridge::RemoveSynchronizedDevice(const chip_rpc_SynchronizedDev
     NodeId nodeId = request.node_id;
     ChipLogProgress(NotSpecified, "Received RemoveSynchronizedDevice: " ChipLogFormatX64, ChipLogValueX64(nodeId));
 
-    int removed_idx = BridgeDeviceMgr().RemoveDeviceByNodeId(nodeId);
-    if (removed_idx < 0)
+    auto removed_idx = BridgeDeviceMgr().RemoveDeviceByNodeId(nodeId);
+    if (!removed_idx.has_value())
     {
         ChipLogError(NotSpecified, "Failed to remove device with nodeId=0x" ChipLogFormatX64, ChipLogValueX64(nodeId));
         return pw::Status::NotFound();

From ece219b382e45eacf1d14a52cc14abcbd68072f7 Mon Sep 17 00:00:00 2001
From: Andrei Litvin <andy314@gmail.com>
Date: Wed, 7 Aug 2024 09:12:57 -0400
Subject: [PATCH 08/41] Bump revision to 4

---
 .../src/BridgedDeviceBasicInformationImpl.cpp                   | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDeviceBasicInformationImpl.cpp b/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDeviceBasicInformationImpl.cpp
index cf35230dc1e155..62630d730b4355 100644
--- a/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDeviceBasicInformationImpl.cpp
+++ b/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDeviceBasicInformationImpl.cpp
@@ -23,7 +23,7 @@
 
 #include <app/AttributeAccessInterfaceRegistry.h>
 
-static constexpr unsigned kBridgedDeviceBasicInformationClusterRevision = 2;
+static constexpr unsigned kBridgedDeviceBasicInformationClusterRevision = 4;
 static constexpr unsigned kBridgedDeviceBasicInformationFeatureMap      = 0;
 
 using namespace ::chip;

From 9f20d0fedebcec541d912bfeb241debabe8d9aee Mon Sep 17 00:00:00 2001
From: Andrei Litvin <andy314@gmail.com>
Date: Wed, 7 Aug 2024 09:29:10 -0400
Subject: [PATCH 09/41] Forward attributes from the create call into the
 bridged device

---
 .../include/BridgedDevice.h                   | 28 +++++++++++++------
 .../src/BridgedDevice.cpp                     | 10 ++-----
 .../src/BridgedDeviceBasicInformationImpl.cpp |  2 +-
 .../src/BridgedDeviceManager.cpp              |  3 +-
 .../fabric-bridge-app/linux/RpcServer.cpp     | 15 ++++++++++
 5 files changed, 40 insertions(+), 18 deletions(-)

diff --git a/examples/fabric-bridge-app/fabric-bridge-common/include/BridgedDevice.h b/examples/fabric-bridge-app/fabric-bridge-common/include/BridgedDevice.h
index a237d93d133eb7..78c5caa79aa316 100644
--- a/examples/fabric-bridge-app/fabric-bridge-common/include/BridgedDevice.h
+++ b/examples/fabric-bridge-app/fabric-bridge-common/include/BridgedDevice.h
@@ -30,31 +30,43 @@
 class BridgedDevice
 {
 public:
-    static const int kDeviceNameSize = 32;
+    /// Defines all attributes that we keep track of for a bridged device
+    struct BridgedAttributes
+    {
+        std::string uniqueId;
+        std::string vendorName;
+        uint16_t vendorId = 0;
+        std::string productName;
+        uint16_t productId = 0;
+        std::string nodeLabel;
+        uint16_t hardwareVersion = 0;
+        std::string hardwareVersionString;
+        uint32_t softwareVersion = 0;
+        std::string softwareVersionString;
+    };
 
     BridgedDevice(chip::NodeId nodeId);
     virtual ~BridgedDevice() {}
 
     bool IsReachable();
     void SetReachable(bool reachable);
-    void SetName(const char * name);
-    void SetLocation(std::string location) { mLocation = location; };
+
     inline void SetEndpointId(chip::EndpointId id) { mEndpointId = id; };
     inline chip::EndpointId GetEndpointId() { return mEndpointId; };
     inline chip::NodeId GetNodeId() { return mNodeId; };
     inline void SetParentEndpointId(chip::EndpointId id) { mParentEndpointId = id; };
     inline chip::EndpointId GetParentEndpointId() { return mParentEndpointId; };
-    inline char * GetName() { return mName; };
-    inline std::string GetLocation() { return mLocation; };
-    inline std::string GetZone() { return mZone; };
-    inline void SetZone(std::string zone) { mZone = zone; };
+
+    const BridgedAttributes & GetBridgedAttributes() const { return mAttributes; }
+    void SetBridgedAttributes(const BridgedAttributes& value) { mAttributes = value; }
 
 protected:
     bool mReachable;
-    char mName[kDeviceNameSize];
     std::string mLocation;
     chip::NodeId mNodeId;
     chip::EndpointId mEndpointId;
     chip::EndpointId mParentEndpointId;
     std::string mZone;
+
+    BridgedAttributes mAttributes;
 };
diff --git a/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDevice.cpp b/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDevice.cpp
index d641f3743d43f0..48729ac86195ed 100644
--- a/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDevice.cpp
+++ b/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDevice.cpp
@@ -43,17 +43,11 @@ void BridgedDevice::SetReachable(bool reachable)
 
     if (reachable)
     {
-        ChipLogProgress(NotSpecified, "BridgedDevice[%s]: ONLINE", mName);
+        ChipLogProgress(NotSpecified, "BridgedDevice[%s]: ONLINE", mAttributes.uniqueId.c_str());
     }
     else
     {
-        ChipLogProgress(NotSpecified, "BridgedDevice[%s]: OFFLINE", mName);
+        ChipLogProgress(NotSpecified, "BridgedDevice[%s]: OFFLINE", mAttributes.uniqueId.c_str());
     }
 }
 
-void BridgedDevice::SetName(const char * name)
-{
-    ChipLogProgress(NotSpecified, "BridgedDevice[%s]: New Name=\"%s\"", mName, name);
-
-    chip::Platform::CopyString(mName, name);
-}
diff --git a/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDeviceBasicInformationImpl.cpp b/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDeviceBasicInformationImpl.cpp
index 62630d730b4355..7127f8704008e2 100644
--- a/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDeviceBasicInformationImpl.cpp
+++ b/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDeviceBasicInformationImpl.cpp
@@ -44,7 +44,7 @@ CHIP_ERROR BridgedDeviceBasicInformationImpl::Read(const ConcreteReadAttributePa
         encoder.Encode(dev->IsReachable());
         break;
     case BasicInformation::Attributes::NodeLabel::Id:
-        encoder.Encode(CharSpan::fromCharString(dev->GetName()));
+        encoder.Encode(CharSpan::fromCharString(dev->GetBridgedAttributes().nodeLabel.c_str()));
         break;
     case BasicInformation::Attributes::ClusterRevision::Id:
         encoder.Encode(kBridgedDeviceBasicInformationClusterRevision);
diff --git a/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDeviceManager.cpp b/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDeviceManager.cpp
index 674f973d3562f0..bb6c3577648a7a 100644
--- a/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDeviceManager.cpp
+++ b/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDeviceManager.cpp
@@ -211,7 +211,8 @@ int BridgedDeviceManager::RemoveDeviceEndpoint(BridgedDevice * dev)
             // disabled.
             [[maybe_unused]] EndpointId ep = emberAfClearDynamicEndpoint(index);
             mDevices[index]                = nullptr;
-            ChipLogProgress(NotSpecified, "Removed device %s from dynamic endpoint %d (index=%d)", dev->GetName(), ep, index);
+            ChipLogProgress(NotSpecified, "Removed device %s from dynamic endpoint %d (index=%d)",
+                            dev->GetBridgedAttributes().uniqueId.c_str(), ep, index);
             return index;
         }
         index++;
diff --git a/examples/fabric-bridge-app/linux/RpcServer.cpp b/examples/fabric-bridge-app/linux/RpcServer.cpp
index b04ec3b3c35187..20361e8984c6d4 100644
--- a/examples/fabric-bridge-app/linux/RpcServer.cpp
+++ b/examples/fabric-bridge-app/linux/RpcServer.cpp
@@ -54,6 +54,21 @@ pw::Status FabricBridge::AddSynchronizedDevice(const chip_rpc_SynchronizedDevice
     auto device = std::make_unique<BridgedDevice>(nodeId);
     device->SetReachable(true);
 
+    BridgedDevice::BridgedAttributes attributes;
+
+    attributes.uniqueId              = request.unique_id;
+    attributes.vendorName            = request.vendor_name;
+    attributes.vendorId              = request.vendor_id;
+    attributes.productName           = request.product_name;
+    attributes.productId             = request.product_id;
+    attributes.nodeLabel             = request.node_label;
+    attributes.hardwareVersion       = request.hardware_version;
+    attributes.hardwareVersionString = request.hardware_version_string;
+    attributes.softwareVersion       = request.software_version;
+    attributes.softwareVersionString = request.software_version_string;
+
+    device->SetBridgedAttributes(attributes);
+
     auto result = BridgeDeviceMgr().AddDeviceEndpoint(std::move(device), 1 /* parentEndpointId */);
     if (!result.has_value())
     {

From 5a1cb33d2f0483b832b1bcf20ac593078184cdab Mon Sep 17 00:00:00 2001
From: Andrei Litvin <andy314@gmail.com>
Date: Wed, 7 Aug 2024 09:33:26 -0400
Subject: [PATCH 10/41] Make attribute mapping actually work

---
 .../src/BridgedDeviceBasicInformationImpl.cpp | 27 +++++++++++++++++++
 1 file changed, 27 insertions(+)

diff --git a/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDeviceBasicInformationImpl.cpp b/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDeviceBasicInformationImpl.cpp
index 7127f8704008e2..c088935df30c59 100644
--- a/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDeviceBasicInformationImpl.cpp
+++ b/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDeviceBasicInformationImpl.cpp
@@ -52,6 +52,33 @@ CHIP_ERROR BridgedDeviceBasicInformationImpl::Read(const ConcreteReadAttributePa
     case BasicInformation::Attributes::FeatureMap::Id:
         encoder.Encode(kBridgedDeviceBasicInformationFeatureMap);
         break;
+    case BasicInformation::Attributes::UniqueID::Id:
+        encoder.Encode(CharSpan::fromCharString(dev->GetBridgedAttributes().uniqueId.c_str()));
+        break;
+    case BasicInformation::Attributes::VendorName::Id:
+        encoder.Encode(CharSpan::fromCharString(dev->GetBridgedAttributes().vendorName.c_str()));
+        break;
+    case BasicInformation::Attributes::VendorID::Id:
+        encoder.Encode(dev->GetBridgedAttributes().vendorId);
+        break;
+    case BasicInformation::Attributes::ProductName::Id:
+        encoder.Encode(CharSpan::fromCharString(dev->GetBridgedAttributes().productName.c_str()));
+        break;
+    case BasicInformation::Attributes::ProductID::Id:
+        encoder.Encode(dev->GetBridgedAttributes().productId);
+        break;
+    case BasicInformation::Attributes::HardwareVersion::Id:
+        encoder.Encode(dev->GetBridgedAttributes().hardwareVersion);
+        break;
+    case BasicInformation::Attributes::HardwareVersionString::Id:
+        encoder.Encode(CharSpan::fromCharString(dev->GetBridgedAttributes().hardwareVersionString.c_str()));
+        break;
+    case BasicInformation::Attributes::SoftwareVersion::Id:
+        encoder.Encode(dev->GetBridgedAttributes().softwareVersion);
+        break;
+    case BasicInformation::Attributes::SoftwareVersionString::Id:
+        encoder.Encode(CharSpan::fromCharString(dev->GetBridgedAttributes().softwareVersionString.c_str()));
+        break;
     default:
         return CHIP_ERROR_INVALID_ARGUMENT;
     }

From 4475143d03d2e3c0463161859fb877af06586d8d Mon Sep 17 00:00:00 2001
From: Andrei Litvin <andy314@gmail.com>
Date: Wed, 7 Aug 2024 09:33:43 -0400
Subject: [PATCH 11/41] Restyle

---
 .../fabric-bridge-common/include/BridgedDevice.h                | 2 +-
 .../fabric-bridge-common/src/BridgedDevice.cpp                  | 1 -
 2 files changed, 1 insertion(+), 2 deletions(-)

diff --git a/examples/fabric-bridge-app/fabric-bridge-common/include/BridgedDevice.h b/examples/fabric-bridge-app/fabric-bridge-common/include/BridgedDevice.h
index 78c5caa79aa316..e57219f7751b76 100644
--- a/examples/fabric-bridge-app/fabric-bridge-common/include/BridgedDevice.h
+++ b/examples/fabric-bridge-app/fabric-bridge-common/include/BridgedDevice.h
@@ -58,7 +58,7 @@ class BridgedDevice
     inline chip::EndpointId GetParentEndpointId() { return mParentEndpointId; };
 
     const BridgedAttributes & GetBridgedAttributes() const { return mAttributes; }
-    void SetBridgedAttributes(const BridgedAttributes& value) { mAttributes = value; }
+    void SetBridgedAttributes(const BridgedAttributes & value) { mAttributes = value; }
 
 protected:
     bool mReachable;
diff --git a/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDevice.cpp b/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDevice.cpp
index 48729ac86195ed..425bb4da32e896 100644
--- a/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDevice.cpp
+++ b/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDevice.cpp
@@ -50,4 +50,3 @@ void BridgedDevice::SetReachable(bool reachable)
         ChipLogProgress(NotSpecified, "BridgedDevice[%s]: OFFLINE", mAttributes.uniqueId.c_str());
     }
 }
-

From 152d2259abfb9a7457381f53420b2489dfdf05e1 Mon Sep 17 00:00:00 2001
From: Andrei Litvin <andy314@gmail.com>
Date: Wed, 7 Aug 2024 10:03:16 -0400
Subject: [PATCH 12/41] Ensure unique IDs are generated

---
 .../include/BridgedDevice.h                   | 13 +++--
 .../include/BridgedDeviceManager.h            | 17 ++++++-
 .../src/BridgedDeviceManager.cpp              | 49 +++++++++++++++++++
 3 files changed, 71 insertions(+), 8 deletions(-)

diff --git a/examples/fabric-bridge-app/fabric-bridge-common/include/BridgedDevice.h b/examples/fabric-bridge-app/fabric-bridge-common/include/BridgedDevice.h
index e57219f7751b76..97aef059482fbd 100644
--- a/examples/fabric-bridge-app/fabric-bridge-common/include/BridgedDevice.h
+++ b/examples/fabric-bridge-app/fabric-bridge-common/include/BridgedDevice.h
@@ -20,12 +20,7 @@
 
 #include <app/util/attribute-storage.h>
 
-#include <stdbool.h>
-#include <stdint.h>
-
-#include <functional>
 #include <string>
-#include <vector>
 
 class BridgedDevice
 {
@@ -46,7 +41,7 @@ class BridgedDevice
     };
 
     BridgedDevice(chip::NodeId nodeId);
-    virtual ~BridgedDevice() {}
+    virtual ~BridgedDevice() = default;
 
     bool IsReachable();
     void SetReachable(bool reachable);
@@ -57,9 +52,13 @@ class BridgedDevice
     inline void SetParentEndpointId(chip::EndpointId id) { mParentEndpointId = id; };
     inline chip::EndpointId GetParentEndpointId() { return mParentEndpointId; };
 
-    const BridgedAttributes & GetBridgedAttributes() const { return mAttributes; }
+    [[nodiscard]] const BridgedAttributes & GetBridgedAttributes() const { return mAttributes; }
     void SetBridgedAttributes(const BridgedAttributes & value) { mAttributes = value; }
 
+    /// Convenience method to set just the unique id of a bridged device as it
+    /// is one of the few attributes that is not always bulk-set
+    void SetUniqueId(const std::string &value) { mAttributes.uniqueId = value; }
+
 protected:
     bool mReachable;
     std::string mLocation;
diff --git a/examples/fabric-bridge-app/fabric-bridge-common/include/BridgedDeviceManager.h b/examples/fabric-bridge-app/fabric-bridge-common/include/BridgedDeviceManager.h
index 6c2829a8a4bb38..ac28d31edf507c 100644
--- a/examples/fabric-bridge-app/fabric-bridge-common/include/BridgedDeviceManager.h
+++ b/examples/fabric-bridge-app/fabric-bridge-common/include/BridgedDeviceManager.h
@@ -43,7 +43,12 @@ class BridgedDeviceManager
      * This function attempts to add a device to a dynamic endpoint. It tries to find an available
      * endpoint slot and retries the addition process up to a specified maximum number of times if
      * the endpoint already exists. If the addition is successful, it returns the index of the
-     * dynamic endpoint; otherwise, it returns -1.
+     * dynamic endpoint;
+     *
+     * Ensures that the device has a unique id:
+     *   - device MUST set its unique id if any BEFORE calling this method
+     *   - if no unique id (i.e. empty string), a new unique id will be generated
+     *   - Add will fail if the unique id is not unique
      *
      * @param dev A pointer to the device to be added.
      * @param parentEndpointId The parent endpoint ID. Defaults to an invalid endpoint ID.
@@ -100,9 +105,19 @@ class BridgedDeviceManager
      */
     std::optional<unsigned> RemoveDeviceByNodeId(chip::NodeId nodeId);
 
+    /**
+     * Finds the device with the given unique id (if any)
+     */
+    BridgedDevice * GetDeviceByUniqueId(const std::string & id);
+
 private:
     friend BridgedDeviceManager & BridgeDeviceMgr();
 
+    /**
+     * Creates a new unique ID that is not used by any other mDevice
+     */
+    std::string GenerateUniqueId();
+
     static BridgedDeviceManager sInstance;
 
     chip::EndpointId mCurrentEndpointId;
diff --git a/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDeviceManager.cpp b/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDeviceManager.cpp
index bb6c3577648a7a..ea873aa8ef4b27 100644
--- a/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDeviceManager.cpp
+++ b/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDeviceManager.cpp
@@ -29,6 +29,7 @@
 #include <app/util/attribute-storage.h>
 #include <app/util/endpoint-config-api.h>
 #include <app/util/util.h>
+#include <crypto/RandUtils.h>
 #include <lib/support/CHIPMem.h>
 #include <lib/support/ZclString.h>
 
@@ -160,6 +161,16 @@ std::optional<unsigned> BridgedDeviceManager::AddDeviceEndpoint(std::unique_ptr<
     const chip::Span<const EmberAfDeviceType> & deviceTypeList = Span<const EmberAfDeviceType>(sBridgedDeviceTypes);
     const chip::Span<chip::DataVersion> & dataVersionStorage   = Span<DataVersion>(sBridgedNodeDataVersions);
 
+    if (dev->GetBridgedAttributes().uniqueId.empty())
+    {
+        dev->SetUniqueId(GenerateUniqueId());
+    }
+    else if (GetDeviceByUniqueId(dev->GetBridgedAttributes().uniqueId) != nullptr)
+    {
+        ChipLogProgress(NotSpecified, "A device with unique id '%s' already exists", dev->GetBridgedAttributes().uniqueId.c_str());
+        return std::nullopt;
+    }
+
     for (unsigned index = 0; index < CHIP_DEVICE_CONFIG_DYNAMIC_ENDPOINT_COUNT; index++)
     {
         if (mDevices[index])
@@ -232,6 +243,44 @@ BridgedDevice * BridgedDeviceManager::GetDevice(chip::EndpointId endpointId) con
     return nullptr;
 }
 
+std::string BridgedDeviceManager::GenerateUniqueId()
+{
+    char rand_buffer[kUniqueIdSize + 1];
+    memset(rand_buffer, 0, sizeof(rand_buffer));
+
+    static const char kRandCharChoices[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+
+    while (true)
+    {
+        /// for nice viewing, prefix the generated value
+        memcpy(rand_buffer, "GEN-", 4);
+        for (unsigned idx = 4; idx < kUniqueIdSize; idx++)
+        {
+            rand_buffer[idx] = kRandCharChoices[Crypto::GetRandU8() % (sizeof(kRandCharChoices) - 1)];
+        }
+
+        // we know zero-terminated due to the memset
+        std::string uniqueIdChoice = rand_buffer;
+
+        if (!GetDeviceByUniqueId(uniqueIdChoice))
+        {
+            return uniqueIdChoice;
+        }
+    }
+}
+
+BridgedDevice * BridgedDeviceManager::GetDeviceByUniqueId(const std::string & id)
+{
+    for (uint8_t index = 0; index < CHIP_DEVICE_CONFIG_DYNAMIC_ENDPOINT_COUNT; ++index)
+    {
+        if (mDevices[index] && mDevices[index]->GetBridgedAttributes().uniqueId == id)
+        {
+            return mDevices[index].get();
+        }
+    }
+    return nullptr;
+}
+
 BridgedDevice * BridgedDeviceManager::GetDeviceByNodeId(chip::NodeId nodeId) const
 {
     for (uint8_t index = 0; index < CHIP_DEVICE_CONFIG_DYNAMIC_ENDPOINT_COUNT; ++index)

From c6877c887ca85daf8c5e8840d481a72c9353464c Mon Sep 17 00:00:00 2001
From: Andrei Litvin <andy314@gmail.com>
Date: Wed, 7 Aug 2024 10:03:31 -0400
Subject: [PATCH 13/41] Restyle

---
 .../fabric-bridge-common/include/BridgedDevice.h                | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/examples/fabric-bridge-app/fabric-bridge-common/include/BridgedDevice.h b/examples/fabric-bridge-app/fabric-bridge-common/include/BridgedDevice.h
index 97aef059482fbd..cde2055473e44a 100644
--- a/examples/fabric-bridge-app/fabric-bridge-common/include/BridgedDevice.h
+++ b/examples/fabric-bridge-app/fabric-bridge-common/include/BridgedDevice.h
@@ -57,7 +57,7 @@ class BridgedDevice
 
     /// Convenience method to set just the unique id of a bridged device as it
     /// is one of the few attributes that is not always bulk-set
-    void SetUniqueId(const std::string &value) { mAttributes.uniqueId = value; }
+    void SetUniqueId(const std::string & value) { mAttributes.uniqueId = value; }
 
 protected:
     bool mReachable;

From 28c8bb3d9f935668f75bfb7db94e8dd7b7430485 Mon Sep 17 00:00:00 2001
From: Andrei Litvin <andy314@gmail.com>
Date: Wed, 7 Aug 2024 10:12:07 -0400
Subject: [PATCH 14/41] Increase size to 33 to allow for a null terminator

---
 .../pigweed/protos/fabric_bridge_service.options     | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/examples/common/pigweed/protos/fabric_bridge_service.options b/examples/common/pigweed/protos/fabric_bridge_service.options
index d5ad57e57d6447..b52b5cc7367f14 100644
--- a/examples/common/pigweed/protos/fabric_bridge_service.options
+++ b/examples/common/pigweed/protos/fabric_bridge_service.options
@@ -1,6 +1,6 @@
-chip.rpc.SynchronizedDevice.unique_id max_size:32
-chip.rpc.SynchronizedDevice.vendor_name max_size:32
-chip.rpc.SynchronizedDevice.product_name max_size:32
-chip.rpc.SynchronizedDevice.node_label max_size:32
-chip.rpc.SynchronizedDevice.hardware_version_string max_size:32
-chip.rpc.SynchronizedDevice.software_version_string max_size:32
+chip.rpc.SynchronizedDevice.unique_id max_size:33
+chip.rpc.SynchronizedDevice.vendor_name max_size:33
+chip.rpc.SynchronizedDevice.product_name max_size:33
+chip.rpc.SynchronizedDevice.node_label max_size:33
+chip.rpc.SynchronizedDevice.hardware_version_string max_size:33
+chip.rpc.SynchronizedDevice.software_version_string max_size:33

From 23d61ebeed93af772c3231005b7aa52aa0fa7fff Mon Sep 17 00:00:00 2001
From: Andrei Litvin <andy314@gmail.com>
Date: Wed, 7 Aug 2024 10:15:47 -0400
Subject: [PATCH 15/41] make sure that the rpc structures are initialized

---
 examples/fabric-admin/rpc/RpcClient.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/examples/fabric-admin/rpc/RpcClient.cpp b/examples/fabric-admin/rpc/RpcClient.cpp
index 00ca1204cc1f19..2e992f7b0b2081 100644
--- a/examples/fabric-admin/rpc/RpcClient.cpp
+++ b/examples/fabric-admin/rpc/RpcClient.cpp
@@ -117,7 +117,7 @@ CHIP_ERROR AddSynchronizedDevice(chip::NodeId nodeId)
 {
     ChipLogProgress(NotSpecified, "AddSynchronizedDevice");
 
-    chip_rpc_SynchronizedDevice device;
+    chip_rpc_SynchronizedDevice device = chip_rpc_SynchronizedDevice_init_default;
     device.node_id = nodeId;
 
     // The RPC call is kept alive until it completes. When a response is received, it will be logged by the handler
@@ -137,7 +137,7 @@ CHIP_ERROR RemoveSynchronizedDevice(chip::NodeId nodeId)
 {
     ChipLogProgress(NotSpecified, "RemoveSynchronizedDevice");
 
-    chip_rpc_SynchronizedDevice device;
+    chip_rpc_SynchronizedDevice device = chip_rpc_SynchronizedDevice_init_default;
     device.node_id = nodeId;
 
     // The RPC call is kept alive until it completes. When a response is received, it will be logged by the handler

From 6628f5cb41bc561a3d868ec37c3ec886ddb46e35 Mon Sep 17 00:00:00 2001
From: Andrei Litvin <andy314@gmail.com>
Date: Wed, 7 Aug 2024 10:17:19 -0400
Subject: [PATCH 16/41] Restyle

---
 examples/fabric-admin/rpc/RpcClient.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/examples/fabric-admin/rpc/RpcClient.cpp b/examples/fabric-admin/rpc/RpcClient.cpp
index 2e992f7b0b2081..9166f482c4cd7e 100644
--- a/examples/fabric-admin/rpc/RpcClient.cpp
+++ b/examples/fabric-admin/rpc/RpcClient.cpp
@@ -118,7 +118,7 @@ CHIP_ERROR AddSynchronizedDevice(chip::NodeId nodeId)
     ChipLogProgress(NotSpecified, "AddSynchronizedDevice");
 
     chip_rpc_SynchronizedDevice device = chip_rpc_SynchronizedDevice_init_default;
-    device.node_id = nodeId;
+    device.node_id                     = nodeId;
 
     // The RPC call is kept alive until it completes. When a response is received, it will be logged by the handler
     // function and the call will complete.
@@ -138,7 +138,7 @@ CHIP_ERROR RemoveSynchronizedDevice(chip::NodeId nodeId)
     ChipLogProgress(NotSpecified, "RemoveSynchronizedDevice");
 
     chip_rpc_SynchronizedDevice device = chip_rpc_SynchronizedDevice_init_default;
-    device.node_id = nodeId;
+    device.node_id                     = nodeId;
 
     // The RPC call is kept alive until it completes. When a response is received, it will be logged by the handler
     // function and the call will complete.

From 33f25174ade8cac014b52dce8d3274bdcae2e69b Mon Sep 17 00:00:00 2001
From: Andrei Litvin <andy314@gmail.com>
Date: Wed, 7 Aug 2024 10:20:12 -0400
Subject: [PATCH 17/41] Add some fake data to test moving the data around

---
 examples/fabric-admin/rpc/RpcClient.cpp | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/examples/fabric-admin/rpc/RpcClient.cpp b/examples/fabric-admin/rpc/RpcClient.cpp
index 9166f482c4cd7e..57e668d127f3cd 100644
--- a/examples/fabric-admin/rpc/RpcClient.cpp
+++ b/examples/fabric-admin/rpc/RpcClient.cpp
@@ -120,6 +120,17 @@ CHIP_ERROR AddSynchronizedDevice(chip::NodeId nodeId)
     chip_rpc_SynchronizedDevice device = chip_rpc_SynchronizedDevice_init_default;
     device.node_id                     = nodeId;
 
+    // TODO: fill this with real data. For now we just add things for testing
+    strcpy(device.vendor_name, "Test Vendor");
+    device.vendor_id = 123;
+    strcpy(device.product_name, "Test Product");
+    device.product_id = 234;
+    strcpy(device.node_label, "Device Label");
+    device.hardware_version = 11;
+    strcpy(device.hardware_version_string, "Hardware");
+    device.software_version = 22;
+    strcpy(device.software_version_string, "Test 1.4.22");
+
     // The RPC call is kept alive until it completes. When a response is received, it will be logged by the handler
     // function and the call will complete.
     auto call = fabricBridgeClient.AddSynchronizedDevice(device, OnAddDeviceResponseCompleted);

From fbb42acc44edd12b7929d7431bc03d583c7bc042 Mon Sep 17 00:00:00 2001
From: Andrei Litvin <andy314@gmail.com>
Date: Wed, 7 Aug 2024 10:48:21 -0400
Subject: [PATCH 18/41] Remove unused members that were likely just copied over

---
 .../fabric-bridge-common/include/BridgedDevice.h                | 2 --
 1 file changed, 2 deletions(-)

diff --git a/examples/fabric-bridge-app/fabric-bridge-common/include/BridgedDevice.h b/examples/fabric-bridge-app/fabric-bridge-common/include/BridgedDevice.h
index cde2055473e44a..5c09cfa04d2521 100644
--- a/examples/fabric-bridge-app/fabric-bridge-common/include/BridgedDevice.h
+++ b/examples/fabric-bridge-app/fabric-bridge-common/include/BridgedDevice.h
@@ -61,11 +61,9 @@ class BridgedDevice
 
 protected:
     bool mReachable;
-    std::string mLocation;
     chip::NodeId mNodeId;
     chip::EndpointId mEndpointId;
     chip::EndpointId mParentEndpointId;
-    std::string mZone;
 
     BridgedAttributes mAttributes;
 };

From 4abba221fa516472d9ed076428add324ddc7dc03 Mon Sep 17 00:00:00 2001
From: Andrei Litvin <andy314@gmail.com>
Date: Wed, 7 Aug 2024 11:01:23 -0400
Subject: [PATCH 19/41] make the attributes optional

---
 .../protos/fabric_bridge_service.proto        | 20 +++----
 examples/fabric-admin/rpc/RpcClient.cpp       | 17 ++++++
 .../fabric-bridge-app/linux/RpcServer.cpp     | 59 +++++++++++++++----
 3 files changed, 76 insertions(+), 20 deletions(-)

diff --git a/examples/common/pigweed/protos/fabric_bridge_service.proto b/examples/common/pigweed/protos/fabric_bridge_service.proto
index 120bfdb88ccfcc..f2e4fd2f32fe53 100644
--- a/examples/common/pigweed/protos/fabric_bridge_service.proto
+++ b/examples/common/pigweed/protos/fabric_bridge_service.proto
@@ -8,16 +8,16 @@ package chip.rpc;
 message SynchronizedDevice {
   uint64 node_id = 1;
 
-  string unique_id = 2;
-  string vendor_name = 3;
-  uint32 vendor_id = 4;
-  string product_name = 5;
-  uint32 product_id = 6;
-  string node_label = 7;
-  uint32 hardware_version = 8;
-  string hardware_version_string = 9;
-  uint32 software_version = 10;
-  string software_version_string = 11;
+  optional string unique_id = 2;
+  optional string vendor_name = 3;
+  optional uint32 vendor_id = 4;
+  optional string product_name = 5;
+  optional uint32 product_id = 6;
+  optional string node_label = 7;
+  optional uint32 hardware_version = 8;
+  optional string hardware_version_string = 9;
+  optional uint32 software_version = 10;
+  optional string software_version_string = 11;
 }
 
 service FabricBridge {
diff --git a/examples/fabric-admin/rpc/RpcClient.cpp b/examples/fabric-admin/rpc/RpcClient.cpp
index 57e668d127f3cd..18a170723e9ede 100644
--- a/examples/fabric-admin/rpc/RpcClient.cpp
+++ b/examples/fabric-admin/rpc/RpcClient.cpp
@@ -122,14 +122,31 @@ CHIP_ERROR AddSynchronizedDevice(chip::NodeId nodeId)
 
     // TODO: fill this with real data. For now we just add things for testing
     strcpy(device.vendor_name, "Test Vendor");
+    device.has_vendor_name = true;
+
     device.vendor_id = 123;
+    device.has_vendor_id = true;
+
     strcpy(device.product_name, "Test Product");
+    device.has_product_name = true;
+
     device.product_id = 234;
+    device.has_product_id = true;
+
     strcpy(device.node_label, "Device Label");
+    device.has_node_label = true;
+
     device.hardware_version = 11;
+    device.has_hardware_version = true;
+
     strcpy(device.hardware_version_string, "Hardware");
+    device.has_hardware_version_string = true;
+
     device.software_version = 22;
+    device.has_software_version = true;
+
     strcpy(device.software_version_string, "Test 1.4.22");
+    device.has_software_version_string = true;
 
     // The RPC call is kept alive until it completes. When a response is received, it will be logged by the handler
     // function and the call will complete.
diff --git a/examples/fabric-bridge-app/linux/RpcServer.cpp b/examples/fabric-bridge-app/linux/RpcServer.cpp
index 20361e8984c6d4..aae7e239b694ef 100644
--- a/examples/fabric-bridge-app/linux/RpcServer.cpp
+++ b/examples/fabric-bridge-app/linux/RpcServer.cpp
@@ -56,16 +56,55 @@ pw::Status FabricBridge::AddSynchronizedDevice(const chip_rpc_SynchronizedDevice
 
     BridgedDevice::BridgedAttributes attributes;
 
-    attributes.uniqueId              = request.unique_id;
-    attributes.vendorName            = request.vendor_name;
-    attributes.vendorId              = request.vendor_id;
-    attributes.productName           = request.product_name;
-    attributes.productId             = request.product_id;
-    attributes.nodeLabel             = request.node_label;
-    attributes.hardwareVersion       = request.hardware_version;
-    attributes.hardwareVersionString = request.hardware_version_string;
-    attributes.softwareVersion       = request.software_version;
-    attributes.softwareVersionString = request.software_version_string;
+    if (request.has_unique_id)
+    {
+        attributes.uniqueId = request.unique_id;
+    }
+
+    if (request.has_vendor_name)
+    {
+        attributes.vendorName = request.vendor_name;
+    }
+
+    if (request.has_vendor_id)
+    {
+        attributes.vendorId = request.vendor_id;
+    }
+
+    if (request.has_product_name)
+    {
+        attributes.productName = request.product_name;
+    }
+
+    if (request.has_product_id)
+    {
+        attributes.productId = request.product_id;
+    }
+
+    if (request.has_node_label)
+    {
+        attributes.nodeLabel = request.node_label;
+    }
+
+    if (request.has_hardware_version)
+    {
+        attributes.hardwareVersion = request.hardware_version;
+    }
+
+    if (request.has_hardware_version_string)
+    {
+        attributes.hardwareVersionString = request.hardware_version_string;
+    }
+
+    if (request.has_software_version)
+    {
+        attributes.softwareVersion = request.software_version;
+    }
+
+    if (request.has_software_version_string)
+    {
+        attributes.softwareVersionString = request.software_version_string;
+    }
 
     device->SetBridgedAttributes(attributes);
 

From fab3b061e1dc0c324b0d3de2982d413a3097d1f8 Mon Sep 17 00:00:00 2001
From: Andrei Litvin <andy314@gmail.com>
Date: Wed, 7 Aug 2024 12:15:48 -0400
Subject: [PATCH 20/41] Prepare some device sync data - reading the basic info
 cluster

---
 examples/fabric-admin/BUILD.gn                            | 2 ++
 examples/fabric-admin/commands/pairing/PairingCommand.cpp | 7 ++++---
 2 files changed, 6 insertions(+), 3 deletions(-)

diff --git a/examples/fabric-admin/BUILD.gn b/examples/fabric-admin/BUILD.gn
index be8313d7a944ac..7fbd13e07183ed 100644
--- a/examples/fabric-admin/BUILD.gn
+++ b/examples/fabric-admin/BUILD.gn
@@ -72,6 +72,8 @@ static_library("fabric-admin-utils") {
     "commands/common/RemoteDataModelLogger.cpp",
     "commands/common/RemoteDataModelLogger.h",
     "commands/fabric-sync/FabricSyncCommand.cpp",
+    "commands/pairing/DeviceSynchronization.cpp",
+    "commands/pairing/DeviceSynchronization.h",
     "commands/pairing/OpenCommissioningWindowCommand.cpp",
     "commands/pairing/OpenCommissioningWindowCommand.h",
     "commands/pairing/PairingCommand.cpp",
diff --git a/examples/fabric-admin/commands/pairing/PairingCommand.cpp b/examples/fabric-admin/commands/pairing/PairingCommand.cpp
index 521325a796dce0..7ca7855d181b26 100644
--- a/examples/fabric-admin/commands/pairing/PairingCommand.cpp
+++ b/examples/fabric-admin/commands/pairing/PairingCommand.cpp
@@ -18,7 +18,10 @@
 
 #include "PairingCommand.h"
 
+#include <app-common/zap-generated/ids/Clusters.h>
 #include <commands/common/DeviceScanner.h>
+#include <commands/interactive/InteractiveCommands.h>
+#include <commands/pairing/DeviceSynchronization.h>
 #include <controller/ExampleOperationalCredentialsIssuer.h>
 #include <crypto/CHIPCryptoPAL.h>
 #include <lib/core/CHIPSafeCasts.h>
@@ -400,10 +403,8 @@ void PairingCommand::OnCommissioningComplete(NodeId nodeId, CHIP_ERROR err)
     {
         // print to console
         fprintf(stderr, "New device with Node ID: 0x%lx has been successfully added.\n", nodeId);
+        DeviceSynchronizer::Instance().StartDeviceSynchronization(ScopedNodeId(mNodeId, CurrentCommissioner().GetFabricIndex()));
 
-#if defined(PW_RPC_ENABLED)
-        AddSynchronizedDevice(nodeId);
-#endif
     }
     else
     {

From f2d353eff4081f394b9c288f2362c9e9e5a37588 Mon Sep 17 00:00:00 2001
From: Andrei Litvin <andy314@gmail.com>
Date: Wed, 7 Aug 2024 12:26:15 -0400
Subject: [PATCH 21/41] Prepare some device sync data - reading the basic info
 cluster

---
 examples/fabric-admin/commands/pairing/PairingCommand.cpp | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/examples/fabric-admin/commands/pairing/PairingCommand.cpp b/examples/fabric-admin/commands/pairing/PairingCommand.cpp
index 7ca7855d181b26..40a9f7aab74b5b 100644
--- a/examples/fabric-admin/commands/pairing/PairingCommand.cpp
+++ b/examples/fabric-admin/commands/pairing/PairingCommand.cpp
@@ -403,8 +403,7 @@ void PairingCommand::OnCommissioningComplete(NodeId nodeId, CHIP_ERROR err)
     {
         // print to console
         fprintf(stderr, "New device with Node ID: 0x%lx has been successfully added.\n", nodeId);
-        DeviceSynchronizer::Instance().StartDeviceSynchronization(ScopedNodeId(mNodeId, CurrentCommissioner().GetFabricIndex()));
-
+        DeviceSynchronizer::Instance().StartDeviceSynchronization(CurrentCommissioner(), mNodeId);
     }
     else
     {

From 0d0ddae872d1fe25e143f1379b626a2efc146343 Mon Sep 17 00:00:00 2001
From: Andrei Litvin <andy314@gmail.com>
Date: Wed, 7 Aug 2024 12:50:26 -0400
Subject: [PATCH 22/41] Full implementation of forwarding data

---
 .../protos/fabric_bridge_service.proto        |  1 +
 .../commands/pairing/PairingCommand.cpp       |  2 +-
 examples/fabric-admin/rpc/RpcClient.cpp       | 44 ++-----------------
 examples/fabric-admin/rpc/RpcClient.h         |  5 ++-
 4 files changed, 8 insertions(+), 44 deletions(-)

diff --git a/examples/common/pigweed/protos/fabric_bridge_service.proto b/examples/common/pigweed/protos/fabric_bridge_service.proto
index f2e4fd2f32fe53..e0370dd278c7a2 100644
--- a/examples/common/pigweed/protos/fabric_bridge_service.proto
+++ b/examples/common/pigweed/protos/fabric_bridge_service.proto
@@ -18,6 +18,7 @@ message SynchronizedDevice {
   optional string hardware_version_string = 9;
   optional uint32 software_version = 10;
   optional string software_version_string = 11;
+  optional bool is_icd = 12;
 }
 
 service FabricBridge {
diff --git a/examples/fabric-admin/commands/pairing/PairingCommand.cpp b/examples/fabric-admin/commands/pairing/PairingCommand.cpp
index 40a9f7aab74b5b..21b023f423ed84 100644
--- a/examples/fabric-admin/commands/pairing/PairingCommand.cpp
+++ b/examples/fabric-admin/commands/pairing/PairingCommand.cpp
@@ -403,7 +403,7 @@ void PairingCommand::OnCommissioningComplete(NodeId nodeId, CHIP_ERROR err)
     {
         // print to console
         fprintf(stderr, "New device with Node ID: 0x%lx has been successfully added.\n", nodeId);
-        DeviceSynchronizer::Instance().StartDeviceSynchronization(CurrentCommissioner(), mNodeId);
+        DeviceSynchronizer::Instance().StartDeviceSynchronization(CurrentCommissioner(), mNodeId, mDeviceIsICD);
     }
     else
     {
diff --git a/examples/fabric-admin/rpc/RpcClient.cpp b/examples/fabric-admin/rpc/RpcClient.cpp
index 18a170723e9ede..54282eba414230 100644
--- a/examples/fabric-admin/rpc/RpcClient.cpp
+++ b/examples/fabric-admin/rpc/RpcClient.cpp
@@ -22,16 +22,9 @@
 #include <chrono>
 #include <condition_variable>
 #include <mutex>
-#include <string>
-#include <thread>
 
+#include "fabric_bridge_service/fabric_bridge_service.pb.h"
 #include "fabric_bridge_service/fabric_bridge_service.rpc.pb.h"
-#include "pw_assert/check.h"
-#include "pw_hdlc/decoder.h"
-#include "pw_hdlc/default_addresses.h"
-#include "pw_hdlc/rpc_channel.h"
-#include "pw_rpc/client.h"
-#include "pw_stream/socket_stream.h"
 
 using namespace chip;
 
@@ -113,44 +106,13 @@ CHIP_ERROR InitRpcClient(uint16_t rpcServerPort)
     return rpc::client::StartPacketProcessing();
 }
 
-CHIP_ERROR AddSynchronizedDevice(chip::NodeId nodeId)
+CHIP_ERROR AddSynchronizedDevice(const chip_rpc_SynchronizedDevice &data)
 {
     ChipLogProgress(NotSpecified, "AddSynchronizedDevice");
 
-    chip_rpc_SynchronizedDevice device = chip_rpc_SynchronizedDevice_init_default;
-    device.node_id                     = nodeId;
-
-    // TODO: fill this with real data. For now we just add things for testing
-    strcpy(device.vendor_name, "Test Vendor");
-    device.has_vendor_name = true;
-
-    device.vendor_id = 123;
-    device.has_vendor_id = true;
-
-    strcpy(device.product_name, "Test Product");
-    device.has_product_name = true;
-
-    device.product_id = 234;
-    device.has_product_id = true;
-
-    strcpy(device.node_label, "Device Label");
-    device.has_node_label = true;
-
-    device.hardware_version = 11;
-    device.has_hardware_version = true;
-
-    strcpy(device.hardware_version_string, "Hardware");
-    device.has_hardware_version_string = true;
-
-    device.software_version = 22;
-    device.has_software_version = true;
-
-    strcpy(device.software_version_string, "Test 1.4.22");
-    device.has_software_version_string = true;
-
     // The RPC call is kept alive until it completes. When a response is received, it will be logged by the handler
     // function and the call will complete.
-    auto call = fabricBridgeClient.AddSynchronizedDevice(device, OnAddDeviceResponseCompleted);
+    auto call = fabricBridgeClient.AddSynchronizedDevice(data, OnAddDeviceResponseCompleted);
 
     if (!call.active())
     {
diff --git a/examples/fabric-admin/rpc/RpcClient.h b/examples/fabric-admin/rpc/RpcClient.h
index a1754b3846d508..a5bd833ad5d5b3 100644
--- a/examples/fabric-admin/rpc/RpcClient.h
+++ b/examples/fabric-admin/rpc/RpcClient.h
@@ -20,6 +20,8 @@
 
 #include <platform/CHIPDeviceLayer.h>
 
+#include "fabric_bridge_service/fabric_bridge_service.rpc.pb.h"
+
 constexpr uint16_t kFabricBridgeServerPort = 33002;
 
 /**
@@ -39,13 +41,12 @@ CHIP_ERROR InitRpcClient(uint16_t rpcServerPort);
  * It logs the progress and checks if an `AddSynchronizedDevice` operation is already in progress.
  * If an operation is in progress, it returns `CHIP_ERROR_BUSY`.
  *
- * @param nodeId The Node ID of the device to be added.
  * @return CHIP_ERROR An error code indicating the success or failure of the operation.
  * - CHIP_NO_ERROR: The RPC command was successfully processed.
  * - CHIP_ERROR_BUSY: Another operation is currently in progress.
  * - CHIP_ERROR_INTERNAL: An internal error occurred while activating the RPC call.
  */
-CHIP_ERROR AddSynchronizedDevice(chip::NodeId nodeId);
+CHIP_ERROR AddSynchronizedDevice(const chip_rpc_SynchronizedDevice & data);
 
 /**
  * @brief Removes a synchronized device from the RPC client.

From a4bc1b8d0c82976436431ca42dcfb095a592da38 Mon Sep 17 00:00:00 2001
From: Andrei Litvin <andy314@gmail.com>
Date: Wed, 7 Aug 2024 12:50:37 -0400
Subject: [PATCH 23/41] Restyle

---
 examples/fabric-admin/rpc/RpcClient.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/examples/fabric-admin/rpc/RpcClient.cpp b/examples/fabric-admin/rpc/RpcClient.cpp
index 54282eba414230..f7892abd61172a 100644
--- a/examples/fabric-admin/rpc/RpcClient.cpp
+++ b/examples/fabric-admin/rpc/RpcClient.cpp
@@ -106,7 +106,7 @@ CHIP_ERROR InitRpcClient(uint16_t rpcServerPort)
     return rpc::client::StartPacketProcessing();
 }
 
-CHIP_ERROR AddSynchronizedDevice(const chip_rpc_SynchronizedDevice &data)
+CHIP_ERROR AddSynchronizedDevice(const chip_rpc_SynchronizedDevice & data)
 {
     ChipLogProgress(NotSpecified, "AddSynchronizedDevice");
 

From ff840277a074de73c525150b432138c5406db828 Mon Sep 17 00:00:00 2001
From: Andrei Litvin <andy314@gmail.com>
Date: Wed, 7 Aug 2024 12:53:01 -0400
Subject: [PATCH 24/41] Add missing file

---
 .../pairing/DeviceSynchronization.cpp         | 179 ++++++++++++++++++
 .../commands/pairing/DeviceSynchronization.h  |  69 +++++++
 2 files changed, 248 insertions(+)
 create mode 100644 examples/fabric-admin/commands/pairing/DeviceSynchronization.cpp
 create mode 100644 examples/fabric-admin/commands/pairing/DeviceSynchronization.h

diff --git a/examples/fabric-admin/commands/pairing/DeviceSynchronization.cpp b/examples/fabric-admin/commands/pairing/DeviceSynchronization.cpp
new file mode 100644
index 00000000000000..d9dad2a8e14e7e
--- /dev/null
+++ b/examples/fabric-admin/commands/pairing/DeviceSynchronization.cpp
@@ -0,0 +1,179 @@
+/*
+ *   Copyright (c) 2024 Project CHIP Authors
+ *   All rights reserved.
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+
+#include "DeviceSynchronization.h"
+#include "rpc/RpcClient.h"
+
+#include <app/InteractionModelEngine.h>
+#include <app/server/Server.h>
+
+#include <app-common/zap-generated/ids/Attributes.h>
+#include <app-common/zap-generated/ids/Clusters.h>
+
+using namespace ::chip;
+using namespace ::chip::app;
+using chip::app::ReadClient;
+
+namespace {
+
+void OnDeviceConnectedWrapper(void * context, Messaging::ExchangeManager & exchangeMgr, const SessionHandle & sessionHandle)
+{
+    reinterpret_cast<DeviceSynchronizer *>(context)->OnDeviceConnected(exchangeMgr, sessionHandle);
+}
+
+void OnDeviceConnectionFailureWrapper(void * context, const ScopedNodeId & peerId, CHIP_ERROR error)
+{
+    reinterpret_cast<DeviceSynchronizer *>(context)->OnDeviceConnectionFailure(peerId, error);
+}
+
+bool SuccessOrLog(CHIP_ERROR err, const char * name)
+{
+    if (err == CHIP_NO_ERROR)
+    {
+        return true;
+    }
+
+    ChipLogError(NotSpecified, "Failed to read %s: %" CHIP_ERROR_FORMAT, name, err.Format());
+
+    return false;
+}
+
+} // namespace
+
+DeviceSynchronizer & DeviceSynchronizer::Instance()
+{
+    static DeviceSynchronizer instance;
+    return instance;
+}
+
+DeviceSynchronizer::DeviceSynchronizer() :
+    mOnDeviceConnectedCallback(OnDeviceConnectedWrapper, this),
+    mOnDeviceConnectionFailureCallback(OnDeviceConnectionFailureWrapper, this)
+{}
+
+void DeviceSynchronizer::OnAttributeData(const ConcreteDataAttributePath & path, TLV::TLVReader * data, const StatusIB & status)
+{
+    VerifyOrDie(path.mEndpointId == kRootEndpointId);
+    VerifyOrDie(path.mClusterId == Clusters::BasicInformation::Id);
+
+    ChipLogProgress(NotSpecified, "Attribute data");
+    path.LogPath();
+
+    switch (path.mAttributeId)
+    {
+    case Clusters::BasicInformation::Attributes::UniqueID::Id:
+        mCurrentDeviceData.has_unique_id =
+            SuccessOrLog(data->GetString(mCurrentDeviceData.unique_id, sizeof(mCurrentDeviceData.unique_id)), "UniqueId");
+        break;
+    case Clusters::BasicInformation::Attributes::VendorName::Id:
+        mCurrentDeviceData.has_vendor_name =
+            SuccessOrLog(data->GetString(mCurrentDeviceData.vendor_name, sizeof(mCurrentDeviceData.vendor_name)), "VendorName");
+        break;
+    case Clusters::BasicInformation::Attributes::VendorID::Id:
+        mCurrentDeviceData.has_vendor_id = SuccessOrLog(data->Get(mCurrentDeviceData.vendor_id), "VendorID");
+        break;
+    case Clusters::BasicInformation::Attributes::ProductName::Id:
+        mCurrentDeviceData.has_product_name =
+            SuccessOrLog(data->GetString(mCurrentDeviceData.product_name, sizeof(mCurrentDeviceData.product_name)), "ProductName");
+        break;
+    case Clusters::BasicInformation::Attributes::ProductID::Id:
+        mCurrentDeviceData.has_product_id = SuccessOrLog(data->Get(mCurrentDeviceData.product_id), "ProductID");
+        break;
+    case Clusters::BasicInformation::Attributes::NodeLabel::Id:
+        mCurrentDeviceData.has_node_label =
+            SuccessOrLog(data->GetString(mCurrentDeviceData.node_label, sizeof(mCurrentDeviceData.node_label)), "NodeLabel");
+        break;
+    case Clusters::BasicInformation::Attributes::HardwareVersion::Id:
+        mCurrentDeviceData.has_hardware_version = SuccessOrLog(data->Get(mCurrentDeviceData.hardware_version), "HardwareVersion");
+        break;
+    case Clusters::BasicInformation::Attributes::HardwareVersionString::Id:
+        mCurrentDeviceData.has_hardware_version_string = SuccessOrLog(
+            data->GetString(mCurrentDeviceData.hardware_version_string, sizeof(mCurrentDeviceData.hardware_version_string)),
+            "HardwareVersionString");
+        break;
+    case Clusters::BasicInformation::Attributes::SoftwareVersion::Id:
+        mCurrentDeviceData.has_software_version = SuccessOrLog(data->Get(mCurrentDeviceData.software_version), "HardwareVersion");
+        break;
+    case Clusters::BasicInformation::Attributes::SoftwareVersionString::Id:
+        mCurrentDeviceData.has_software_version_string = SuccessOrLog(
+            data->GetString(mCurrentDeviceData.software_version_string, sizeof(mCurrentDeviceData.software_version_string)),
+            "SoftwareVersionString");
+        break;
+    default:
+        ChipLogProgress(NotSpecified, "Attribute data not processed");
+        break;
+    }
+}
+
+void DeviceSynchronizer::OnReportEnd()
+{
+    // Report end is at the end of all attributes (success)
+    AddSynchronizedDevice(mCurrentDeviceData);
+}
+
+void DeviceSynchronizer::OnDone(chip::app::ReadClient * apReadClient) 
+{
+    // Nothing to do: error reported on OnError or report ended called.
+}
+
+void DeviceSynchronizer::OnError(CHIP_ERROR error)
+{
+    ChipLogProgress(NotSpecified, "Error fetching device data: %" CHIP_ERROR_FORMAT, error.Format());
+}
+
+void DeviceSynchronizer::OnDeviceConnected(chip::Messaging::ExchangeManager & exchangeMgr,
+                                           const chip::SessionHandle & sessionHandle)
+{
+    if (!mClient)
+    {
+        mClient = std::make_unique<ReadClient>(app::InteractionModelEngine::GetInstance(), &exchangeMgr /* echangeMgr */,
+                                               *this /* callback */, ReadClient::InteractionType::Read);
+        VerifyOrDie(mClient);
+    }
+
+    AttributePathParams readPaths[1];
+    readPaths[0] = AttributePathParams(kRootEndpointId, Clusters::BasicInformation::Id);
+
+    ReadPrepareParams readParams(sessionHandle);
+
+    readParams.mpAttributePathParamsList    = readPaths;
+    readParams.mAttributePathParamsListSize = 1;
+
+    CHIP_ERROR err = mClient->SendRequest(readParams);
+
+    if (err != CHIP_NO_ERROR)
+    {
+        ChipLogError(NotSpecified, "Failed to issue read for BasicInformation data");
+    }
+}
+
+void DeviceSynchronizer::OnDeviceConnectionFailure(const chip::ScopedNodeId & peerId, CHIP_ERROR error)
+{
+    ChipLogError(NotSpecified, "Device Sync failed to connect to " ChipLogFormatX64, ChipLogValueX64(peerId.GetNodeId()));
+}
+
+void DeviceSynchronizer::StartDeviceSynchronization(chip::Controller::DeviceController & controller, chip::NodeId nodeId, bool deviceIsIcd)
+{
+    mCurrentDeviceData         = chip_rpc_SynchronizedDevice_init_default;
+    mCurrentDeviceData.node_id = nodeId;
+    mCurrentDeviceData.has_is_icd = true;
+    mCurrentDeviceData.is_icd = deviceIsIcd;
+
+
+    controller.GetConnectedDevice(nodeId, &mOnDeviceConnectedCallback, &mOnDeviceConnectionFailureCallback);
+}
diff --git a/examples/fabric-admin/commands/pairing/DeviceSynchronization.h b/examples/fabric-admin/commands/pairing/DeviceSynchronization.h
new file mode 100644
index 00000000000000..e2c341b53f0845
--- /dev/null
+++ b/examples/fabric-admin/commands/pairing/DeviceSynchronization.h
@@ -0,0 +1,69 @@
+/*
+ *   Copyright (c) 2024 Project CHIP Authors
+ *   All rights reserved.
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+#pragma once
+
+#include <app/ReadClient.h>
+#include <controller/CHIPDeviceController.h>
+#include <lib/core/DataModelTypes.h>
+
+#include <memory>
+
+#include "fabric_bridge_service/fabric_bridge_service.pb.h"
+#include "fabric_bridge_service/fabric_bridge_service.rpc.pb.h"
+
+/// Ensures that device data is synchronized to the remove fabric bridge.
+///
+/// Includes a state machine that:
+///   - initiates a "read basic information data" command to fetch basic information
+///   - upon receiving such information, ensures that synchronized device data is sent
+///     to the remote end.
+class DeviceSynchronizer : public chip::app::ReadClient::Callback
+{
+public:
+    DeviceSynchronizer();
+
+    /// Usually called after commissioning is complete, initiates a
+    /// read of required data from the remote node ID and then will synchronize
+    /// the device towards the fabric bridge
+    void StartDeviceSynchronization(chip::Controller::DeviceController & controller, chip::NodeId nodeId, bool deviceIsIcd);
+
+    ///////////////////////////////////////////////////////////////
+    // ReadClient::Callback implementation
+    ///////////////////////////////////////////////////////////////
+    void OnAttributeData(const chip::app::ConcreteDataAttributePath & path, chip::TLV::TLVReader * data,
+                         const chip::app::StatusIB & status) override;
+    void OnReportEnd() override;
+    void OnError(CHIP_ERROR error) override;
+    void OnDone(chip::app::ReadClient * apReadClient) override;
+
+    ///////////////////////////////////////////////////////////////
+    // callbacks for CASE session establishment
+    ///////////////////////////////////////////////////////////////
+    void OnDeviceConnected(chip::Messaging::ExchangeManager & exchangeMgr, const chip::SessionHandle & sessionHandle);
+    void OnDeviceConnectionFailure(const chip::ScopedNodeId & peerId, CHIP_ERROR error);
+
+    static DeviceSynchronizer & Instance();
+
+private:
+    std::unique_ptr<chip::app::ReadClient> mClient;
+
+    chip::Callback::Callback<chip::OnDeviceConnected> mOnDeviceConnectedCallback;
+    chip::Callback::Callback<chip::OnDeviceConnectionFailure> mOnDeviceConnectionFailureCallback;
+
+    chip_rpc_SynchronizedDevice mCurrentDeviceData = chip_rpc_SynchronizedDevice_init_default;
+};

From c60afe61461bbca5ab90fbef610bae9e2379db11 Mon Sep 17 00:00:00 2001
From: Andrei Litvin <andy314@gmail.com>
Date: Wed, 7 Aug 2024 12:53:12 -0400
Subject: [PATCH 25/41] Restyle

---
 .../commands/pairing/DeviceSynchronization.cpp       | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/examples/fabric-admin/commands/pairing/DeviceSynchronization.cpp b/examples/fabric-admin/commands/pairing/DeviceSynchronization.cpp
index d9dad2a8e14e7e..8c0aae730a6274 100644
--- a/examples/fabric-admin/commands/pairing/DeviceSynchronization.cpp
+++ b/examples/fabric-admin/commands/pairing/DeviceSynchronization.cpp
@@ -126,7 +126,7 @@ void DeviceSynchronizer::OnReportEnd()
     AddSynchronizedDevice(mCurrentDeviceData);
 }
 
-void DeviceSynchronizer::OnDone(chip::app::ReadClient * apReadClient) 
+void DeviceSynchronizer::OnDone(chip::app::ReadClient * apReadClient)
 {
     // Nothing to do: error reported on OnError or report ended called.
 }
@@ -167,13 +167,13 @@ void DeviceSynchronizer::OnDeviceConnectionFailure(const chip::ScopedNodeId & pe
     ChipLogError(NotSpecified, "Device Sync failed to connect to " ChipLogFormatX64, ChipLogValueX64(peerId.GetNodeId()));
 }
 
-void DeviceSynchronizer::StartDeviceSynchronization(chip::Controller::DeviceController & controller, chip::NodeId nodeId, bool deviceIsIcd)
+void DeviceSynchronizer::StartDeviceSynchronization(chip::Controller::DeviceController & controller, chip::NodeId nodeId,
+                                                    bool deviceIsIcd)
 {
-    mCurrentDeviceData         = chip_rpc_SynchronizedDevice_init_default;
-    mCurrentDeviceData.node_id = nodeId;
+    mCurrentDeviceData            = chip_rpc_SynchronizedDevice_init_default;
+    mCurrentDeviceData.node_id    = nodeId;
     mCurrentDeviceData.has_is_icd = true;
-    mCurrentDeviceData.is_icd = deviceIsIcd;
-
+    mCurrentDeviceData.is_icd     = deviceIsIcd;
 
     controller.GetConnectedDevice(nodeId, &mOnDeviceConnectedCallback, &mOnDeviceConnectionFailureCallback);
 }

From 348030af9759a4fa6fe8625876950618ac88b662 Mon Sep 17 00:00:00 2001
From: Andrei Litvin <andy314@gmail.com>
Date: Wed, 7 Aug 2024 12:56:22 -0400
Subject: [PATCH 26/41] reset readclient, since this may reset the exchange
 manager ... seems cleaner

---
 .../commands/pairing/DeviceSynchronization.cpp            | 8 ++------
 1 file changed, 2 insertions(+), 6 deletions(-)

diff --git a/examples/fabric-admin/commands/pairing/DeviceSynchronization.cpp b/examples/fabric-admin/commands/pairing/DeviceSynchronization.cpp
index 8c0aae730a6274..514b23a03ae162 100644
--- a/examples/fabric-admin/commands/pairing/DeviceSynchronization.cpp
+++ b/examples/fabric-admin/commands/pairing/DeviceSynchronization.cpp
@@ -139,12 +139,8 @@ void DeviceSynchronizer::OnError(CHIP_ERROR error)
 void DeviceSynchronizer::OnDeviceConnected(chip::Messaging::ExchangeManager & exchangeMgr,
                                            const chip::SessionHandle & sessionHandle)
 {
-    if (!mClient)
-    {
-        mClient = std::make_unique<ReadClient>(app::InteractionModelEngine::GetInstance(), &exchangeMgr /* echangeMgr */,
-                                               *this /* callback */, ReadClient::InteractionType::Read);
-        VerifyOrDie(mClient);
-    }
+    mClient = std::make_unique<ReadClient>(app::InteractionModelEngine::GetInstance(), &exchangeMgr /* echangeMgr */,
+                                           *this /* callback */, ReadClient::InteractionType::Read);
 
     AttributePathParams readPaths[1];
     readPaths[0] = AttributePathParams(kRootEndpointId, Clusters::BasicInformation::Id);

From 471941c2ad365943bfe9a94250bafc0eb5d7b68c Mon Sep 17 00:00:00 2001
From: Andrei Litvin <andy314@gmail.com>
Date: Wed, 7 Aug 2024 12:56:52 -0400
Subject: [PATCH 27/41] Add the verifyOrDie

---
 examples/fabric-admin/commands/pairing/DeviceSynchronization.cpp | 1 +
 1 file changed, 1 insertion(+)

diff --git a/examples/fabric-admin/commands/pairing/DeviceSynchronization.cpp b/examples/fabric-admin/commands/pairing/DeviceSynchronization.cpp
index 514b23a03ae162..d6f4d3d01f1c6b 100644
--- a/examples/fabric-admin/commands/pairing/DeviceSynchronization.cpp
+++ b/examples/fabric-admin/commands/pairing/DeviceSynchronization.cpp
@@ -141,6 +141,7 @@ void DeviceSynchronizer::OnDeviceConnected(chip::Messaging::ExchangeManager & ex
 {
     mClient = std::make_unique<ReadClient>(app::InteractionModelEngine::GetInstance(), &exchangeMgr /* echangeMgr */,
                                            *this /* callback */, ReadClient::InteractionType::Read);
+    VerifyOrDie(mClient);
 
     AttributePathParams readPaths[1];
     readPaths[0] = AttributePathParams(kRootEndpointId, Clusters::BasicInformation::Id);

From f9465eb57335030b325f2e197fd2266113bb98c5 Mon Sep 17 00:00:00 2001
From: "Restyled.io" <commits@restyled.io>
Date: Wed, 7 Aug 2024 16:59:25 +0000
Subject: [PATCH 28/41] Restyled by clang-format

---
 examples/fabric-admin/rpc/RpcClient.cpp | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/examples/fabric-admin/rpc/RpcClient.cpp b/examples/fabric-admin/rpc/RpcClient.cpp
index 18a170723e9ede..816ea04691d71b 100644
--- a/examples/fabric-admin/rpc/RpcClient.cpp
+++ b/examples/fabric-admin/rpc/RpcClient.cpp
@@ -124,25 +124,25 @@ CHIP_ERROR AddSynchronizedDevice(chip::NodeId nodeId)
     strcpy(device.vendor_name, "Test Vendor");
     device.has_vendor_name = true;
 
-    device.vendor_id = 123;
+    device.vendor_id     = 123;
     device.has_vendor_id = true;
 
     strcpy(device.product_name, "Test Product");
     device.has_product_name = true;
 
-    device.product_id = 234;
+    device.product_id     = 234;
     device.has_product_id = true;
 
     strcpy(device.node_label, "Device Label");
     device.has_node_label = true;
 
-    device.hardware_version = 11;
+    device.hardware_version     = 11;
     device.has_hardware_version = true;
 
     strcpy(device.hardware_version_string, "Hardware");
     device.has_hardware_version_string = true;
 
-    device.software_version = 22;
+    device.software_version     = 22;
     device.has_software_version = true;
 
     strcpy(device.software_version_string, "Test 1.4.22");

From c256b3b72fe86243c3cc9b4210ac93ff5661daac Mon Sep 17 00:00:00 2001
From: Andrei Litvin <andy314@gmail.com>
Date: Wed, 7 Aug 2024 13:16:49 -0400
Subject: [PATCH 29/41] Fix string size for HW and software versions

---
 examples/common/pigweed/protos/fabric_bridge_service.options  | 4 ++--
 .../fabric-bridge-common/src/BridgedDeviceManager.cpp         | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/examples/common/pigweed/protos/fabric_bridge_service.options b/examples/common/pigweed/protos/fabric_bridge_service.options
index b52b5cc7367f14..a095d85788eb1c 100644
--- a/examples/common/pigweed/protos/fabric_bridge_service.options
+++ b/examples/common/pigweed/protos/fabric_bridge_service.options
@@ -2,5 +2,5 @@ chip.rpc.SynchronizedDevice.unique_id max_size:33
 chip.rpc.SynchronizedDevice.vendor_name max_size:33
 chip.rpc.SynchronizedDevice.product_name max_size:33
 chip.rpc.SynchronizedDevice.node_label max_size:33
-chip.rpc.SynchronizedDevice.hardware_version_string max_size:33
-chip.rpc.SynchronizedDevice.software_version_string max_size:33
+chip.rpc.SynchronizedDevice.hardware_version_string max_size:65
+chip.rpc.SynchronizedDevice.software_version_string max_size:65
diff --git a/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDeviceManager.cpp b/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDeviceManager.cpp
index ea873aa8ef4b27..2bdfc8a2c3e54a 100644
--- a/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDeviceManager.cpp
+++ b/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDeviceManager.cpp
@@ -52,8 +52,8 @@ constexpr int kNodeLabelSize       = 32;
 constexpr int kUniqueIdSize        = 32;
 constexpr int kVendorNameSize      = 32;
 constexpr int kProductNameSize     = 32;
-constexpr int kHardwareVersionSize = 32;
-constexpr int kSoftwareVersionSize = 32;
+constexpr int kHardwareVersionSize = 64;
+constexpr int kSoftwareVersionSize = 64;
 
 // Current ZCL implementation of Struct uses a max-size array of 254 bytes
 constexpr int kDescriptorAttributeArraySize = 254;

From e0156e4cf51004a4e832d8d08b0ae1a10c05ac8f Mon Sep 17 00:00:00 2001
From: Andrei Litvin <andy314@gmail.com>
Date: Wed, 7 Aug 2024 14:33:00 -0400
Subject: [PATCH 30/41] Move ICD support: set separate commands, handle feature
 mask

---
 .../include/BridgedDevice.h                   | 15 ++++++---
 .../src/BridgedDevice.cpp                     |  7 -----
 .../src/BridgedDeviceBasicInformationImpl.cpp | 10 +++---
 .../src/BridgedDeviceManager.cpp              | 31 ++++++++++++++++---
 .../fabric-bridge-app/linux/RpcServer.cpp     |  1 +
 5 files changed, 44 insertions(+), 20 deletions(-)

diff --git a/examples/fabric-bridge-app/fabric-bridge-common/include/BridgedDevice.h b/examples/fabric-bridge-app/fabric-bridge-common/include/BridgedDevice.h
index 5c09cfa04d2521..fdb3bb1b9b56cb 100644
--- a/examples/fabric-bridge-app/fabric-bridge-common/include/BridgedDevice.h
+++ b/examples/fabric-bridge-app/fabric-bridge-common/include/BridgedDevice.h
@@ -43,9 +43,12 @@ class BridgedDevice
     BridgedDevice(chip::NodeId nodeId);
     virtual ~BridgedDevice() = default;
 
-    bool IsReachable();
+    [[nodiscard]] bool IsReachable() const { return mReachable; }
     void SetReachable(bool reachable);
 
+    [[nodiscard]] bool IsIcd() const { return mIsIcd; }
+    void SetIcd(bool icd) { mIsIcd = icd; }
+
     inline void SetEndpointId(chip::EndpointId id) { mEndpointId = id; };
     inline chip::EndpointId GetEndpointId() { return mEndpointId; };
     inline chip::NodeId GetNodeId() { return mNodeId; };
@@ -60,10 +63,12 @@ class BridgedDevice
     void SetUniqueId(const std::string & value) { mAttributes.uniqueId = value; }
 
 protected:
-    bool mReachable;
-    chip::NodeId mNodeId;
-    chip::EndpointId mEndpointId;
-    chip::EndpointId mParentEndpointId;
+    bool mReachable = false;
+    bool mIsIcd     = false;
+
+    chip::NodeId mNodeId               = 0;
+    chip::EndpointId mEndpointId       = 0;
+    chip::EndpointId mParentEndpointId = 0;
 
     BridgedAttributes mAttributes;
 };
diff --git a/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDevice.cpp b/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDevice.cpp
index 425bb4da32e896..dfc8bf69d45984 100644
--- a/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDevice.cpp
+++ b/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDevice.cpp
@@ -21,8 +21,6 @@
 #include <cstdio>
 #include <platform/CHIPDeviceLayer.h>
 
-#include <string>
-
 using namespace chip::app::Clusters::Actions;
 
 BridgedDevice::BridgedDevice(chip::NodeId nodeId)
@@ -32,11 +30,6 @@ BridgedDevice::BridgedDevice(chip::NodeId nodeId)
     mEndpointId = chip::kInvalidEndpointId;
 }
 
-bool BridgedDevice::IsReachable()
-{
-    return mReachable;
-}
-
 void BridgedDevice::SetReachable(bool reachable)
 {
     mReachable = reachable;
diff --git a/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDeviceBasicInformationImpl.cpp b/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDeviceBasicInformationImpl.cpp
index c088935df30c59..7fa48a4a158ddd 100644
--- a/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDeviceBasicInformationImpl.cpp
+++ b/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDeviceBasicInformationImpl.cpp
@@ -24,7 +24,6 @@
 #include <app/AttributeAccessInterfaceRegistry.h>
 
 static constexpr unsigned kBridgedDeviceBasicInformationClusterRevision = 4;
-static constexpr unsigned kBridgedDeviceBasicInformationFeatureMap      = 0;
 
 using namespace ::chip;
 using namespace ::chip::app;
@@ -49,9 +48,12 @@ CHIP_ERROR BridgedDeviceBasicInformationImpl::Read(const ConcreteReadAttributePa
     case BasicInformation::Attributes::ClusterRevision::Id:
         encoder.Encode(kBridgedDeviceBasicInformationClusterRevision);
         break;
-    case BasicInformation::Attributes::FeatureMap::Id:
-        encoder.Encode(kBridgedDeviceBasicInformationFeatureMap);
-        break;
+    case BasicInformation::Attributes::FeatureMap::Id: {
+        BitMask<Clusters::BridgedDeviceBasicInformation::Feature> features;
+        features.Set(Clusters::BridgedDeviceBasicInformation::Feature::kBridgedICDSupport, dev->IsIcd());
+        encoder.Encode(features);
+    }
+    break;
     case BasicInformation::Attributes::UniqueID::Id:
         encoder.Encode(CharSpan::fromCharString(dev->GetBridgedAttributes().uniqueId.c_str()));
         break;
diff --git a/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDeviceManager.cpp b/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDeviceManager.cpp
index ea873aa8ef4b27..bebf315ed8ad7f 100644
--- a/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDeviceManager.cpp
+++ b/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDeviceManager.cpp
@@ -129,15 +129,35 @@ constexpr CommandId administratorCommissioningCommands[] = {
     kInvalidCommandId,
 };
 
+constexpr CommandId icdBridgedDeviceCommands[] = {
+    app::Clusters::BridgedDeviceBasicInformation::Commands::KeepActive::Id,
+    kInvalidCommandId,
+};
+
+// clang-format off
 // Declare Cluster List for Bridged Node endpoint
 DECLARE_DYNAMIC_CLUSTER_LIST_BEGIN(bridgedNodeClusters)
-DECLARE_DYNAMIC_CLUSTER(Descriptor::Id, descriptorAttrs, ZAP_CLUSTER_MASK(SERVER), nullptr, nullptr),
+    DECLARE_DYNAMIC_CLUSTER(Descriptor::Id, descriptorAttrs, ZAP_CLUSTER_MASK(SERVER), nullptr, nullptr),
     DECLARE_DYNAMIC_CLUSTER(BridgedDeviceBasicInformation::Id, bridgedDeviceBasicAttrs, ZAP_CLUSTER_MASK(SERVER), nullptr, nullptr),
     DECLARE_DYNAMIC_CLUSTER(AdministratorCommissioning::Id, AdministratorCommissioningAttrs, ZAP_CLUSTER_MASK(SERVER),
-                            administratorCommissioningCommands, nullptr) DECLARE_DYNAMIC_CLUSTER_LIST_END;
+                            administratorCommissioningCommands, nullptr)
+DECLARE_DYNAMIC_CLUSTER_LIST_END;
+
+DECLARE_DYNAMIC_CLUSTER_LIST_BEGIN(icdBridgedNodeClusters)
+    DECLARE_DYNAMIC_CLUSTER(Descriptor::Id, descriptorAttrs, ZAP_CLUSTER_MASK(SERVER), nullptr, nullptr),
+    DECLARE_DYNAMIC_CLUSTER(BridgedDeviceBasicInformation::Id, bridgedDeviceBasicAttrs, ZAP_CLUSTER_MASK(SERVER), 
+                            icdBridgedDeviceCommands, nullptr),
+    DECLARE_DYNAMIC_CLUSTER(AdministratorCommissioning::Id, AdministratorCommissioningAttrs, ZAP_CLUSTER_MASK(SERVER),
+                            administratorCommissioningCommands, nullptr)
+DECLARE_DYNAMIC_CLUSTER_LIST_END;
+// clang-format on
 
 // Declare Bridged Node endpoint
 DECLARE_DYNAMIC_ENDPOINT(sBridgedNodeEndpoint, bridgedNodeClusters);
+DECLARE_DYNAMIC_ENDPOINT(sIcdBridgedNodeEndpoint, icdBridgedNodeClusters);
+
+// TODO: this is a single version array, however we may have many
+//       different clusters that are independent.
 DataVersion sBridgedNodeDataVersions[ArraySize(bridgedNodeClusters)];
 
 const EmberAfDeviceType sBridgedDeviceTypes[] = { { DEVICE_TYPE_BRIDGED_NODE, DEVICE_VERSION_DEFAULT } };
@@ -157,9 +177,12 @@ void BridgedDeviceManager::Init()
 std::optional<unsigned> BridgedDeviceManager::AddDeviceEndpoint(std::unique_ptr<BridgedDevice> dev,
                                                                 chip::EndpointId parentEndpointId)
 {
-    EmberAfEndpointType * ep                                   = &sBridgedNodeEndpoint;
+    EmberAfEndpointType * ep = dev->IsIcd() ? &sIcdBridgedNodeEndpoint : &sBridgedNodeEndpoint;
+
     const chip::Span<const EmberAfDeviceType> & deviceTypeList = Span<const EmberAfDeviceType>(sBridgedDeviceTypes);
-    const chip::Span<chip::DataVersion> & dataVersionStorage   = Span<DataVersion>(sBridgedNodeDataVersions);
+
+    // TODO: this shares data version among different clusters, which seems incorrect
+    const chip::Span<chip::DataVersion> & dataVersionStorage = Span<DataVersion>(sBridgedNodeDataVersions);
 
     if (dev->GetBridgedAttributes().uniqueId.empty())
     {
diff --git a/examples/fabric-bridge-app/linux/RpcServer.cpp b/examples/fabric-bridge-app/linux/RpcServer.cpp
index aae7e239b694ef..840135d6d2b4d0 100644
--- a/examples/fabric-bridge-app/linux/RpcServer.cpp
+++ b/examples/fabric-bridge-app/linux/RpcServer.cpp
@@ -107,6 +107,7 @@ pw::Status FabricBridge::AddSynchronizedDevice(const chip_rpc_SynchronizedDevice
     }
 
     device->SetBridgedAttributes(attributes);
+    device->SetIcd(request.has_is_icd && request.is_icd);
 
     auto result = BridgeDeviceMgr().AddDeviceEndpoint(std::move(device), 1 /* parentEndpointId */);
     if (!result.has_value())

From 3d78200397a193d42b5e7a76f84f2825dbcbe74d Mon Sep 17 00:00:00 2001
From: Andrei Litvin <andy314@gmail.com>
Date: Wed, 7 Aug 2024 14:33:22 -0400
Subject: [PATCH 31/41] Restyle

---
 .../fabric-bridge-common/src/BridgedDeviceManager.cpp           | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDeviceManager.cpp b/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDeviceManager.cpp
index bebf315ed8ad7f..67bcf0ac5b2752 100644
--- a/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDeviceManager.cpp
+++ b/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDeviceManager.cpp
@@ -145,7 +145,7 @@ DECLARE_DYNAMIC_CLUSTER_LIST_END;
 
 DECLARE_DYNAMIC_CLUSTER_LIST_BEGIN(icdBridgedNodeClusters)
     DECLARE_DYNAMIC_CLUSTER(Descriptor::Id, descriptorAttrs, ZAP_CLUSTER_MASK(SERVER), nullptr, nullptr),
-    DECLARE_DYNAMIC_CLUSTER(BridgedDeviceBasicInformation::Id, bridgedDeviceBasicAttrs, ZAP_CLUSTER_MASK(SERVER), 
+    DECLARE_DYNAMIC_CLUSTER(BridgedDeviceBasicInformation::Id, bridgedDeviceBasicAttrs, ZAP_CLUSTER_MASK(SERVER),
                             icdBridgedDeviceCommands, nullptr),
     DECLARE_DYNAMIC_CLUSTER(AdministratorCommissioning::Id, AdministratorCommissioningAttrs, ZAP_CLUSTER_MASK(SERVER),
                             administratorCommissioningCommands, nullptr)

From f2841eb96eb392d72f08d97072623e5f7662db94 Mon Sep 17 00:00:00 2001
From: Andrei Litvin <andy314@gmail.com>
Date: Wed, 7 Aug 2024 19:38:45 -0400
Subject: [PATCH 32/41] Remove some of the spammier logs

---
 .../fabric-admin/commands/pairing/DeviceSynchronization.cpp   | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/examples/fabric-admin/commands/pairing/DeviceSynchronization.cpp b/examples/fabric-admin/commands/pairing/DeviceSynchronization.cpp
index d6f4d3d01f1c6b..b512daa42469cb 100644
--- a/examples/fabric-admin/commands/pairing/DeviceSynchronization.cpp
+++ b/examples/fabric-admin/commands/pairing/DeviceSynchronization.cpp
@@ -71,9 +71,6 @@ void DeviceSynchronizer::OnAttributeData(const ConcreteDataAttributePath & path,
     VerifyOrDie(path.mEndpointId == kRootEndpointId);
     VerifyOrDie(path.mClusterId == Clusters::BasicInformation::Id);
 
-    ChipLogProgress(NotSpecified, "Attribute data");
-    path.LogPath();
-
     switch (path.mAttributeId)
     {
     case Clusters::BasicInformation::Attributes::UniqueID::Id:
@@ -115,7 +112,6 @@ void DeviceSynchronizer::OnAttributeData(const ConcreteDataAttributePath & path,
             "SoftwareVersionString");
         break;
     default:
-        ChipLogProgress(NotSpecified, "Attribute data not processed");
         break;
     }
 }

From dc75ac56a5f7721e377079ebfdfb595d5ca9bb50 Mon Sep 17 00:00:00 2001
From: Andrei Litvin <andy314@gmail.com>
Date: Wed, 7 Aug 2024 19:40:15 -0400
Subject: [PATCH 33/41] Enfore RPC enabling for synchronized device addition

---
 .../fabric-admin/commands/pairing/DeviceSynchronization.cpp   | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/examples/fabric-admin/commands/pairing/DeviceSynchronization.cpp b/examples/fabric-admin/commands/pairing/DeviceSynchronization.cpp
index b512daa42469cb..90f9e1eaa06619 100644
--- a/examples/fabric-admin/commands/pairing/DeviceSynchronization.cpp
+++ b/examples/fabric-admin/commands/pairing/DeviceSynchronization.cpp
@@ -119,7 +119,11 @@ void DeviceSynchronizer::OnAttributeData(const ConcreteDataAttributePath & path,
 void DeviceSynchronizer::OnReportEnd()
 {
     // Report end is at the end of all attributes (success)
+#if defined(PW_RPC_ENABLED)
     AddSynchronizedDevice(mCurrentDeviceData);
+#else
+    ChipLogError(NotSpecified, "Cannot synchronize device with fabric bridge: RPC not enabled");
+#endif
 }
 
 void DeviceSynchronizer::OnDone(chip::app::ReadClient * apReadClient)

From 2501d42410bfa1f9361c33a0767fbcb17b0b2a15 Mon Sep 17 00:00:00 2001
From: Andrei Litvin <andreilitvin@google.com>
Date: Thu, 8 Aug 2024 08:26:26 -0400
Subject: [PATCH 34/41] Add device sync in progress tracking

---
 .../commands/pairing/DeviceSynchronization.cpp         | 10 ++++++++++
 .../commands/pairing/DeviceSynchronization.h           |  1 +
 third_party/nxp/nxp_matter_support                     |  2 +-
 3 files changed, 12 insertions(+), 1 deletion(-)

diff --git a/examples/fabric-admin/commands/pairing/DeviceSynchronization.cpp b/examples/fabric-admin/commands/pairing/DeviceSynchronization.cpp
index 90f9e1eaa06619..a7f236bf02c971 100644
--- a/examples/fabric-admin/commands/pairing/DeviceSynchronization.cpp
+++ b/examples/fabric-admin/commands/pairing/DeviceSynchronization.cpp
@@ -124,6 +124,7 @@ void DeviceSynchronizer::OnReportEnd()
 #else
     ChipLogError(NotSpecified, "Cannot synchronize device with fabric bridge: RPC not enabled");
 #endif
+    mDeviceSyncInProcess = false;
 }
 
 void DeviceSynchronizer::OnDone(chip::app::ReadClient * apReadClient)
@@ -134,6 +135,7 @@ void DeviceSynchronizer::OnDone(chip::app::ReadClient * apReadClient)
 void DeviceSynchronizer::OnError(CHIP_ERROR error)
 {
     ChipLogProgress(NotSpecified, "Error fetching device data: %" CHIP_ERROR_FORMAT, error.Format());
+    mDeviceSyncInProcess = false;
 }
 
 void DeviceSynchronizer::OnDeviceConnected(chip::Messaging::ExchangeManager & exchangeMgr,
@@ -167,10 +169,18 @@ void DeviceSynchronizer::OnDeviceConnectionFailure(const chip::ScopedNodeId & pe
 void DeviceSynchronizer::StartDeviceSynchronization(chip::Controller::DeviceController & controller, chip::NodeId nodeId,
                                                     bool deviceIsIcd)
 {
+    if (mDeviceSyncInProcess)
+    {
+        ChipLogError(NotSpecified, "Device Sync NOT POSSIBLE: another sync is in progress");
+        return;
+    }
+
     mCurrentDeviceData            = chip_rpc_SynchronizedDevice_init_default;
     mCurrentDeviceData.node_id    = nodeId;
     mCurrentDeviceData.has_is_icd = true;
     mCurrentDeviceData.is_icd     = deviceIsIcd;
 
+    mDeviceSyncInProcess = true;
+
     controller.GetConnectedDevice(nodeId, &mOnDeviceConnectedCallback, &mOnDeviceConnectionFailureCallback);
 }
diff --git a/examples/fabric-admin/commands/pairing/DeviceSynchronization.h b/examples/fabric-admin/commands/pairing/DeviceSynchronization.h
index e2c341b53f0845..48972370691207 100644
--- a/examples/fabric-admin/commands/pairing/DeviceSynchronization.h
+++ b/examples/fabric-admin/commands/pairing/DeviceSynchronization.h
@@ -65,5 +65,6 @@ class DeviceSynchronizer : public chip::app::ReadClient::Callback
     chip::Callback::Callback<chip::OnDeviceConnected> mOnDeviceConnectedCallback;
     chip::Callback::Callback<chip::OnDeviceConnectionFailure> mOnDeviceConnectionFailureCallback;
 
+    bool mDeviceSyncInProcess = false;
     chip_rpc_SynchronizedDevice mCurrentDeviceData = chip_rpc_SynchronizedDevice_init_default;
 };
diff --git a/third_party/nxp/nxp_matter_support b/third_party/nxp/nxp_matter_support
index e6deaf56001387..ac504a0cc38963 160000
--- a/third_party/nxp/nxp_matter_support
+++ b/third_party/nxp/nxp_matter_support
@@ -1 +1 @@
-Subproject commit e6deaf5600138763ea68418e34bc62a02d1aef0d
+Subproject commit ac504a0cc389632c0e26b4f04e65914d3a9ba8bd

From 9ff1c0d89c718deeee3e8c5f5b334f3c455d739e Mon Sep 17 00:00:00 2001
From: Andrei Litvin <andreilitvin@google.com>
Date: Thu, 8 Aug 2024 08:27:42 -0400
Subject: [PATCH 35/41] Undo submodule update

---
 third_party/nxp/nxp_matter_support | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/third_party/nxp/nxp_matter_support b/third_party/nxp/nxp_matter_support
index ac504a0cc38963..e6deaf56001387 160000
--- a/third_party/nxp/nxp_matter_support
+++ b/third_party/nxp/nxp_matter_support
@@ -1 +1 @@
-Subproject commit ac504a0cc389632c0e26b4f04e65914d3a9ba8bd
+Subproject commit e6deaf5600138763ea68418e34bc62a02d1aef0d

From 46b75f2c503a940252186ec74da7b7620c960573 Mon Sep 17 00:00:00 2001
From: Andrei Litvin <andreilitvin@google.com>
Date: Thu, 8 Aug 2024 08:48:19 -0400
Subject: [PATCH 36/41] Fix up device sync progress tracking to better handle
 errors

---
 .../fabric-admin/commands/pairing/DeviceSynchronization.cpp  | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/examples/fabric-admin/commands/pairing/DeviceSynchronization.cpp b/examples/fabric-admin/commands/pairing/DeviceSynchronization.cpp
index a7f236bf02c971..3974761fdc4bc2 100644
--- a/examples/fabric-admin/commands/pairing/DeviceSynchronization.cpp
+++ b/examples/fabric-admin/commands/pairing/DeviceSynchronization.cpp
@@ -124,18 +124,17 @@ void DeviceSynchronizer::OnReportEnd()
 #else
     ChipLogError(NotSpecified, "Cannot synchronize device with fabric bridge: RPC not enabled");
 #endif
-    mDeviceSyncInProcess = false;
 }
 
 void DeviceSynchronizer::OnDone(chip::app::ReadClient * apReadClient)
 {
     // Nothing to do: error reported on OnError or report ended called.
+    mDeviceSyncInProcess = false;
 }
 
 void DeviceSynchronizer::OnError(CHIP_ERROR error)
 {
     ChipLogProgress(NotSpecified, "Error fetching device data: %" CHIP_ERROR_FORMAT, error.Format());
-    mDeviceSyncInProcess = false;
 }
 
 void DeviceSynchronizer::OnDeviceConnected(chip::Messaging::ExchangeManager & exchangeMgr,
@@ -158,12 +157,14 @@ void DeviceSynchronizer::OnDeviceConnected(chip::Messaging::ExchangeManager & ex
     if (err != CHIP_NO_ERROR)
     {
         ChipLogError(NotSpecified, "Failed to issue read for BasicInformation data");
+        mDeviceSyncInProcess = false;
     }
 }
 
 void DeviceSynchronizer::OnDeviceConnectionFailure(const chip::ScopedNodeId & peerId, CHIP_ERROR error)
 {
     ChipLogError(NotSpecified, "Device Sync failed to connect to " ChipLogFormatX64, ChipLogValueX64(peerId.GetNodeId()));
+    mDeviceSyncInProcess = false;
 }
 
 void DeviceSynchronizer::StartDeviceSynchronization(chip::Controller::DeviceController & controller, chip::NodeId nodeId,

From 4ae53d009c18be23016e6026595a9a08ca76f950 Mon Sep 17 00:00:00 2001
From: "Restyled.io" <commits@restyled.io>
Date: Thu, 8 Aug 2024 12:48:42 +0000
Subject: [PATCH 37/41] Restyled by clang-format

---
 examples/fabric-admin/commands/pairing/DeviceSynchronization.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/examples/fabric-admin/commands/pairing/DeviceSynchronization.h b/examples/fabric-admin/commands/pairing/DeviceSynchronization.h
index 48972370691207..16c0e264928639 100644
--- a/examples/fabric-admin/commands/pairing/DeviceSynchronization.h
+++ b/examples/fabric-admin/commands/pairing/DeviceSynchronization.h
@@ -65,6 +65,6 @@ class DeviceSynchronizer : public chip::app::ReadClient::Callback
     chip::Callback::Callback<chip::OnDeviceConnected> mOnDeviceConnectedCallback;
     chip::Callback::Callback<chip::OnDeviceConnectionFailure> mOnDeviceConnectionFailureCallback;
 
-    bool mDeviceSyncInProcess = false;
+    bool mDeviceSyncInProcess                      = false;
     chip_rpc_SynchronizedDevice mCurrentDeviceData = chip_rpc_SynchronizedDevice_init_default;
 };

From a59fef76b86c5866c1c1c6e938fe0300232c6fb4 Mon Sep 17 00:00:00 2001
From: Andrei Litvin <andreilitvin@google.com>
Date: Thu, 8 Aug 2024 11:19:55 -0400
Subject: [PATCH 38/41] Fix typo

---
 examples/fabric-admin/commands/pairing/DeviceSynchronization.h | 2 +-
 third_party/bouffalolab/repo                                   | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/examples/fabric-admin/commands/pairing/DeviceSynchronization.h b/examples/fabric-admin/commands/pairing/DeviceSynchronization.h
index 16c0e264928639..6aca23f31cbeaa 100644
--- a/examples/fabric-admin/commands/pairing/DeviceSynchronization.h
+++ b/examples/fabric-admin/commands/pairing/DeviceSynchronization.h
@@ -26,7 +26,7 @@
 #include "fabric_bridge_service/fabric_bridge_service.pb.h"
 #include "fabric_bridge_service/fabric_bridge_service.rpc.pb.h"
 
-/// Ensures that device data is synchronized to the remove fabric bridge.
+/// Ensures that device data is synchronized to the remote fabric bridge.
 ///
 /// Includes a state machine that:
 ///   - initiates a "read basic information data" command to fetch basic information
diff --git a/third_party/bouffalolab/repo b/third_party/bouffalolab/repo
index 51a4f451b67a33..07ac148f70e1e3 160000
--- a/third_party/bouffalolab/repo
+++ b/third_party/bouffalolab/repo
@@ -1 +1 @@
-Subproject commit 51a4f451b67a33d07f11cc55e4dbd8ff5d374eb0
+Subproject commit 07ac148f70e1e3773f0ba0fa5ccad00bdf40e4d9

From 29e2dcd492511c5cef1efb42c64e31f68e77775e Mon Sep 17 00:00:00 2001
From: Andrei Litvin <andreilitvin@google.com>
Date: Thu, 8 Aug 2024 11:21:30 -0400
Subject: [PATCH 39/41] Undo submodule update

---
 third_party/bouffalolab/repo | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/third_party/bouffalolab/repo b/third_party/bouffalolab/repo
index 07ac148f70e1e3..51a4f451b67a33 160000
--- a/third_party/bouffalolab/repo
+++ b/third_party/bouffalolab/repo
@@ -1 +1 @@
-Subproject commit 07ac148f70e1e3773f0ba0fa5ccad00bdf40e4d9
+Subproject commit 51a4f451b67a33d07f11cc55e4dbd8ff5d374eb0

From c4064f068b5fb431939c6eba6a6b5b073bdc2d11 Mon Sep 17 00:00:00 2001
From: Andrei Litvin <andreilitvin@google.com>
Date: Thu, 8 Aug 2024 12:49:52 -0400
Subject: [PATCH 40/41] Fix merge

---
 .../fabric-bridge-common/include/BridgedDevice.h    | 13 -------------
 1 file changed, 13 deletions(-)

diff --git a/examples/fabric-bridge-app/fabric-bridge-common/include/BridgedDevice.h b/examples/fabric-bridge-app/fabric-bridge-common/include/BridgedDevice.h
index b7730e8176bab5..3dab8d3b16b2d6 100644
--- a/examples/fabric-bridge-app/fabric-bridge-common/include/BridgedDevice.h
+++ b/examples/fabric-bridge-app/fabric-bridge-common/include/BridgedDevice.h
@@ -65,25 +65,12 @@ class BridgedDevice
     void SetUniqueId(const std::string & value) { mAttributes.uniqueId = value; }
 
 protected:
-<<<<<<< HEAD
     bool mReachable = false;
     bool mIsIcd     = false;
 
     chip::NodeId mNodeId               = 0;
     chip::EndpointId mEndpointId       = 0;
     chip::EndpointId mParentEndpointId = 0;
-||||||| a315c91a2d
-    bool mReachable;
-    chip::NodeId mNodeId;
-    chip::EndpointId mEndpointId;
-    chip::EndpointId mParentEndpointId;
-=======
-    bool mReachable;
-    bool mIsIcd = false;
-    chip::NodeId mNodeId;
-    chip::EndpointId mEndpointId;
-    chip::EndpointId mParentEndpointId;
->>>>>>> master
 
     BridgedAttributes mAttributes;
 };

From efcb58a92ff4657b5fe6445d7b2ffc7af7c52cf1 Mon Sep 17 00:00:00 2001
From: "Restyled.io" <commits@restyled.io>
Date: Thu, 8 Aug 2024 16:50:24 +0000
Subject: [PATCH 41/41] Restyled by clang-format

---
 .../fabric-bridge-common/src/BridgedDeviceManager.cpp            | 1 -
 1 file changed, 1 deletion(-)

diff --git a/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDeviceManager.cpp b/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDeviceManager.cpp
index 0657e40993655b..8db44c3e8bfd9b 100644
--- a/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDeviceManager.cpp
+++ b/examples/fabric-bridge-app/fabric-bridge-common/src/BridgedDeviceManager.cpp
@@ -141,7 +141,6 @@ constexpr CommandId administratorCommissioningCommands[] = {
     kInvalidCommandId,
 };
 
-
 // clang-format off
 // Declare Cluster List for Bridged Node endpoint
 DECLARE_DYNAMIC_CLUSTER_LIST_BEGIN(bridgedNodeClusters)