From 5665d3871b5c4c0250a3d437ea5245835953f8c9 Mon Sep 17 00:00:00 2001 From: jwinder-ca <105392648+jwinder-ca@users.noreply.github.com> Date: Thu, 21 Jul 2022 10:35:30 -0600 Subject: [PATCH] Added support to the bridge-app for action-lists. (#20121) * Added support to the bridge-app for action-lists. Added the actions to turn on/off lights in a room (endpoint-list). The instant-action is the supported command to run the actions. Also, the setup-url attrubute was changed to be active. * Restyled by clang-format * Fixed build for esp32 bridge-app. * Changes to return status correctly. Co-authored-by: Restyled.io --- .../bridge-common/bridge-app.matter | 9 + .../bridge-app/bridge-common/bridge-app.zap | 179 +++++++++--------- examples/bridge-app/esp32/main/main.cpp | 10 + examples/bridge-app/linux/Device.cpp | 12 ++ .../bridge-app/linux/bridged-actions-stub.cpp | 22 ++- examples/bridge-app/linux/include/Device.h | 25 +++ examples/bridge-app/linux/include/main.h | 2 + examples/bridge-app/linux/main.cpp | 109 +++++++++++ .../zap-generated/IMClusterCommandHandler.cpp | 40 ++++ .../zap-generated/endpoint_config.h | 47 +++-- 10 files changed, 352 insertions(+), 103 deletions(-) diff --git a/examples/bridge-app/bridge-common/bridge-app.matter b/examples/bridge-app/bridge-common/bridge-app.matter index cc4b20444d6399..9f36feecb38ac0 100644 --- a/examples/bridge-app/bridge-common/bridge-app.matter +++ b/examples/bridge-app/bridge-common/bridge-app.matter @@ -420,11 +420,19 @@ server cluster BridgedActions = 37 { readonly attribute ActionStruct actionList[] = 0; readonly attribute EndpointListStruct endpointList[] = 1; + readonly attribute long_char_string<512> setupUrl = 2; readonly attribute command_id generatedCommandList[] = 65528; readonly attribute command_id acceptedCommandList[] = 65529; readonly attribute attrib_id attributeList[] = 65531; readonly attribute bitmap32 featureMap = 65532; readonly attribute int16u clusterRevision = 65533; + + request struct InstantActionRequest { + INT16U actionID = 0; + optional INT32U invokeID = 1; + } + + command InstantAction(InstantActionRequest): DefaultSuccess = 0; } server cluster Basic = 40 { @@ -1723,6 +1731,7 @@ endpoint 1 { server cluster BridgedActions { callback attribute actionList; callback attribute endpointList; + ram attribute setupUrl default = "https://example.com"; callback attribute generatedCommandList; callback attribute acceptedCommandList; callback attribute attributeList; diff --git a/examples/bridge-app/bridge-common/bridge-app.zap b/examples/bridge-app/bridge-common/bridge-app.zap index 6d01b0254bb3d5..10bffcd24bbd32 100644 --- a/examples/bridge-app/bridge-common/bridge-app.zap +++ b/examples/bridge-app/bridge-common/bridge-app.zap @@ -1,5 +1,5 @@ { - "featureLevel": 71, + "featureLevel": 72, "creator": "zap", "keyValuePairs": [ { @@ -115,7 +115,7 @@ "singleton": 0, "bounded": 0, "defaultValue": "", - "reportable": 0, + "reportable": 1, "minInterval": 0, "maxInterval": 65344, "reportableChange": 0 @@ -131,7 +131,7 @@ "singleton": 0, "bounded": 0, "defaultValue": "", - "reportable": 0, + "reportable": 1, "minInterval": 0, "maxInterval": 65344, "reportableChange": 0 @@ -147,7 +147,7 @@ "singleton": 0, "bounded": 0, "defaultValue": "", - "reportable": 0, + "reportable": 1, "minInterval": 0, "maxInterval": 65344, "reportableChange": 0 @@ -159,7 +159,7 @@ "side": "server", "type": "array", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, "defaultValue": "", @@ -175,7 +175,7 @@ "side": "server", "type": "array", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, "defaultValue": "", @@ -191,7 +191,7 @@ "side": "server", "type": "array", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, "defaultValue": "", @@ -297,7 +297,7 @@ "singleton": 0, "bounded": 0, "defaultValue": "", - "reportable": 0, + "reportable": 1, "minInterval": 1, "maxInterval": 65534, "reportableChange": 0 @@ -313,7 +313,7 @@ "singleton": 0, "bounded": 0, "defaultValue": "", - "reportable": 0, + "reportable": 1, "minInterval": 1, "maxInterval": 65534, "reportableChange": 0 @@ -373,7 +373,7 @@ "side": "server", "type": "array", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, "defaultValue": "", @@ -389,7 +389,7 @@ "side": "server", "type": "array", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, "defaultValue": "", @@ -511,7 +511,7 @@ "singleton": 1, "bounded": 0, "defaultValue": "10", - "reportable": 0, + "reportable": 1, "minInterval": 0, "maxInterval": 65344, "reportableChange": 0 @@ -527,7 +527,7 @@ "singleton": 1, "bounded": 0, "defaultValue": "", - "reportable": 0, + "reportable": 1, "minInterval": 0, "maxInterval": 65344, "reportableChange": 0 @@ -543,7 +543,7 @@ "singleton": 1, "bounded": 0, "defaultValue": "", - "reportable": 0, + "reportable": 1, "minInterval": 0, "maxInterval": 65344, "reportableChange": 0 @@ -559,7 +559,7 @@ "singleton": 1, "bounded": 0, "defaultValue": "", - "reportable": 0, + "reportable": 1, "minInterval": 0, "maxInterval": 65344, "reportableChange": 0 @@ -575,7 +575,7 @@ "singleton": 1, "bounded": 0, "defaultValue": "", - "reportable": 0, + "reportable": 1, "minInterval": 0, "maxInterval": 65344, "reportableChange": 0 @@ -591,7 +591,7 @@ "singleton": 1, "bounded": 0, "defaultValue": "", - "reportable": 0, + "reportable": 1, "minInterval": 0, "maxInterval": 65344, "reportableChange": 0 @@ -607,7 +607,7 @@ "singleton": 1, "bounded": 0, "defaultValue": "XX", - "reportable": 0, + "reportable": 1, "minInterval": 0, "maxInterval": 65344, "reportableChange": 0 @@ -623,7 +623,7 @@ "singleton": 1, "bounded": 0, "defaultValue": "0", - "reportable": 0, + "reportable": 1, "minInterval": 0, "maxInterval": 65344, "reportableChange": 0 @@ -639,7 +639,7 @@ "singleton": 1, "bounded": 0, "defaultValue": "", - "reportable": 0, + "reportable": 1, "minInterval": 0, "maxInterval": 65344, "reportableChange": 0 @@ -655,7 +655,7 @@ "singleton": 1, "bounded": 0, "defaultValue": "0", - "reportable": 0, + "reportable": 1, "minInterval": 0, "maxInterval": 65344, "reportableChange": 0 @@ -671,7 +671,7 @@ "singleton": 1, "bounded": 0, "defaultValue": "", - "reportable": 0, + "reportable": 1, "minInterval": 0, "maxInterval": 65344, "reportableChange": 0 @@ -827,7 +827,7 @@ "side": "server", "type": "array", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 1, "bounded": 0, "defaultValue": "", @@ -843,7 +843,7 @@ "side": "server", "type": "array", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 1, "bounded": 0, "defaultValue": "", @@ -859,7 +859,7 @@ "side": "server", "type": "array", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 1, "bounded": 0, "defaultValue": "", @@ -965,7 +965,7 @@ "singleton": 0, "bounded": 0, "defaultValue": "en-US", - "reportable": 0, + "reportable": 1, "minInterval": 1, "maxInterval": 65534, "reportableChange": 0 @@ -981,7 +981,7 @@ "singleton": 0, "bounded": 0, "defaultValue": "", - "reportable": 0, + "reportable": 1, "minInterval": 1, "maxInterval": 65534, "reportableChange": 0 @@ -993,7 +993,7 @@ "side": "server", "type": "array", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, "defaultValue": "", @@ -1009,7 +1009,7 @@ "side": "server", "type": "array", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, "defaultValue": "", @@ -1025,7 +1025,7 @@ "side": "server", "type": "array", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, "defaultValue": "", @@ -1131,7 +1131,7 @@ "singleton": 0, "bounded": 0, "defaultValue": "0", - "reportable": 0, + "reportable": 1, "minInterval": 1, "maxInterval": 65534, "reportableChange": 0 @@ -1175,7 +1175,7 @@ "side": "server", "type": "array", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, "defaultValue": "", @@ -1191,7 +1191,7 @@ "side": "server", "type": "array", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, "defaultValue": "", @@ -1207,7 +1207,7 @@ "side": "server", "type": "array", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, "defaultValue": "", @@ -1325,7 +1325,7 @@ "side": "server", "type": "array", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, "defaultValue": "", @@ -1341,7 +1341,7 @@ "side": "server", "type": "array", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, "defaultValue": "", @@ -1357,7 +1357,7 @@ "side": "server", "type": "array", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, "defaultValue": "", @@ -1589,7 +1589,7 @@ "side": "server", "type": "array", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, "defaultValue": "", @@ -1605,7 +1605,7 @@ "side": "server", "type": "array", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, "defaultValue": "", @@ -1621,7 +1621,7 @@ "side": "server", "type": "array", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, "defaultValue": "", @@ -1925,7 +1925,7 @@ "side": "server", "type": "array", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, "defaultValue": "", @@ -1941,7 +1941,7 @@ "side": "server", "type": "array", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, "defaultValue": "", @@ -2273,7 +2273,7 @@ "side": "server", "type": "array", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, "defaultValue": "", @@ -2289,7 +2289,7 @@ "side": "server", "type": "array", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, "defaultValue": "", @@ -2305,7 +2305,7 @@ "side": "server", "type": "array", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, "defaultValue": "", @@ -4175,7 +4175,7 @@ "side": "server", "type": "array", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, "defaultValue": "", @@ -4191,7 +4191,7 @@ "side": "server", "type": "array", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, "defaultValue": "", @@ -4207,7 +4207,7 @@ "side": "server", "type": "array", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, "defaultValue": "", @@ -4503,7 +4503,7 @@ "side": "server", "type": "array", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, "defaultValue": "", @@ -4519,7 +4519,7 @@ "side": "server", "type": "array", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, "defaultValue": "", @@ -4535,7 +4535,7 @@ "side": "server", "type": "array", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, "defaultValue": "", @@ -4687,7 +4687,7 @@ "side": "server", "type": "array", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, "defaultValue": "", @@ -4703,7 +4703,7 @@ "side": "server", "type": "array", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, "defaultValue": "", @@ -4719,7 +4719,7 @@ "side": "server", "type": "int16u", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, "defaultValue": "", @@ -4735,7 +4735,7 @@ "side": "server", "type": "int16u", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, "defaultValue": "", @@ -4751,7 +4751,7 @@ "side": "server", "type": "array", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, "defaultValue": "", @@ -4767,7 +4767,7 @@ "side": "server", "type": "array", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, "defaultValue": "", @@ -4783,7 +4783,7 @@ "side": "server", "type": "array", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, "defaultValue": "", @@ -5052,7 +5052,7 @@ "singleton": 0, "bounded": 0, "defaultValue": "0x0", - "reportable": 0, + "reportable": 1, "minInterval": 1, "maxInterval": 65534, "reportableChange": 0 @@ -5068,7 +5068,7 @@ "singleton": 0, "bounded": 0, "defaultValue": "0x0", - "reportable": 0, + "reportable": 1, "minInterval": 1, "maxInterval": 65534, "reportableChange": 0 @@ -5080,7 +5080,7 @@ "side": "server", "type": "array", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, "defaultValue": "", @@ -5096,7 +5096,7 @@ "side": "server", "type": "array", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, "defaultValue": "", @@ -5112,7 +5112,7 @@ "side": "server", "type": "array", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, "defaultValue": "", @@ -5214,7 +5214,7 @@ "side": "server", "type": "array", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, "defaultValue": "", @@ -5230,11 +5230,11 @@ "side": "server", "type": "array", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, "defaultValue": "", - "reportable": 0, + "reportable": 1, "minInterval": 1, "maxInterval": 65534, "reportableChange": 0 @@ -5246,11 +5246,11 @@ "side": "server", "type": "array", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, "defaultValue": "", - "reportable": 0, + "reportable": 1, "minInterval": 1, "maxInterval": 65534, "reportableChange": 0 @@ -5262,11 +5262,11 @@ "side": "server", "type": "array", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, "defaultValue": "", - "reportable": 0, + "reportable": 1, "minInterval": 1, "maxInterval": 65534, "reportableChange": 0 @@ -5278,7 +5278,7 @@ "side": "server", "type": "array", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, "defaultValue": "", @@ -5294,7 +5294,7 @@ "side": "server", "type": "array", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, "defaultValue": "", @@ -5310,7 +5310,7 @@ "side": "server", "type": "array", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, "defaultValue": "", @@ -5412,7 +5412,7 @@ "side": "server", "type": "array", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, "defaultValue": "", @@ -5428,7 +5428,7 @@ "side": "server", "type": "array", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, "defaultValue": "", @@ -5444,7 +5444,7 @@ "side": "server", "type": "array", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, "defaultValue": "", @@ -5460,7 +5460,7 @@ "side": "server", "type": "array", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, "defaultValue": "", @@ -5510,7 +5510,16 @@ "define": "BRIDGED_ACTIONS_CLUSTER", "side": "client", "enabled": 0, - "commands": [], + "commands": [ + { + "name": "InstantAction", + "code": 0, + "mfgCode": null, + "source": "client", + "incoming": 1, + "outgoing": 0 + } + ], "attributes": [ { "name": "FeatureMap", @@ -5562,7 +5571,7 @@ "side": "server", "type": "array", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, "defaultValue": "", @@ -5578,7 +5587,7 @@ "side": "server", "type": "array", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, "defaultValue": "", @@ -5593,11 +5602,11 @@ "mfgCode": null, "side": "server", "type": "long_char_string", - "included": 0, + "included": 1, "storageOption": "RAM", "singleton": 0, "bounded": 0, - "defaultValue": "", + "defaultValue": "https://example.com", "reportable": 1, "minInterval": 1, "maxInterval": 65534, @@ -5610,7 +5619,7 @@ "side": "server", "type": "array", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, "defaultValue": "", @@ -5626,7 +5635,7 @@ "side": "server", "type": "array", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, "defaultValue": "", @@ -5642,7 +5651,7 @@ "side": "server", "type": "array", "included": 1, - "storageOption": "RAM", + "storageOption": "External", "singleton": 0, "bounded": 0, "defaultValue": "", diff --git a/examples/bridge-app/esp32/main/main.cpp b/examples/bridge-app/esp32/main/main.cpp index 3b94d192d216e1..0d022828740cfb 100644 --- a/examples/bridge-app/esp32/main/main.cpp +++ b/examples/bridge-app/esp32/main/main.cpp @@ -50,6 +50,7 @@ using namespace ::chip; using namespace ::chip::DeviceManager; using namespace ::chip::Platform; using namespace ::chip::Credentials; +using namespace ::chip::app::Clusters; static AppDeviceCallbacks AppCallback; @@ -328,6 +329,15 @@ void HandleDeviceStatusChanged(Device * dev, Device::Changed_t itemChangedMask) } } +bool emberAfBridgedActionsClusterInstantActionCallback(app::CommandHandler * commandObj, + const app::ConcreteCommandPath & commandPath, + const BridgedActions::Commands::InstantAction::DecodableType & commandData) +{ + // No actions are implemented, just return status NotFound. + commandObj->AddStatus(commandPath, Protocols::InteractionModel::Status::NotFound); + return true; +} + const EmberAfDeviceType gBridgedRootDeviceTypes[] = { { DEVICE_TYPE_ROOT_NODE, DEVICE_VERSION_DEFAULT }, { DEVICE_TYPE_BRIDGE, DEVICE_VERSION_DEFAULT } }; diff --git a/examples/bridge-app/linux/Device.cpp b/examples/bridge-app/linux/Device.cpp index e2d2122a49ce25..12e78324ddc04c 100644 --- a/examples/bridge-app/linux/Device.cpp +++ b/examples/bridge-app/linux/Device.cpp @@ -262,3 +262,15 @@ Room::Room(std::string name, uint16_t endpointListId, EndpointListTypeEnum type, mType = type; mIsVisible = isVisible; } + +Action::Action(uint16_t actionId, std::string name, ActionTypeEnum type, uint16_t endpointListId, uint16_t supportedCommands, + ActionStateEnum status, bool isVisible) +{ + mActionId = actionId; + mName = name; + mType = type; + mEndpointListId = endpointListId; + mSupportedCommands = supportedCommands; + mStatus = status; + mIsVisible = isVisible; +} diff --git a/examples/bridge-app/linux/bridged-actions-stub.cpp b/examples/bridge-app/linux/bridged-actions-stub.cpp index 21712982dea9f7..debf2538206d57 100644 --- a/examples/bridge-app/linux/bridged-actions-stub.cpp +++ b/examples/bridge-app/linux/bridged-actions-stub.cpp @@ -57,8 +57,26 @@ constexpr uint16_t BridgedActionsAttrAccess::ClusterRevision; CHIP_ERROR BridgedActionsAttrAccess::ReadActionListAttribute(EndpointId endpoint, AttributeValueEncoder & aEncoder) { - // Just return an empty list - return aEncoder.EncodeEmptyList(); + CHIP_ERROR err = aEncoder.EncodeList([&endpoint](const auto & encoder) -> CHIP_ERROR { + std::vector actionList = GetActionListInfo(endpoint); + + for (auto action : actionList) + { + if (action->getIsVisible()) + { + BridgedActions::Structs::ActionStruct::Type actionStruct = { action->getActionId(), + CharSpan::fromCharString(action->getName().c_str()), + action->getType(), + action->getEndpointListId(), + action->getSupportedCommands(), + action->getStatus() }; + ReturnErrorOnFailure(encoder.Encode(actionStruct)); + } + } + + return CHIP_NO_ERROR; + }); + return err; } CHIP_ERROR BridgedActionsAttrAccess::ReadEndpointListAttribute(EndpointId endpoint, AttributeValueEncoder & aEncoder) diff --git a/examples/bridge-app/linux/include/Device.h b/examples/bridge-app/linux/include/Device.h index 1eea58a71a2eb1..75ea521e90d4d8 100644 --- a/examples/bridge-app/linux/include/Device.h +++ b/examples/bridge-app/linux/include/Device.h @@ -217,3 +217,28 @@ class Room uint16_t mEndpointListId; chip::app::Clusters::BridgedActions::EndpointListTypeEnum mType; }; + +class Action +{ +public: + Action(uint16_t actionId, std::string name, chip::app::Clusters::BridgedActions::ActionTypeEnum type, uint16_t endpointListId, + uint16_t supportedCommands, chip::app::Clusters::BridgedActions::ActionStateEnum status, bool isVisible); + inline void setName(std::string name) { mName = name; }; + inline std::string getName() { return mName; }; + inline chip::app::Clusters::BridgedActions::ActionTypeEnum getType() { return mType; }; + inline chip::app::Clusters::BridgedActions::ActionStateEnum getStatus() { return mStatus; }; + inline uint16_t getActionId() { return mActionId; }; + inline uint16_t getEndpointListId() { return mEndpointListId; }; + inline uint16_t getSupportedCommands() { return mSupportedCommands; }; + inline void setIsVisible(bool isVisible) { mIsVisible = isVisible; }; + inline bool getIsVisible() { return mIsVisible; }; + +private: + std::string mName; + chip::app::Clusters::BridgedActions::ActionTypeEnum mType; + chip::app::Clusters::BridgedActions::ActionStateEnum mStatus; + uint16_t mActionId; + uint16_t mEndpointListId; + uint16_t mSupportedCommands; + bool mIsVisible; +}; diff --git a/examples/bridge-app/linux/include/main.h b/examples/bridge-app/linux/include/main.h index fe81d30685f7ec..df7ba595cd6ece 100644 --- a/examples/bridge-app/linux/include/main.h +++ b/examples/bridge-app/linux/include/main.h @@ -19,3 +19,5 @@ #pragma once std::vector GetEndpointListInfo(chip::EndpointId parentId); + +std::vector GetActionListInfo(chip::EndpointId parentId); diff --git a/examples/bridge-app/linux/main.cpp b/examples/bridge-app/linux/main.cpp index d0b411446a210b..db5eafb1bf5544 100644 --- a/examples/bridge-app/linux/main.cpp +++ b/examples/bridge-app/linux/main.cpp @@ -24,6 +24,7 @@ #include #include +#include #include #include #include @@ -68,6 +69,7 @@ EndpointId gCurrentEndpointId; EndpointId gFirstDynamicEndpointId; Device * gDevices[CHIP_DEVICE_CONFIG_DYNAMIC_ENDPOINT_COUNT]; std::vector gRooms; +std::vector gActions; // ENDPOINT DEFINITIONS: // ================================================================================= @@ -168,6 +170,13 @@ Room room1("Room 1", 0xE001, BridgedActions::EndpointListTypeEnum::kRoom, true); Room room2("Room 2", 0xE002, BridgedActions::EndpointListTypeEnum::kRoom, true); Room room3("Zone 3", 0xE003, BridgedActions::EndpointListTypeEnum::kZone, false); +Action action1(0x1001, "Room 1 On", BridgedActions::ActionTypeEnum::kAutomation, 0xE001, 0x1, + BridgedActions::ActionStateEnum::kInactive, true); +Action action2(0x1002, "Turn On Room 2", BridgedActions::ActionTypeEnum::kAutomation, 0xE002, 0x01, + BridgedActions::ActionStateEnum::kInactive, true); +Action action3(0x1003, "Turn Off Room 1", BridgedActions::ActionTypeEnum::kAutomation, 0xE003, 0x01, + BridgedActions::ActionStateEnum::kInactive, false); + // --------------------------------------------------------------------------- // // SWITCH ENDPOINT: contains the following clusters: @@ -360,6 +369,11 @@ std::vector GetEndpointListInfo(chip::EndpointId parentId) return infoList; } +std::vector GetActionListInfo(chip::EndpointId parentId) +{ + return gActions; +} + void HandleDeviceStatusChanged(Device * dev, Device::Changed_t itemChangedMask) { if (itemChangedMask & Device::kChanged_Reachable) @@ -640,6 +654,82 @@ EmberAfStatus emberAfExternalAttributeWriteCallback(EndpointId endpoint, Cluster return ret; } +void runOnOffRoomAction(Room * room, bool actionOn, EndpointId endpointId, uint16_t actionID, uint32_t invokeID, bool hasInvokeID) +{ + if (hasInvokeID) + { + BridgedActions::Events::StateChanged::Type event{ actionID, invokeID, BridgedActions::ActionStateEnum::kActive }; + EventNumber eventNumber; + chip::app::LogEvent(event, endpointId, eventNumber); + } + + // Check and run the action for ActionLight1 - ActionLight4 + if (room->getName().compare(ActionLight1.GetLocation()) == 0) + { + ActionLight1.SetOnOff(actionOn); + } + if (room->getName().compare(ActionLight2.GetLocation()) == 0) + { + ActionLight2.SetOnOff(actionOn); + } + if (room->getName().compare(ActionLight3.GetLocation()) == 0) + { + ActionLight3.SetOnOff(actionOn); + } + if (room->getName().compare(ActionLight4.GetLocation()) == 0) + { + ActionLight4.SetOnOff(actionOn); + } + + if (hasInvokeID) + { + BridgedActions::Events::StateChanged::Type event{ actionID, invokeID, BridgedActions::ActionStateEnum::kInactive }; + EventNumber eventNumber; + chip::app::LogEvent(event, endpointId, eventNumber); + } +} + +bool emberAfBridgedActionsClusterInstantActionCallback(app::CommandHandler * commandObj, + const app::ConcreteCommandPath & commandPath, + const BridgedActions::Commands::InstantAction::DecodableType & commandData) +{ + bool hasInvokeID = false; + uint32_t invokeID = 0; + EndpointId endpointID = commandPath.mEndpointId; + auto & actionID = commandData.actionID; + + if (commandData.invokeID.HasValue()) + { + hasInvokeID = true; + invokeID = commandData.invokeID.Value(); + } + + if (actionID == action1.getActionId() && action1.getIsVisible()) + { + // Turn On Lights in Room 1 + runOnOffRoomAction(&room1, true, endpointID, actionID, invokeID, hasInvokeID); + commandObj->AddStatus(commandPath, Protocols::InteractionModel::Status::Success); + return true; + } + if (actionID == action2.getActionId() && action2.getIsVisible()) + { + // Turn On Lights in Room 2 + runOnOffRoomAction(&room2, true, endpointID, actionID, invokeID, hasInvokeID); + commandObj->AddStatus(commandPath, Protocols::InteractionModel::Status::Success); + return true; + } + if (actionID == action3.getActionId() && action3.getIsVisible()) + { + // Turn Off Lights in Room 1 + runOnOffRoomAction(&room1, false, endpointID, actionID, invokeID, hasInvokeID); + commandObj->AddStatus(commandPath, Protocols::InteractionModel::Status::Success); + return true; + } + + commandObj->AddStatus(commandPath, Protocols::InteractionModel::Status::NotFound); + return true; +} + void ApplicationInit() {} const EmberAfDeviceType gBridgedOnOffDeviceTypes[] = { { DEVICE_TYPE_LO_ON_OFF_LIGHT, DEVICE_VERSION_DEFAULT }, @@ -744,6 +834,21 @@ void * bridge_polling_thread(void * context) room3.setIsVisible(true); ActionLight2.SetZone("Zone 3"); } + if (ch == 'm') + { + // TC-ACT-2.2 step 3c, rename "Turn on Room 1 lights" + action1.setName("Turn On Room 1"); + } + if (ch == 'n') + { + // TC-ACT-2.2 step 3f, remove "Turn on Room 2 lights" + action2.setIsVisible(false); + } + if (ch == 'o') + { + // TC-ACT-2.2 step 3i, add "Turn off Room 1 renamed lights" + action3.setIsVisible(true); + } continue; } @@ -866,6 +971,10 @@ int main(int argc, char * argv[]) gRooms.push_back(&room2); gRooms.push_back(&room3); + gActions.push_back(&action1); + gActions.push_back(&action2); + gActions.push_back(&action3); + { pthread_t poll_thread; int res = pthread_create(&poll_thread, nullptr, bridge_polling_thread, nullptr); diff --git a/zzz_generated/bridge-app/zap-generated/IMClusterCommandHandler.cpp b/zzz_generated/bridge-app/zap-generated/IMClusterCommandHandler.cpp index 93cd15f439ed14..198b5688cd957c 100644 --- a/zzz_generated/bridge-app/zap-generated/IMClusterCommandHandler.cpp +++ b/zzz_generated/bridge-app/zap-generated/IMClusterCommandHandler.cpp @@ -99,6 +99,43 @@ void DispatchServerCommand(CommandHandler * apCommandObj, const ConcreteCommandP } // namespace AdministratorCommissioning +namespace BridgedActions { + +void DispatchServerCommand(CommandHandler * apCommandObj, const ConcreteCommandPath & aCommandPath, TLV::TLVReader & aDataTlv) +{ + CHIP_ERROR TLVError = CHIP_NO_ERROR; + bool wasHandled = false; + { + switch (aCommandPath.mCommandId) + { + case Commands::InstantAction::Id: { + Commands::InstantAction::DecodableType commandData; + TLVError = DataModel::Decode(aDataTlv, commandData); + if (TLVError == CHIP_NO_ERROR) + { + wasHandled = emberAfBridgedActionsClusterInstantActionCallback(apCommandObj, aCommandPath, commandData); + } + break; + } + default: { + // Unrecognized command ID, error status will apply. + apCommandObj->AddStatus(aCommandPath, Protocols::InteractionModel::Status::UnsupportedCommand); + ChipLogError(Zcl, "Unknown command " ChipLogFormatMEI " for cluster " ChipLogFormatMEI, + ChipLogValueMEI(aCommandPath.mCommandId), ChipLogValueMEI(aCommandPath.mClusterId)); + return; + } + } + } + + if (CHIP_NO_ERROR != TLVError || !wasHandled) + { + apCommandObj->AddStatus(aCommandPath, Protocols::InteractionModel::Status::InvalidCommand); + ChipLogProgress(Zcl, "Failed to dispatch command, TLVError=%" CHIP_ERROR_FORMAT, TLVError.Format()); + } +} + +} // namespace BridgedActions + namespace DiagnosticLogs { void DispatchServerCommand(CommandHandler * apCommandObj, const ConcreteCommandPath & aCommandPath, TLV::TLVReader & aDataTlv) @@ -729,6 +766,9 @@ void DispatchSingleClusterCommand(const ConcreteCommandPath & aCommandPath, TLV: case Clusters::AdministratorCommissioning::Id: Clusters::AdministratorCommissioning::DispatchServerCommand(apCommandObj, aCommandPath, aReader); break; + case Clusters::BridgedActions::Id: + Clusters::BridgedActions::DispatchServerCommand(apCommandObj, aCommandPath, aReader); + break; case Clusters::DiagnosticLogs::Id: Clusters::DiagnosticLogs::DispatchServerCommand(apCommandObj, aCommandPath, aReader); break; diff --git a/zzz_generated/bridge-app/zap-generated/endpoint_config.h b/zzz_generated/bridge-app/zap-generated/endpoint_config.h index 2959aa6b9f8e48..3ccf64ec0b6f0a 100644 --- a/zzz_generated/bridge-app/zap-generated/endpoint_config.h +++ b/zzz_generated/bridge-app/zap-generated/endpoint_config.h @@ -38,6 +38,11 @@ \ /* 6 - Breadcrumb, */ \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + \ + /* Endpoint: 1, Cluster: Bridged Actions (server), big-endian */ \ + \ + /* 14 - setup url, */ \ + 0, 19, 'h', 't', 't', 'p', 's', ':', '/', '/', 'e', 'x', 'a', 'm', 'p', 'l', 'e', '.', 'c', 'o', 'm', \ } #else // !BIGENDIAN_CPU @@ -53,11 +58,16 @@ \ /* 6 - Breadcrumb, */ \ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + \ + /* Endpoint: 1, Cluster: Bridged Actions (server), little-endian */ \ + \ + /* 14 - setup url, */ \ + 0, 19, 'h', 't', 't', 'p', 's', ':', '/', '/', 'e', 'x', 'a', 'm', 'p', 'l', 'e', '.', 'c', 'o', 'm', \ } #endif // BIGENDIAN_CPU -#define GENERATED_DEFAULTS_COUNT (2) +#define GENERATED_DEFAULTS_COUNT (3) #define ZAP_TYPE(type) ZCL_##type##_ATTRIBUTE_TYPE #define ZAP_LONG_DEFAULTS_INDEX(index) \ @@ -90,7 +100,7 @@ #define ZAP_ATTRIBUTE_MASK(mask) ATTRIBUTE_MASK_##mask // This is an array of EmberAfAttributeMetadata structures. -#define GENERATED_ATTRIBUTE_COUNT 240 +#define GENERATED_ATTRIBUTE_COUNT 241 #define GENERATED_ATTRIBUTES \ { \ \ @@ -439,6 +449,7 @@ /* Endpoint: 1, Cluster: Bridged Actions (server) */ \ { 0x00000000, ZAP_TYPE(ARRAY), 0, ZAP_ATTRIBUTE_MASK(EXTERNAL_STORAGE), ZAP_EMPTY_DEFAULT() }, /* action list */ \ { 0x00000001, ZAP_TYPE(ARRAY), 0, ZAP_ATTRIBUTE_MASK(EXTERNAL_STORAGE), ZAP_EMPTY_DEFAULT() }, /* endpoint list */ \ + { 0x00000002, ZAP_TYPE(LONG_CHAR_STRING), 514, 0, ZAP_LONG_DEFAULTS_INDEX(14) }, /* setup url */ \ { 0x0000FFFC, ZAP_TYPE(BITMAP32), 4, 0, ZAP_SIMPLE_DEFAULT(0) }, /* FeatureMap */ \ { 0x0000FFFD, ZAP_TYPE(INT16U), 2, 0, ZAP_SIMPLE_DEFAULT(1) }, /* ClusterRevision */ \ \ @@ -600,14 +611,18 @@ 0x00000000 /* Identify */, \ 0x00000040 /* TriggerEffect */, \ chip::kInvalidCommandId /* end of list */, \ - /* Endpoint: 2, Cluster: On/Off (server) */\ + /* Endpoint: 1, Cluster: Bridged Actions (server) */\ /* AcceptedCommandList (index=57) */ \ + 0x00000000 /* InstantAction */, \ + chip::kInvalidCommandId /* end of list */, \ + /* Endpoint: 2, Cluster: On/Off (server) */\ + /* AcceptedCommandList (index=59) */ \ 0x00000000 /* Off */, \ 0x00000001 /* On */, \ 0x00000002 /* Toggle */, \ chip::kInvalidCommandId /* end of list */, \ /* Endpoint: 2, Cluster: Level Control (server) */\ - /* AcceptedCommandList (index=61) */ \ + /* AcceptedCommandList (index=63) */ \ 0x00000000 /* MoveToLevel */, \ 0x00000001 /* Move */, \ 0x00000002 /* Step */, \ @@ -872,39 +887,39 @@ /* Endpoint: 1, Cluster: Bridged Actions (server) */ \ .clusterId = 0x00000025, \ .attributes = ZAP_ATTRIBUTE_INDEX(206), \ - .attributeCount = 4, \ - .clusterSize = 6, \ + .attributeCount = 5, \ + .clusterSize = 520, \ .mask = ZAP_CLUSTER_MASK(SERVER), \ .functions = NULL, \ - .acceptedCommandList = nullptr ,\ + .acceptedCommandList = ZAP_GENERATED_COMMANDS_INDEX( 57 ) ,\ .generatedCommandList = nullptr ,\ },\ { \ /* Endpoint: 2, Cluster: On/Off (server) */ \ .clusterId = 0x00000006, \ - .attributes = ZAP_ATTRIBUTE_INDEX(210), \ + .attributes = ZAP_ATTRIBUTE_INDEX(211), \ .attributeCount = 3, \ .clusterSize = 7, \ .mask = ZAP_CLUSTER_MASK(SERVER) | ZAP_CLUSTER_MASK(INIT_FUNCTION), \ .functions = chipFuncArrayOnOffServer, \ - .acceptedCommandList = ZAP_GENERATED_COMMANDS_INDEX( 57 ) ,\ + .acceptedCommandList = ZAP_GENERATED_COMMANDS_INDEX( 59 ) ,\ .generatedCommandList = nullptr ,\ },\ { \ /* Endpoint: 2, Cluster: Level Control (server) */ \ .clusterId = 0x00000008, \ - .attributes = ZAP_ATTRIBUTE_INDEX(213), \ + .attributes = ZAP_ATTRIBUTE_INDEX(214), \ .attributeCount = 16, \ .clusterSize = 27, \ .mask = ZAP_CLUSTER_MASK(SERVER) | ZAP_CLUSTER_MASK(INIT_FUNCTION), \ .functions = chipFuncArrayLevelControlServer, \ - .acceptedCommandList = ZAP_GENERATED_COMMANDS_INDEX( 61 ) ,\ + .acceptedCommandList = ZAP_GENERATED_COMMANDS_INDEX( 63 ) ,\ .generatedCommandList = nullptr ,\ },\ { \ /* Endpoint: 2, Cluster: Descriptor (server) */ \ .clusterId = 0x0000001D, \ - .attributes = ZAP_ATTRIBUTE_INDEX(229), \ + .attributes = ZAP_ATTRIBUTE_INDEX(230), \ .attributeCount = 6, \ .clusterSize = 4, \ .mask = ZAP_CLUSTER_MASK(SERVER), \ @@ -915,7 +930,7 @@ { \ /* Endpoint: 2, Cluster: Switch (server) */ \ .clusterId = 0x0000003B, \ - .attributes = ZAP_ATTRIBUTE_INDEX(235), \ + .attributes = ZAP_ATTRIBUTE_INDEX(236), \ .attributeCount = 5, \ .clusterSize = 9, \ .mask = ZAP_CLUSTER_MASK(SERVER), \ @@ -934,11 +949,11 @@ // This is an array of EmberAfEndpointType structures. #define GENERATED_ENDPOINT_TYPES \ { \ - { ZAP_CLUSTER_INDEX(0), 19, 230 }, { ZAP_CLUSTER_INDEX(19), 4, 21 }, { ZAP_CLUSTER_INDEX(23), 4, 47 }, \ + { ZAP_CLUSTER_INDEX(0), 19, 230 }, { ZAP_CLUSTER_INDEX(19), 4, 535 }, { ZAP_CLUSTER_INDEX(23), 4, 47 }, \ } // Largest attribute size is needed for various buffers -#define ATTRIBUTE_LARGEST (259) +#define ATTRIBUTE_LARGEST (515) static_assert(ATTRIBUTE_LARGEST <= CHIP_CONFIG_MAX_ATTRIBUTE_STORE_ELEMENT_SIZE, "ATTRIBUTE_LARGEST larger than expected"); @@ -946,7 +961,7 @@ static_assert(ATTRIBUTE_LARGEST <= CHIP_CONFIG_MAX_ATTRIBUTE_STORE_ELEMENT_SIZE, #define ATTRIBUTE_SINGLETONS_SIZE (37) // Total size of attribute storage -#define ATTRIBUTE_MAX_SIZE (298) +#define ATTRIBUTE_MAX_SIZE (812) // Number of fixed endpoints #define FIXED_ENDPOINT_COUNT (3)