Skip to content

Commit

Permalink
Update
Browse files Browse the repository at this point in the history
  • Loading branch information
erjiaqing committed May 23, 2024
1 parent 4b9334f commit 8713f26
Show file tree
Hide file tree
Showing 9 changed files with 107 additions and 28 deletions.
2 changes: 1 addition & 1 deletion src/app/icd/client/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,11 @@ source_set("manager") {
# All sources and configurations used by the CheckInHandler need to go in this source-set
source_set("handler") {
sources = [
"CheckInDelegate.h",
"CheckInHandler.cpp",
"CheckInHandler.h",
"DefaultCheckInDelegate.cpp",
"DefaultCheckInDelegate.h",
"PyChipCheckInDelegate.h",
"RefreshKeySender.cpp",
"RefreshKeySender.h",
]
Expand Down
4 changes: 2 additions & 2 deletions src/controller/python/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,8 @@ shared_library("ChipDeviceCtrl") {
"chip/crypto/p256keypair.cpp",
"chip/crypto/p256keypair.h",
"chip/discovery/NodeResolution.cpp",
"chip/icd/CheckInDelegate.cpp",
"chip/icd/CheckInDelegate.h",
"chip/icd/PyChipCheckInDelegate.cpp",
"chip/icd/PyChipCheckInDelegate.h",
"chip/interaction_model/Delegate.cpp",
"chip/interaction_model/Delegate.h",
"chip/internal/ChipThreadWork.cpp",
Expand Down
21 changes: 14 additions & 7 deletions src/controller/python/ChipDeviceController-ScriptBinding.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@
#include <controller/python/ChipDeviceController-ScriptDevicePairingDelegate.h>
#include <controller/python/ChipDeviceController-ScriptPairingDeviceDiscoveryDelegate.h>
#include <controller/python/ChipDeviceController-StorageDelegate.h>
#include <controller/python/chip/icd/CheckInDelegate.h>
#include <controller/python/chip/icd/PyChipCheckInDelegate.h>
#include <controller/python/chip/interaction_model/Delegate.h>
#include <controller/python/chip/native/PyChipError.h>

Expand Down Expand Up @@ -133,6 +133,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
Expand Down Expand Up @@ -273,12 +274,6 @@ PyChipError pychip_DeviceController_StackInit(Controller::Python::StorageAdapter

sICDClientStorage.Init(storageAdapter, &sSessionKeystore);

auto engine = chip::app::InteractionModelEngine::GetInstance();
PyReturnErrorOnFailure(ToPyChipError(PyChipCheckInDelegate::GetInstance().Init(&sICDClientStorage, engine)));
PyReturnErrorOnFailure(
ToPyChipError(sCheckInHandler.Init(DeviceControllerFactory::GetInstance().GetSystemState()->ExchangeMgr(),
&sICDClientStorage, &PyChipCheckInDelegate::GetInstance(), engine)));

sGroupDataProvider.SetStorageDelegate(storageAdapter);
sGroupDataProvider.SetSessionKeystore(factoryParams.sessionKeystore);
PyReturnErrorOnFailure(ToPyChipError(sGroupDataProvider.Init()));
Expand Down Expand Up @@ -309,6 +304,12 @@ PyChipError pychip_DeviceController_StackInit(Controller::Python::StorageAdapter
//
DeviceControllerFactory::GetInstance().RetainSystemState();

auto engine = chip::app::InteractionModelEngine::GetInstance();
PyReturnErrorOnFailure(ToPyChipError(PyChipCheckInDelegate::GetInstance().Init(&sICDClientStorage, engine)));
PyReturnErrorOnFailure(
ToPyChipError(sCheckInHandler.Init(DeviceControllerFactory::GetInstance().GetSystemState()->ExchangeMgr(),
&sICDClientStorage, &PyChipCheckInDelegate::GetInstance(), 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.
Expand Down Expand Up @@ -361,6 +362,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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -201,13 +201,13 @@ void ScriptDevicePairingDelegate::OnICDRegistrationComplete(NodeId nodeId, uint3
if (err != CHIP_NO_ERROR)
{
sICDClientStorage.RemoveKey(clientInfo);
ChipLogError(chipTool, "Failed to persist symmetric key for " ChipLogFormatX64 ": %s", ChipLogValueX64(nodeId),
ChipLogError(Controller, "Failed to persist symmetric key for " ChipLogFormatX64 ": %s", ChipLogValueX64(nodeId),
err.AsString());
return;
}

ChipLogProgress(Zcl, "Saved ICD Symmetric key for " ChipLogFormatX64, ChipLogValueX64(nodeId));
ChipLogProgress(Zcl,
ChipLogProgress(Controller, "Saved ICD Symmetric key for " ChipLogFormatX64, ChipLogValueX64(nodeId));
ChipLogProgress(Controller,
"ICD Registration Complete for device " ChipLogFormatX64 " / Check-In NodeID: " ChipLogFormatX64
" / Monitored Subject: " ChipLogFormatX64 " / ICDCounter %u",
ChipLogValueX64(nodeId), ChipLogValueX64(sCommissioningParameters.GetICDCheckInNodeId().Value()),
Expand All @@ -216,7 +216,7 @@ void ScriptDevicePairingDelegate::OnICDRegistrationComplete(NodeId nodeId, uint3

void ScriptDevicePairingDelegate::OnICDStayActiveComplete(NodeId deviceId, uint32_t promisedActiveDuration)
{
ChipLogProgress(Zcl, "ICD Stay Active Complete for device " ChipLogFormatX64 " / promisedActiveDuration: %u",
ChipLogProgress(Controller, "ICD Stay Active Complete for device " ChipLogFormatX64 " / promisedActiveDuration: %u",
ChipLogValueX64(deviceId), promisedActiveDuration);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ class ScriptDevicePairingDelegate final : public Controller::DevicePairingDelega
Callback::Callback<Controller::OnOpenCommissioningWindow> mOpenWindowCallback;
Controller::CommissioningWindowOpener * mWindowOpener = nullptr;
bool expectingPairingComplete = false;
FabricIndex mFabricIndex;
FabricIndex mFabricIndex = 0;
};

} // namespace Controller
Expand Down
64 changes: 55 additions & 9 deletions src/controller/python/chip/ChipDeviceCtrl.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@

from . import FabricAdmin
from . import clusters as Clusters
from . import discovery
from . import discovery, icd
from .clusters import Attribute as ClusterAttribute
from .clusters import ClusterObjects as ClusterObjects
from .clusters import Command as ClusterCommand
Expand Down Expand Up @@ -101,6 +101,14 @@ class NOCChain:
adminSubject: int


@dataclass
class ICDRegistrationParameters:
symmetricKey: typing.Optional[bytes] = None
checkInNodeId: typing.Optional[int] = None
monitoredSubject: typing.Optional[int] = None
stayActiveMs: typing.Optional[int] = None


@_DeviceAvailableCallbackFunct
def _DeviceAvailableCallback(closure, device, err):
closure.deviceAvailable(device, err)
Expand Down Expand Up @@ -272,6 +280,7 @@ def HandleCommissioningComplete(nodeid, err):
else:
logging.warning("Failed to commission: {}".format(err))

self.DisableIcdRegistration()
self.state = DCState.IDLE
self._ChipStack.callbackRes = err
self._ChipStack.commissioningEventRes = err
Expand Down Expand Up @@ -350,6 +359,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):
Expand Down Expand Up @@ -769,6 +779,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()
Expand Down Expand Up @@ -844,6 +867,18 @@ def deviceAvailable(self, device, err):

return DeviceProxyWrapper(returnDevice, self._dmLib)

async def WaitForActive(self, nodeid, stayActiveDurationMilliseconds=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
stayActiveDurationMilliseconds: The duration in the StayActive command, in milliseconds
Returns:
- StayActiveResponse on success
'''
await icd.WaitForCheckIn(self._fabricIndex, nodeid)
return await self.SendCommand(nodeid, 0, GeneratedObjects.IcdManagement.Commands.StayActiveRequest(stayActiveDuration=stayActiveDurationMilliseconds))

async def GetConnectedDevice(self, nodeid, allowPASE: bool = True, timeoutMs: int = None):
''' Gets an OperationalDeviceProxy or CommissioneeDeviceProxy for the specified Node.
Expand Down Expand Up @@ -1822,6 +1857,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

Expand Down Expand Up @@ -1984,22 +2022,30 @@ def SetCheckMatchingFabric(self, check: bool):
lambda: self._dmLib.pychip_DeviceController_SetCheckMatchingFabric(check)
).raise_on_error()

def SetIcdRegistrationParameters(self, symmetricKey: bytes = None, checkInNodeId: int = 0, monitoredSubject: int = 0, stayActiveMs: int = 0):
if symmetricKey is not None:
def EnableICDRegistration(self, parameters: typing.Optional[ICDRegistrationParameters] = None):
''' 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:
parameters = ICDRegistrationParameters()
if parameters.symmetricKey is not None:
if len(symmetricKey) != 16:
raise ValueError("symmetricKey should be 16 bytes")
if not checkInNodeId:
checkInNodeId = self._nodeId
if not monitoredSubject:
monitoredSubject = checkInNodeId
if parameters.checkInNodeId is None:
parameters.checkInNodeId = self._nodeId
if parameters.monitoredSubject is None:
parameters.monitoredSubject = checkInNodeId

self.CheckIsActive()
self._ChipStack.Call(
lambda: self._dmLib.pychip_DeviceController_SetIcdRegistrationParameters(
self.devCtrl, True, symmetricKey, checkInNodeId, monitoredSubject, stayActiveMs)
self.devCtrl, True, parameters.symmetricKey, parameters.checkInNodeId, parameters.monitoredSubject, parameters.stayActiveMs)
).raise_on_error()

def DisableIcdRegistration(self):
def DisableICDRegistration(self):
''' Disables ICD registration. '''
self.CheckIsActive()
self._ChipStack.Call(
lambda: self._dmLib.pychip_DeviceController_SetIcdRegistrationParameters(self.devCtrl, False, None, 0, 0, 0)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
* limitations under the License.
*/

#include "CheckInDelegate.h"
#include "PyChipCheckInDelegate.h"

using namespace ::chip;
using namespace ::chip::app;
Expand All @@ -33,7 +33,7 @@ void PyChipCheckInDelegate::OnCheckInComplete(const ICDClientInfo & clientInfo)
}
}

void pychip_CheckInDelegate_SetOnCheckInCompleteCallback(PyChipCheckInDelegate::OnCheckInCompleteCallback * callback)
extern "C" void pychip_CheckInDelegate_SetOnCheckInCompleteCallback(PyChipCheckInDelegate::OnCheckInCompleteCallback * callback)
{
PyChipCheckInDelegate::GetInstance().SetOnCheckInCompleteCallback(callback);
}
30 changes: 28 additions & 2 deletions src/controller/python/chip/icd/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
# limitations under the License.
#

import asyncio
from ctypes import CFUNCTYPE, c_uint8, c_uint64
from dataclasses import dataclass
from threading import Condition, Event, Lock
Expand Down Expand Up @@ -62,13 +63,38 @@ def _ensureInit():
_initialized = True


def AddOnActiveCallback(fabricIndex: int, nodeId: int, callback: Callable[None, [OnCheckInCompleteParams]]):
def RegisterOnActiveCallback(fabricIndex: int, nodeId: int, callback: Callable[None, [OnCheckInCompleteParams]]):
''' Registers a callback when the device with given (fabric index, node id) becomes active.
Does nothing if the callback is already registered.
'''
_ensureInit()
with _OnCheckInCompleteWaitListLock:
waitList = _OnCheckInCompleteWaitList.get((fabricIndex, nodeId), set())
waitList.add(callback)
_OnCheckInCompleteWaitList[(fabricIndex, nodeId)] = waitList


def RemoveOnActiveCallback(fabricIndex: int, nodeId: int, callback: Callable[None, [OnCheckInCompleteParams]]):
def UnregisterOnActiveCallback(fabricIndex: int, nodeId: int, callback: Callable[None, [OnCheckInCompleteParams]]):
''' 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((fabricIndex, nodeId), set()).remove(callback)


def WaitForCheckIn(fabricIndex: int, nodeId: int):
''' 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))
RemoveOnActiveCallback(fabricIndex, nodeId, OnCheckInCallback)
AddOnActiveCallback(fabricIndex, nodeId, OnCheckInCallback)
return future

0 comments on commit 8713f26

Please sign in to comment.