Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Invoke Matter Commands Internally in ESP-Matter (CON-1562) #1290

Open
markgergis opened this issue Feb 24, 2025 · 5 comments
Open

Invoke Matter Commands Internally in ESP-Matter (CON-1562) #1290

markgergis opened this issue Feb 24, 2025 · 5 comments

Comments

@markgergis
Copy link

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_id
  • cluster_id
  • command_id
  • command_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:

  1. The device receives an MQTT message containing the command details.
  2. The command details (endpoint_id, cluster_id, command_id, command_payload) are extracted.
  3. The system calls a generic function to process the command internally as if it were received via Matter.
  4. 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.

@github-actions github-actions bot changed the title Invoke Matter Commands Internally in ESP-Matter Invoke Matter Commands Internally in ESP-Matter (CON-1562) Feb 24, 2025
@wqx6
Copy link
Contributor

wqx6 commented Feb 25, 2025

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.

@markgergis
Copy link
Author

markgergis commented Feb 26, 2025

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

@wqx6
Copy link
Contributor

wqx6 commented Mar 3, 2025

Did you call set_fabric_index() to set the fabric index on which the controller APIs work?

@markgergis
Copy link
Author

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

@wqx6
Copy link
Contributor

wqx6 commented Mar 5, 2025

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants