From d8e7e43fec024800a3441762f68123b369c85164 Mon Sep 17 00:00:00 2001 From: Song GUO Date: Tue, 4 Jun 2024 17:53:30 +0000 Subject: [PATCH] [python] Add ICD support to Python binding (#33533) * [icd] Add ICD support to python * [python] Add ICD support to Python binding * Update * update * update * Update * Use ScopedNodeId in ICD commissioning callbacks * update * fix --- .../commands/pairing/PairingCommand.cpp | 14 +- .../commands/pairing/PairingCommand.h | 4 +- .../commands/pairing/PairingCommand.cpp | 16 +- .../commands/pairing/PairingCommand.h | 4 +- src/controller/CHIPDeviceController.cpp | 10 +- src/controller/DevicePairingDelegate.h | 4 +- .../java/AndroidDeviceControllerWrapper.cpp | 12 +- .../java/AndroidDeviceControllerWrapper.h | 2 +- src/controller/python/BUILD.gn | 3 + .../ChipDeviceController-ScriptBinding.cpp | 88 +++++++++- ...Controller-ScriptDevicePairingDelegate.cpp | 40 +++++ ...ceController-ScriptDevicePairingDelegate.h | 8 +- src/controller/python/OpCredsBinding.cpp | 5 + src/controller/python/chip/ChipDeviceCtrl.py | 163 +++++++++++++++++- src/controller/python/chip/ChipReplStartup.py | 4 +- .../python/chip/icd/PyChipCheckInDelegate.cpp | 33 ++++ .../python/chip/icd/PyChipCheckInDelegate.h | 42 +++++ src/controller/python/chip/internal/types.py | 6 +- 18 files changed, 419 insertions(+), 39 deletions(-) create mode 100644 src/controller/python/chip/icd/PyChipCheckInDelegate.cpp create mode 100644 src/controller/python/chip/icd/PyChipCheckInDelegate.h diff --git a/examples/chip-tool/commands/pairing/PairingCommand.cpp b/examples/chip-tool/commands/pairing/PairingCommand.cpp index 5f6c179779f3c2..76c8ac8a58cc19 100644 --- a/examples/chip-tool/commands/pairing/PairingCommand.cpp +++ b/examples/chip-tool/commands/pairing/PairingCommand.cpp @@ -436,7 +436,7 @@ void PairingCommand::OnReadCommissioningInfo(const Controller::ReadCommissioning info.icd.idleModeDuration, info.icd.activeModeDuration, info.icd.activeModeThreshold); } -void PairingCommand::OnICDRegistrationComplete(NodeId nodeId, uint32_t icdCounter) +void PairingCommand::OnICDRegistrationComplete(ScopedNodeId nodeId, uint32_t icdCounter) { char icdSymmetricKeyHex[chip::Crypto::kAES_CCM128_Key_Length * 2 + 1]; @@ -444,7 +444,7 @@ void PairingCommand::OnICDRegistrationComplete(NodeId nodeId, uint32_t icdCounte sizeof(icdSymmetricKeyHex), chip::Encoding::HexFlags::kNullTerminate); app::ICDClientInfo clientInfo; - clientInfo.peer_node = ScopedNodeId(nodeId, CurrentCommissioner().GetFabricIndex()); + clientInfo.peer_node = nodeId; clientInfo.monitored_subject = mICDMonitoredSubject.Value(); clientInfo.start_icd_counter = icdCounter; @@ -457,7 +457,7 @@ void PairingCommand::OnICDRegistrationComplete(NodeId nodeId, uint32_t icdCounte if (err != CHIP_NO_ERROR) { CHIPCommand::sICDClientStorage.RemoveKey(clientInfo); - ChipLogError(chipTool, "Failed to persist symmetric key for " ChipLogFormatX64 ": %s", ChipLogValueX64(nodeId), + ChipLogError(chipTool, "Failed to persist symmetric key for " ChipLogFormatX64 ": %s", ChipLogValueX64(nodeId.GetNodeId()), err.AsString()); SetCommandExitStatus(err); return; @@ -465,18 +465,18 @@ void PairingCommand::OnICDRegistrationComplete(NodeId nodeId, uint32_t icdCounte mDeviceIsICD = true; - ChipLogProgress(chipTool, "Saved ICD Symmetric key for " ChipLogFormatX64, ChipLogValueX64(nodeId)); + ChipLogProgress(chipTool, "Saved ICD Symmetric key for " ChipLogFormatX64, ChipLogValueX64(nodeId.GetNodeId())); ChipLogProgress(chipTool, "ICD Registration Complete for device " ChipLogFormatX64 " / Check-In NodeID: " ChipLogFormatX64 " / Monitored Subject: " ChipLogFormatX64 " / Symmetric Key: %s / ICDCounter %u", - ChipLogValueX64(nodeId), ChipLogValueX64(mICDCheckInNodeId.Value()), + ChipLogValueX64(nodeId.GetNodeId()), ChipLogValueX64(mICDCheckInNodeId.Value()), ChipLogValueX64(mICDMonitoredSubject.Value()), icdSymmetricKeyHex, icdCounter); } -void PairingCommand::OnICDStayActiveComplete(NodeId deviceId, uint32_t promisedActiveDuration) +void PairingCommand::OnICDStayActiveComplete(ScopedNodeId deviceId, uint32_t promisedActiveDuration) { ChipLogProgress(chipTool, "ICD Stay Active Complete for device " ChipLogFormatX64 " / promisedActiveDuration: %u", - ChipLogValueX64(deviceId), promisedActiveDuration); + ChipLogValueX64(deviceId.GetNodeId()), promisedActiveDuration); } void PairingCommand::OnDiscoveredDevice(const chip::Dnssd::CommissionNodeData & nodeData) diff --git a/examples/chip-tool/commands/pairing/PairingCommand.h b/examples/chip-tool/commands/pairing/PairingCommand.h index 99b0fd0c91882e..aaa8dc714e1017 100644 --- a/examples/chip-tool/commands/pairing/PairingCommand.h +++ b/examples/chip-tool/commands/pairing/PairingCommand.h @@ -197,8 +197,8 @@ class PairingCommand : public CHIPCommand, void OnPairingDeleted(CHIP_ERROR error) override; void OnReadCommissioningInfo(const chip::Controller::ReadCommissioningInfo & info) override; void OnCommissioningComplete(NodeId deviceId, CHIP_ERROR error) override; - void OnICDRegistrationComplete(NodeId deviceId, uint32_t icdCounter) override; - void OnICDStayActiveComplete(NodeId deviceId, uint32_t promisedActiveDuration) override; + void OnICDRegistrationComplete(chip::ScopedNodeId deviceId, uint32_t icdCounter) override; + void OnICDStayActiveComplete(chip::ScopedNodeId deviceId, uint32_t promisedActiveDuration) override; /////////// DeviceDiscoveryDelegate Interface ///////// void OnDiscoveredDevice(const chip::Dnssd::CommissionNodeData & nodeData) override; diff --git a/examples/fabric-admin/commands/pairing/PairingCommand.cpp b/examples/fabric-admin/commands/pairing/PairingCommand.cpp index 379b56431379e4..92754c2adaa69a 100644 --- a/examples/fabric-admin/commands/pairing/PairingCommand.cpp +++ b/examples/fabric-admin/commands/pairing/PairingCommand.cpp @@ -436,7 +436,7 @@ void PairingCommand::OnReadCommissioningInfo(const Controller::ReadCommissioning info.icd.idleModeDuration, info.icd.activeModeDuration, info.icd.activeModeThreshold); } -void PairingCommand::OnICDRegistrationComplete(NodeId nodeId, uint32_t icdCounter) +void PairingCommand::OnICDRegistrationComplete(ScopedNodeId nodeId, uint32_t icdCounter) { char icdSymmetricKeyHex[chip::Crypto::kAES_CCM128_Key_Length * 2 + 1]; @@ -444,7 +444,7 @@ void PairingCommand::OnICDRegistrationComplete(NodeId nodeId, uint32_t icdCounte sizeof(icdSymmetricKeyHex), chip::Encoding::HexFlags::kNullTerminate); app::ICDClientInfo clientInfo; - clientInfo.peer_node = ScopedNodeId(nodeId, CurrentCommissioner().GetFabricIndex()); + clientInfo.peer_node = nodeId; clientInfo.monitored_subject = mICDMonitoredSubject.Value(); clientInfo.start_icd_counter = icdCounter; @@ -457,26 +457,26 @@ void PairingCommand::OnICDRegistrationComplete(NodeId nodeId, uint32_t icdCounte if (err != CHIP_NO_ERROR) { CHIPCommand::sICDClientStorage.RemoveKey(clientInfo); - ChipLogError(NotSpecified, "Failed to persist symmetric key for " ChipLogFormatX64 ": %s", ChipLogValueX64(nodeId), - err.AsString()); + ChipLogError(NotSpecified, "Failed to persist symmetric key for " ChipLogFormatX64 ": %s", + ChipLogValueX64(nodeId.GetNodeId()), err.AsString()); SetCommandExitStatus(err); return; } mDeviceIsICD = true; - ChipLogProgress(NotSpecified, "Saved ICD Symmetric key for " ChipLogFormatX64, ChipLogValueX64(nodeId)); + ChipLogProgress(NotSpecified, "Saved ICD Symmetric key for " ChipLogFormatX64, ChipLogValueX64(nodeId.GetNodeId())); ChipLogProgress(NotSpecified, "ICD Registration Complete for device " ChipLogFormatX64 " / Check-In NodeID: " ChipLogFormatX64 " / Monitored Subject: " ChipLogFormatX64 " / Symmetric Key: %s / ICDCounter %u", - ChipLogValueX64(nodeId), ChipLogValueX64(mICDCheckInNodeId.Value()), + ChipLogValueX64(nodeId.GetNodeId()), ChipLogValueX64(mICDCheckInNodeId.Value()), ChipLogValueX64(mICDMonitoredSubject.Value()), icdSymmetricKeyHex, icdCounter); } -void PairingCommand::OnICDStayActiveComplete(NodeId deviceId, uint32_t promisedActiveDuration) +void PairingCommand::OnICDStayActiveComplete(ScopedNodeId deviceId, uint32_t promisedActiveDuration) { ChipLogProgress(NotSpecified, "ICD Stay Active Complete for device " ChipLogFormatX64 " / promisedActiveDuration: %u", - ChipLogValueX64(deviceId), promisedActiveDuration); + ChipLogValueX64(deviceId.GetNodeId()), promisedActiveDuration); } void PairingCommand::OnDiscoveredDevice(const chip::Dnssd::CommissionNodeData & nodeData) diff --git a/examples/fabric-admin/commands/pairing/PairingCommand.h b/examples/fabric-admin/commands/pairing/PairingCommand.h index 8de34a0ba989ed..331d177448aed5 100644 --- a/examples/fabric-admin/commands/pairing/PairingCommand.h +++ b/examples/fabric-admin/commands/pairing/PairingCommand.h @@ -196,8 +196,8 @@ class PairingCommand : public CHIPCommand, void OnPairingDeleted(CHIP_ERROR error) override; void OnReadCommissioningInfo(const chip::Controller::ReadCommissioningInfo & info) override; void OnCommissioningComplete(NodeId deviceId, CHIP_ERROR error) override; - void OnICDRegistrationComplete(NodeId deviceId, uint32_t icdCounter) override; - void OnICDStayActiveComplete(NodeId deviceId, uint32_t promisedActiveDuration) override; + void OnICDRegistrationComplete(chip::ScopedNodeId deviceId, uint32_t icdCounter) override; + void OnICDStayActiveComplete(chip::ScopedNodeId deviceId, uint32_t promisedActiveDuration) override; /////////// DeviceDiscoveryDelegate Interface ///////// void OnDiscoveredDevice(const chip::Dnssd::CommissionNodeData & nodeData) override; diff --git a/src/controller/CHIPDeviceController.cpp b/src/controller/CHIPDeviceController.cpp index 1381ed3381a649..75c95ee20abc06 100644 --- a/src/controller/CHIPDeviceController.cpp +++ b/src/controller/CHIPDeviceController.cpp @@ -1326,8 +1326,8 @@ void DeviceCommissioner::OnICDManagementRegisterClientResponse( if (commissioner->mPairingDelegate != nullptr) { - commissioner->mPairingDelegate->OnICDRegistrationComplete(commissioner->mDeviceBeingCommissioned->GetDeviceId(), - data.ICDCounter); + commissioner->mPairingDelegate->OnICDRegistrationComplete( + ScopedNodeId(commissioner->mDeviceBeingCommissioned->GetDeviceId(), commissioner->GetFabricIndex()), data.ICDCounter); } exit: @@ -1346,8 +1346,10 @@ void DeviceCommissioner::OnICDManagementStayActiveResponse( if (commissioner->mPairingDelegate != nullptr) { - commissioner->mPairingDelegate->OnICDStayActiveComplete(commissioner->mDeviceBeingCommissioned->GetDeviceId(), - data.promisedActiveDuration); + commissioner->mPairingDelegate->OnICDStayActiveComplete( + + ScopedNodeId(commissioner->mDeviceBeingCommissioned->GetDeviceId(), commissioner->GetFabricIndex()), + data.promisedActiveDuration); } exit: diff --git a/src/controller/DevicePairingDelegate.h b/src/controller/DevicePairingDelegate.h index 558a6c16a6bc2e..849df45436d9e8 100644 --- a/src/controller/DevicePairingDelegate.h +++ b/src/controller/DevicePairingDelegate.h @@ -136,7 +136,7 @@ class DLL_EXPORT DevicePairingDelegate * @param[in] icdNodeId The node id of the ICD. * @param[in] icdCounter The ICD Counter received from the device. */ - virtual void OnICDRegistrationComplete(NodeId icdNodeId, uint32_t icdCounter) {} + virtual void OnICDRegistrationComplete(ScopedNodeId icdNodeId, uint32_t icdCounter) {} /** * @brief @@ -147,7 +147,7 @@ class DLL_EXPORT DevicePairingDelegate * @param[in] promisedActiveDurationMsec The actual duration that the ICD server can stay active * from the time it receives the StayActiveRequest command. */ - virtual void OnICDStayActiveComplete(NodeId icdNodeId, uint32_t promisedActiveDurationMsec) {} + virtual void OnICDStayActiveComplete(ScopedNodeId icdNodeId, uint32_t promisedActiveDurationMsec) {} }; } // namespace Controller diff --git a/src/controller/java/AndroidDeviceControllerWrapper.cpp b/src/controller/java/AndroidDeviceControllerWrapper.cpp index 526f6830844f13..87f53735bcf617 100644 --- a/src/controller/java/AndroidDeviceControllerWrapper.cpp +++ b/src/controller/java/AndroidDeviceControllerWrapper.cpp @@ -994,13 +994,13 @@ void AndroidDeviceControllerWrapper::OnICDRegistrationInfoRequired() env->CallVoidMethod(mJavaObjectRef.ObjectRef(), onICDRegistrationInfoRequiredMethod); } -void AndroidDeviceControllerWrapper::OnICDRegistrationComplete(chip::NodeId icdNodeId, uint32_t icdCounter) +void AndroidDeviceControllerWrapper::OnICDRegistrationComplete(chip::ScopedNodeId icdNodeId, uint32_t icdCounter) { chip::DeviceLayer::StackUnlock unlock; CHIP_ERROR err = CHIP_NO_ERROR; chip::app::ICDClientInfo clientInfo; - clientInfo.peer_node = ScopedNodeId(icdNodeId, Controller()->GetFabricIndex()); + clientInfo.peer_node = icdNodeId; clientInfo.monitored_subject = mAutoCommissioner.GetCommissioningParameters().GetICDMonitoredSubject().Value(); clientInfo.start_icd_counter = icdCounter; @@ -1014,13 +1014,13 @@ void AndroidDeviceControllerWrapper::OnICDRegistrationComplete(chip::NodeId icdN if (err == CHIP_NO_ERROR) { - ChipLogProgress(Controller, "Saved ICD Symmetric key for " ChipLogFormatX64, ChipLogValueX64(icdNodeId)); + ChipLogProgress(Controller, "Saved ICD Symmetric key for " ChipLogFormatX64, ChipLogValueX64(icdNodeId.GetNodeId())); } else { getICDClientStorage()->RemoveKey(clientInfo); - ChipLogError(Controller, "Failed to persist symmetric key for " ChipLogFormatX64 ": %s", ChipLogValueX64(icdNodeId), - err.AsString()); + ChipLogError(Controller, "Failed to persist symmetric key for " ChipLogFormatX64 ": %s", + ChipLogValueX64(icdNodeId.GetNodeId()), err.AsString()); } mDeviceIsICD = true; @@ -1055,7 +1055,7 @@ void AndroidDeviceControllerWrapper::OnICDRegistrationComplete(chip::NodeId icdN icdDeviceInfoObj = env->NewObject( icdDeviceInfoClass, icdDeviceInfoStructCtor, jSymmetricKey, static_cast(mUserActiveModeTriggerHint.Raw()), jUserActiveModeTriggerInstruction, static_cast(mIdleModeDuration), static_cast(mActiveModeDuration), - static_cast(mActiveModeThreshold), static_cast(icdNodeId), static_cast(icdCounter), + static_cast(mActiveModeThreshold), static_cast(icdNodeId.GetNodeId()), static_cast(icdCounter), static_cast(mAutoCommissioner.GetCommissioningParameters().GetICDMonitoredSubject().Value()), static_cast(Controller()->GetFabricId()), static_cast(Controller()->GetFabricIndex())); diff --git a/src/controller/java/AndroidDeviceControllerWrapper.h b/src/controller/java/AndroidDeviceControllerWrapper.h index 1d26d31d112774..02d50499bbbcda 100644 --- a/src/controller/java/AndroidDeviceControllerWrapper.h +++ b/src/controller/java/AndroidDeviceControllerWrapper.h @@ -118,7 +118,7 @@ class AndroidDeviceControllerWrapper : public chip::Controller::DevicePairingDel const chip::app::Clusters::NetworkCommissioning::Commands::ScanNetworksResponse::DecodableType & dataResponse) override; void OnScanNetworksFailure(CHIP_ERROR error) override; void OnICDRegistrationInfoRequired() override; - void OnICDRegistrationComplete(chip::NodeId icdNodeId, uint32_t icdCounter) override; + void OnICDRegistrationComplete(chip::ScopedNodeId icdNodeId, uint32_t icdCounter) override; // PersistentStorageDelegate implementation CHIP_ERROR SyncSetKeyValue(const char * key, const void * value, uint16_t size) override; diff --git a/src/controller/python/BUILD.gn b/src/controller/python/BUILD.gn index 4676f89b362970..9adda770125317 100644 --- a/src/controller/python/BUILD.gn +++ b/src/controller/python/BUILD.gn @@ -76,6 +76,8 @@ shared_library("ChipDeviceCtrl") { "chip/crypto/p256keypair.cpp", "chip/crypto/p256keypair.h", "chip/discovery/NodeResolution.cpp", + "chip/icd/PyChipCheckInDelegate.cpp", + "chip/icd/PyChipCheckInDelegate.h", "chip/interaction_model/Delegate.cpp", "chip/interaction_model/Delegate.h", "chip/internal/ChipThreadWork.cpp", @@ -121,6 +123,7 @@ shared_library("ChipDeviceCtrl") { public_deps = [ "${chip_root}/src/app", + "${chip_root}/src/app/icd/client:handler", "${chip_root}/src/app/server", "${chip_root}/src/credentials:default_attestation_verifier", "${chip_root}/src/lib", diff --git a/src/controller/python/ChipDeviceController-ScriptBinding.cpp b/src/controller/python/ChipDeviceController-ScriptBinding.cpp index 728fd5801f1cb1..821b2a34e03b60 100644 --- a/src/controller/python/ChipDeviceController-ScriptBinding.cpp +++ b/src/controller/python/ChipDeviceController-ScriptBinding.cpp @@ -42,6 +42,9 @@ #include #include +#include +#include +#include #include #include #include @@ -55,7 +58,9 @@ #include #include #include +#include #include +#include #include #include @@ -101,20 +106,24 @@ chip::Platform::ScopedMemoryBuffer sDefaultNTPBuf; app::Clusters::TimeSynchronization::Structs::DSTOffsetStruct::Type sDSTBuf; app::Clusters::TimeSynchronization::Structs::TimeZoneStruct::Type sTimeZoneBuf; chip::Platform::ScopedMemoryBuffer sTimeZoneNameBuf; -chip::Controller::CommissioningParameters sCommissioningParameters; - } // namespace +chip::Controller::CommissioningParameters sCommissioningParameters; +chip::app::DefaultICDClientStorage sICDClientStorage; chip::Controller::ScriptPairingDeviceDiscoveryDelegate sPairingDeviceDiscoveryDelegate; chip::Credentials::GroupDataProviderImpl sGroupDataProvider; chip::Credentials::PersistentStorageOpCertStore sPersistentStorageOpCertStore; chip::Crypto::RawKeySessionKeystore sSessionKeystore; +chip::app::CheckInHandler sCheckInHandler; + // NOTE: Remote device ID is in sync with the echo server device id // At some point, we may want to add an option to connect to a device without // knowing its id, because the ID can be learned on the first response that is received. +chip::Controller::PyChipCheckInDelegate sCheckInDelegate; chip::NodeId kDefaultLocalDeviceId = chip::kTestControllerNodeId; chip::NodeId kRemoteDeviceId = chip::kTestDeviceNodeId; +uint8_t sICDSymmetricKey[chip::Crypto::kAES_CCM128_Key_Length]; extern "C" { PyChipError pychip_DeviceController_StackInit(Controller::Python::StorageAdapter * storageAdapter, bool enableServerInteractions); @@ -126,6 +135,7 @@ PyChipError pychip_DeviceController_GetAddressAndPort(chip::Controller::DeviceCo char * outAddress, uint64_t maxAddressLen, uint16_t * outPort); PyChipError pychip_DeviceController_GetCompressedFabricId(chip::Controller::DeviceCommissioner * devCtrl, uint64_t * outFabricId); PyChipError pychip_DeviceController_GetFabricId(chip::Controller::DeviceCommissioner * devCtrl, uint64_t * outFabricId); +PyChipError pychip_DeviceController_GetFabricIndex(chip::Controller::DeviceCommissioner * devCtrl, uint8_t * outFabricIndex); PyChipError pychip_DeviceController_GetNodeId(chip::Controller::DeviceCommissioner * devCtrl, uint64_t * outNodeId); // Rendezvous @@ -144,6 +154,8 @@ PyChipError pychip_DeviceController_SetDSTOffset(int32_t offset, uint64_t validS PyChipError pychip_DeviceController_SetDefaultNtp(const char * defaultNTP); PyChipError pychip_DeviceController_SetTrustedTimeSource(chip::NodeId nodeId, chip::EndpointId endpoint); PyChipError pychip_DeviceController_SetCheckMatchingFabric(bool check); +struct IcdRegistrationParameters; +PyChipError pychip_DeviceController_SetIcdRegistrationParameters(bool enabled, const IcdRegistrationParameters * params); PyChipError pychip_DeviceController_ResetCommissioningParameters(); PyChipError pychip_DeviceController_CloseSession(chip::Controller::DeviceCommissioner * devCtrl, chip::NodeId nodeid); PyChipError pychip_DeviceController_EstablishPASESessionIP(chip::Controller::DeviceCommissioner * devCtrl, const char * peerAddrStr, @@ -235,6 +247,11 @@ void * pychip_Storage_InitializeStorageAdapter(chip::Controller::Python::PyObjec chip::Controller::Python::SetGetKeyValueCb getCb, chip::Controller::Python::SyncDeleteKeyValueCb deleteCb); void pychip_Storage_ShutdownAdapter(chip::Controller::Python::StorageAdapter * storageAdapter); + +// +// ICD +// +void pychip_CheckInDelegate_SetOnCheckInCompleteCallback(PyChipCheckInDelegate::OnCheckInCompleteCallback * callback); } void * pychip_Storage_InitializeStorageAdapter(chip::Controller::Python::PyObject * context, @@ -260,6 +277,8 @@ PyChipError pychip_DeviceController_StackInit(Controller::Python::StorageAdapter factoryParams.fabricIndependentStorage = storageAdapter; factoryParams.sessionKeystore = &sSessionKeystore; + sICDClientStorage.Init(storageAdapter, &sSessionKeystore); + sGroupDataProvider.SetStorageDelegate(storageAdapter); sGroupDataProvider.SetSessionKeystore(factoryParams.sessionKeystore); PyReturnErrorOnFailure(ToPyChipError(sGroupDataProvider.Init())); @@ -290,6 +309,11 @@ PyChipError pychip_DeviceController_StackInit(Controller::Python::StorageAdapter // DeviceControllerFactory::GetInstance().RetainSystemState(); + auto engine = chip::app::InteractionModelEngine::GetInstance(); + PyReturnErrorOnFailure(ToPyChipError(sCheckInDelegate.Init(&sICDClientStorage, engine))); + PyReturnErrorOnFailure(ToPyChipError(sCheckInHandler.Init( + DeviceControllerFactory::GetInstance().GetSystemState()->ExchangeMgr(), &sICDClientStorage, &sCheckInDelegate, engine))); + // // Finally, start up the main Matter thread. Any further interactions with the stack // will now need to happen on the Matter thread, OR protected with the stack lock. @@ -342,6 +366,12 @@ PyChipError pychip_DeviceController_GetFabricId(chip::Controller::DeviceCommissi return ToPyChipError(CHIP_NO_ERROR); } +PyChipError pychip_DeviceController_GetFabricIndex(chip::Controller::DeviceCommissioner * devCtrl, uint8_t * outFabricIndex) +{ + *outFabricIndex = devCtrl->GetFabricIndex(); + return ToPyChipError(CHIP_NO_ERROR); +} + PyChipError pychip_DeviceController_GetNodeId(chip::Controller::DeviceCommissioner * devCtrl, uint64_t * outNodeId) { *outNodeId = devCtrl->GetNodeId(); @@ -554,6 +584,55 @@ PyChipError pychip_DeviceController_SetCheckMatchingFabric(bool check) return ToPyChipError(CHIP_NO_ERROR); } +struct IcdRegistrationParameters +{ + uint8_t * symmetricKey; + size_t symmetricKeyLength; + uint64_t checkInNodeId; + uint64_t monitoredSubject; + uint32_t stayActiveMsec; +}; + +PyChipError pychip_DeviceController_SetIcdRegistrationParameters(bool enabled, const IcdRegistrationParameters * params) +{ + if (!enabled) + { + sCommissioningParameters.SetICDRegistrationStrategy(ICDRegistrationStrategy::kIgnore); + return ToPyChipError(CHIP_NO_ERROR); + } + + if (params == nullptr) + { + return ToPyChipError(CHIP_ERROR_INVALID_ARGUMENT); + } + + if (params->symmetricKey == nullptr || params->symmetricKeyLength != sizeof(sICDSymmetricKey)) + { + return ToPyChipError(CHIP_ERROR_INVALID_ARGUMENT); + } + + if (params->checkInNodeId == 0) + { + return ToPyChipError(CHIP_ERROR_INVALID_ARGUMENT); + } + if (params->monitoredSubject == 0) + { + return ToPyChipError(CHIP_ERROR_INVALID_ARGUMENT); + } + + memcpy(sICDSymmetricKey, params->symmetricKey, sizeof(sICDSymmetricKey)); + sCommissioningParameters.SetICDSymmetricKey(ByteSpan(sICDSymmetricKey)); + if (params->stayActiveMsec != 0) + { + sCommissioningParameters.SetICDStayActiveDurationMsec(params->stayActiveMsec); + } + sCommissioningParameters.SetICDCheckInNodeId(params->checkInNodeId); + sCommissioningParameters.SetICDMonitoredSubject(params->monitoredSubject); + sCommissioningParameters.SetICDRegistrationStrategy(ICDRegistrationStrategy::kBeforeComplete); + + return ToPyChipError(CHIP_NO_ERROR); +} + PyChipError pychip_DeviceController_ResetCommissioningParameters() { sCommissioningParameters = CommissioningParameters(); @@ -871,3 +950,8 @@ PyChipError pychip_DeviceController_PostTaskOnChipThread(ChipThreadTaskRunnerFun PlatformMgr().ScheduleWork(callback, reinterpret_cast(pythonContext)); return ToPyChipError(CHIP_NO_ERROR); } + +void pychip_CheckInDelegate_SetOnCheckInCompleteCallback(PyChipCheckInDelegate::OnCheckInCompleteCallback * callback) +{ + chip::MainLoopWork::ExecuteInMainLoop([callback]() { sCheckInDelegate.SetOnCheckInCompleteCallback(callback); }); +} diff --git a/src/controller/python/ChipDeviceController-ScriptDevicePairingDelegate.cpp b/src/controller/python/ChipDeviceController-ScriptDevicePairingDelegate.cpp index c1df8125793d02..c979e0d9cd77a3 100644 --- a/src/controller/python/ChipDeviceController-ScriptDevicePairingDelegate.cpp +++ b/src/controller/python/ChipDeviceController-ScriptDevicePairingDelegate.cpp @@ -19,12 +19,17 @@ #include "ChipDeviceController-ScriptDevicePairingDelegate.h" #include "lib/support/TypeTraits.h" +#include #include #include #include #include +extern chip::app::DefaultICDClientStorage sICDClientStorage; +extern chip::Controller::CommissioningParameters sCommissioningParameters; +extern uint8_t sICDSymmetricKey[chip::Crypto::kAES_CCM128_Key_Length]; + namespace chip { namespace Controller { @@ -180,5 +185,40 @@ ScriptDevicePairingDelegate::GetOpenWindowCallback(Controller::CommissioningWind return &mOpenWindowCallback; } +void ScriptDevicePairingDelegate::OnICDRegistrationComplete(ScopedNodeId nodeId, uint32_t icdCounter) +{ + app::ICDClientInfo clientInfo; + clientInfo.peer_node = nodeId; + clientInfo.monitored_subject = sCommissioningParameters.GetICDMonitoredSubject().Value(); + clientInfo.start_icd_counter = icdCounter; + + CHIP_ERROR err = sICDClientStorage.SetKey(clientInfo, ByteSpan(sICDSymmetricKey)); + if (err == CHIP_NO_ERROR) + { + err = sICDClientStorage.StoreEntry(clientInfo); + } + + if (err != CHIP_NO_ERROR) + { + sICDClientStorage.RemoveKey(clientInfo); + ChipLogError(Controller, "Failed to persist symmetric key for " ChipLogFormatX64 ": %s", + ChipLogValueX64(nodeId.GetNodeId()), err.AsString()); + return; + } + + ChipLogProgress(Controller, "Saved ICD Symmetric key for " ChipLogFormatX64, ChipLogValueX64(nodeId.GetNodeId())); + ChipLogProgress(Controller, + "ICD Registration Complete for device " ChipLogFormatX64 " / Check-In NodeID: " ChipLogFormatX64 + " / Monitored Subject: " ChipLogFormatX64 " / ICDCounter %u", + ChipLogValueX64(nodeId.GetNodeId()), ChipLogValueX64(sCommissioningParameters.GetICDCheckInNodeId().Value()), + ChipLogValueX64(clientInfo.monitored_subject), icdCounter); +} + +void ScriptDevicePairingDelegate::OnICDStayActiveComplete(ScopedNodeId deviceId, uint32_t promisedActiveDuration) +{ + ChipLogProgress(Controller, "ICD Stay Active Complete for device " ChipLogFormatX64 " / promisedActiveDuration: %u", + ChipLogValueX64(deviceId.GetNodeId()), promisedActiveDuration); +} + } // namespace Controller } // namespace chip diff --git a/src/controller/python/ChipDeviceController-ScriptDevicePairingDelegate.h b/src/controller/python/ChipDeviceController-ScriptDevicePairingDelegate.h index 2740b6eb85e983..d6665f8fb2baba 100644 --- a/src/controller/python/ChipDeviceController-ScriptDevicePairingDelegate.h +++ b/src/controller/python/ChipDeviceController-ScriptDevicePairingDelegate.h @@ -27,6 +27,7 @@ #include #include +#include #include namespace chip { @@ -68,11 +69,14 @@ class ScriptDevicePairingDelegate final : public Controller::DevicePairingDelega void OnCommissioningFailure(PeerId peerId, CHIP_ERROR error, CommissioningStage stageFailed, Optional additionalErrorInfo) override; void OnCommissioningStatusUpdate(PeerId peerId, CommissioningStage stageCompleted, CHIP_ERROR error) override; + void OnICDRegistrationComplete(ScopedNodeId deviceId, uint32_t icdCounter) override; + void OnICDStayActiveComplete(ScopedNodeId deviceId, uint32_t promisedActiveDuration) override; void OnFabricCheck(NodeId matchingNodeId) override; Callback::Callback * GetOpenWindowCallback(Controller::CommissioningWindowOpener * context); void OnOpenCommissioningWindow(NodeId deviceId, CHIP_ERROR status, SetupPayload payload); void SetExpectingPairingComplete(bool value) { expectingPairingComplete = value; } + void SetFabricIndex(FabricIndex fabricIndex) { mFabricIndex = fabricIndex; } private: DevicePairingDelegate_OnPairingCompleteFunct mOnPairingCompleteCallback = nullptr; @@ -84,7 +88,9 @@ class ScriptDevicePairingDelegate final : public Controller::DevicePairingDelega DevicePairingDelegate_OnFabricCheckFunct mOnFabricCheckCallback = nullptr; Callback::Callback mOpenWindowCallback; Controller::CommissioningWindowOpener * mWindowOpener = nullptr; - bool expectingPairingComplete = false; + + bool expectingPairingComplete = false; + FabricIndex mFabricIndex = 0; }; } // namespace Controller diff --git a/src/controller/python/OpCredsBinding.cpp b/src/controller/python/OpCredsBinding.cpp index 5fd4205d4c7ce7..427ee9be46ba3c 100644 --- a/src/controller/python/OpCredsBinding.cpp +++ b/src/controller/python/OpCredsBinding.cpp @@ -26,6 +26,7 @@ #include "controller/python/chip/crypto/p256keypair.h" #include "controller/python/chip/interaction_model/Delegate.h" +#include #include #include #include @@ -104,6 +105,7 @@ class OperationalCredentialsAdapter : public OperationalCredentialsDelegate extern chip::Credentials::GroupDataProviderImpl sGroupDataProvider; extern chip::Controller::ScriptDevicePairingDelegate sPairingDelegate; +extern chip::app::DefaultICDClientStorage sICDClientStorage; class TestCommissioner : public chip::Controller::AutoCommissioner { @@ -569,6 +571,9 @@ PyChipError pychip_OpCreds_AllocateController(OpCredsContext * context, chip::Co chip::Credentials::SetSingleIpkEpochKey(&sGroupDataProvider, devCtrl->GetFabricIndex(), defaultIpk, compressedFabricIdSpan); VerifyOrReturnError(err == CHIP_NO_ERROR, ToPyChipError(err)); + sICDClientStorage.UpdateFabricList(devCtrl->GetFabricIndex()); + pairingDelegate->SetFabricIndex(devCtrl->GetFabricIndex()); + *outDevCtrl = devCtrl.release(); *outPairingDelegate = pairingDelegate.release(); diff --git a/src/controller/python/chip/ChipDeviceCtrl.py b/src/controller/python/chip/ChipDeviceCtrl.py index 4fb8fb28bcaf90..2ba7c584db927b 100644 --- a/src/controller/python/chip/ChipDeviceCtrl.py +++ b/src/controller/python/chip/ChipDeviceCtrl.py @@ -35,11 +35,12 @@ import enum import json import logging +import secrets import threading import time import typing -from ctypes import (CDLL, CFUNCTYPE, POINTER, byref, c_bool, c_char, c_char_p, c_int, c_int32, c_size_t, c_uint8, c_uint16, - c_uint32, c_uint64, c_void_p, create_string_buffer, pointer, py_object, resize, string_at) +from ctypes import (CDLL, CFUNCTYPE, POINTER, Structure, byref, c_bool, c_char, c_char_p, c_int, c_int32, c_size_t, c_uint8, + c_uint16, c_uint32, c_uint64, c_void_p, create_string_buffer, pointer, py_object, resize, string_at) from dataclasses import dataclass import dacite @@ -98,6 +99,21 @@ class NOCChain: adminSubject: int +@dataclass +class ICDRegistrationParameters: + symmetricKey: typing.Optional[bytes] + checkInNodeId: typing.Optional[int] + monitoredSubject: typing.Optional[int] + stayActiveMs: typing.Optional[int] + + class CStruct(Structure): + _fields_ = [('symmetricKey', c_char_p), ('symmetricKeyLength', c_size_t), ('checkInNodeId', + c_uint64), ('monitoredSubject', c_uint64), ('stayActiveMsec', c_uint32)] + + def to_c(self): + return ICDRegistrationParameters.CStruct(self.symmetricKey, len(self.symmetricKey), self.checkInNodeId, self.monitoredSubject, self.stayActiveMs) + + @_DeviceAvailableCallbackFunct def _DeviceAvailableCallback(closure, device, err): closure.deviceAvailable(device, err) @@ -123,6 +139,77 @@ def _IssueNOCChainCallbackPythonCallback(devCtrl, status: PyChipError, noc: c_vo nocChain = NOCChain(nocBytes, icacBytes, rcacBytes, ipkBytes, adminSubject) devCtrl.NOCChainCallback(nocChain) + +# Methods for ICD +class ScopedNodeId(Structure): + _fields_ = [("nodeId", c_uint64), ("fabricIndex", c_uint8)] + + def __hash__(self): + return self.nodeId << 8 | self.fabricIndex + + def __str__(self): + return f"({self.fabricIndex}:{self.nodeId:16x})" + + def __eq__(self, other): + return self.nodeId == other.nodeId and self.fabricIndex == other.fabricIndex + + +_OnCheckInCompleteFunct = CFUNCTYPE(None, ScopedNodeId) + +_OnCheckInCompleteWaitListLock = threading.Lock() +_OnCheckInCompleteWaitList = dict() + + +@_OnCheckInCompleteFunct +def _OnCheckInComplete(scopedNodeId: ScopedNodeId): + callbacks = [] + with _OnCheckInCompleteWaitListLock: + callbacks = list(_OnCheckInCompleteWaitList.get(scopedNodeId, set())) + + for callback in callbacks: + callback(scopedNodeId) + + +def RegisterOnActiveCallback(scopedNodeId: ScopedNodeId, callback: typing.Callable[None, [ScopedNodeId]]): + ''' Registers a callback when the device with given (fabric index, node id) becomes active. + + Does nothing if the callback is already registered. + ''' + with _OnCheckInCompleteWaitListLock: + waitList = _OnCheckInCompleteWaitList.get(scopedNodeId, set()) + waitList.add(callback) + _OnCheckInCompleteWaitList[scopedNodeId] = waitList + + +def UnregisterOnActiveCallback(scopedNodeId: ScopedNodeId, callback: typing.Callable[None, [ScopedNodeId]]): + ''' Unregisters a callback when the device with given (fabric index, node id) becomes active. + + Does nothing if the callback has not been registered. + ''' + with _OnCheckInCompleteWaitListLock: + _OnCheckInCompleteWaitList.get(scopedNodeId, set()).remove(callback) + + +async def WaitForCheckIn(scopedNodeId: ScopedNodeId, timeoutSeconds: float): + ''' Waits for a device becomes active. + + Returns: + - A future, completes when the device becomes active. + ''' + eventLoop = asyncio.get_running_loop() + future = eventLoop.create_future() + + def OnCheckInCallback(nodeid): + eventLoop.call_soon_threadsafe(lambda: future.done() or future.set_result(None)) + + RegisterOnActiveCallback(scopedNodeId, OnCheckInCallback) + + try: + async with asyncio.timeout(timeoutSeconds): + await future + finally: + UnregisterOnActiveCallback(scopedNodeId, OnCheckInCallback) + # This is a fix for WEAV-429. Jay Logue recommends revisiting this at a later # date to allow for truly multiple instances so this is temporary. @@ -269,6 +356,7 @@ def HandleCommissioningComplete(nodeid, err): else: logging.warning("Failed to commission: {}".format(err)) + self._dmLib.pychip_DeviceController_SetIcdRegistrationParameters(False, None) self.state = DCState.IDLE self._ChipStack.callbackRes = err self._ChipStack.commissioningEventRes = err @@ -347,6 +435,7 @@ def HandlePASEEstablishmentComplete(err: PyChipError): self._isActive = True # Validate FabricID/NodeID followed from NOC Chain self._fabricId = self.GetFabricIdInternal() + self._fabricIndex = self.GetFabricIndexInternal() self._nodeId = self.GetNodeIdInternal() def _finish_init(self): @@ -766,6 +855,19 @@ def GetFabricIdInternal(self): return fabricid.value + def GetFabricIndexInternal(self): + """Get the fabric index from the object. Only used to validate cached value from property.""" + self.CheckIsActive() + + fabricindex = c_uint8(0) + + self._ChipStack.Call( + lambda: self._dmLib.pychip_DeviceController_GetFabricIndex( + self.devCtrl, pointer(fabricindex)) + ).raise_on_error() + + return fabricindex.value + def GetNodeIdInternal(self) -> int: """Get the node ID from the object. Only used to validate cached value from property.""" self.CheckIsActive() @@ -841,6 +943,18 @@ def deviceAvailable(self, device, err): return DeviceProxyWrapper(returnDevice, self._dmLib) + async def WaitForActive(self, nodeid, *, timeoutSeconds=30.0, stayActiveDurationMs=30000): + ''' Waits a LIT ICD device to become active. Will send a StayActive command to the device on active to allow human operations. + + nodeId: Node ID of the LID ICD + stayActiveDurationMs: The duration in the StayActive command, in milliseconds + + Returns: + - StayActiveResponse on success + ''' + await WaitForCheckIn(ScopedNodeId(nodeid, self._fabricIndex), timeoutSeconds=timeoutSeconds) + return await self.SendCommand(nodeid, 0, Clusters.IcdManagement.Commands.StayActiveRequest(stayActiveDuration=stayActiveDurationMs)) + async def GetConnectedDevice(self, nodeid, allowPASE: bool = True, timeoutMs: int = None): ''' Gets an OperationalDeviceProxy or CommissioneeDeviceProxy for the specified Node. @@ -1536,6 +1650,11 @@ def _InitLib(self): self._dmLib.pychip_DeviceController_SetCheckMatchingFabric.restype = PyChipError self._dmLib.pychip_DeviceController_SetCheckMatchingFabric.argtypes = [c_bool] + self._dmLib.pychip_DeviceController_SetIcdRegistrationParameters.restype = PyChipError + self._dmLib.pychip_DeviceController_SetIcdRegistrationParameters.argtypes = [ + c_bool, c_void_p + ] + self._dmLib.pychip_DeviceController_ResetCommissioningParameters.restype = PyChipError self._dmLib.pychip_DeviceController_ResetCommissioningParameters.argtypes = [] @@ -1722,6 +1841,9 @@ def _InitLib(self): self._dmLib.pychip_DeviceController_GetFabricId.argtypes = [c_void_p, POINTER(c_uint64)] self._dmLib.pychip_DeviceController_GetFabricId.restype = PyChipError + self._dmLib.pychip_DeviceController_GetFabricIndex.argtypes = [c_void_p, POINTER(c_uint8)] + self._dmLib.pychip_DeviceController_GetFabricIndex.restype = PyChipError + self._dmLib.pychip_DeviceController_GetLogFilter = [None] self._dmLib.pychip_DeviceController_GetLogFilter = c_uint8 @@ -1736,6 +1858,11 @@ def _InitLib(self): self._dmLib.pychip_DeviceController_SetIpk.argtypes = [c_void_p, POINTER(c_char), c_size_t] self._dmLib.pychip_DeviceController_SetIpk.restype = PyChipError + self._dmLib.pychip_CheckInDelegate_SetOnCheckInCompleteCallback.restype = None + self._dmLib.pychip_CheckInDelegate_SetOnCheckInCompleteCallback.argtypes = [_OnCheckInCompleteFunct] + + self._dmLib.pychip_CheckInDelegate_SetOnCheckInCompleteCallback(_OnCheckInComplete) + class ChipDeviceController(ChipDeviceControllerBase): ''' The ChipDeviceCommissioner binding, named as ChipDeviceController @@ -1884,6 +2011,38 @@ def SetCheckMatchingFabric(self, check: bool): lambda: self._dmLib.pychip_DeviceController_SetCheckMatchingFabric(check) ).raise_on_error() + def GenerateICDRegistrationParameters(self): + ''' Generates ICD registration parameters for this controller. ''' + return ICDRegistrationParameters( + secrets.token_bytes(16), + self._nodeId, + self._nodeId, + 30) + + def EnableICDRegistration(self, parameters: ICDRegistrationParameters): + ''' Enables ICD registration for the following commissioning session. + + Args: + parameters: A ICDRegistrationParameters for the parameters used for ICD registration, or None for default arguments. + ''' + if parameters is None: + raise ValueError("ICD registration parameter required.") + if len(parameters.symmetricKey) != 16: + raise ValueError("symmetricKey should be 16 bytes") + + self.CheckIsActive() + self._ChipStack.Call( + lambda: self._dmLib.pychip_DeviceController_SetIcdRegistrationParameters( + True, pointer(parameters.to_c())) + ).raise_on_error() + + def DisableICDRegistration(self): + ''' Disables ICD registration. ''' + self.CheckIsActive() + self._ChipStack.Call( + lambda: self._dmLib.pychip_DeviceController_SetIcdRegistrationParameters(False, None) + ).raise_on_error() + def GetFabricCheckResult(self) -> int: ''' Returns the fabric check result if SetCheckMatchingFabric was used.''' return self.fabricCheckNodeId diff --git a/src/controller/python/chip/ChipReplStartup.py b/src/controller/python/chip/ChipReplStartup.py index b75c77efcd5b2b..13a93a1efb453b 100644 --- a/src/controller/python/chip/ChipReplStartup.py +++ b/src/controller/python/chip/ChipReplStartup.py @@ -96,6 +96,8 @@ def main(): "-t", "--trust-store", help="Path to the PAA trust store.", action="store", default="./credentials/development/paa-root-certs") parser.add_argument( "-b", "--ble-adapter", help="Set the Bluetooth adapter index.", type=int, default=None) + parser.add_argument( + "-s", "--server-interactions", help="Enable server interactions.", action="store_true") args = parser.parse_args() if not os.path.exists(args.trust_store): @@ -139,7 +141,7 @@ def main(): ReplInit(args.debug) - chipStack = ChipStack(persistentStoragePath=args.storagepath, enableServerInteractions=False) + chipStack = ChipStack(persistentStoragePath=args.storagepath, enableServerInteractions=args.server_interactions) certificateAuthorityManager = chip.CertificateAuthority.CertificateAuthorityManager(chipStack, chipStack.GetStorageManager()) certificateAuthorityManager.LoadAuthoritiesFromStorage() diff --git a/src/controller/python/chip/icd/PyChipCheckInDelegate.cpp b/src/controller/python/chip/icd/PyChipCheckInDelegate.cpp new file mode 100644 index 00000000000000..03f6b7de1003e6 --- /dev/null +++ b/src/controller/python/chip/icd/PyChipCheckInDelegate.cpp @@ -0,0 +1,33 @@ +/* + * + * 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 "PyChipCheckInDelegate.h" + +using namespace ::chip; +using namespace ::chip::app; +using namespace ::chip::Controller; + +void PyChipCheckInDelegate::OnCheckInComplete(const ICDClientInfo & clientInfo) +{ + DefaultCheckInDelegate::OnCheckInComplete(clientInfo); + + if (mCallback != nullptr) + { + mCallback(clientInfo.peer_node); + } +} diff --git a/src/controller/python/chip/icd/PyChipCheckInDelegate.h b/src/controller/python/chip/icd/PyChipCheckInDelegate.h new file mode 100644 index 00000000000000..3e3a3d9871af24 --- /dev/null +++ b/src/controller/python/chip/icd/PyChipCheckInDelegate.h @@ -0,0 +1,42 @@ +/* + * + * 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 + +namespace chip { +namespace Controller { + +class PyChipCheckInDelegate : public chip::app::DefaultCheckInDelegate +{ +public: + using OnCheckInCompleteCallback = void(chip::ScopedNodeId); + + virtual ~PyChipCheckInDelegate() = default; + + void OnCheckInComplete(const chip::app::ICDClientInfo & clientInfo) override; + + void SetOnCheckInCompleteCallback(OnCheckInCompleteCallback * callback) { mCallback = callback; } + +private: + OnCheckInCompleteCallback * mCallback; +}; + +} // namespace Controller +} // namespace chip diff --git a/src/controller/python/chip/internal/types.py b/src/controller/python/chip/internal/types.py index 190456969b2006..34c14737a47ff7 100644 --- a/src/controller/python/chip/internal/types.py +++ b/src/controller/python/chip/internal/types.py @@ -14,7 +14,7 @@ # limitations under the License. # -from ctypes import CFUNCTYPE, c_size_t, c_uint32, c_void_p +from ctypes import CFUNCTYPE, Structure, c_size_t, c_uint32, c_uint64, c_void_p # General callback of 'network credentials requested. No python-data # is available as the underlying callback is used internally @@ -26,3 +26,7 @@ # Notification that pairing has been coompleted PairingComplete = CFUNCTYPE(None, c_uint32) + + +class ScopedNodeId(Structure): + _fields_ = [("node_id", c_uint64), ("fabric_index", "c_uint8")]