Skip to content

Commit 7c1536e

Browse files
[Bridge-App/Linux] Fix the bridge-app to use generic actions cluster interface using delegate. (#39035)
* [Bridge-App/Linux] Fix the bridge-app to use generic actions cluster interface using delegate. * Address review comments.
1 parent 3d8a630 commit 7c1536e

File tree

3 files changed

+206
-103
lines changed

3 files changed

+206
-103
lines changed

examples/bridge-app/linux/bridged-actions-stub.cpp

Lines changed: 191 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include <app-common/zap-generated/ids/Clusters.h>
2121
#include <app/AttributeAccessInterface.h>
2222
#include <app/AttributeAccessInterfaceRegistry.h>
23+
#include <app/clusters/actions-server/actions-server.h>
2324
#include <app/util/attribute-storage.h>
2425
#include <lib/support/CodeUtils.h>
2526
#include <lib/support/logging/CHIPLogging.h>
@@ -32,106 +33,235 @@
3233
using namespace chip;
3334
using namespace chip::app;
3435
using namespace chip::app::Clusters;
36+
using namespace chip::app::Clusters::Actions;
3537
using namespace chip::app::Clusters::Actions::Attributes;
38+
using namespace chip::Protocols::InteractionModel;
3639

3740
namespace {
3841

39-
class ActionsAttrAccess : public AttributeAccessInterface
42+
class LinuxActionsDelegateImpl : public Actions::Delegate
4043
{
4144
public:
42-
// Register for the Actions cluster on all endpoints.
43-
ActionsAttrAccess() : AttributeAccessInterface(Optional<EndpointId>::Missing(), Actions::Id) {}
45+
LinuxActionsDelegateImpl() : mEndpointId(1) {}
4446

45-
CHIP_ERROR Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder) override;
47+
void SetEndpointId(chip::EndpointId endpointId) { mEndpointId = endpointId; }
48+
chip::EndpointId GetEndpointId() const { return mEndpointId; }
4649

47-
private:
48-
static constexpr uint16_t ClusterRevision = 1;
50+
CHIP_ERROR ReadActionAtIndex(uint16_t index, ActionStructStorage & action) override;
51+
CHIP_ERROR ReadEndpointListAtIndex(uint16_t index, EndpointListStorage & epList) override;
52+
bool HaveActionWithId(uint16_t actionId, uint16_t & actionIndex) override;
53+
54+
Status HandleInstantAction(uint16_t actionId, Optional<uint32_t> invokeId) override;
55+
Status HandleInstantActionWithTransition(uint16_t actionId, uint16_t transitionTime, Optional<uint32_t> invokeId) override;
56+
Status HandleStartAction(uint16_t actionId, Optional<uint32_t> invokeId) override;
57+
Status HandleStartActionWithDuration(uint16_t actionId, uint32_t duration, Optional<uint32_t> invokeId) override;
58+
Status HandleStopAction(uint16_t actionId, Optional<uint32_t> invokeId) override;
59+
Status HandlePauseAction(uint16_t actionId, Optional<uint32_t> invokeId) override;
60+
Status HandlePauseActionWithDuration(uint16_t actionId, uint32_t duration, Optional<uint32_t> invokeId) override;
61+
Status HandleResumeAction(uint16_t actionId, Optional<uint32_t> invokeId) override;
62+
Status HandleEnableAction(uint16_t actionId, Optional<uint32_t> invokeId) override;
63+
Status HandleEnableActionWithDuration(uint16_t actionId, uint32_t duration, Optional<uint32_t> invokeId) override;
64+
Status HandleDisableAction(uint16_t actionId, Optional<uint32_t> invokeId) override;
65+
Status HandleDisableActionWithDuration(uint16_t actionId, uint32_t duration, Optional<uint32_t> invokeId) override;
4966

50-
CHIP_ERROR ReadActionListAttribute(EndpointId endpoint, AttributeValueEncoder & aEncoder);
51-
CHIP_ERROR ReadEndpointListAttribute(EndpointId endpoint, AttributeValueEncoder & aEncoder);
52-
CHIP_ERROR ReadSetupUrlAttribute(EndpointId endpoint, AttributeValueEncoder & aEncoder);
53-
CHIP_ERROR ReadClusterRevision(EndpointId endpoint, AttributeValueEncoder & aEncoder);
67+
private:
68+
chip::EndpointId mEndpointId;
5469
};
5570

56-
constexpr uint16_t ActionsAttrAccess::ClusterRevision;
71+
LinuxActionsDelegateImpl gLinuxActionsDelegateImpl;
72+
std::unique_ptr<Actions::ActionsServer> sActionsServer;
5773

58-
CHIP_ERROR ActionsAttrAccess::ReadActionListAttribute(EndpointId endpoint, AttributeValueEncoder & aEncoder)
74+
CHIP_ERROR LinuxActionsDelegateImpl::ReadActionAtIndex(uint16_t index, ActionStructStorage & action)
5975
{
60-
CHIP_ERROR err = aEncoder.EncodeList([&endpoint](const auto & encoder) -> CHIP_ERROR {
61-
std::vector<Action *> actionList = GetActionListInfo(endpoint);
76+
std::vector<Action *> actionList = GetActionListInfo(mEndpointId);
6277

63-
for (auto action : actionList)
78+
uint16_t visibleCount = 0;
79+
for (auto actionPtr : actionList)
80+
{
81+
if (actionPtr->getIsVisible())
6482
{
65-
if (action->getIsVisible())
83+
if (visibleCount == index)
6684
{
67-
Actions::Structs::ActionStruct::Type actionStruct = { action->getActionId(),
68-
CharSpan::fromCharString(action->getName().c_str()),
69-
action->getType(),
70-
action->getEndpointListId(),
71-
action->getSupportedCommands(),
72-
action->getStatus() };
73-
ReturnErrorOnFailure(encoder.Encode(actionStruct));
85+
// Found the visible action at the requested index
86+
action.Set(actionPtr->getActionId(), CharSpan::fromCharString(actionPtr->getName().c_str()), actionPtr->getType(),
87+
actionPtr->getEndpointListId(), actionPtr->getSupportedCommands(), actionPtr->getStatus());
88+
return CHIP_NO_ERROR;
7489
}
90+
visibleCount++;
7591
}
92+
}
93+
94+
return CHIP_ERROR_PROVIDER_LIST_EXHAUSTED;
95+
}
96+
97+
CHIP_ERROR LinuxActionsDelegateImpl::ReadEndpointListAtIndex(uint16_t index, EndpointListStorage & epList)
98+
{
99+
std::vector<EndpointListInfo> infoList = GetEndpointListInfo(mEndpointId);
76100

77-
return CHIP_NO_ERROR;
78-
});
79-
return err;
101+
if (index >= infoList.size())
102+
{
103+
return CHIP_ERROR_PROVIDER_LIST_EXHAUSTED;
104+
}
105+
106+
// Get the endpoint list at the specified index
107+
EndpointListInfo info = infoList[index];
108+
DataModel::List<const EndpointId> endpointList(info.GetEndpointListData(), info.GetEndpointListSize());
109+
110+
epList.Set(info.GetEndpointListId(), CharSpan::fromCharString(info.GetName().c_str()), info.GetType(), endpointList);
111+
112+
return CHIP_NO_ERROR;
80113
}
81114

82-
CHIP_ERROR ActionsAttrAccess::ReadEndpointListAttribute(EndpointId endpoint, AttributeValueEncoder & aEncoder)
115+
bool LinuxActionsDelegateImpl::HaveActionWithId(uint16_t actionId, uint16_t & actionIndex)
83116
{
84-
std::vector<EndpointListInfo> infoList = GetEndpointListInfo(endpoint);
117+
std::vector<Action *> actionList = GetActionListInfo(mEndpointId);
85118

86-
CHIP_ERROR err = aEncoder.EncodeList([&infoList](const auto & encoder) -> CHIP_ERROR {
87-
for (auto info : infoList)
119+
uint16_t visibleCount = 0;
120+
for (size_t i = 0; i < actionList.size(); i++)
121+
{
122+
if (actionList[i]->getIsVisible())
88123
{
89-
Actions::Structs::EndpointListStruct::Type endpointListStruct = {
90-
info.GetEndpointListId(), CharSpan::fromCharString(info.GetName().c_str()), info.GetType(),
91-
DataModel::List<chip::EndpointId>(info.GetEndpointListData(), info.GetEndpointListSize())
92-
};
93-
ReturnErrorOnFailure(encoder.Encode(endpointListStruct));
124+
if (actionList[i]->getActionId() == actionId)
125+
{
126+
actionIndex = visibleCount;
127+
return true;
128+
}
129+
visibleCount++;
94130
}
95-
return CHIP_NO_ERROR;
96-
});
97-
return err;
131+
}
132+
133+
return false;
98134
}
99135

100-
CHIP_ERROR ActionsAttrAccess::ReadSetupUrlAttribute(EndpointId endpoint, AttributeValueEncoder & aEncoder)
136+
Status LinuxActionsDelegateImpl::HandleInstantAction(uint16_t actionId, Optional<uint32_t> invokeId)
101137
{
102-
static const char SetupUrl[] = "https://example.com";
103-
return aEncoder.Encode(chip::CharSpan::fromCharString(SetupUrl));
138+
EndpointId endpointID = mEndpointId;
139+
bool hasInvokeID = invokeId.HasValue();
140+
uint32_t invokeIDValue = invokeId.ValueOr(0);
141+
142+
Action * targetAction = nullptr;
143+
std::vector<Action *> actionList = GetActionListInfo(mEndpointId);
144+
for (auto * action : actionList)
145+
{
146+
if (action->getActionId() == actionId && action->getIsVisible())
147+
{
148+
targetAction = action;
149+
break;
150+
}
151+
}
152+
153+
if (targetAction)
154+
{
155+
// Determine the room and if it's an "on" action based on action ID
156+
Room * targetRoom = nullptr;
157+
bool turnOn = true;
158+
159+
// Find room with matching endpoint list ID
160+
std::vector<Room *> roomList = GetRoomListInfo(mEndpointId);
161+
for (auto * room : roomList)
162+
{
163+
if (room->getEndpointListId() == targetAction->getEndpointListId())
164+
{
165+
targetRoom = room;
166+
break;
167+
}
168+
}
169+
170+
// Determine if this is an "on" or "off" action based on name
171+
if (targetAction->getName().find("Off") != std::string::npos)
172+
{
173+
turnOn = false;
174+
}
175+
176+
if (targetRoom)
177+
{
178+
runOnOffRoomAction(targetRoom, turnOn, endpointID, actionId, invokeIDValue, hasInvokeID);
179+
return Status::Success;
180+
}
181+
}
182+
183+
return Status::NotFound;
104184
}
105185

106-
CHIP_ERROR ActionsAttrAccess::ReadClusterRevision(EndpointId endpoint, AttributeValueEncoder & aEncoder)
186+
Status LinuxActionsDelegateImpl::HandleInstantActionWithTransition(uint16_t actionId, uint16_t transitionTime,
187+
Optional<uint32_t> invokeId)
107188
{
108-
return aEncoder.Encode(ClusterRevision);
189+
// Not implemented
190+
return Status::NotFound;
109191
}
110192

111-
ActionsAttrAccess gAttrAccess;
193+
Status LinuxActionsDelegateImpl::HandleStartAction(uint16_t actionId, Optional<uint32_t> invokeId)
194+
{
195+
// Not implemented
196+
return Status::NotFound;
197+
}
112198

113-
CHIP_ERROR ActionsAttrAccess::Read(const ConcreteReadAttributePath & aPath, AttributeValueEncoder & aEncoder)
199+
Status LinuxActionsDelegateImpl::HandleStartActionWithDuration(uint16_t actionId, uint32_t duration, Optional<uint32_t> invokeId)
114200
{
115-
VerifyOrDie(aPath.mClusterId == Actions::Id);
201+
// Not implemented
202+
return Status::NotFound;
203+
}
116204

117-
switch (aPath.mAttributeId)
118-
{
119-
case ActionList::Id:
120-
return ReadActionListAttribute(aPath.mEndpointId, aEncoder);
121-
case EndpointLists::Id:
122-
return ReadEndpointListAttribute(aPath.mEndpointId, aEncoder);
123-
case SetupURL::Id:
124-
return ReadSetupUrlAttribute(aPath.mEndpointId, aEncoder);
125-
case ClusterRevision::Id:
126-
return ReadClusterRevision(aPath.mEndpointId, aEncoder);
127-
default:
128-
break;
129-
}
130-
return CHIP_NO_ERROR;
205+
Status LinuxActionsDelegateImpl::HandleStopAction(uint16_t actionId, Optional<uint32_t> invokeId)
206+
{
207+
// Not implemented
208+
return Status::NotFound;
209+
}
210+
211+
Status LinuxActionsDelegateImpl::HandlePauseAction(uint16_t actionId, Optional<uint32_t> invokeId)
212+
{
213+
// Not implemented
214+
return Status::NotFound;
131215
}
216+
217+
Status LinuxActionsDelegateImpl::HandlePauseActionWithDuration(uint16_t actionId, uint32_t duration, Optional<uint32_t> invokeId)
218+
{
219+
// Not implemented
220+
return Status::NotFound;
221+
}
222+
223+
Status LinuxActionsDelegateImpl::HandleResumeAction(uint16_t actionId, Optional<uint32_t> invokeId)
224+
{
225+
// Not implemented
226+
return Status::NotFound;
227+
}
228+
229+
Status LinuxActionsDelegateImpl::HandleEnableAction(uint16_t actionId, Optional<uint32_t> invokeId)
230+
{
231+
// Not implemented
232+
return Status::NotFound;
233+
}
234+
235+
Status LinuxActionsDelegateImpl::HandleEnableActionWithDuration(uint16_t actionId, uint32_t duration, Optional<uint32_t> invokeId)
236+
{
237+
// Not implemented
238+
return Status::NotFound;
239+
}
240+
241+
Status LinuxActionsDelegateImpl::HandleDisableAction(uint16_t actionId, Optional<uint32_t> invokeId)
242+
{
243+
// Not implemented
244+
return Status::NotFound;
245+
}
246+
247+
Status LinuxActionsDelegateImpl::HandleDisableActionWithDuration(uint16_t actionId, uint32_t duration, Optional<uint32_t> invokeId)
248+
{
249+
// Not implemented
250+
return Status::NotFound;
251+
}
252+
132253
} // anonymous namespace
133254

