From e8e9fc5a21d825b1b5b718dc328a11e486e2f6fa Mon Sep 17 00:00:00 2001 From: Yufeng Wang Date: Thu, 15 Aug 2024 14:25:38 -0700 Subject: [PATCH] [Fabric-Admin] Add API to commission local bridge within its own fabric (#35020) * Add local bridge handle API * Update examples/fabric-admin/commands/fabric-sync/FabricSyncCommand.cpp Co-authored-by: saurabhst * Update examples/fabric-admin/commands/fabric-sync/FabricSyncCommand.cpp Co-authored-by: saurabhst * Use VerifyOrDie to check pairingCommand --------- Co-authored-by: saurabhst --- .../commands/fabric-sync/Commands.h | 2 + .../fabric-sync/FabricSyncCommand.cpp | 121 ++++++++++++++++-- .../commands/fabric-sync/FabricSyncCommand.h | 47 ++++++- .../device_manager/DeviceManager.cpp | 25 +++- .../device_manager/DeviceManager.h | 30 ++++- 5 files changed, 210 insertions(+), 15 deletions(-) diff --git a/examples/fabric-admin/commands/fabric-sync/Commands.h b/examples/fabric-admin/commands/fabric-sync/Commands.h index 94de1d31d8ba09..a6bf1c258f9475 100644 --- a/examples/fabric-admin/commands/fabric-sync/Commands.h +++ b/examples/fabric-admin/commands/fabric-sync/Commands.h @@ -28,6 +28,8 @@ void registerCommandsFabricSync(Commands & commands, CredentialIssuerCommands * commands_list clusterCommands = { make_unique(credsIssuerConfig), make_unique(credsIssuerConfig), + make_unique(credsIssuerConfig), + make_unique(credsIssuerConfig), make_unique(credsIssuerConfig), make_unique(credsIssuerConfig), }; diff --git a/examples/fabric-admin/commands/fabric-sync/FabricSyncCommand.cpp b/examples/fabric-admin/commands/fabric-sync/FabricSyncCommand.cpp index f62d85ce5afd40..704996d189d9c2 100644 --- a/examples/fabric-admin/commands/fabric-sync/FabricSyncCommand.cpp +++ b/examples/fabric-admin/commands/fabric-sync/FabricSyncCommand.cpp @@ -32,10 +32,6 @@ using namespace ::chip; namespace { -// Constants -constexpr uint32_t kCommissionPrepareTimeMs = 500; -constexpr uint16_t kMaxManaulCodeLength = 21; - void CheckFabricBridgeSynchronizationSupport(intptr_t ignored) { DeviceMgr().ReadSupportedDeviceCategories(); @@ -43,7 +39,7 @@ void CheckFabricBridgeSynchronizationSupport(intptr_t ignored) } // namespace -void FabricSyncAddBridgeCommand::OnCommissioningComplete(chip::NodeId deviceId, CHIP_ERROR err) +void FabricSyncAddBridgeCommand::OnCommissioningComplete(NodeId deviceId, CHIP_ERROR err) { if (mBridgeNodeId != deviceId) { @@ -90,7 +86,7 @@ CHIP_ERROR FabricSyncAddBridgeCommand::RunCommand(NodeId remoteId) if (DeviceMgr().IsFabricSyncReady()) { // print to console - fprintf(stderr, "Remote Fabric Bridge has been alread configured."); + fprintf(stderr, "Remote Fabric Bridge has already been configured."); return CHIP_NO_ERROR; } @@ -98,7 +94,7 @@ CHIP_ERROR FabricSyncAddBridgeCommand::RunCommand(NodeId remoteId) if (pairingCommand == nullptr) { - ChipLogError(NotSpecified, "Pairing onnetwork command is not available"); + ChipLogError(NotSpecified, "Pairing already-discovered command is not available"); return CHIP_ERROR_NOT_IMPLEMENTED; } @@ -110,7 +106,7 @@ CHIP_ERROR FabricSyncAddBridgeCommand::RunCommand(NodeId remoteId) return CHIP_NO_ERROR; } -void FabricSyncRemoveBridgeCommand::OnDeviceRemoved(chip::NodeId deviceId, CHIP_ERROR err) +void FabricSyncRemoveBridgeCommand::OnDeviceRemoved(NodeId deviceId, CHIP_ERROR err) { if (mBridgeNodeId != deviceId) { @@ -150,7 +146,7 @@ CHIP_ERROR FabricSyncRemoveBridgeCommand::RunCommand() if (pairingCommand == nullptr) { - ChipLogError(NotSpecified, "Pairing code command is not available"); + ChipLogError(NotSpecified, "Pairing unpair command is not available"); return CHIP_ERROR_NOT_IMPLEMENTED; } @@ -161,13 +157,116 @@ CHIP_ERROR FabricSyncRemoveBridgeCommand::RunCommand() return CHIP_NO_ERROR; } +void FabricSyncAddLocalBridgeCommand::OnCommissioningComplete(NodeId deviceId, CHIP_ERROR err) +{ + if (mLocalBridgeNodeId != deviceId) + { + if (err != CHIP_NO_ERROR) + { + ChipLogError(NotSpecified, "Failed to pair non-bridge device (0x:" ChipLogFormatX64 ") with error: %" CHIP_ERROR_FORMAT, + ChipLogValueX64(deviceId), err.Format()); + } + else + { + ChipLogProgress(NotSpecified, "Commissioning complete for non-bridge device: NodeId: " ChipLogFormatX64, + ChipLogValueX64(deviceId)); + } + return; + } + + if (err == CHIP_NO_ERROR) + { + DeviceMgr().SetLocalBridgeNodeId(mLocalBridgeNodeId); + ChipLogProgress(NotSpecified, "Successfully paired local bridge device: NodeId: " ChipLogFormatX64, + ChipLogValueX64(mLocalBridgeNodeId)); + } + else + { + ChipLogError(NotSpecified, "Failed to pair local bridge device (0x:" ChipLogFormatX64 ") with error: %" CHIP_ERROR_FORMAT, + ChipLogValueX64(deviceId), err.Format()); + } + + mLocalBridgeNodeId = kUndefinedNodeId; +} + +CHIP_ERROR FabricSyncAddLocalBridgeCommand::RunCommand(NodeId deviceId) +{ + if (DeviceMgr().IsLocalBridgeReady()) + { + // print to console + fprintf(stderr, "Local Fabric Bridge has already been configured."); + return CHIP_NO_ERROR; + } + + PairingCommand * pairingCommand = static_cast(CommandMgr().GetCommandByName("pairing", "already-discovered")); + VerifyOrDie(pairingCommand != nullptr); + + pairingCommand->RegisterCommissioningDelegate(this); + mLocalBridgeNodeId = deviceId; + + DeviceMgr().PairLocalFabricBridge(deviceId); + + return CHIP_NO_ERROR; +} + +void FabricSyncRemoveLocalBridgeCommand::OnDeviceRemoved(NodeId deviceId, CHIP_ERROR err) +{ + if (mLocalBridgeNodeId != deviceId) + { + ChipLogProgress(NotSpecified, "A non-bridge device: NodeId: " ChipLogFormatX64 " is removed.", ChipLogValueX64(deviceId)); + return; + } + + if (err == CHIP_NO_ERROR) + { + DeviceMgr().SetLocalBridgeNodeId(kUndefinedNodeId); + ChipLogProgress(NotSpecified, "Successfully removed local bridge device: NodeId: " ChipLogFormatX64, + ChipLogValueX64(mLocalBridgeNodeId)); + } + else + { + ChipLogError(NotSpecified, "Failed to remove local bridge device (0x:" ChipLogFormatX64 ") with error: %" CHIP_ERROR_FORMAT, + ChipLogValueX64(deviceId), err.Format()); + } + + mLocalBridgeNodeId = kUndefinedNodeId; +} + +CHIP_ERROR FabricSyncRemoveLocalBridgeCommand::RunCommand() +{ + NodeId bridgeNodeId = DeviceMgr().GetLocalBridgeNodeId(); + + if (bridgeNodeId == kUndefinedNodeId) + { + // print to console + fprintf(stderr, "Local Fabric Bridge is not configured yet, nothing to remove."); + return CHIP_NO_ERROR; + } + + mLocalBridgeNodeId = bridgeNodeId; + + PairingCommand * pairingCommand = static_cast(CommandMgr().GetCommandByName("pairing", "unpair")); + + if (pairingCommand == nullptr) + { + ChipLogError(NotSpecified, "Pairing unpair command is not available"); + return CHIP_ERROR_NOT_IMPLEMENTED; + } + + pairingCommand->RegisterPairingDelegate(this); + + DeviceMgr().UnpairLocalFabricBridge(); + + return CHIP_NO_ERROR; +} + void FabricSyncDeviceCommand::OnCommissioningWindowOpened(NodeId deviceId, CHIP_ERROR err, chip::SetupPayload payload) { ChipLogProgress(NotSpecified, "FabricSyncDeviceCommand::OnCommissioningWindowOpened"); if (err == CHIP_NO_ERROR) { - char payloadBuffer[kMaxManaulCodeLength + 1]; + char payloadBuffer[kMaxManualCodeLength + 1]; MutableCharSpan manualCode(payloadBuffer); CHIP_ERROR error = ManualSetupPayloadGenerator(payload).payloadDecimalStringRepresentation(manualCode); if (error == CHIP_NO_ERROR) @@ -202,7 +301,7 @@ void FabricSyncDeviceCommand::OnCommissioningWindowOpened(NodeId deviceId, CHIP_ } } -void FabricSyncDeviceCommand::OnCommissioningComplete(chip::NodeId deviceId, CHIP_ERROR err) +void FabricSyncDeviceCommand::OnCommissioningComplete(NodeId deviceId, CHIP_ERROR err) { if (mAssignedNodeId != deviceId) { diff --git a/examples/fabric-admin/commands/fabric-sync/FabricSyncCommand.h b/examples/fabric-admin/commands/fabric-sync/FabricSyncCommand.h index ca1b105207f832..1bbd22d293f39d 100644 --- a/examples/fabric-admin/commands/fabric-sync/FabricSyncCommand.h +++ b/examples/fabric-admin/commands/fabric-sync/FabricSyncCommand.h @@ -22,6 +22,10 @@ #include #include +// Constants +constexpr uint32_t kCommissionPrepareTimeMs = 500; +constexpr uint16_t kMaxManualCodeLength = 21; + class FabricSyncAddBridgeCommand : public CHIPCommand, public CommissioningDelegate { public: @@ -31,7 +35,7 @@ class FabricSyncAddBridgeCommand : public CHIPCommand, public CommissioningDeleg AddArgument("device-remote-ip", &mRemoteAddr); } - void OnCommissioningComplete(NodeId deviceId, CHIP_ERROR err) override; + void OnCommissioningComplete(chip::NodeId deviceId, CHIP_ERROR err) override; /////////// CHIPCommand Interface ///////// CHIP_ERROR RunCommand() override { return RunCommand(mNodeId); } @@ -63,6 +67,47 @@ class FabricSyncRemoveBridgeCommand : public CHIPCommand, public PairingDelegate chip::NodeId mBridgeNodeId; }; +class FabricSyncAddLocalBridgeCommand : public CHIPCommand, public CommissioningDelegate +{ +public: + FabricSyncAddLocalBridgeCommand(CredentialIssuerCommands * credIssuerCommands) : + CHIPCommand("add-local-bridge", credIssuerCommands) + { + AddArgument("nodeid", 0, UINT64_MAX, &mNodeId); + } + + void OnCommissioningComplete(NodeId deviceId, CHIP_ERROR err) override; + + /////////// CHIPCommand Interface ///////// + CHIP_ERROR RunCommand() override { return RunCommand(mNodeId); } + + chip::System::Clock::Timeout GetWaitDuration() const override { return chip::System::Clock::Seconds16(1); } + +private: + chip::NodeId mNodeId; + chip::NodeId mLocalBridgeNodeId; + + CHIP_ERROR RunCommand(chip::NodeId deviceId); +}; + +class FabricSyncRemoveLocalBridgeCommand : public CHIPCommand, public PairingDelegate +{ +public: + FabricSyncRemoveLocalBridgeCommand(CredentialIssuerCommands * credIssuerCommands) : + CHIPCommand("remove-local-bridge", credIssuerCommands) + {} + + void OnDeviceRemoved(chip::NodeId deviceId, CHIP_ERROR err) override; + + /////////// CHIPCommand Interface ///////// + CHIP_ERROR RunCommand() override; + + chip::System::Clock::Timeout GetWaitDuration() const override { return chip::System::Clock::Seconds16(1); } + +private: + chip::NodeId mLocalBridgeNodeId; +}; + class FabricSyncDeviceCommand : public CHIPCommand, public CommissioningWindowDelegate, public CommissioningDelegate { public: diff --git a/examples/fabric-admin/device_manager/DeviceManager.cpp b/examples/fabric-admin/device_manager/DeviceManager.cpp index 7204e153d2807f..17adcc2427f9c6 100644 --- a/examples/fabric-admin/device_manager/DeviceManager.cpp +++ b/examples/fabric-admin/device_manager/DeviceManager.cpp @@ -33,6 +33,7 @@ namespace { // Constants constexpr uint32_t kSetupPinCode = 20202021; constexpr uint16_t kRemoteBridgePort = 5540; +constexpr uint16_t kLocalBridgePort = 5540; constexpr uint16_t kWindowTimeout = 300; constexpr uint16_t kIteration = 1000; constexpr uint16_t kSubscribeMinInterval = 0; @@ -117,6 +118,8 @@ void DeviceManager::RemoveSyncedDevice(NodeId nodeId) void DeviceManager::OpenDeviceCommissioningWindow(NodeId nodeId, uint32_t commissioningTimeout, uint32_t iterations, uint32_t discriminator, const char * saltHex, const char * verifierHex) { + ChipLogProgress(NotSpecified, "Open the commissioning window of device with NodeId:" ChipLogFormatX64, ChipLogValueX64(nodeId)); + // Open the commissioning window of a device within its own fabric. StringBuilder commandBuilder; @@ -132,7 +135,7 @@ void DeviceManager::OpenRemoteDeviceCommissioningWindow(EndpointId remoteEndpoin // Open the commissioning window of a device from another fabric via its fabric bridge. // This method constructs and sends a command to open the commissioning window for a device // that is part of a different fabric, accessed through a fabric bridge. - StringBuilder<512> commandBuilder; + StringBuilder commandBuilder; // Use random discriminator to have less chance of collission. uint16_t discriminator = @@ -166,6 +169,16 @@ void DeviceManager::PairRemoteDevice(chip::NodeId nodeId, const char * payload) PushCommand(commandBuilder.c_str()); } +void DeviceManager::PairLocalFabricBridge(NodeId nodeId) +{ + StringBuilder commandBuilder; + + commandBuilder.Add("pairing already-discovered "); + commandBuilder.AddFormat("%lu %d ::1 %d", nodeId, kSetupPinCode, kLocalBridgePort); + + PushCommand(commandBuilder.c_str()); +} + void DeviceManager::UnpairRemoteFabricBridge() { StringBuilder commandBuilder; @@ -176,6 +189,16 @@ void DeviceManager::UnpairRemoteFabricBridge() PushCommand(commandBuilder.c_str()); } +void DeviceManager::UnpairLocalFabricBridge() +{ + StringBuilder commandBuilder; + + commandBuilder.Add("pairing unpair "); + commandBuilder.AddFormat("%lu", mLocalBridgeNodeId); + + PushCommand(commandBuilder.c_str()); +} + void DeviceManager::SubscribeRemoteFabricBridge() { // Listen to the state changes of the remote fabric bridge. diff --git a/examples/fabric-admin/device_manager/DeviceManager.h b/examples/fabric-admin/device_manager/DeviceManager.h index cad573a9311421..454986bd7a40f0 100644 --- a/examples/fabric-admin/device_manager/DeviceManager.h +++ b/examples/fabric-admin/device_manager/DeviceManager.h @@ -55,14 +55,20 @@ class DeviceManager : public PairingDelegate chip::NodeId GetRemoteBridgeNodeId() const { return mRemoteBridgeNodeId; } + chip::NodeId GetLocalBridgeNodeId() const { return mLocalBridgeNodeId; } + void UpdateLastUsedNodeId(chip::NodeId nodeId); - void SetRemoteBridgeNodeId(chip::NodeId remoteBridgeNodeId) { mRemoteBridgeNodeId = remoteBridgeNodeId; } + void SetRemoteBridgeNodeId(chip::NodeId nodeId) { mRemoteBridgeNodeId = nodeId; } + + void SetLocalBridgeNodeId(chip::NodeId nodeId) { mLocalBridgeNodeId = nodeId; } bool IsAutoSyncEnabled() const { return mAutoSyncEnabled; } bool IsFabricSyncReady() const { return mRemoteBridgeNodeId != chip::kUndefinedNodeId; } + bool IsLocalBridgeReady() const { return mLocalBridgeNodeId != chip::kUndefinedNodeId; } + void EnableAutoSync(bool state) { mAutoSyncEnabled = state; } void AddSyncedDevice(const Device & device); @@ -126,8 +132,20 @@ class DeviceManager : public PairingDelegate */ void PairRemoteDevice(chip::NodeId nodeId, const char * payload); + /** + * @brief Pair a local fabric bridge with a given node ID. + * + * This function initiates the pairing process for the local fabric bridge using the specified parameters. + + * @param nodeId The user-defined ID for the node being commissioned. It doesn’t need to be the same ID, + * as for the first fabric. + */ + void PairLocalFabricBridge(chip::NodeId nodeId); + void UnpairRemoteFabricBridge(); + void UnpairLocalFabricBridge(); + void SubscribeRemoteFabricBridge(); void StartReverseCommissioning(); @@ -147,8 +165,16 @@ class DeviceManager : public PairingDelegate static DeviceManager sInstance; - chip::NodeId mLastUsedNodeId = 0; + chip::NodeId mLastUsedNodeId = 0; + + // The Node ID of the remote bridge used for Fabric-Sync + // This represents the bridge on the other ecosystem. chip::NodeId mRemoteBridgeNodeId = chip::kUndefinedNodeId; + + // The Node ID of the local bridge used for Fabric-Sync + // This represents the bridge within its own ecosystem. + chip::NodeId mLocalBridgeNodeId = chip::kUndefinedNodeId; + std::set mSyncedDevices; bool mAutoSyncEnabled = false; bool mInitialized = false;