diff --git a/src/controller/python/chip/clusters/Attribute.py b/src/controller/python/chip/clusters/Attribute.py index 96a66f5706f174..9e46eed469d39f 100644 --- a/src/controller/python/chip/clusters/Attribute.py +++ b/src/controller/python/chip/clusters/Attribute.py @@ -520,6 +520,21 @@ def GetReportingIntervalsSeconds(self) -> Tuple[int, int]: return minIntervalSec.value, maxIntervalSec.value + def GetSubscriptionTimeoutMs(self) -> int: + ''' + Returns the timeout(milliseconds) after which we consider the subscription to have + dropped, if we have received no messages within that amount of time. + Returns 0 milliseconds if a subscription has not yet been established (and + hence the MaxInterval is not yet known), or if the subscription session + is gone and hence the relevant MRP parameters can no longer be determined. + ''' + timeoutMs = ctypes.c_uint32(0) + handle = chip.native.GetLibraryHandle() + builtins.chipStack.Call( + lambda: handle.pychip_ReadClient_GetSubscriptionTimeoutMs(self._readTransaction._pReadClient, ctypes.pointer(timeoutMs)) + ) + return timeoutMs.value + def SetResubscriptionAttemptedCallback(self, callback: Callable[[SubscriptionTransaction, int, int], None], isAsync=False): ''' Sets the callback function that gets invoked anytime a re-subscription is attempted. The callback is expected diff --git a/src/controller/python/chip/clusters/attribute.cpp b/src/controller/python/chip/clusters/attribute.cpp index 8abaaab18e1ed9..e31f3431b8b2a0 100644 --- a/src/controller/python/chip/clusters/attribute.cpp +++ b/src/controller/python/chip/clusters/attribute.cpp @@ -472,6 +472,22 @@ PyChipError pychip_ReadClient_GetReportingIntervals(ReadClient * pReadClient, ui return ToPyChipError(err); } +void pychip_ReadClient_GetSubscriptionTimeoutMs(ReadClient * pReadClient, uint32_t * milliSec) +{ + VerifyOrDie(pReadClient != nullptr); + + Optional duration = pReadClient->GetSubscriptionTimeout(); + + // The return value of GetSubscriptionTimeout cannot be 0 + // so milliSec=0 can be considered as the subscription has been abnormal. + *milliSec = 0; + if (duration.HasValue()) + { + System::Clock::Milliseconds32 msec = std::chrono::duration_cast(duration.Value()); + *milliSec = msec.count(); + } +} + PyChipError pychip_ReadClient_Read(void * appContext, ReadClient ** pReadClient, ReadClientCallback ** pCallback, DeviceProxy * device, uint8_t * readParamsBuf, void ** attributePathsFromPython, size_t numAttributePaths, void ** dataversionFiltersFromPython, size_t numDataversionFilters, @@ -561,11 +577,22 @@ PyChipError pychip_ReadClient_Read(void * appContext, ReadClient ** pReadClient, params.mKeepSubscriptions = pyParams.keepSubscriptions; callback->SetAutoResubscribe(pyParams.autoResubscribe); - dataVersionFilters.release(); - attributePaths.release(); - eventPaths.release(); +#if CONFIG_BUILD_FOR_HOST_UNIT_TEST + if (!pyParams.autoResubscribe) + { + // We want to allow certain kinds of spec-invalid subscriptions so we + // can test how the server reacts to them. + err = readClient->SendSubscribeRequestWithoutValidation(params); + } + else +#endif // CONFIG_BUILD_FOR_HOST_UNIT_TEST + { + dataVersionFilters.release(); + attributePaths.release(); + eventPaths.release(); - err = readClient->SendAutoResubscribeRequest(std::move(params)); + err = readClient->SendAutoResubscribeRequest(std::move(params)); + } SuccessOrExit(err); } else