diff --git a/src/controller/python/chip/ChipDeviceCtrl.py b/src/controller/python/chip/ChipDeviceCtrl.py index 4a38348575eccf..0eb22d5f81bf47 100644 --- a/src/controller/python/chip/ChipDeviceCtrl.py +++ b/src/controller/python/chip/ChipDeviceCtrl.py @@ -53,7 +53,7 @@ from .clusters.CHIPClusters import ChipClusters from .crypto import p256keypair from .exceptions import UnknownAttribute, UnknownCommand -from .interaction_model import InteractionModelError +from .interaction_model import InteractionModelError, SessionParameters, SessionParametersStruct from .interaction_model import delegate as im from .native import PyChipError @@ -809,6 +809,36 @@ def ComputeRoundTripTimeout(self, nodeid, upperLayerProcessingTimeoutMs: int = 0 device.deviceProxy, upperLayerProcessingTimeoutMs)) return res + def GetRemoteSessionParameters(self, nodeid) -> typing.Optional[SessionParameters]: + ''' Returns the SessionParameters of reported by the remote node associated with `nodeid`. + If there is some error in getting SessionParameters None is returned. + + This will result in a session being established if one wasn't already established. + ''' + + # First creating the struct to make building the ByteArray to be sent to CFFI easier. + sessionParametersStruct = SessionParametersStruct.parse(b'\x00' * SessionParametersStruct.sizeof()) + sessionParametersByteArray = SessionParametersStruct.build(sessionParametersStruct) + device = self.GetConnectedDeviceSync(nodeid) + res = self._ChipStack.Call(lambda: self._dmLib.pychip_DeviceProxy_GetRemoteSessionParameters( + device.deviceProxy, ctypes.c_char_p(sessionParametersByteArray))) + + # 0 is CHIP_NO_ERROR + if res != 0: + return None + + sessionParametersStruct = SessionParametersStruct.parse(sessionParametersByteArray) + return SessionParameters( + sessionIdleInterval=sessionParametersStruct.SessionIdleInterval if sessionParametersStruct.SessionIdleInterval != 0 else None, + sessionActiveInterval=sessionParametersStruct.SessionActiveInterval if sessionParametersStruct.SessionActiveInterval != 0 else None, + sessionActiveThreshold=sessionParametersStruct.SessionActiveThreshold if sessionParametersStruct.SessionActiveThreshold != 0 else None, + dataModelRevision=sessionParametersStruct.DataModelRevision if sessionParametersStruct.DataModelRevision != 0 else None, + interactionModelRevision=sessionParametersStruct.InteractionModelRevision if sessionParametersStruct.InteractionModelRevision != 0 else None, + specficiationVersion=sessionParametersStruct.SpecificationVersion if sessionParametersStruct.SpecificationVersion != 0 else None, + maxPathsPerInvoke=sessionParametersStruct.MaxPathsPerInvoke) + + return res + async def TestOnlySendCommandTimedRequestFlagWithNoTimedInvoke(self, nodeid: int, endpoint: int, payload: ClusterObjects.ClusterCommand, responseType=None): ''' diff --git a/src/controller/python/chip/interaction_model/__init__.py b/src/controller/python/chip/interaction_model/__init__.py index bd064f2df87d34..ec6065152d71c0 100644 --- a/src/controller/python/chip/interaction_model/__init__.py +++ b/src/controller/python/chip/interaction_model/__init__.py @@ -26,10 +26,12 @@ from chip.exceptions import ChipStackException -from .delegate import AttributePath, AttributePathIBstruct, DataVersionFilterIBstruct, EventPath, EventPathIBstruct +from .delegate import (AttributePath, AttributePathIBstruct, DataVersionFilterIBstruct, EventPath, EventPathIBstruct, + SessionParameters, SessionParametersStruct) __all__ = ["AttributePath", "AttributePathIBstruct", "DataVersionFilterIBstruct", - "EventPath", "EventPathIBstruct", "Status", "InteractionModelError"] + "EventPath", "EventPathIBstruct", "InteractionModelError", + "SessionParameters", "SessionParametersStruct", "Status"] # defined src/controller/python/chip/interaction_model/Delegate.h diff --git a/src/controller/python/chip/interaction_model/delegate.py b/src/controller/python/chip/interaction_model/delegate.py index f5037ec44cf9f4..74acb3921ec820 100644 --- a/src/controller/python/chip/interaction_model/delegate.py +++ b/src/controller/python/chip/interaction_model/delegate.py @@ -69,6 +69,16 @@ "DataVersion" / Int32ul, ) +SessionParametersStruct = Struct( + "SessionIdleInterval" / Int32ul, + "SessionActiveInterval" / Int32ul, + "SessionActiveThreshold" / Int16ul, + "DataModelRevision" / Int16ul, + "InteractionModelRevision" / Int16ul, + "SpecificationVersion" / Int32ul, + "MaxPathsPerInvoke" / Int16ul, +) + @dataclass class AttributePath: @@ -107,6 +117,17 @@ class AttributeWriteResult: status: int +@dataclass +class SessionParameters: + sessionIdleInterval: typing.Optional[int] + sessionActiveInterval: typing.Optional[int] + sessionActiveThreshold: typing.Optional[int] + dataModelRevision: typing.Optional[int] + interactionModelRevision: typing.Optional[int] + specficiationVersion: typing.Optional[int] + maxPathsPerInvoke: int + + # typedef void (*PythonInteractionModelDelegate_OnCommandResponseStatusCodeReceivedFunct)(uint64_t commandSenderPtr, # void * commandStatusBuf); # typedef void (*PythonInteractionModelDelegate_OnCommandResponseProtocolErrorFunct)(uint64_t commandSenderPtr, diff --git a/src/controller/python/chip/utils/DeviceProxyUtils.cpp b/src/controller/python/chip/utils/DeviceProxyUtils.cpp index d3bb2c6e65e204..e29c88cdb41d2c 100644 --- a/src/controller/python/chip/utils/DeviceProxyUtils.cpp +++ b/src/controller/python/chip/utils/DeviceProxyUtils.cpp @@ -33,6 +33,21 @@ using namespace chip; +namespace python { + +struct __attribute__((packed)) SessionParametersStruct +{ + uint32_t sessionIdleInterval = 0; + uint32_t sessionActiveInterval = 0; + uint16_t sessionActiveThreshold = 0; + uint16_t dataModelRevision = 0; + uint16_t interactionModelRevision = 0; + uint32_t specificationVersion = 0; + uint16_t maxPathsPerInvoke = 0; +}; + +} // namespace python + extern "C" { /** @@ -59,4 +74,31 @@ uint32_t pychip_DeviceProxy_ComputeRoundTripTimeout(DeviceProxy * device, uint32 ->ComputeRoundTripTimeout(System::Clock::Milliseconds32(upperLayerProcessingTimeoutMs)) .count(); } + +/** + * @brief This gets the Session Parameters reported by remote node. + * + * A valid DeviceProxy pointer with a valid established session is required for this method. + */ +PyChipError pychip_DeviceProxy_GetRemoteSessionParameters(DeviceProxy * device, void * sessionParametersStructPointer) +{ + VerifyOrReturnError(device != nullptr || sessionParametersStructPointer, ToPyChipError(CHIP_ERROR_INVALID_ARGUMENT)); + + auto * deviceProxy = static_cast(device); + VerifyOrReturnError(deviceProxy->GetSecureSession().HasValue(), ToPyChipError(CHIP_ERROR_INCORRECT_STATE)); + + auto remoteSessionParameters = deviceProxy->GetSecureSession().Value()->GetRemoteSessionParameters(); + auto remoteMrpConfig = remoteSessionParameters.GetMRPConfig(); + + python::SessionParametersStruct * sessionParam = static_cast(sessionParametersStructPointer); + + sessionParam->sessionIdleInterval = remoteMrpConfig.mIdleRetransTimeout.count(); + sessionParam->sessionActiveInterval = remoteMrpConfig.mActiveRetransTimeout.count(); + sessionParam->sessionActiveThreshold = remoteMrpConfig.mActiveThresholdTime.count(); + sessionParam->dataModelRevision = remoteSessionParameters.GetDataModelRevision().ValueOr(0); + sessionParam->interactionModelRevision = remoteSessionParameters.GetInteractionModelRevision().ValueOr(0); + sessionParam->specificationVersion = remoteSessionParameters.GetSpecificationVersion().ValueOr(0); + sessionParam->maxPathsPerInvoke = remoteSessionParameters.GetMaxPathsPerInvoke(); + return ToPyChipError(CHIP_NO_ERROR); +} }