diff --git a/examples/all-clusters-app/all-clusters-common/all-clusters-app.matter b/examples/all-clusters-app/all-clusters-common/all-clusters-app.matter index 45e58fffca24ea..abf4f302af9edf 100644 --- a/examples/all-clusters-app/all-clusters-common/all-clusters-app.matter +++ b/examples/all-clusters-app/all-clusters-common/all-clusters-app.matter @@ -8170,9 +8170,22 @@ endpoint 1 { server cluster Actions { callback attribute actionList; callback attribute endpointLists; - callback attribute setupURL; + ram attribute setupURL default = "https://example.com"; ram attribute featureMap default = 0; - callback attribute clusterRevision default = 1; + ram attribute clusterRevision default = 1; + + handle command InstantAction; + handle command InstantActionWithTransition; + handle command StartAction; + handle command StartActionWithDuration; + handle command StopAction; + handle command PauseAction; + handle command PauseActionWithDuration; + handle command ResumeAction; + handle command EnableAction; + handle command EnableActionWithDuration; + handle command DisableAction; + handle command DisableActionWithDuration; } server cluster PowerSource { diff --git a/examples/all-clusters-app/all-clusters-common/all-clusters-app.zap b/examples/all-clusters-app/all-clusters-common/all-clusters-app.zap index f8e3dbd8806c3f..722ab67f04c2f2 100644 --- a/examples/all-clusters-app/all-clusters-common/all-clusters-app.zap +++ b/examples/all-clusters-app/all-clusters-common/all-clusters-app.zap @@ -7343,6 +7343,104 @@ "define": "ACTIONS_CLUSTER", "side": "server", "enabled": 1, + "commands": [ + { + "name": "InstantAction", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "InstantActionWithTransition", + "code": 1, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "StartAction", + "code": 2, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "StartActionWithDuration", + "code": 3, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "StopAction", + "code": 4, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "PauseAction", + "code": 5, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "PauseActionWithDuration", + "code": 6, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "ResumeAction", + "code": 7, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "EnableAction", + "code": 8, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "EnableActionWithDuration", + "code": 9, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "DisableAction", + "code": 10, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "DisableActionWithDuration", + "code": 11, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + } + ], "attributes": [ { "name": "ActionList", @@ -7383,10 +7481,10 @@ "side": "server", "type": "long_char_string", "included": 1, - "storageOption": "External", + "storageOption": "RAM", "singleton": 0, "bounded": 0, - "defaultValue": "", + "defaultValue": "https://example.com", "reportable": 1, "minInterval": 0, "maxInterval": 65344, @@ -7415,7 +7513,7 @@ "side": "server", "type": "int16u", "included": 1, - "storageOption": "External", + "storageOption": "RAM", "singleton": 0, "bounded": 0, "defaultValue": "1", diff --git a/examples/all-clusters-app/all-clusters-common/include/bridged-actions-stub.h b/examples/all-clusters-app/all-clusters-common/include/bridged-actions-stub.h new file mode 100644 index 00000000000000..ca8b0e26d2004d --- /dev/null +++ b/examples/all-clusters-app/all-clusters-common/include/bridged-actions-stub.h @@ -0,0 +1,82 @@ +/* + * + * Copyright (c) 2024 Project CHIP Authors + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +namespace chip { +namespace app { +namespace Clusters { +namespace Actions { +const uint16_t kActionListSize = 3; +const uint16_t kEndpointListSize = 3; +class ActionsDelegateImpl : public Delegate +{ +private: + const ActionStructStorage kActionList[kActionListSize] = { + ActionStructStorage(0, CharSpan::fromCharString("TurnOnLight"), ActionTypeEnum::kScene, 0, 0, ActionStateEnum::kInactive), + ActionStructStorage(1, CharSpan::fromCharString("TurnOffLight"), ActionTypeEnum::kScene, 1, 0, ActionStateEnum::kInactive), + ActionStructStorage(2, CharSpan::fromCharString("ToggleLight"), ActionTypeEnum::kScene, 2, 0, ActionStateEnum::kInactive), + }; + + // Dummy endpoint list. + const EndpointId firstEpList[1] = { 0 }; + const EndpointId secondEpList[1] = { 0 }; + const EndpointId thirdEpList[1] = { 0 }; + + const EndpointListStorage kEndpointList[kEndpointListSize] = { + EndpointListStorage(0, CharSpan::fromCharString("On"), EndpointListTypeEnum::kOther, + DataModel::List(firstEpList)), + EndpointListStorage(1, CharSpan::fromCharString("Off"), EndpointListTypeEnum::kOther, + DataModel::List(secondEpList)), + EndpointListStorage(2, CharSpan::fromCharString("Toggle"), EndpointListTypeEnum::kOther, + DataModel::List(thirdEpList)), + }; + + CHIP_ERROR ReadActionAtIndex(uint16_t index, ActionStructStorage & action) override; + CHIP_ERROR ReadEndpointListAtIndex(uint16_t index, EndpointListStorage & epList) override; + bool FindActionIdInActionList(uint16_t actionId) override; + + Protocols::InteractionModel::Status HandleInstantAction(uint16_t actionId, Optional invokeId) override; + Protocols::InteractionModel::Status HandleInstantActionWithTransition(uint16_t actionId, uint16_t transitionTime, + Optional invokeId) override; + Protocols::InteractionModel::Status HandleStartAction(uint16_t actionId, Optional invokeId) override; + Protocols::InteractionModel::Status HandleStartActionWithDuration(uint16_t actionId, uint32_t duration, + Optional invokeId) override; + Protocols::InteractionModel::Status HandleStopAction(uint16_t actionId, Optional invokeId) override; + Protocols::InteractionModel::Status HandlePauseAction(uint16_t actionId, Optional invokeId) override; + Protocols::InteractionModel::Status HandlePauseActionWithDuration(uint16_t actionId, uint32_t duration, + Optional invokeId) override; + Protocols::InteractionModel::Status HandleResumeAction(uint16_t actionId, Optional invokeId) override; + Protocols::InteractionModel::Status HandleEnableAction(uint16_t actionId, Optional invokeId) override; + Protocols::InteractionModel::Status HandleEnableActionWithDuration(uint16_t actionId, uint32_t duration, + Optional invokeId) override; + Protocols::InteractionModel::Status HandleDisableAction(uint16_t actionId, Optional invokeId) override; + Protocols::InteractionModel::Status HandleDisableActionWithDuration(uint16_t actionId, uint32_t duration, + Optional invokeId) override; +}; +} // namespace Actions +} // namespace Clusters +} // namespace app +} // namespace chip diff --git a/examples/all-clusters-app/all-clusters-common/src/bridged-actions-stub.cpp b/examples/all-clusters-app/all-clusters-common/src/bridged-actions-stub.cpp index 90d1b9ebd115b0..e5e7c98ae0d0c1 100644 --- a/examples/all-clusters-app/all-clusters-common/src/bridged-actions-stub.cpp +++ b/examples/all-clusters-app/all-clusters-common/src/bridged-actions-stub.cpp @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2021 Project CHIP Authors + * Copyright (c) 2024 Project CHIP Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,88 +15,114 @@ * limitations under the License. */ -#include -#include -#include -#include -#include -#include -#include -#include +#include using namespace chip; using namespace chip::app; using namespace chip::app::Clusters; +using namespace chip::app::Clusters::Actions; using namespace chip::app::Clusters::Actions::Attributes; +using namespace chip::Protocols::InteractionModel; -namespace { +CHIP_ERROR ActionsDelegateImpl::ReadActionAtIndex(uint16_t index, ActionStructStorage & action) +{ + if (index >= ArraySize(kActionList)) + { + return CHIP_ERROR_PROVIDER_LIST_EXHAUSTED; + } + action = kActionList[index]; + return CHIP_NO_ERROR; +} -class ActionsAttrAccess : public AttributeAccessInterface +CHIP_ERROR ActionsDelegateImpl::ReadEndpointListAtIndex(uint16_t index, EndpointListStorage & epList) { -public: - // Register for the Actions cluster on all endpoints. - ActionsAttrAccess() : AttributeAccessInterface(Optional::Missing(), Actions::Id) {} + if (index >= ArraySize(kEndpointList)) + { + return CHIP_ERROR_PROVIDER_LIST_EXHAUSTED; + } + epList = kEndpointList[index]; + return CHIP_NO_ERROR; +} - CHIP_ERROR Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder) override; +bool ActionsDelegateImpl::FindActionIdInActionList(uint16_t actionId) +{ + for (uint16_t i = 0; i < kActionListSize; i++) + { + if (kActionList[i].actionID == actionId) + return true; + } + return false; +} -private: - static constexpr uint16_t ClusterRevision = 1; +Status ActionsDelegateImpl::HandleInstantAction(uint16_t actionId, Optional invokeId) +{ + // Not implemented + return Status::NotFound; +} - CHIP_ERROR ReadActionListAttribute(EndpointId endpoint, AttributeValueEncoder & aEncoder); - CHIP_ERROR ReadEndpointListAttribute(EndpointId endpoint, AttributeValueEncoder & aEncoder); - CHIP_ERROR ReadSetupUrlAttribute(EndpointId endpoint, AttributeValueEncoder & aEncoder); - CHIP_ERROR ReadClusterRevision(EndpointId endpoint, AttributeValueEncoder & aEncoder); -}; +Status ActionsDelegateImpl::HandleInstantActionWithTransition(uint16_t actionId, uint16_t transitionTime, + Optional invokeId) +{ + // Not implemented + return Status::NotFound; +} -constexpr uint16_t ActionsAttrAccess::ClusterRevision; +Status ActionsDelegateImpl::HandleStartAction(uint16_t actionId, Optional invokeId) +{ + // Not implemented + return Status::NotFound; +} + +Status ActionsDelegateImpl::HandleStartActionWithDuration(uint16_t actionId, uint32_t duration, Optional invokeId) +{ + // Not implemented + return Status::NotFound; +} -CHIP_ERROR ActionsAttrAccess::ReadActionListAttribute(EndpointId endpoint, AttributeValueEncoder & aEncoder) +Status ActionsDelegateImpl::HandleStopAction(uint16_t actionId, Optional invokeId) { - // Just return an empty list - return aEncoder.EncodeEmptyList(); + // Not implemented + return Status::NotFound; } -CHIP_ERROR ActionsAttrAccess::ReadEndpointListAttribute(EndpointId endpoint, AttributeValueEncoder & aEncoder) +Status ActionsDelegateImpl::HandlePauseAction(uint16_t actionId, Optional invokeId) { - // Just return an empty list - return aEncoder.EncodeEmptyList(); + // Not implemented + return Status::NotFound; } -CHIP_ERROR ActionsAttrAccess::ReadSetupUrlAttribute(EndpointId endpoint, AttributeValueEncoder & aEncoder) +Status ActionsDelegateImpl::HandlePauseActionWithDuration(uint16_t actionId, uint32_t duration, Optional invokeId) { - static const char SetupUrl[] = "https://example.com"; - return aEncoder.Encode(chip::Span(SetupUrl, strlen(SetupUrl))); + // Not implemented + return Status::NotFound; } -CHIP_ERROR ActionsAttrAccess::ReadClusterRevision(EndpointId endpoint, AttributeValueEncoder & aEncoder) +Status ActionsDelegateImpl::HandleResumeAction(uint16_t actionId, Optional invokeId) { - return aEncoder.Encode(ClusterRevision); + // Not implemented + return Status::NotFound; } -ActionsAttrAccess gAttrAccess; +Status ActionsDelegateImpl::HandleEnableAction(uint16_t actionId, Optional invokeId) +{ + // Not implemented + return Status::NotFound; +} -CHIP_ERROR ActionsAttrAccess::Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder) +Status ActionsDelegateImpl::HandleEnableActionWithDuration(uint16_t actionId, uint32_t duration, Optional invokeId) { - VerifyOrDie(aPath.mClusterId == Actions::Id); + // Not implemented + return Status::NotFound; +} - switch (aPath.mAttributeId) - { - case ActionList::Id: - return ReadActionListAttribute(aPath.mEndpointId, aEncoder); - case EndpointLists::Id: - return ReadEndpointListAttribute(aPath.mEndpointId, aEncoder); - case SetupURL::Id: - return ReadSetupUrlAttribute(aPath.mEndpointId, aEncoder); - case ClusterRevision::Id: - return ReadClusterRevision(aPath.mEndpointId, aEncoder); - default: - break; - } - return CHIP_NO_ERROR; +Status ActionsDelegateImpl::HandleDisableAction(uint16_t actionId, Optional invokeId) +{ + // Not implemented + return Status::NotFound; } -} // anonymous namespace -void MatterActionsPluginServerInitCallback() +Status ActionsDelegateImpl::HandleDisableActionWithDuration(uint16_t actionId, uint32_t duration, Optional invokeId) { - AttributeAccessInterfaceRegistry::Instance().Register(&gAttrAccess); + // Not implemented + return Status::NotFound; } diff --git a/examples/all-clusters-app/esp32/main/CMakeLists.txt b/examples/all-clusters-app/esp32/main/CMakeLists.txt index 31292543ca5f50..85f655004ec1de 100644 --- a/examples/all-clusters-app/esp32/main/CMakeLists.txt +++ b/examples/all-clusters-app/esp32/main/CMakeLists.txt @@ -83,6 +83,7 @@ set(SRC_DIRS_LIST "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/group-key-mgmt-server" "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/basic-information" "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/bindings" + "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/actions-server" "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/icd-management-server" "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/diagnostic-logs-server" "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/occupancy-sensor-server" diff --git a/examples/all-clusters-app/esp32/main/main.cpp b/examples/all-clusters-app/esp32/main/main.cpp index 6a0d0d389a92e2..d6ddf464bc1db1 100644 --- a/examples/all-clusters-app/esp32/main/main.cpp +++ b/examples/all-clusters-app/esp32/main/main.cpp @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -96,6 +97,7 @@ AppCallbacks sCallbacks; app::Clusters::TemperatureControl::AppSupportedTemperatureLevelsDelegate sAppSupportedTemperatureLevelsDelegate; app::Clusters::ModeSelect::StaticSupportedModesManager sStaticSupportedModesManager; +app::Clusters::Actions::ActionsDelegateImpl sActionsDelegateImpl; constexpr EndpointId kNetworkCommissioningEndpointSecondary = 0xFFFE; @@ -126,9 +128,14 @@ static void InitServer(intptr_t context) app::Clusters::TemperatureControl::SetInstance(&sAppSupportedTemperatureLevelsDelegate); app::Clusters::ModeSelect::setSupportedModesManager(&sStaticSupportedModesManager); + app::Clusters::Actions::Instance::GetInstance()->SetDefaultDelegate(&sActionsDelegateImpl); +} + +void emberAfActionsClusterInitCallback(EndpointId endpoint) +{ + app::Clusters::Actions::Instance::GetInstance()->SetDefaultDelegate(&sActionsDelegateImpl); } -// #include #include #include diff --git a/examples/all-clusters-app/linux/main-common.cpp b/examples/all-clusters-app/linux/main-common.cpp index b62d154f0d58f7..543168a804fea5 100644 --- a/examples/all-clusters-app/linux/main-common.cpp +++ b/examples/all-clusters-app/linux/main-common.cpp @@ -55,6 +55,7 @@ #include #include #include +#include #include #include #include @@ -87,6 +88,7 @@ Clusters::TemperatureControl::AppSupportedTemperatureLevelsDelegate sAppSupporte Clusters::ModeSelect::StaticSupportedModesManager sStaticSupportedModesManager; Clusters::ValveConfigurationAndControl::ValveControlDelegate sValveDelegate; Clusters::TimeSynchronization::ExtendedTimeSyncDelegate sTimeSyncDelegate; +Clusters::Actions::ActionsDelegateImpl sActionsDelegateImpl; // Please refer to https://github.com/CHIP-Specifications/connectedhomeip-spec/blob/master/src/namespaces constexpr const uint8_t kNamespaceCommon = 7; @@ -340,6 +342,11 @@ void emberAfThermostatClusterInitCallback(EndpointId endpoint) SetDefaultDelegate(endpoint, &delegate); } +void emberAfActionsClusterInitCallback(EndpointId endpoint) +{ + Clusters::Actions::Instance::GetInstance()->SetDefaultDelegate(&sActionsDelegateImpl); +} + Status emberAfExternalAttributeReadCallback(EndpointId endpoint, ClusterId clusterId, const EmberAfAttributeMetadata * attributeMetadata, uint8_t * buffer, uint16_t maxReadLength) diff --git a/examples/all-clusters-minimal-app/esp32/main/CMakeLists.txt b/examples/all-clusters-minimal-app/esp32/main/CMakeLists.txt index f82f301e3ae362..39253c24ed3fad 100644 --- a/examples/all-clusters-minimal-app/esp32/main/CMakeLists.txt +++ b/examples/all-clusters-minimal-app/esp32/main/CMakeLists.txt @@ -94,6 +94,7 @@ set(SRC_DIRS_LIST "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/power-source-configuration-server" "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/power-source-server" "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/resource-monitoring-server" + "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/actions-server" "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/examples/all-clusters-app/all-clusters-common/src" ) diff --git a/examples/all-clusters-minimal-app/esp32/sdkconfig_m5stack.defaults b/examples/all-clusters-minimal-app/esp32/sdkconfig_m5stack.defaults index 287262d17e57cc..03691548ea91db 100644 --- a/examples/all-clusters-minimal-app/esp32/sdkconfig_m5stack.defaults +++ b/examples/all-clusters-minimal-app/esp32/sdkconfig_m5stack.defaults @@ -73,3 +73,9 @@ CONFIG_BUILD_CHIP_TESTS=y # Move functions from IRAM to flash CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH=y + +# Reduce the event logging buffer to reduce the DRAM usage +# TODO: [ESP32] Fix the DRAM overflow in esp32 apps #34717 +CONFIG_EVENT_LOGGING_CRIT_BUFFER_SIZE=512 +CONFIG_EVENT_LOGGING_INFO_BUFFER_SIZE=512 +CONFIG_EVENT_LOGGING_DEBUG_BUFFER_SIZE=512 diff --git a/examples/all-clusters-minimal-app/esp32/sdkconfig_m5stack_rpc.defaults b/examples/all-clusters-minimal-app/esp32/sdkconfig_m5stack_rpc.defaults index d2eaffb9bfd15b..6c4907410a1c22 100644 --- a/examples/all-clusters-minimal-app/esp32/sdkconfig_m5stack_rpc.defaults +++ b/examples/all-clusters-minimal-app/esp32/sdkconfig_m5stack_rpc.defaults @@ -88,3 +88,9 @@ CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH=y CONFIG_EVENT_LOGGING_CRIT_BUFFER_SIZE=1024 CONFIG_DIAG_USE_EXTERNAL_LOG_WRAP=y + +# Reduce the event logging buffer to reduce the DRAM usage +# TODO: [ESP32] Fix the DRAM overflow in esp32 apps #34717 +CONFIG_EVENT_LOGGING_CRIT_BUFFER_SIZE=512 +CONFIG_EVENT_LOGGING_INFO_BUFFER_SIZE=512 +CONFIG_EVENT_LOGGING_DEBUG_BUFFER_SIZE=512 diff --git a/examples/bridge-app/asr/BUILD.gn b/examples/bridge-app/asr/BUILD.gn index 0fb9be4dcd99c4..19f8263e12bb7c 100755 --- a/examples/bridge-app/asr/BUILD.gn +++ b/examples/bridge-app/asr/BUILD.gn @@ -78,7 +78,6 @@ asr_executable("bridge_app") { "${examples_plat_dir}/shell/matter_shell.cpp", "src/AppTask.cpp", "src/DeviceCallbacks.cpp", - "src/bridged-actions-stub.cpp", "src/main.cpp", "subdevice/SubDevice.cpp", "subdevice/SubDeviceManager.cpp", diff --git a/examples/bridge-app/asr/src/bridged-actions-stub.cpp b/examples/bridge-app/asr/src/bridged-actions-stub.cpp deleted file mode 100755 index 73b7e8dd9877a0..00000000000000 --- a/examples/bridge-app/asr/src/bridged-actions-stub.cpp +++ /dev/null @@ -1,101 +0,0 @@ -/* - * - * Copyright (c) 2021 Project CHIP Authors - * - * 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 -#include -#include -#include -#include -#include -#include -#include - -using namespace chip; -using namespace chip::app; -using namespace chip::app::Clusters; -using namespace chip::app::Clusters::Actions::Attributes; - -namespace { - -class ActionsAttrAccess : public AttributeAccessInterface -{ -public: - // Register for the Actions cluster on all endpoints. - ActionsAttrAccess() : AttributeAccessInterface(Optional::Missing(), Actions::Id) {} - - CHIP_ERROR Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder) override; - -private: - static constexpr uint16_t ClusterRevision = 1; - - CHIP_ERROR ReadActionListAttribute(EndpointId endpoint, AttributeValueEncoder & aEncoder); - CHIP_ERROR ReadEndpointListAttribute(EndpointId endpoint, AttributeValueEncoder & aEncoder); - CHIP_ERROR ReadSetupUrlAttribute(EndpointId endpoint, AttributeValueEncoder & aEncoder); - CHIP_ERROR ReadClusterRevision(EndpointId endpoint, AttributeValueEncoder & aEncoder); -}; - -constexpr uint16_t ActionsAttrAccess::ClusterRevision; - -CHIP_ERROR ActionsAttrAccess::ReadActionListAttribute(EndpointId endpoint, AttributeValueEncoder & aEncoder) -{ - // Just return an empty list - return aEncoder.EncodeEmptyList(); -} - -CHIP_ERROR ActionsAttrAccess::ReadEndpointListAttribute(EndpointId endpoint, AttributeValueEncoder & aEncoder) -{ - // Just return an empty list - return aEncoder.EncodeEmptyList(); -} - -CHIP_ERROR ActionsAttrAccess::ReadSetupUrlAttribute(EndpointId endpoint, AttributeValueEncoder & aEncoder) -{ - static const char SetupUrl[] = "https://example.com"; - return aEncoder.Encode(chip::Span(SetupUrl, strlen(SetupUrl))); -} - -CHIP_ERROR ActionsAttrAccess::ReadClusterRevision(EndpointId endpoint, AttributeValueEncoder & aEncoder) -{ - return aEncoder.Encode(ClusterRevision); -} - -ActionsAttrAccess gAttrAccess; - -CHIP_ERROR ActionsAttrAccess::Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder) -{ - VerifyOrDie(aPath.mClusterId == Actions::Id); - - switch (aPath.mAttributeId) - { - case ActionList::Id: - return ReadActionListAttribute(aPath.mEndpointId, aEncoder); - case EndpointLists::Id: - return ReadEndpointListAttribute(aPath.mEndpointId, aEncoder); - case SetupURL::Id: - return ReadSetupUrlAttribute(aPath.mEndpointId, aEncoder); - case ClusterRevision::Id: - return ReadClusterRevision(aPath.mEndpointId, aEncoder); - default: - break; - } - return CHIP_NO_ERROR; -} -} // anonymous namespace - -void MatterActionsPluginServerInitCallback(void) -{ - AttributeAccessInterfaceRegistry::Instance().Register(&gAttrAccess); -} diff --git a/examples/bridge-app/asr/subdevice/SubDeviceManager.cpp b/examples/bridge-app/asr/subdevice/SubDeviceManager.cpp index 3508068c4832c6..c73f5fab84a88b 100644 --- a/examples/bridge-app/asr/subdevice/SubDeviceManager.cpp +++ b/examples/bridge-app/asr/subdevice/SubDeviceManager.cpp @@ -243,14 +243,6 @@ void HandleDeviceStatusChanged(SubDevice * dev, SubDevice::Changed_t itemChanged const EmberAfDeviceType gRootDeviceTypes[] = { { DEVICE_TYPE_ROOT_NODE, DEVICE_VERSION_DEFAULT } }; const EmberAfDeviceType gAggregateNodeDeviceTypes[] = { { DEVICE_TYPE_BRIDGE, DEVICE_VERSION_DEFAULT } }; -bool emberAfActionsClusterInstantActionCallback(app::CommandHandler * commandObj, const app::ConcreteCommandPath & commandPath, - const Actions::Commands::InstantAction::DecodableType & commandData) -{ - // No actions are implemented, just return status NotFound. - commandObj->AddStatus(commandPath, Protocols::InteractionModel::Status::NotFound); - return true; -} - void Init_Bridge_Endpoint() { // bridge will have own database named gSubDevices. diff --git a/examples/bridge-app/esp32/main/main.cpp b/examples/bridge-app/esp32/main/main.cpp index 016b75803cd69b..bbb3d0dab776ba 100644 --- a/examples/bridge-app/esp32/main/main.cpp +++ b/examples/bridge-app/esp32/main/main.cpp @@ -349,14 +349,6 @@ void HandleDeviceStatusChanged(Device * dev, Device::Changed_t itemChangedMask) } } -bool emberAfActionsClusterInstantActionCallback(app::CommandHandler * commandObj, const app::ConcreteCommandPath & commandPath, - const Actions::Commands::InstantAction::DecodableType & commandData) -{ - // No actions are implemented, just return status NotFound. - commandObj->AddStatus(commandPath, Protocols::InteractionModel::Status::NotFound); - return true; -} - const EmberAfDeviceType gRootDeviceTypes[] = { { DEVICE_TYPE_ROOT_NODE, DEVICE_VERSION_DEFAULT } }; const EmberAfDeviceType gAggregateNodeDeviceTypes[] = { { DEVICE_TYPE_BRIDGE, DEVICE_VERSION_DEFAULT } }; diff --git a/examples/bridge-app/linux/bridged-actions-stub.cpp b/examples/bridge-app/linux/bridged-actions-stub.cpp index 580f4f2239bd1a..f5224199a03336 100644 --- a/examples/bridge-app/linux/bridged-actions-stub.cpp +++ b/examples/bridge-app/linux/bridged-actions-stub.cpp @@ -131,7 +131,7 @@ CHIP_ERROR ActionsAttrAccess::Read(const ConcreteReadAttributePath & aPath, Attr } } // anonymous namespace -void MatterActionsPluginServerInitCallback() +void emberAfActionsClusterInitCallback() { AttributeAccessInterfaceRegistry::Instance().Register(&gAttrAccess); } diff --git a/examples/bridge-app/telink/CMakeLists.txt b/examples/bridge-app/telink/CMakeLists.txt index f2e80864d46e01..e7984bc1332853 100644 --- a/examples/bridge-app/telink/CMakeLists.txt +++ b/examples/bridge-app/telink/CMakeLists.txt @@ -38,7 +38,6 @@ target_include_directories(app PRIVATE target_sources(app PRIVATE src/AppTask.cpp src/Device.cpp - src/DeviceCallbacks.cpp ${TELINK_COMMON}/common/src/mainCommon.cpp ${TELINK_COMMON}/common/src/AppTaskCommon.cpp ${TELINK_COMMON}/util/src/LEDManager.cpp diff --git a/examples/bridge-app/telink/src/AppTask.cpp b/examples/bridge-app/telink/src/AppTask.cpp index e080e40eb5dda9..122fa53ad064be 100644 --- a/examples/bridge-app/telink/src/AppTask.cpp +++ b/examples/bridge-app/telink/src/AppTask.cpp @@ -387,14 +387,6 @@ void HandleDeviceStatusChanged(Device * dev, Device::Changed_t itemChangedMask) } } -bool emberAfActionsClusterInstantActionCallback(app::CommandHandler * commandObj, const app::ConcreteCommandPath & commandPath, - const Clusters::Actions::Commands::InstantAction::DecodableType & commandData) -{ - // No actions are implemented, just return status NotFound. - commandObj->AddStatus(commandPath, Protocols::InteractionModel::Status::NotFound); - return true; -} - CHIP_ERROR AppTask::Init(void) { SetExampleButtonCallbacks(LightingActionEventHandler); diff --git a/examples/bridge-app/telink/src/DeviceCallbacks.cpp b/examples/bridge-app/telink/src/DeviceCallbacks.cpp deleted file mode 100644 index 9e3273e7107472..00000000000000 --- a/examples/bridge-app/telink/src/DeviceCallbacks.cpp +++ /dev/null @@ -1,105 +0,0 @@ -/* - * - * Copyright (c) 2023 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 -#include -#include -#include -#include -#include -#include -#include - -using namespace ::chip; -using namespace ::chip::app; -using namespace ::chip::app::Clusters; -using namespace ::chip::app::Clusters::Actions::Attributes; -using namespace ::chip::Inet; -using namespace ::chip::System; - -namespace { - -class ActionsAttrAccess : public AttributeAccessInterface -{ -public: - // Register for the Actions cluster on all endpoints. - ActionsAttrAccess() : AttributeAccessInterface(Optional::Missing(), Actions::Id) {} - - CHIP_ERROR Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder) override; - -private: - static constexpr uint16_t ClusterRevision = 1; - - CHIP_ERROR ReadActionListAttribute(EndpointId endpoint, AttributeValueEncoder & aEncoder); - CHIP_ERROR ReadEndpointListAttribute(EndpointId endpoint, AttributeValueEncoder & aEncoder); - CHIP_ERROR ReadSetupUrlAttribute(EndpointId endpoint, AttributeValueEncoder & aEncoder); - CHIP_ERROR ReadClusterRevision(EndpointId endpoint, AttributeValueEncoder & aEncoder); -}; - -constexpr uint16_t ActionsAttrAccess::ClusterRevision; - -CHIP_ERROR ActionsAttrAccess::ReadActionListAttribute(EndpointId endpoint, AttributeValueEncoder & aEncoder) -{ - // Just return an empty list - return aEncoder.EncodeEmptyList(); -} - -CHIP_ERROR ActionsAttrAccess::ReadEndpointListAttribute(EndpointId endpoint, AttributeValueEncoder & aEncoder) -{ - // Just return an empty list - return aEncoder.EncodeEmptyList(); -} - -CHIP_ERROR ActionsAttrAccess::ReadSetupUrlAttribute(EndpointId endpoint, AttributeValueEncoder & aEncoder) -{ - static const char SetupUrl[] = "https://example.com"; - return aEncoder.Encode(chip::CharSpan::fromCharString(SetupUrl)); -} - -CHIP_ERROR ActionsAttrAccess::ReadClusterRevision(EndpointId endpoint, AttributeValueEncoder & aEncoder) -{ - return aEncoder.Encode(ClusterRevision); -} - -ActionsAttrAccess gAttrAccess; - -CHIP_ERROR ActionsAttrAccess::Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder) -{ - VerifyOrDie(aPath.mClusterId == Actions::Id); - - switch (aPath.mAttributeId) - { - case ActionList::Id: - return ReadActionListAttribute(aPath.mEndpointId, aEncoder); - case EndpointLists::Id: - return ReadEndpointListAttribute(aPath.mEndpointId, aEncoder); - case SetupURL::Id: - return ReadSetupUrlAttribute(aPath.mEndpointId, aEncoder); - case ClusterRevision::Id: - return ReadClusterRevision(aPath.mEndpointId, aEncoder); - default: - break; - } - return CHIP_NO_ERROR; -} -} // anonymous namespace - -void MatterActionsPluginServerInitCallback(void) -{ - AttributeAccessInterfaceRegistry::Instance().Register(&gAttrAccess); -} diff --git a/examples/placeholder/linux/apps/app1/BUILD.gn b/examples/placeholder/linux/apps/app1/BUILD.gn index aba1e870f7a041..f8cc1b36a2b0ee 100644 --- a/examples/placeholder/linux/apps/app1/BUILD.gn +++ b/examples/placeholder/linux/apps/app1/BUILD.gn @@ -28,7 +28,6 @@ source_set("app1") { sources = [ "../../resource-monitoring-delegates.cpp", - "../../src/bridged-actions-stub.cpp", "../../static-supported-modes-manager.cpp", "../../thread-border-router-management.cpp", ] diff --git a/examples/placeholder/linux/apps/app2/BUILD.gn b/examples/placeholder/linux/apps/app2/BUILD.gn index 2bea36611ffb37..302054f5bf927b 100644 --- a/examples/placeholder/linux/apps/app2/BUILD.gn +++ b/examples/placeholder/linux/apps/app2/BUILD.gn @@ -28,7 +28,6 @@ source_set("app2") { sources = [ "../../resource-monitoring-delegates.cpp", - "../../src/bridged-actions-stub.cpp", "../../static-supported-modes-manager.cpp", ] diff --git a/examples/placeholder/linux/src/bridged-actions-stub.cpp b/examples/placeholder/linux/src/bridged-actions-stub.cpp deleted file mode 100644 index d7abf17cd9106e..00000000000000 --- a/examples/placeholder/linux/src/bridged-actions-stub.cpp +++ /dev/null @@ -1,102 +0,0 @@ -/* - * - * Copyright (c) 2021 Project CHIP Authors - * - * 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 -#include -#include -#include -#include -#include -#include -#include - -using namespace chip; -using namespace chip::app; -using namespace chip::app::Clusters; -using namespace chip::app::Clusters::Actions::Attributes; - -namespace { - -class ActionsAttrAccess : public AttributeAccessInterface -{ -public: - // Register for the Actions cluster on all endpoints. - ActionsAttrAccess() : AttributeAccessInterface(Optional::Missing(), Actions::Id) {} - - CHIP_ERROR Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder) override; - -private: - static constexpr uint16_t ClusterRevision = 1; - - CHIP_ERROR ReadActionListAttribute(EndpointId endpoint, AttributeValueEncoder & aEncoder); - CHIP_ERROR ReadEndpointListAttribute(EndpointId endpoint, AttributeValueEncoder & aEncoder); - CHIP_ERROR ReadSetupUrlAttribute(EndpointId endpoint, AttributeValueEncoder & aEncoder); - CHIP_ERROR ReadClusterRevision(EndpointId endpoint, AttributeValueEncoder & aEncoder); -}; - -constexpr uint16_t ActionsAttrAccess::ClusterRevision; - -CHIP_ERROR ActionsAttrAccess::ReadActionListAttribute(EndpointId endpoint, AttributeValueEncoder & aEncoder) -{ - // Just return an empty list - return aEncoder.EncodeEmptyList(); -} - -CHIP_ERROR ActionsAttrAccess::ReadEndpointListAttribute(EndpointId endpoint, AttributeValueEncoder & aEncoder) -{ - // Just return an empty list - return aEncoder.EncodeEmptyList(); -} - -CHIP_ERROR ActionsAttrAccess::ReadSetupUrlAttribute(EndpointId endpoint, AttributeValueEncoder & aEncoder) -{ - static const char SetupUrl[] = "https://example.com"; - return aEncoder.Encode(chip::Span(SetupUrl, strlen(SetupUrl))); -} - -CHIP_ERROR ActionsAttrAccess::ReadClusterRevision(EndpointId endpoint, AttributeValueEncoder & aEncoder) -{ - return aEncoder.Encode(ClusterRevision); -} - -ActionsAttrAccess gAttrAccess; - -CHIP_ERROR ActionsAttrAccess::Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder) -{ - VerifyOrDie(aPath.mClusterId == Actions::Id); - - switch (aPath.mAttributeId) - { - case ActionList::Id: - return ReadActionListAttribute(aPath.mEndpointId, aEncoder); - case EndpointLists::Id: - return ReadEndpointListAttribute(aPath.mEndpointId, aEncoder); - case SetupURL::Id: - return ReadSetupUrlAttribute(aPath.mEndpointId, aEncoder); - case ClusterRevision::Id: - return ReadClusterRevision(aPath.mEndpointId, aEncoder); - default: - break; - } - return CHIP_NO_ERROR; -} -} // anonymous namespace - -void MatterActionsPluginServerInitCallback(void) -{ - chip::app::AttributeAccessInterfaceRegistry::Instance().Register(&gAttrAccess); -} diff --git a/scripts/tools/check_includes_config.py b/scripts/tools/check_includes_config.py index 2e79c6f8f9cfa9..910b595f912e31 100644 --- a/scripts/tools/check_includes_config.py +++ b/scripts/tools/check_includes_config.py @@ -127,6 +127,7 @@ 'src/app/clusters/application-launcher-server/application-launcher-server.cpp': {'string'}, 'src/app/clusters/application-launcher-server/application-launcher-delegate.h': {'list'}, 'src/app/clusters/audio-output-server/audio-output-delegate.h': {'list'}, + 'src/app/clusters/actions-server/actions-server.h': {'vector'}, # EcosystemInformationCluster is for Fabric Sync and is intended to run on device that are capable of handling these types. 'src/app/clusters/ecosystem-information-server/ecosystem-information-server.h': {'map', 'string', 'vector'}, 'src/app/clusters/channel-server/channel-delegate.h': {'list'}, diff --git a/src/app/clusters/actions-server/actions-server.cpp b/src/app/clusters/actions-server/actions-server.cpp new file mode 100644 index 00000000000000..543e4e6aa078b7 --- /dev/null +++ b/src/app/clusters/actions-server/actions-server.cpp @@ -0,0 +1,359 @@ +/* + * + * Copyright (c) 2024 Project CHIP Authors + * + * 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 "actions-server.h" +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace chip; +using namespace chip::app; +using namespace chip::app::Clusters; +using namespace chip::app::Clusters::Actions; +using namespace chip::app::Clusters::Actions::Attributes; +using namespace chip::Protocols::InteractionModel; + +Instance Instance::instance; +Instance * Instance::GetInstance() +{ + return &instance; +} + +void Instance::OnStateChanged(EndpointId endpoint, uint16_t actionId, uint32_t invokeId, ActionStateEnum actionState) +{ + ChipLogProgress(Zcl, "ActionsServer: OnStateChanged"); + + // Record StateChanged event + EventNumber eventNumber; + Events::StateChanged::Type event{ actionId, invokeId, actionState }; + + if (CHIP_NO_ERROR != LogEvent(event, endpoint, eventNumber)) + { + ChipLogError(Zcl, "ActionsServer: Failed to record OnStateChanged event"); + } +} + +void Instance::OnActionFailed(EndpointId endpoint, uint16_t actionId, uint32_t invokeId, ActionStateEnum actionState, + ActionErrorEnum actionError) +{ + ChipLogProgress(Zcl, "ActionsServer: OnActionFailed"); + + // Record ActionFailed event + EventNumber eventNumber; + Events::ActionFailed::Type event{ actionId, invokeId, actionState, actionError }; + + if (CHIP_NO_ERROR != LogEvent(event, endpoint, eventNumber)) + { + ChipLogError(Zcl, "ActionsServer: Failed to record OnActionFailed event"); + } +} + +CHIP_ERROR Instance::ReadActionListAttribute(const AttributeValueEncoder::ListEncodeHelper & encoder) +{ + if (GetInstance()->mDelegate == nullptr) + { + ChipLogError(Zcl, "Actions delegate is null!!!"); + return CHIP_ERROR_INCORRECT_STATE; + } + for (uint16_t i = 0; true; i++) + { + ActionStructStorage action; + + CHIP_ERROR err = GetInstance()->mDelegate->ReadActionAtIndex(i, action); + if (err == CHIP_ERROR_PROVIDER_LIST_EXHAUSTED) + { + return CHIP_NO_ERROR; + } + + ReturnErrorOnFailure(encoder.Encode(action)); + } + return CHIP_NO_ERROR; +} + +CHIP_ERROR Instance::ReadEndpointListAttribute(const AttributeValueEncoder::ListEncodeHelper & encoder) +{ + if (GetInstance()->mDelegate == nullptr) + { + ChipLogError(Zcl, "Actions delegate is null!!!"); + return CHIP_ERROR_INCORRECT_STATE; + } + for (uint16_t i = 0; true; i++) + { + EndpointListStorage epList; + + CHIP_ERROR err = GetInstance()->mDelegate->ReadEndpointListAtIndex(i, epList); + if (err == CHIP_ERROR_PROVIDER_LIST_EXHAUSTED) + { + return CHIP_NO_ERROR; + } + + ReturnErrorOnFailure(encoder.Encode(epList)); + } + return CHIP_NO_ERROR; +} + +void Instance::SetDefaultDelegate(Delegate * aDelegate) +{ + if (aDelegate == nullptr) + { + ChipLogError(Zcl, "Cannot set empty delegate!!!"); + return; + } + mDelegate = aDelegate; +} + +CHIP_ERROR Instance::Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder) +{ + VerifyOrDie(aPath.mClusterId == Actions::Id); + + switch (aPath.mAttributeId) + { + case ActionList::Id: { + Instance * d = this; + CHIP_ERROR err = + aEncoder.EncodeList([d](const auto & encoder) -> CHIP_ERROR { return d->ReadActionListAttribute(encoder); }); + return err; + } + case EndpointLists::Id: { + Instance * d = this; + CHIP_ERROR err = + aEncoder.EncodeList([d](const auto & encoder) -> CHIP_ERROR { return d->ReadEndpointListAttribute(encoder); }); + return err; + } + default: + break; + } + return CHIP_NO_ERROR; +} + +bool Instance::FindActionIdInActionList(uint16_t actionId) +{ + if (GetInstance()->mDelegate == nullptr) + { + ChipLogError(Zcl, "Actions delegate is null!!!"); + return false; + } + return GetInstance()->mDelegate->FindActionIdInActionList(actionId); +} + +template +void Instance::HandleCommand(HandlerContext & handlerContext, FuncT func) +{ + if (!handlerContext.mCommandHandled && (handlerContext.mRequestPath.mCommandId == RequestT::GetCommandId())) + { + RequestT requestPayload; + + // If the command matches what the caller is looking for, let's mark this as being handled + // even if errors happen after this. This ensures that we don't execute any fall-back strategies + // to handle this command since at this point, the caller is taking responsibility for handling + // the command in its entirety, warts and all. + // + handlerContext.SetCommandHandled(); + + if (DataModel::Decode(handlerContext.mPayload, requestPayload) != CHIP_NO_ERROR) + { + handlerContext.mCommandHandler.AddStatus(handlerContext.mRequestPath, + Protocols::InteractionModel::Status::InvalidCommand); + return; + } + + uint16_t actionId = requestPayload.actionID; + if (!GetInstance()->FindActionIdInActionList(actionId)) + { + handlerContext.mCommandHandler.AddStatus(handlerContext.mRequestPath, Protocols::InteractionModel::Status::NotFound); + return; + } + + func(handlerContext, requestPayload); + } +} + +void Instance::HandleInstantAction(HandlerContext & ctx, const Commands::InstantAction::DecodableType & commandData) +{ + uint16_t actionId = commandData.actionID; + Optional invokeId = commandData.invokeID; + Status status = GetInstance()->mDelegate->HandleInstantAction(actionId, invokeId); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, status); +} + +void Instance::HandleInstantActionWithTransition(HandlerContext & ctx, + const Commands::InstantActionWithTransition::DecodableType & commandData) +{ + uint16_t actionId = commandData.actionID; + Optional invokeId = commandData.invokeID; + uint16_t transitionTime = commandData.transitionTime; + Status status = GetInstance()->mDelegate->HandleInstantActionWithTransition(actionId, transitionTime, invokeId); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, status); +} + +void Instance::HandleStartAction(HandlerContext & ctx, const Commands::StartAction::DecodableType & commandData) +{ + uint16_t actionId = commandData.actionID; + Optional invokeId = commandData.invokeID; + Status status = GetInstance()->mDelegate->HandleStartAction(actionId, invokeId); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, status); +} + +void Instance::HandleStartActionWithDuration(HandlerContext & ctx, + const Commands::StartActionWithDuration::DecodableType & commandData) +{ + uint16_t actionId = commandData.actionID; + Optional invokeId = commandData.invokeID; + uint32_t duration = commandData.duration; + Status status = GetInstance()->mDelegate->HandleStartActionWithDuration(actionId, duration, invokeId); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, status); +} + +void Instance::HandleStopAction(HandlerContext & ctx, const Commands::StopAction::DecodableType & commandData) +{ + uint16_t actionId = commandData.actionID; + Optional invokeId = commandData.invokeID; + Status status = GetInstance()->mDelegate->HandleStopAction(actionId, invokeId); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, status); +} + +void Instance::HandlePauseAction(HandlerContext & ctx, const Commands::PauseAction::DecodableType & commandData) +{ + uint16_t actionId = commandData.actionID; + Optional invokeId = commandData.invokeID; + Status status = GetInstance()->mDelegate->HandlePauseAction(actionId, invokeId); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, status); +} + +void Instance::HandlePauseActionWithDuration(HandlerContext & ctx, + const Commands::PauseActionWithDuration::DecodableType & commandData) +{ + uint16_t actionId = commandData.actionID; + Optional invokeId = commandData.invokeID; + uint32_t duration = commandData.duration; + Status status = GetInstance()->mDelegate->HandlePauseActionWithDuration(actionId, duration, invokeId); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, status); +} + +void Instance::HandleResumeAction(HandlerContext & ctx, const Commands::ResumeAction::DecodableType & commandData) +{ + uint16_t actionId = commandData.actionID; + Optional invokeId = commandData.invokeID; + Status status = GetInstance()->mDelegate->HandleResumeAction(actionId, invokeId); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, status); +} + +void Instance::HandleEnableAction(HandlerContext & ctx, const Commands::EnableAction::DecodableType & commandData) +{ + uint16_t actionId = commandData.actionID; + Optional invokeId = commandData.invokeID; + Status status = GetInstance()->mDelegate->HandleEnableAction(actionId, invokeId); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, status); +} + +void Instance::HandleEnableActionWithDuration(HandlerContext & ctx, + const Commands::EnableActionWithDuration::DecodableType & commandData) +{ + uint16_t actionId = commandData.actionID; + Optional invokeId = commandData.invokeID; + uint32_t duration = commandData.duration; + Status status = GetInstance()->mDelegate->HandleEnableActionWithDuration(actionId, duration, invokeId); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, status); +} + +void Instance::HandleDisableAction(HandlerContext & ctx, const Commands::DisableAction::DecodableType & commandData) +{ + uint16_t actionId = commandData.actionID; + Optional invokeId = commandData.invokeID; + Status status = GetInstance()->mDelegate->HandleDisableAction(actionId, invokeId); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, status); +} + +void Instance::HandleDisableActionWithDuration(HandlerContext & ctx, + const Commands::DisableActionWithDuration::DecodableType & commandData) +{ + uint16_t actionId = commandData.actionID; + Optional invokeId = commandData.invokeID; + uint32_t duration = commandData.duration; + Status status = GetInstance()->mDelegate->HandleDisableActionWithDuration(actionId, duration, invokeId); + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, status); +} + +void Instance::InvokeCommand(HandlerContext & handlerContext) +{ + switch (handlerContext.mRequestPath.mCommandId) + { + case Actions::Commands::InstantAction::Id: + HandleCommand( + handlerContext, [this](HandlerContext & ctx, const auto & commandData) { HandleInstantAction(ctx, commandData); }); + return; + case Actions::Commands::InstantActionWithTransition::Id: + HandleCommand( + handlerContext, + [this](HandlerContext & ctx, const auto & commandData) { HandleInstantActionWithTransition(ctx, commandData); }); + return; + case Actions::Commands::StartAction::Id: + HandleCommand( + handlerContext, [this](HandlerContext & ctx, const auto & commandData) { HandleStartAction(ctx, commandData); }); + return; + case Actions::Commands::StartActionWithDuration::Id: + HandleCommand( + handlerContext, + [this](HandlerContext & ctx, const auto & commandData) { HandleStartActionWithDuration(ctx, commandData); }); + return; + case Actions::Commands::StopAction::Id: + HandleCommand( + handlerContext, [this](HandlerContext & ctx, const auto & commandData) { HandleStopAction(ctx, commandData); }); + return; + case Actions::Commands::PauseAction::Id: + HandleCommand( + handlerContext, [this](HandlerContext & ctx, const auto & commandData) { HandlePauseAction(ctx, commandData); }); + return; + case Actions::Commands::PauseActionWithDuration::Id: + HandleCommand( + handlerContext, + [this](HandlerContext & ctx, const auto & commandData) { HandlePauseActionWithDuration(ctx, commandData); }); + return; + case Actions::Commands::ResumeAction::Id: + HandleCommand( + handlerContext, [this](HandlerContext & ctx, const auto & commandData) { HandleResumeAction(ctx, commandData); }); + return; + case Actions::Commands::EnableAction::Id: + HandleCommand( + handlerContext, [this](HandlerContext & ctx, const auto & commandData) { HandleEnableAction(ctx, commandData); }); + return; + case Actions::Commands::EnableActionWithDuration::Id: + HandleCommand( + handlerContext, + [this](HandlerContext & ctx, const auto & commandData) { HandleEnableActionWithDuration(ctx, commandData); }); + return; + case Actions::Commands::DisableAction::Id: + HandleCommand( + handlerContext, [this](HandlerContext & ctx, const auto & commandData) { HandleDisableAction(ctx, commandData); }); + return; + case Actions::Commands::DisableActionWithDuration::Id: + HandleCommand( + handlerContext, + [this](HandlerContext & ctx, const auto & commandData) { HandleDisableActionWithDuration(ctx, commandData); }); + return; + } +} +void MatterActionsPluginServerInitCallback() +{ + AttributeAccessInterfaceRegistry::Instance().Register(Instance::GetInstance()); + CommandHandlerInterfaceRegistry::Instance().RegisterCommandHandler(Instance::GetInstance()); +} diff --git a/src/app/clusters/actions-server/actions-server.h b/src/app/clusters/actions-server/actions-server.h new file mode 100644 index 00000000000000..ba30566a1e3101 --- /dev/null +++ b/src/app/clusters/actions-server/actions-server.h @@ -0,0 +1,339 @@ +/* + * + * Copyright (c) 2024 Project CHIP Authors + * + * 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 +#include +#include +#include +#include +#include + +namespace chip { +namespace app { +namespace Clusters { +namespace Actions { + +static constexpr size_t kActionNameMaxSize = 128u; +static constexpr size_t kEndpointListNameMaxSize = 128u; +static constexpr size_t kEndpointListMaxSize = 256u; + +class Delegate; + +struct ActionStructStorage : public Structs::ActionStruct::Type +{ + ActionStructStorage() : mActionName(mBuffer, sizeof(mBuffer)){}; + + ActionStructStorage(uint16_t action, CharSpan actionName, ActionTypeEnum actionType, uint16_t epListID, + BitMask commands, ActionStateEnum actionState) : + mActionName(mBuffer, sizeof(mBuffer)) + { + Set(action, actionName, actionType, epListID, commands, actionState); + } + + ActionStructStorage(const ActionStructStorage & action) : mActionName(mBuffer, sizeof(mBuffer)) { *this = action; } + + ActionStructStorage & operator=(const ActionStructStorage & action) + { + Set(action.actionID, action.name, action.type, action.endpointListID, action.supportedCommands, action.state); + return *this; + } + + void Set(uint16_t action, CharSpan actionName, ActionTypeEnum actionType, uint16_t epListID, BitMask commands, + ActionStateEnum actionState) + { + actionID = action; + type = actionType; + endpointListID = epListID; + supportedCommands = commands; + state = actionState; + CopyCharSpanToMutableCharSpanWithTruncation(actionName, mActionName); + name = mActionName; + } + +private: + char mBuffer[kActionNameMaxSize]; + MutableCharSpan mActionName; +}; + +struct EndpointListStorage : public Structs::EndpointListStruct::Type +{ + EndpointListStorage() : mEpListName(mBuffer, sizeof(mBuffer)){}; + + EndpointListStorage(uint16_t epListId, CharSpan epListName, EndpointListTypeEnum epListType, + DataModel::List endpointList) : + mEpListName(mBuffer, sizeof(mBuffer)) + { + Set(epListId, epListName, epListType, endpointList); + } + + EndpointListStorage(const EndpointListStorage & epList) : mEpListName(mBuffer, sizeof(mBuffer)) { *this = epList; } + + EndpointListStorage & operator=(const EndpointListStorage & epList) + { + Set(epList.endpointListID, epList.name, epList.type, epList.endpoints); + return *this; + } + + void Set(uint16_t epListId, CharSpan epListName, EndpointListTypeEnum epListType, + DataModel::List endpointList) + { + endpointListID = epListId; + type = epListType; + + for (uint8_t index = 0; index < std::min(endpointList.size(), kEndpointListMaxSize); index++) + { + mEpList.push_back(endpointList[index]); + } + mEpListSpan = Span(mEpList.data(), mEpList.size()); + endpoints = DataModel::List(mEpListSpan); + CopyCharSpanToMutableCharSpanWithTruncation(epListName, mEpListName); + name = mEpListName; + } + +private: + char mBuffer[kEndpointListNameMaxSize]; + MutableCharSpan mEpListName; + std::vector mEpList; + Span mEpListSpan; +}; + +class Instance : public AttributeAccessInterface, public CommandHandlerInterface +{ +public: + // Register for the Actions cluster on all endpoints. + Instance() : + AttributeAccessInterface(Optional::Missing(), Actions::Id), + CommandHandlerInterface(Optional::Missing(), Actions::Id) + {} + + /** + * @brief + * Called when the state of action is changed. + */ + void OnStateChanged(EndpointId endpoint, uint16_t actionId, uint32_t invokeId, ActionStateEnum actionState); + + /** + * @brief + * Called when the action is failed.. + */ + void OnActionFailed(EndpointId endpoint, uint16_t actionId, uint32_t invokeId, ActionStateEnum actionState, + ActionErrorEnum actionError); + + static Instance * GetInstance(); + void SetDefaultDelegate(Delegate * aDelegate); + +private: + Delegate * mDelegate; + static Instance instance; + + CHIP_ERROR Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder) override; + + CHIP_ERROR ReadActionListAttribute(const AttributeValueEncoder::ListEncodeHelper & encoder); + CHIP_ERROR ReadEndpointListAttribute(const AttributeValueEncoder::ListEncodeHelper & encoder); + bool FindActionIdInActionList(uint16_t actionId); + + // CommandHandlerInterface + template + void HandleCommand(HandlerContext & handlerContext, FuncT func); + + void InvokeCommand(HandlerContext & handlerContext) override; + + void HandleInstantAction(HandlerContext & ctx, const Commands::InstantAction::DecodableType & commandData); + void HandleInstantActionWithTransition(HandlerContext & ctx, + const Commands::InstantActionWithTransition::DecodableType & commandData); + void HandleStartAction(HandlerContext & ctx, const Commands::StartAction::DecodableType & commandData); + void HandleStartActionWithDuration(HandlerContext & ctx, const Commands::StartActionWithDuration::DecodableType & commandData); + void HandleStopAction(HandlerContext & ctx, const Commands::StopAction::DecodableType & commandData); + void HandlePauseAction(HandlerContext & ctx, const Commands::PauseAction::DecodableType & commandData); + void HandlePauseActionWithDuration(HandlerContext & ctx, const Commands::PauseActionWithDuration::DecodableType & commandData); + void HandleResumeAction(HandlerContext & ctx, const Commands::ResumeAction::DecodableType & commandData); + void HandleEnableAction(HandlerContext & ctx, const Commands::EnableAction::DecodableType & commandData); + void HandleEnableActionWithDuration(HandlerContext & ctx, + const Commands::EnableActionWithDuration::DecodableType & commandData); + void HandleDisableAction(HandlerContext & ctx, const Commands::DisableAction::DecodableType & commandData); + void HandleDisableActionWithDuration(HandlerContext & ctx, + const Commands::DisableActionWithDuration::DecodableType & commandData); +}; + +class Delegate +{ +public: + virtual ~Delegate() = default; + + /** + * Get the action at the Nth index from list of actions. + * @param index The index of the action to be returned. It is assumed that actions are indexable from 0 and with no gaps. + * @param action A reference to the ActionStructStorage which should be initialized via copy/assignments or calling Set(). + * @return Returns a CHIP_NO_ERROR if there was no error and the action was returned successfully. + * CHIP_ERROR_PROVIDER_LIST_EXHAUSTED if the index in beyond the list of available actions. + */ + virtual CHIP_ERROR ReadActionAtIndex(uint16_t index, ActionStructStorage & action) = 0; + + /** + * Get the EndpointList at the Nth index from list of endpointList. + * @param index The index of the endpointList to be returned. It is assumed that actions are indexable from 0 and with no gaps. + * @param action A reference to the EndpointListStorage which should be initialized via copy/assignments or calling Set(). + * @return Returns a CHIP_NO_ERROR if there was no error and the epList was returned successfully. + * CHIP_ERROR_PROVIDER_LIST_EXHAUSTED if the index in beyond the list of available endpointList. + */ + virtual CHIP_ERROR ReadEndpointListAtIndex(uint16_t index, EndpointListStorage & epList) = 0; + + /** + * Find the action with matching actionId in the list of action. + * @param actionId The action to be find in the list of action. + * @return Returns a true if matching action is found otherwise false. + */ + virtual bool FindActionIdInActionList(uint16_t actionId) = 0; + + /** + * On receipt of each and every command, + * if the InvokeID data field is provided by the client when invoking a command, the server SHALL generate a StateChanged event + * when the action changes to a new state or an ActionFailed event when execution of the action fails. + * + * @return If the command refers to an action which currently is not in a state where the command applies, a response SHALL be + * generated with the StatusCode INVALID_COMMAND. + */ + + /** + * When an InstantAction command is received, an action (state change) on the involved endpoints shall trigger, + * in a "fire and forget" manner. Afterwards, the action’s state SHALL be Inactive. + * + * @param actionId The id of an action on which an action shall takes place. + * @return Returns a Success if an action took place successfully otherwise, suitable error. + */ + virtual Protocols::InteractionModel::Status HandleInstantAction(uint16_t actionId, Optional invokeId) = 0; + + /** + * When an InstantActionWithTransition command is received, an action (state change) on the involved endpoints shall trigger, + * with a specified time to transition from the current state to the new state. During the transition, the action’s state SHALL + * be Active. Afterwards, the action’s state SHALL be Inactive. + * + * @param actionId The id of an action on which an action shall takes place. + * @param transitionTime The time for transition from the current state to the new state. + * @return Returns a Success if an action took place successfully otherwise, suitable error. + */ + virtual Protocols::InteractionModel::Status HandleInstantActionWithTransition(uint16_t actionId, uint16_t transitionTime, + Optional invokeId) = 0; + + /** + * When a StartAction command is received, the commencement of an action on the involved endpoints shall trigger. Afterwards, + * the action’s state SHALL be Inactive. + * + * @param actionId The id of an action on which an action shall takes place. + * @return Returns a Success if an action took place successfully otherwise, suitable error. + */ + virtual Protocols::InteractionModel::Status HandleStartAction(uint16_t actionId, Optional invokeId) = 0; + + /** + * When a StartActionWithDuration command is received, the commencement of an action on the involved endpoints shall trigger, + * and SHALL change the action’s state to Active. After the specified Duration, the action will stop, and the action’s state + * SHALL change to Inactive. + * + * @param actionId The id of an action on which an action shall takes place. + * @param duration The time for which an action shall be in start state. + * @return Returns a Success if an action took place successfully otherwise, suitable error. + */ + virtual Protocols::InteractionModel::Status HandleStartActionWithDuration(uint16_t actionId, uint32_t duration, + Optional invokeId) = 0; + + /** + * When a StopAction command is received, the ongoing action on the involved endpoints shall stop. Afterwards, the action’s + * state SHALL be Inactive. + * + * @param actionId The id of an action on which an action shall takes place. + * @return Returns a Success if an action took place successfully otherwise, suitable error. + */ + virtual Protocols::InteractionModel::Status HandleStopAction(uint16_t actionId, Optional invokeId) = 0; + + /** + * When a PauseAction command is received, the ongoing action on the involved endpoints shall pause and SHALL change the + * action’s state to Paused. + * + * @param actionId The id of an action on which an action shall takes place. + * @return Returns a Success if an action took place successfully otherwise, suitable error. + */ + virtual Protocols::InteractionModel::Status HandlePauseAction(uint16_t actionId, Optional invokeId) = 0; + + /** + * When a PauseActionWithDuration command is received, pauses an ongoing action, and SHALL change the action’s state to Paused. + * After the specified Duration, the ongoing action will be automatically resumed. which SHALL change the action’s state to + * Active. + * + * @param actionId The id of an action on which an action shall takes place. + * @param duration The time for which an action shall be in pause state. + * @return Returns a Success if an action took place successfully otherwise, suitable error. + */ + virtual Protocols::InteractionModel::Status HandlePauseActionWithDuration(uint16_t actionId, uint32_t duration, + Optional invokeId) = 0; + + /** + * When a ResumeAction command is received, the previously paused action shall resume and SHALL change the action’s state to + * Active. + * + * @param actionId The id of an action on which an action shall takes place. + * @return Returns a Success if an action took place successfully otherwise, suitable error. + */ + virtual Protocols::InteractionModel::Status HandleResumeAction(uint16_t actionId, Optional invokeId) = 0; + + /** + * When an EnableAction command is received, it enables a certain action or automation. Afterwards, the action’s state SHALL be + * Active. + * + * @param actionId The id of an action on which an action shall takes place. + * @return Returns a Success if an action took place successfully otherwise, suitable error. + */ + virtual Protocols::InteractionModel::Status HandleEnableAction(uint16_t actionId, Optional invokeId) = 0; + + /** + * When an EnableActionWithDuration command is received, it enables a certain action or automation, and SHALL change the + * action’s state to be Active. After the specified Duration, the action or automation will stop, and the action’s state SHALL + * change to Disabled. + * + * @param actionId The id of an action on which an action shall takes place. + * @param duration The time for which an action shall be in active state. + * @return Returns a Success if an action took place successfully otherwise, suitable error. + */ + virtual Protocols::InteractionModel::Status HandleEnableActionWithDuration(uint16_t actionId, uint32_t duration, + Optional invokeId) = 0; + + /** + * When a DisableAction command is received, it disables a certain action or automation, and SHALL change the action’s state to + * Inactive. + * + * @param actionId The id of an action on which an action shall takes place. + * @return Returns a Success if an action took place successfully otherwise, suitable error. + */ + virtual Protocols::InteractionModel::Status HandleDisableAction(uint16_t actionId, Optional invokeId) = 0; + + /** + * When a DisableActionWithDuration command is received, it disables a certain action or automation, and SHALL change the + * action’s state to Disabled. After the specified Duration, the action or automation will re-start, and the action’s state + * SHALL change to either Inactive or Active, depending on the actions. + * + * @param actionId The id of an action on which an action shall takes place. + * @param duration The time for which an action shall be in disable state. + * @return Returns a Success if an action took place successfully otherwise, suitable error. + */ + virtual Protocols::InteractionModel::Status HandleDisableActionWithDuration(uint16_t actionId, uint32_t duration, + Optional invokeId) = 0; +}; + +} // namespace Actions +} // namespace Clusters +} // namespace app +} // namespace chip diff --git a/src/app/common/templates/config-data.yaml b/src/app/common/templates/config-data.yaml index 61e7c45582268a..2c7e40e709ea4f 100644 --- a/src/app/common/templates/config-data.yaml +++ b/src/app/common/templates/config-data.yaml @@ -47,6 +47,7 @@ CommandHandlerInterfaceOnlyClusters: - Thread Network Directory - Water Heater Management - Water Heater Mode + - Actions # We need a more configurable way of deciding which clusters have which init functions.... # See https://github.com/project-chip/connectedhomeip/issues/4369 diff --git a/src/app/zap_cluster_list.json b/src/app/zap_cluster_list.json index d4c4801058415c..7c877a32065de5 100644 --- a/src/app/zap_cluster_list.json +++ b/src/app/zap_cluster_list.json @@ -320,6 +320,7 @@ "WINDOW_COVERING_CLUSTER": ["window-covering-server"], "WATER_HEATER_MANAGEMENT_CLUSTER": ["water-heater-management-server"], "WATER_HEATER_MODE_CLUSTER": ["mode-base-server"], - "ZONE_MANAGEMENT_CLUSTER": [] + "ZONE_MANAGEMENT_CLUSTER": [], + "ACTIONS_CLUSTER": ["actions-server"] } } diff --git a/zzz_generated/app-common/app-common/zap-generated/callback.h b/zzz_generated/app-common/app-common/zap-generated/callback.h index dcf1cc651ccc62..16a92c3ca682e0 100644 --- a/zzz_generated/app-common/app-common/zap-generated/callback.h +++ b/zzz_generated/app-common/app-common/zap-generated/callback.h @@ -5677,78 +5677,6 @@ bool emberAfLevelControlClusterMoveToClosestFrequencyCallback( bool emberAfAccessControlClusterReviewFabricRestrictionsCallback( chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, const chip::app::Clusters::AccessControl::Commands::ReviewFabricRestrictions::DecodableType & commandData); -/** - * @brief Actions Cluster InstantAction Command callback (from client) - */ -bool emberAfActionsClusterInstantActionCallback( - chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, - const chip::app::Clusters::Actions::Commands::InstantAction::DecodableType & commandData); -/** - * @brief Actions Cluster InstantActionWithTransition Command callback (from client) - */ -bool emberAfActionsClusterInstantActionWithTransitionCallback( - chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, - const chip::app::Clusters::Actions::Commands::InstantActionWithTransition::DecodableType & commandData); -/** - * @brief Actions Cluster StartAction Command callback (from client) - */ -bool emberAfActionsClusterStartActionCallback( - chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, - const chip::app::Clusters::Actions::Commands::StartAction::DecodableType & commandData); -/** - * @brief Actions Cluster StartActionWithDuration Command callback (from client) - */ -bool emberAfActionsClusterStartActionWithDurationCallback( - chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, - const chip::app::Clusters::Actions::Commands::StartActionWithDuration::DecodableType & commandData); -/** - * @brief Actions Cluster StopAction Command callback (from client) - */ -bool emberAfActionsClusterStopActionCallback(chip::app::CommandHandler * commandObj, - const chip::app::ConcreteCommandPath & commandPath, - const chip::app::Clusters::Actions::Commands::StopAction::DecodableType & commandData); -/** - * @brief Actions Cluster PauseAction Command callback (from client) - */ -bool emberAfActionsClusterPauseActionCallback( - chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, - const chip::app::Clusters::Actions::Commands::PauseAction::DecodableType & commandData); -/** - * @brief Actions Cluster PauseActionWithDuration Command callback (from client) - */ -bool emberAfActionsClusterPauseActionWithDurationCallback( - chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, - const chip::app::Clusters::Actions::Commands::PauseActionWithDuration::DecodableType & commandData); -/** - * @brief Actions Cluster ResumeAction Command callback (from client) - */ -bool emberAfActionsClusterResumeActionCallback( - chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, - const chip::app::Clusters::Actions::Commands::ResumeAction::DecodableType & commandData); -/** - * @brief Actions Cluster EnableAction Command callback (from client) - */ -bool emberAfActionsClusterEnableActionCallback( - chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, - const chip::app::Clusters::Actions::Commands::EnableAction::DecodableType & commandData); -/** - * @brief Actions Cluster EnableActionWithDuration Command callback (from client) - */ -bool emberAfActionsClusterEnableActionWithDurationCallback( - chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, - const chip::app::Clusters::Actions::Commands::EnableActionWithDuration::DecodableType & commandData); -/** - * @brief Actions Cluster DisableAction Command callback (from client) - */ -bool emberAfActionsClusterDisableActionCallback( - chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, - const chip::app::Clusters::Actions::Commands::DisableAction::DecodableType & commandData); -/** - * @brief Actions Cluster DisableActionWithDuration Command callback (from client) - */ -bool emberAfActionsClusterDisableActionWithDurationCallback( - chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, - const chip::app::Clusters::Actions::Commands::DisableActionWithDuration::DecodableType & commandData); /** * @brief Basic Information Cluster MfgSpecificPing Command callback (from client) */