Skip to content

Commit ec70d32

Browse files
committed
Merge branch 'group-binding' into 'main'
Example: Add group binding for the light-switch app See merge request app-frameworks/esp-matter!188
2 parents b5802a5 + ad94862 commit ec70d32

File tree

6 files changed

+237
-55
lines changed

6 files changed

+237
-55
lines changed

components/esp_matter/esp_matter_client.cpp

Lines changed: 88 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -37,38 +37,56 @@ namespace esp_matter {
3737
namespace client {
3838

3939
static command_callback_t client_command_callback = NULL;
40-
static void *client_command_callback_priv_data = NULL;
40+
static group_command_callback_t client_group_command_callback = NULL;
41+
static void *command_callback_priv_data;
4142
static bool initialize_binding_manager = false;
4243

43-
esp_err_t set_command_callback(command_callback_t callback, void *priv_data)
44+
esp_err_t set_command_callback(command_callback_t callback, group_command_callback_t g_callback, void *priv_data)
4445
{
4546
client_command_callback = callback;
46-
client_command_callback_priv_data = priv_data;
47+
client_group_command_callback = g_callback;
48+
command_callback_priv_data = priv_data;
4749
return ESP_OK;
4850
}
4951

50-
/** TODO: Change g_remote_endpoint_id to something better. */
51-
uint16_t g_remote_endpoint_id = kInvalidEndpointId;
5252
void esp_matter_connection_success_callback(void *context, ExchangeManager & exchangeMgr, SessionHandle & sessionHandle)
5353
{
54+
command_handle_t *cmd_handle = static_cast<command_handle_t *>(context);
55+
if (!cmd_handle) {
56+
ESP_LOGE(TAG, "Failed to call connect_success_callback since the command handle is NULL");
57+
return;
58+
}
5459
ESP_LOGI(TAG, "New connection success");
60+
// Only unicast binding needs to establish the connection
5561
if (client_command_callback) {
5662
OperationalDeviceProxy device(&exchangeMgr, sessionHandle);
57-
client_command_callback(&device, g_remote_endpoint_id, client_command_callback_priv_data);
63+
client_command_callback(&device, cmd_handle->endpoint_id, cmd_handle, command_callback_priv_data);
5864
}
65+
chip::Platform::Delete(cmd_handle);
5966
}
6067

6168
void esp_matter_connection_failure_callback(void *context, const ScopedNodeId & peerId, CHIP_ERROR error)
6269
{
70+
command_handle_t *cmd_handle = static_cast<command_handle_t *>(context);
6371
ESP_LOGI(TAG, "New connection failure");
72+
if (cmd_handle) {
73+
chip::Platform::Delete(cmd_handle);
74+
}
6475
}
6576

66-
esp_err_t connect(uint8_t fabric_index, uint64_t node_id, uint16_t remote_endpoint_id)
77+
esp_err_t connect(uint8_t fabric_index, uint64_t node_id, command_handle_t *cmd_handle)
6778
{
6879
static Callback<chip::OnDeviceConnected> success_callback(esp_matter_connection_success_callback, NULL);
6980
static Callback<chip::OnDeviceConnectionFailure> failure_callback(esp_matter_connection_failure_callback, NULL);
81+
82+
command_handle_t *context = chip::Platform::New<command_handle_t>(cmd_handle);
83+
if (!context) {
84+
ESP_LOGE(TAG, "failed to alloc memory for the command handle");
85+
return ESP_ERR_NO_MEM;
86+
}
87+
success_callback.mContext = static_cast<void *>(context);
88+
failure_callback.mContext = static_cast<void *>(context);
7089
Server * server = &(chip::Server::GetInstance());
71-
g_remote_endpoint_id = remote_endpoint_id;
7290
server->GetCASESessionManager()->FindOrEstablishSession(ScopedNodeId(node_id, fabric_index), &success_callback,
7391
&failure_callback);
7492
return ESP_OK;
@@ -77,14 +95,44 @@ esp_err_t connect(uint8_t fabric_index, uint64_t node_id, uint16_t remote_endpoi
7795
static void esp_matter_command_client_binding_callback(const EmberBindingTableEntry &binding, OperationalDeviceProxy *peer_device,
7896
void *context)
7997
{
80-
if (client_command_callback) {
81-
client_command_callback(peer_device, binding.remote, client_command_callback_priv_data);
98+
command_handle_t *cmd_handle = static_cast<command_handle_t *>(context);
99+
if (!cmd_handle) {
100+
ESP_LOGE(TAG, "Failed to call the binding callback since command handle is NULL");
101+
return;
102+
}
103+
if (binding.type == EMBER_UNICAST_BINDING && !cmd_handle->is_group && peer_device) {
104+
if (client_command_callback) {
105+
client_command_callback(peer_device, binding.remote, cmd_handle, command_callback_priv_data);
106+
}
107+
} else if (binding.type == EMBER_MULTICAST_BINDING && cmd_handle->is_group && !peer_device) {
108+
if (client_group_command_callback) {
109+
client_group_command_callback(binding.fabricIndex, binding.groupId, cmd_handle, command_callback_priv_data);
110+
}
111+
}
112+
}
113+
114+
static void esp_matter_binding_context_release(void *context)
115+
{
116+
if (context) {
117+
chip::Platform::Delete(static_cast<command_handle_t *>(context));
82118
}
83119
}
84120

85-
esp_err_t cluster_update(uint16_t endpoint_id, uint32_t cluster_id)
121+
esp_err_t cluster_update(uint16_t local_endpoint_id, command_handle_t *cmd_handle)
86122
{
87-
chip::BindingManager::GetInstance().NotifyBoundClusterChanged(endpoint_id, cluster_id, NULL);
123+
command_handle_t *context = chip::Platform::New<command_handle_t>(cmd_handle);
124+
if (!context) {
125+
ESP_LOGE(TAG, "failed to alloc memory for the command handle");
126+
return ESP_ERR_NO_MEM;
127+
}
128+
if (CHIP_NO_ERROR !=
129+
chip::BindingManager::GetInstance().NotifyBoundClusterChanged(local_endpoint_id, cmd_handle->cluster_id,
130+
static_cast<void *>(context))) {
131+
chip::Platform::Delete(context);
132+
ESP_LOGE(TAG, "failed to notify the bound cluster changed");
133+
return ESP_FAIL;
134+
}
135+
88136
return ESP_OK;
89137
}
90138

@@ -99,6 +147,7 @@ static void __binding_manager_init(intptr_t arg)
99147

100148
chip::BindingManager::GetInstance().Init(binding_init_params);
101149
chip::BindingManager::GetInstance().RegisterBoundDeviceChangedHandler(esp_matter_command_client_binding_callback);
150+
chip::BindingManager::GetInstance().RegisterBoundDeviceContextReleaseHandler(esp_matter_binding_context_release);
102151
}
103152

104153
void binding_manager_init()
@@ -139,6 +188,15 @@ esp_err_t send_on(peer_device_t *remote_device, uint16_t remote_endpoint_id)
139188
return ESP_OK;
140189
}
141190

191+
esp_err_t group_send_on(uint8_t fabric_index, uint16_t group_id)
192+
{
193+
OnOff::Commands::On::Type command_data;
194+
chip::Messaging::ExchangeManager & exchange_mgr = chip::Server::GetInstance().GetExchangeManager();
195+
196+
chip::Controller::InvokeGroupCommandRequest(&exchange_mgr, fabric_index, group_id, command_data);
197+
return ESP_OK;
198+
}
199+
142200
esp_err_t send_off(peer_device_t *remote_device, uint16_t remote_endpoint_id)
143201
{
144202
OnOff::Commands::Off::Type command_data;
@@ -148,6 +206,15 @@ esp_err_t send_off(peer_device_t *remote_device, uint16_t remote_endpoint_id)
148206
return ESP_OK;
149207
}
150208

209+
esp_err_t group_send_off(uint8_t fabric_index, uint16_t group_id)
210+
{
211+
OnOff::Commands::Off::Type command_data;
212+
chip::Messaging::ExchangeManager & exchange_mgr = chip::Server::GetInstance().GetExchangeManager();
213+
214+
chip::Controller::InvokeGroupCommandRequest(&exchange_mgr, fabric_index, group_id, command_data);
215+
return ESP_OK;
216+
}
217+
151218
esp_err_t send_toggle(peer_device_t *remote_device, uint16_t remote_endpoint_id)
152219
{
153220
OnOff::Commands::Toggle::Type command_data;
@@ -157,6 +224,15 @@ esp_err_t send_toggle(peer_device_t *remote_device, uint16_t remote_endpoint_id)
157224
return ESP_OK;
158225
}
159226

227+
esp_err_t group_send_toggle(uint8_t fabric_index, uint16_t group_id)
228+
{
229+
OnOff::Commands::Toggle::Type command_data;
230+
chip::Messaging::ExchangeManager & exchange_mgr = chip::Server::GetInstance().GetExchangeManager();
231+
232+
chip::Controller::InvokeGroupCommandRequest(&exchange_mgr, fabric_index, group_id, command_data);
233+
return ESP_OK;
234+
}
235+
160236
} /* command */
161237
} /* on_off */
162238

components/esp_matter/esp_matter_client.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ namespace command {
3131
esp_err_t send_off(peer_device_t *remote_device, uint16_t remote_endpoint_id);
3232
esp_err_t send_on(peer_device_t *remote_device, uint16_t remote_endpoint_id);
3333
esp_err_t send_toggle(peer_device_t *remote_device, uint16_t remote_endpoint_id);
34+
esp_err_t group_send_off(uint8_t fabric_index, uint16_t group_id);
35+
esp_err_t group_send_on(uint8_t fabric_index, uint16_t group_id);
36+
esp_err_t group_send_toggle(uint8_t fabric_index, uint16_t group_id);
3437
} /* command */
3538
} /* on_off */
3639

