From 3400090712fd8e8e0191ce5ecf1401c162244fdc Mon Sep 17 00:00:00 2001 From: Song GUO Date: Wed, 13 Oct 2021 04:13:10 +0800 Subject: [PATCH] [python] Support shutting down subscription (CLI) (#10375) * [python] Support shutting down subscription * Update document * Resolve comments * Update wordlist --- .github/.wordlist.txt | 14 ++++++-- .../guides/python_chip_controller_building.md | 33 +++++++++++++++++-- src/app/InteractionModelEngine.cpp | 16 +++++++++ src/app/InteractionModelEngine.h | 8 +++++ src/app/ReadClient.h | 6 ++++ src/app/util/im-client-callbacks.cpp | 9 +++++ .../ChipDeviceController-ScriptBinding.cpp | 7 ++++ src/controller/python/chip-device-ctrl.py | 6 ++++ src/controller/python/chip/ChipDeviceCtrl.py | 10 ++++++ 9 files changed, 105 insertions(+), 4 deletions(-) diff --git a/.github/.wordlist.txt b/.github/.wordlist.txt index d5b1dc8e357349..67d6916d2a8900 100644 --- a/.github/.wordlist.txt +++ b/.github/.wordlist.txt @@ -33,6 +33,7 @@ APIs apk AppConfig ApplicationBasic +ApplicationIdentifier ApplicationLauncher approver appspot @@ -46,6 +47,7 @@ armv ASYNC att attId +attributeValue attrListName attrMask attSizeBytes @@ -267,6 +269,7 @@ DISTRO Distutils DK DL +DMG DNS Dnsmasq dnsmasqd @@ -441,8 +444,8 @@ Infineon ini init inlined -instantiation installDebug +instantiation integrations IntelliSense InteractionModelVersion @@ -539,6 +542,7 @@ MatterLock matterSdkSourceBuild matterUTestLib MaxInterval +MaxIntervalCeilingSeconds MaxRtrAdvInterval mbedTLS mcu @@ -568,6 +572,7 @@ MicroSD middleware Minicom MinInterval +MinIntervalFloorSeconds MinRtrAdvInterval mkdir mlan @@ -780,8 +785,8 @@ ScriptBinding SDC SDHC SDK -sdkconfig SDK's +sdkconfig SDKs SDKTARGETSYSROOT sdl @@ -836,6 +841,8 @@ subdirectory submodule submodules subprocess +SubscribeResponse +SubscriptionId sudo svg SVR @@ -968,12 +975,14 @@ wrover WS WSL WSTK +xa xab xaver xbef xcd Xcode xd +xdeadbeefcafe xds xdsdfu xef @@ -1000,6 +1009,7 @@ zaptool ZCL zclconfigure zclread +zclsubscribe zclwrite ZephyrConfig zephyrproject diff --git a/docs/guides/python_chip_controller_building.md b/docs/guides/python_chip_controller_building.md index 032b72953d4372..6e8dea42e66fba 100644 --- a/docs/guides/python_chip_controller_building.md +++ b/docs/guides/python_chip_controller_building.md @@ -574,10 +574,39 @@ chip-device-ctrl > zclwrite TestCluster CharString 1 1 0 233233 Note: The format of the value is the same as the format of argument values for ZCL cluster commands. -### `zclconfigure ` +### `zclsubscribe ` Configure ZCL attribute reporting settings. For example: ``` -chip-device-ctrl > zclconfigure OccupancySensing Occupancy 1234 1 0 1000 2000 1 +chip-device-ctrl > zclsubscribe OccupancySensing Occupancy 1234 1 10 20 ``` + +### `zclsubscribe -shutdown ` + +Shutdown an existing attribute subscription. + +``` +chip-device-ctrl > zclsubscribe -shutdown 0xdeadbeefcafe +``` + +The subscription id can be obtained from previous subscription messages: + +``` +chip-device-ctrl > zclsubscribe OnOff OnOff 1 1 10 20 +(omitted messages) +[1633922898.965587][1117858:1117866] CHIP:DMG: SubscribeResponse = +[1633922898.965599][1117858:1117866] CHIP:DMG: { +[1633922898.965610][1117858:1117866] CHIP:DMG: SubscriptionId = 0xdeadbeefcafe, +[1633922898.965622][1117858:1117866] CHIP:DMG: MinIntervalFloorSeconds = 0xa, +[1633922898.965633][1117858:1117866] CHIP:DMG: MaxIntervalCeilingSeconds = 0x14, +[1633922898.965644][1117858:1117866] CHIP:DMG: } +[1633922898.965662][1117858:1117866] CHIP:ZCL: SubscribeResponse: +[1633922898.965673][1117858:1117866] CHIP:ZCL: SubscriptionId: 0xdeadbeefcafe +[1633922898.965683][1117858:1117866] CHIP:ZCL: ApplicationIdentifier: 0 +[1633922898.965694][1117858:1117866] CHIP:ZCL: status: EMBER_ZCL_STATUS_SUCCESS (0x00) +[1633922898.965709][1117858:1117866] CHIP:ZCL: attributeValue: false +(omitted messages) +``` + +The subscription id is `0xdeadbeefcafe` in this case diff --git a/src/app/InteractionModelEngine.cpp b/src/app/InteractionModelEngine.cpp index 4eee0b53c8aa82..410cc61127bdf4 100644 --- a/src/app/InteractionModelEngine.cpp +++ b/src/app/InteractionModelEngine.cpp @@ -142,6 +142,22 @@ CHIP_ERROR InteractionModelEngine::NewReadClient(ReadClient ** const apReadClien return err; } +CHIP_ERROR InteractionModelEngine::ShutdownSubscription(uint64_t aSubscriptionId) +{ + CHIP_ERROR err = CHIP_ERROR_KEY_NOT_FOUND; + + for (auto & readClient : mReadClients) + { + if (!readClient.IsFree() && readClient.IsSubscriptionType() && readClient.IsMatchingClient(aSubscriptionId)) + { + readClient.Shutdown(); + err = CHIP_NO_ERROR; + } + } + + return err; +} + CHIP_ERROR InteractionModelEngine::NewWriteClient(WriteClientHandle & apWriteClient, uint64_t aApplicationIdentifier) { apWriteClient.SetWriteClient(nullptr); diff --git a/src/app/InteractionModelEngine.h b/src/app/InteractionModelEngine.h index 272aa5692d23b7..1cf95012e49805 100644 --- a/src/app/InteractionModelEngine.h +++ b/src/app/InteractionModelEngine.h @@ -110,6 +110,14 @@ class InteractionModelEngine : public Messaging::ExchangeDelegate, public Comman * @retval #CHIP_NO_ERROR On success. */ CHIP_ERROR SendSubscribeRequest(ReadPrepareParams & aReadPrepareParams, uint64_t aAppIdentifier = 0); + + /** + * Tears down an active subscription. + * + * @retval #CHIP_ERROR_KEY_NOT_FOUND If the subscription is not found. + * @retval #CHIP_NO_ERROR On success. + */ + CHIP_ERROR ShutdownSubscription(uint64_t aSubscriptionId); /** * Retrieve a WriteClient that the SDK consumer can use to send a write. If the call succeeds, * see WriteClient documentation for lifetime handling. diff --git a/src/app/ReadClient.h b/src/app/ReadClient.h index fc0c033405edd2..530c4337873aef 100644 --- a/src/app/ReadClient.h +++ b/src/app/ReadClient.h @@ -94,6 +94,12 @@ class ReadClient : public Messaging::ExchangeDelegate CHIP_ERROR OnUnsolicitedReportData(Messaging::ExchangeContext * apExchangeContext, System::PacketBufferHandle && aPayload); uint64_t GetAppIdentifier() const { return mAppIdentifier; } + auto GetSubscriptionId() const + { + using returnType = Optional; + return mInteractionType == InteractionType::Subscribe ? returnType(mSubscriptionId) : returnType::Missing(); + } + NodeId GetPeerNodeId() const { return mPeerNodeId; } bool IsReadType() { return mInteractionType == InteractionType::Read; } bool IsSubscriptionType() const { return mInteractionType == InteractionType::Subscribe; }; diff --git a/src/app/util/im-client-callbacks.cpp b/src/app/util/im-client-callbacks.cpp index 150a0eb2fd1f70..80d64898942e42 100644 --- a/src/app/util/im-client-callbacks.cpp +++ b/src/app/util/im-client-callbacks.cpp @@ -427,7 +427,16 @@ bool IMReadReportAttributesResponseCallback(const app::ReadClient * apReadClient bool IMSubscribeResponseCallback(const chip::app::ReadClient * apSubscribeClient, EmberAfStatus status) { + auto subscriptionId = apSubscribeClient->GetSubscriptionId(); ChipLogProgress(Zcl, "SubscribeResponse:"); + if (subscriptionId.HasValue()) + { + ChipLogProgress(Zcl, " SubscriptionId: 0x%" PRIx64, subscriptionId.Value()); + } + else + { + ChipLogProgress(Zcl, " SubscriptionId: "); + } ChipLogProgress(Zcl, " ApplicationIdentifier: %" PRIx64, apSubscribeClient->GetAppIdentifier()); LogStatus(status); diff --git a/src/controller/python/ChipDeviceController-ScriptBinding.cpp b/src/controller/python/ChipDeviceController-ScriptBinding.cpp index 9f9a724ef401ea..e1f93cb0e1a21c 100644 --- a/src/controller/python/ChipDeviceController-ScriptBinding.cpp +++ b/src/controller/python/ChipDeviceController-ScriptBinding.cpp @@ -167,6 +167,8 @@ ChipError::StorageType pychip_GetConnectedDeviceByNodeId(chip::Controller::Devic uint64_t pychip_GetCommandSenderHandle(chip::Controller::Device * device); // CHIP Stack objects ChipError::StorageType pychip_BLEMgrImpl_ConfigureBle(uint32_t bluetoothAdapterId); + +chip::ChipError::StorageType pychip_InteractionModel_ShutdownSubscription(uint64_t subscriptionId); } ChipError::StorageType pychip_DeviceController_NewDeviceController(chip::Controller::DeviceCommissioner ** outDevCtrl, @@ -588,3 +590,8 @@ ChipError::StorageType pychip_DeviceController_PostTaskOnChipThread(ChipThreadTa PlatformMgr().ScheduleWork(callback, reinterpret_cast(pythonContext)); return CHIP_NO_ERROR.AsInteger(); } + +chip::ChipError::StorageType pychip_InteractionModel_ShutdownSubscription(uint64_t subscriptionId) +{ + return chip::app::InteractionModelEngine::GetInstance()->ShutdownSubscription(subscriptionId).AsInteger(); +} diff --git a/src/controller/python/chip-device-ctrl.py b/src/controller/python/chip-device-ctrl.py index d3e737574fce37..af4011dc50c55a 100755 --- a/src/controller/python/chip-device-ctrl.py +++ b/src/controller/python/chip-device-ctrl.py @@ -809,6 +809,9 @@ def do_zclsubscribe(self, line): """ To subscribe ZCL attribute reporting: zclsubscribe + + To shut down a subscription: + zclsubscribe -shutdown """ try: args = shlex.split(line) @@ -826,6 +829,9 @@ def do_zclsubscribe(self, line): raise exceptions.UnknownCluster(args[0]) self.devCtrl.ZCLSubscribeAttribute(args[0], args[1], int( args[2]), int(args[3]), int(args[4]), int(args[5])) + elif len(args) == 2 and args[0] == '-shutdown': + subscriptionId = int(args[1], base=0) + self.devCtrl.ZCLShutdownSubscription(subscriptionId) else: self.do_help("zclsubscribe") except exceptions.ChipStackException as ex: diff --git a/src/controller/python/chip/ChipDeviceCtrl.py b/src/controller/python/chip/ChipDeviceCtrl.py index 1809d65db49257..582a868e167c8e 100644 --- a/src/controller/python/chip/ChipDeviceCtrl.py +++ b/src/controller/python/chip/ChipDeviceCtrl.py @@ -367,6 +367,12 @@ def ZCLSubscribeAttribute(self, cluster, attribute, nodeid, endpoint, minInterva # We only send 1 command by this function, so index is always 0 return im.WaitCommandIndexStatus(commandSenderHandle, 1) + def ZCLShutdownSubscription(self, subscriptionId: int): + res = self._ChipStack.Call( + lambda: self._dmLib.pychip_InteractionModel_ShutdownSubscription(subscriptionId)) + if res != 0: + raise self._ChipStack.ErrorToException(res) + def ZCLCommandList(self): return self._Cluster.ListClusterCommands() @@ -489,3 +495,7 @@ def _InitLib(self): self._dmLib.pychip_DeviceController_OpenCommissioningWindow.argtypes = [ c_void_p, c_uint64, c_uint16, c_uint16, c_uint16, c_uint8] self._dmLib.pychip_DeviceController_OpenCommissioningWindow.restype = c_uint32 + + self._dmLib.pychip_InteractionModel_ShutdownSubscription.argtypes = [ + c_uint64] + self._dmLib.pychip_InteractionModel_ShutdownSubscription.restype = c_uint32