134255
void emberAfActionsClusterInitCallback(EndpointId endpoint)
135256
{
136-
AttributeAccessInterfaceRegistry::Instance().Register(&gAttrAccess);
257+
VerifyOrReturn(endpoint == 1,
258+
ChipLogError(Zcl, "Actions cluster delegate is not implemented for endpoint with id %d.", endpoint));
259+
VerifyOrReturn(emberAfContainsServer(endpoint, Actions::Id) == true,
260+
ChipLogError(Zcl, "Endpoint %d does not support Actions cluster.", endpoint));
261+
262+
VerifyOrReturn(!sActionsServer);
263+
264+
gLinuxActionsDelegateImpl.SetEndpointId(endpoint);
265+
sActionsServer = std::make_unique<Actions::ActionsServer>(endpoint, gLinuxActionsDelegateImpl);
266+
sActionsServer->Init();
137267
}

examples/bridge-app/linux/include/main.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ std::vector<EndpointListInfo> GetEndpointListInfo(chip::EndpointId parentId);
2626

2727
std::vector<Action *> GetActionListInfo(chip::EndpointId parentId);
2828

29+
std::vector<Room *> GetRoomListInfo(chip::EndpointId parentId);
30+
2931
class BridgeAppCommandHandler
3032
{
3133
public:
@@ -44,3 +46,7 @@ class BridgeCommandDelegate : public NamedPipeCommandDelegate
4446
public:
4547
void OnEventCommandReceived(const char * json) override;
4648
};
49+
50+
// Declare runOnOffRoomAction as an external function that can be called from bridged-actions-stub.cpp
51+
void runOnOffRoomAction(Room * room, bool actionOn, chip::EndpointId endpointId, uint16_t actionID, uint32_t invokeID,
52+
bool hasInvokeID);

0 commit comments

Comments
 (0)