components/esp_matter/esp_matter_core.h

Lines changed: 41 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -705,6 +705,22 @@ uint16_t get_flags(command_t *command);
705705
/* Client APIs */
706706
namespace client {
707707

708+
/** Command handle as the input when calling `connect()` or `cluster_update()`
709+
*
710+
*/
711+
712+
typedef struct command_handle {
713+
uint16_t endpoint_id;
714+
uint32_t cluster_id;
715+
uint32_t command_id;
716+
void *command_data { NULL };
717+
bool is_group;
718+
command_handle() : endpoint_id(chip::kInvalidEndpointId), cluster_id(chip::kInvalidClusterId),
719+
command_id(chip::kInvalidCommandId), command_data(NULL), is_group(false) {}
720+
command_handle(struct command_handle* cmd) : endpoint_id(cmd->endpoint_id), cluster_id(cmd->cluster_id),
721+
command_id(cmd->command_id), command_data(cmd->command_data), is_group(cmd->is_group) {}
722+
} command_handle_t;
723+
708724
/** Peer device handle */
709725
typedef chip::DeviceProxy peer_device_t;
710726

@@ -715,10 +731,24 @@ typedef chip::DeviceProxy peer_device_t;
715731
*
716732
* @param[in] peer_device Peer device handle. This can be passed to the send_command APIs.
717733
* @param[in] remote_endpoint_id Endpoint ID of the other device. This can be passed to the send_command APIs.
734+
* @param[in] cmd_handle Command handle used by `connect()` or `cluster_update()`.
735+
* @param[in] priv_data (Optional) Private data associated with the callback. This will be passed to callback. It
736+
* should stay allocated throughout the lifetime of the device.
737+
*/
738+
typedef void (*command_callback_t)(peer_device_t *peer_device, uint16_t remote_endpoint_id, command_handle_t *cmd_handle,
739+
void *priv_data);
740+
741+
/** Group command send callback
742+
*
743+
* This callback will be called when `cluster_update()` is called and the group command is triggered for binding cluster.
744+
*
745+
* @param[in] fabric_index The index of the fabric that the group command is sent to.
746+
* @param[in] group_id The group_id that the group command is sent to.
747+
* @param[in] cmd_handle Command handle used by `cluster_update()`.
718748
* @param[in] priv_data (Optional) Private data associated with the callback. This will be passed to callback. It
719749
* should stay allocated throughout the lifetime of the device.
720750
*/
721-
typedef void (*command_callback_t)(peer_device_t *peer_device, uint16_t remote_endpoint_id, void *priv_data);
751+
typedef void (*group_command_callback_t)(uint8_t fabric_index, uint16_t group_id, command_handle_t *cmd_handle, void *priv_data);
722752

723753
/** Initialize binding
724754
*
@@ -740,39 +770,41 @@ void binding_manager_init();
740770
*
741771
* @param[in] fabric_index Fabric index.
742772
* @param[in] node_id Node ID of the other device.
743-
* @param[in] remote_endpoint_id Endpoint ID of the other device.
773+
* @param[in] cmd_handle Command to be sent to the remote device.
744774
*
745775
* @return ESP_OK on success.
746776
* @return error in case of failure.
747777
*/
748-
esp_err_t connect(uint8_t fabric_index, uint64_t node_id, uint16_t remote_endpoint_id);
778+
esp_err_t connect(uint8_t fabric_index, uint64_t node_id, command_handle_t *cmd_handle);
749779

750780
/** Set command send callback
751781
*
752-
* Set the common command send callback. This callback will be called when `connect()` or `cluster_update()` is called
753-
* and the connection completes.
782+
* Set the common command send callback and the group command send callback. The common callback will be called
783+
* when `connect()` or `cluster_update()` is called and the connection completes. The group callback will be called
784+
* when `cluster_update()` is called and the group command is triggered.
754785
*
755786
* @param[in] callback command send callback.
787+
* @param[in] g_callback group command send callback
756788
* @param[in] priv_data (Optional) Private data associated with the callback. This will be passed to callback. It
757789
* should stay allocated throughout the lifetime of the device.
758790
*
759791
* @return ESP_OK on success.
760792
* @return error in case of failure.
761793
*/
762-
esp_err_t set_command_callback(command_callback_t callback, void *priv_data);
794+
esp_err_t set_command_callback(command_callback_t callback, group_command_callback_t g_callback, void *priv_data);
763795

764796
/** Cluster update
765797
*
766798
* For an already binded device, this API can be used to get the command send callback, and the send_command APIs can
767799
* then be called from the callback.
768800
*
769-
* @param[in] endpoint_id Local endpoint ID of the command.
770-
* @param[in] cluster_id Cluster ID of the command.
801+
* @param[in] local_endpoint_id The ID of the local endpoint with a binding cluster.
802+
* @param[in] cmd_handle Command information to notify the bound cluster changed.
771803
*
772804
* @return ESP_OK on success.
773805
* @return error in case of failure.
774806
*/
775-
esp_err_t cluster_update(uint16_t endpoint_id, uint32_t cluster_id);
807+
esp_err_t cluster_update(uint16_t local_endpoint_id, command_handle_t *cmd_handle);
776808

777809
} /* client */
778810
} /* esp_matter */

