Invoke Matter Commands Internally in ESP-Matter (CON-1562)
Description
I am developing an ESP-Matter-enabled device that includes an MQTT layer for remote control. I want to create a generic callback function that processes commands from different communication protocols (e.g., MQTT) while reusing the same command execution mechanism that Matter uses internally.
The callback extracts the following from an incoming MQTT message:
endpoint_idcluster_idcommand_idcommand_payload(TLV JSON formatted)
My goal is to invoke the command internally (on Server Cluster) using the same mechanism that Matter uses between a client and a server and receive the same response that Matter would normally return.
Question
Is there a generic way in ESP-Matter to invoke an incoming command internally using the standard Matter mechanism? Should I have a client and a server cluster or can I achieve this on Server Cluster only
Expected Flow:
- The device receives an MQTT message containing the command details.
- The command details (
endpoint_id,cluster_id,command_id,command_payload) are extracted. - The system calls a generic function to process the command internally as if it were received via Matter.
- The response generated should match the response that Matter would return if the command were received from a Matter client.
Thanks in advance for your help.
You can use the cluster_command class to send a command on a client. The flow should be:
- Allocate a cluster_command object with the success&failure callbacks.
- Calling cluster_command->send_command.
I tried this approach with no luck!!
Here is my code
{
cmd_data *data = reinterpret_cast<cmd_data *>(context);
if (data)
{
ESP_LOGI(TAG, "Sending command to cluster %lx, command %lx, data %s", data->cluster_id, data->command_id, (data->data) ? data->data : "NULL");
esp_matter::controller::send_invoke_cluster_command(data->node_id, data->endpoint_id,
data->cluster_id, data->command_id, data->data);
}
else
{
ESP_LOGE(TAG, "Invalid context");
}
}
static void app_driver_button_toggle_cb(void *arg, void *data)
{
ESP_LOGI(TAG, "Toggle button pressed");
uint16_t endpoint_id = light_endpoint_id;
uint32_t cluster_id = OnOff::Id;
uint32_t command_id = isOn ? OnOff::Commands::Off::Id : OnOff::Commands::On::Id;
isOn = !isOn;
cmd_data *mydata = (cmd_data *)malloc(sizeof(cmd_data));
mydata->node_id = 0;
mydata->endpoint_id = endpoint_id;
mydata->cluster_id = cluster_id;
mydata->command_id = command_id;
mydata->data = NULL;
ESP_LOGI(TAG, "Sending command to cluster %lx, command %lx, data %s", mydata->cluster_id, mydata->command_id, (mydata->data) ? mydata->data : "NULL");
chip::DeviceLayer::PlatformMgr().ScheduleWork(send_toggle_command, reinterpret_cast<intptr_t>(mydata));
}
The output is: I (7570) app_driver: Toggle button pressed I (7570) app_driver: Sending command to cluster 6, command 0, data NULL I (7570) app_driver: Sending command to cluster 6, command 0, data NULL I (11890) app_driver: Toggle button pressed I (11890) app_driver: Sending command to cluster 6, command 1, data NULL I (11890) app_driver: Sending command to cluster 6, command 1, data NULL I (15910) app_driver: Toggle button pressed I (15910) app_driver: Sending command to cluster 6, command 0, data NULL I (15910) app_driver: Sending command to cluster 6, command 0, data NULL
But the LED did not TOGGLE
Another thing, I am not using a client, only OnOff cluster with server impl, and my example is that I am using the boot button on the devkit to simulate a command sent
Did you call set_fabric_index() to set the fabric index on which the controller APIs work?
Hi, thanks for the suggestion. However, I was asking about a server-side solution—not for sending commands from a client. My goal is to receive a command (formatted as endpoint_id, cluster_id, command_id, and command_data in TLV format) over protocols like MQTT (Or maybe WebServer) and then invoke the Matter command callback internally on the Matter server. Essentially, I'm trying to avoid having separate callbacks for each command by having a generic dispatcher that maps the incoming command data to the appropriate Matter command handler. Is there any guidance or recommended approach in the ESP-Matter SDK to achieve this?
I was thinking about something like get_callback(command) and then calling err = callback(command_path, tlv_data, opaque_ptr); My problem is I cannot find any implementation for the opaque_ptr (Command Handler) needed by the emberAf* functions
I tried calling DispatchSingleClusterCommand with nullptr opaque_ptr but it didn't work
However, I was asking about a server-side solution—not for sending commands from a client.
So, you aim to implement the following scenario? A Matter device receives a message containing Matter's endpoint ID, cluster ID, command ID, and command data over a non-Matter protocol. However, you want to process this message using Matter's API so that the device behaves as if it received a genuine Matter message.
I tried calling DispatchSingleClusterCommand with nullptr opaque_ptr but it didn't work
The opaque_ptr must also be a CommandHandler, so you cannot use that API with a null opaque_ptr. To resolve this, you need to implement a subclass that inherits from the virtual CommandHandler class. Since you don’t need to handle status or responses for the command, you can leave all virtual functions empty. You can refer to the MockCommandHandler, which is used for unit testing, as an example.
@markgergis Please close the issue if your question is answered
Closing this now. Please reopen if you have additional questions