examples/light_switch/README.md

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,41 @@ Update the switch's binding attribute to add the entry of remote device
3939
binding write binding '[{"fabricIndex": 1, "node":20836, "endpoint":1, "cluster":6}]' 0x7283 0x1
4040
```
4141

42-
### 2.2 Device console
42+
### 2.2 Bind a group to switch
43+
44+
Using the chip-tool, commission 3 (or more) devices, 1 switch and 2 (or more) lights.
45+
If you are having trouble, try commissioning them one at a time (by powering off the other device) as
46+
the default discriminator and passcode are same for both of them.
47+
Then use the below commands to add the devices to the group and bind the group to the switch.
48+
49+
For the commands below:
50+
- Node Id of switch used during commissioning is 0x7283 (29315 in decimal)
51+
- Node Id of light1 used during commissioning is 0x5164 (20836 in decimal)
52+
- Node Id of light2 used during commissioning is 0x5163 (20835 in decimal)
53+
- Group Id for the devices is 257 which is assigned by chip-tool when using the testing-group command
54+
- Binding cluster is currently present on endpoint 1 on the switch
55+
56+
Send the testing-group command to the switch and lights.
57+
This command will write the acl attributes of the nodes and add the endpoint 1 of the nodes to the group 257.
58+
```
59+
tests TestGroupDemoConfig --nodeId 29315
60+
tests TestGroupDemoConfig --nodeId 20836
61+
tests TestGroupDemoConfig --nodeId 20835
62+
```
63+
64+
Update the switch's binding attribute to add the entry of group in the binding table:
65+
```
66+
binding write binding '[{"fabricIndex": 1, "group": 257}]' 0x7283 0x1
67+
```
68+
69+
### 2.3 Device console
4370

4471
Switch specific console commands:
4572

4673
- Send command to all the bound devices on the specified cluster:
4774
(The IDs are in hex):
4875
```
49-
matter esp bound invoke <endpoint_id> <cluster_id> <command_id>
76+
matter esp bound invoke <local_endpoint_id> <cluster_id> <command_id>
5077
```
5178
5279
- Example: Off:
@@ -64,6 +91,27 @@ Switch specific console commands:
6491
matter esp bound invoke 0x1 0x6 0x2
6592
```
6693
94+
- Send command to all the bound groups on the specified cluster:
95+
(The IDs are in hex):
96+
```
97+
matter esp bound invoke-group <local_endpoint_id> <cluster_id> <command_id>
98+
```
99+
100+
- Example: Off:
101+
```
102+
matter esp bound invoke-group 0x1 0x6 0x0
103+
```
104+
105+
- Example: On:
106+
```
107+
matter esp bound invoke-group 0x1 0x6 0x1
108+
```
109+
110+
- Example: Toggle:
111+
```
112+
matter esp bound invoke-group 0x1 0x6 0x2
113+
```
114+
67115
## 3. Device Performance
68116
69117
### 3.1 Memory usage

0 commit comments

Comments
 (0)