mirror of
https://github.com/espressif/esp-matter.git
synced 2026-04-27 11:03:05 +00:00
Merge branch 'controller/commissioning_window_opener' into 'main'
controller: Add support for timed-invoke command and add open enhanced commissioning window command See merge request app-frameworks/esp-matter!766
This commit is contained in:
@@ -23,6 +23,7 @@
|
||||
|
||||
#include <app/server/Server.h>
|
||||
#include <crypto/CHIPCryptoPAL.h>
|
||||
#include <lib/core/Optional.h>
|
||||
#include <setup_payload/ManualSetupPayloadGenerator.h>
|
||||
#include <setup_payload/QRCodeSetupPayloadGenerator.h>
|
||||
#include <setup_payload/SetupPayload.h>
|
||||
@@ -154,8 +155,8 @@ void cluster_command::on_device_connected_fcn(void *context, ExchangeManager &ex
|
||||
chip::OperationalDeviceProxy device_proxy(&exchangeMgr, sessionHandle);
|
||||
chip::app::CommandPathParams command_path = {cmd->m_endpoint_id, 0, cmd->m_cluster_id, cmd->m_command_id,
|
||||
chip::app::CommandPathFlags::kEndpointIdValid};
|
||||
interaction::invoke::send_request(context, &device_proxy, command_path, cmd->m_command_data_field, cmd->on_success_cb,
|
||||
cmd->on_error_cb, chip::NullOptional);
|
||||
interaction::invoke::send_request(context, &device_proxy, command_path, cmd->m_command_data_field,
|
||||
cmd->on_success_cb, cmd->on_error_cb, cmd->m_timed_invoke_timeout_ms);
|
||||
chip::Platform::Delete(cmd);
|
||||
return;
|
||||
}
|
||||
@@ -255,14 +256,15 @@ esp_err_t cluster_command::send_command()
|
||||
}
|
||||
|
||||
esp_err_t send_invoke_cluster_command(uint64_t destination_id, uint16_t endpoint_id, uint32_t cluster_id,
|
||||
uint32_t command_id, const char *command_data_field)
|
||||
uint32_t command_id, const char *command_data_field,
|
||||
chip::Optional<uint16_t> timed_invoke_timeout_ms)
|
||||
{
|
||||
if (command_data_field && strlen(command_data_field) >= k_command_data_field_buffer_size) {
|
||||
ESP_LOGE(TAG, "The command data field buffer is too small for this command, please increase the buffer size");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
cluster_command *cmd =
|
||||
chip::Platform::New<cluster_command>(destination_id, endpoint_id, cluster_id, command_id, command_data_field);
|
||||
cluster_command *cmd = chip::Platform::New<cluster_command>(destination_id, endpoint_id, cluster_id, command_id,
|
||||
command_data_field, timed_invoke_timeout_ms);
|
||||
if (!cmd) {
|
||||
ESP_LOGE(TAG, "Failed to alloc memory for cluster_command");
|
||||
return ESP_ERR_NO_MEM;
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <esp_matter.h>
|
||||
#include <esp_matter_client.h>
|
||||
#include <esp_matter_mem.h>
|
||||
#include <lib/core/Optional.h>
|
||||
|
||||
namespace esp_matter {
|
||||
namespace controller {
|
||||
@@ -39,12 +40,14 @@ class cluster_command {
|
||||
public:
|
||||
cluster_command(uint64_t destination_id, uint16_t endpoint_id, uint32_t cluster_id, uint32_t command_id,
|
||||
const char *command_data_field,
|
||||
const chip::Optional<uint16_t> timed_invoke_timeout_ms = chip::NullOptional,
|
||||
custom_command_callback::on_success_callback_t on_success = default_success_fcn,
|
||||
custom_command_callback::on_error_callback_t on_error = default_error_fcn)
|
||||
: m_destination_id(destination_id)
|
||||
, m_endpoint_id(endpoint_id)
|
||||
, m_cluster_id(cluster_id)
|
||||
, m_command_id(command_id)
|
||||
, m_timed_invoke_timeout_ms(timed_invoke_timeout_ms)
|
||||
, on_device_connected_cb(on_device_connected_fcn, this)
|
||||
, on_device_connection_failure_cb(on_device_connection_failure_fcn, this)
|
||||
, on_success_cb(on_success)
|
||||
@@ -71,6 +74,7 @@ private:
|
||||
uint32_t m_cluster_id;
|
||||
uint32_t m_command_id;
|
||||
char m_command_data_field[k_command_data_field_buffer_size];
|
||||
chip::Optional<uint16_t> m_timed_invoke_timeout_ms;
|
||||
|
||||
static void on_device_connected_fcn(void *context, ExchangeManager &exchangeMgr,
|
||||
const SessionHandle &sessionHandle);
|
||||
@@ -101,12 +105,14 @@ private:
|
||||
* @param[in] command_id CommandId
|
||||
* @param[in] command_data_field Command data string with JSON format
|
||||
* (https://docs.espressif.com/projects/esp-matter/en/latest/esp32/developing.html#cluster-commands)
|
||||
* @param[in] timed_invoke_timeout_ms Timeout in millisecond for timed-invoke command
|
||||
*
|
||||
* @return ESP_OK on success.
|
||||
* @return error in case of failure.
|
||||
*/
|
||||
esp_err_t send_invoke_cluster_command(uint64_t destination_id, uint16_t endpoint_id, uint32_t cluster_id,
|
||||
uint32_t command_id, const char *command_data_field);
|
||||
uint32_t command_id, const char *command_data_field,
|
||||
chip::Optional<uint16_t> timed_invoke_timeout_ms = chip::NullOptional);
|
||||
|
||||
} // namespace controller
|
||||
} // namespace esp_matter
|
||||
|
||||
+185
@@ -0,0 +1,185 @@
|
||||
// Copyright 2024 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <esp_err.h>
|
||||
#include <esp_log.h>
|
||||
#include <esp_matter_controller_client.h>
|
||||
#include <esp_matter_controller_utils.h>
|
||||
#include <esp_matter_controller_commissioning_window_opener.h>
|
||||
|
||||
#include <app-common/zap-generated/cluster-objects.h>
|
||||
#include <app/server/Server.h>
|
||||
#include <controller/CHIPCluster.h>
|
||||
#include <crypto/CHIPCryptoPAL.h>
|
||||
#include <lib/core/CHIPError.h>
|
||||
#include <lib/core/NodeId.h>
|
||||
#include <lib/core/Optional.h>
|
||||
#include <setup_payload/ManualSetupPayloadGenerator.h>
|
||||
#include <setup_payload/QRCodeSetupPayloadGenerator.h>
|
||||
|
||||
using namespace chip::app::Clusters;
|
||||
|
||||
#define TAG "controller"
|
||||
|
||||
namespace esp_matter {
|
||||
namespace controller {
|
||||
|
||||
esp_err_t commissioning_window_opener::send_open_commissioning_window_command(uint64_t node_id, bool is_enhanced,
|
||||
uint16_t timeout, uint32_t iteration,
|
||||
uint16_t discriminator,
|
||||
uint16_t timed_invoke_timeout_ms)
|
||||
{
|
||||
if (!chip::IsOperationalNodeId(node_id)) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
m_is_enhanced = is_enhanced;
|
||||
m_timout = timeout;
|
||||
m_iteration = iteration;
|
||||
m_discriminator = discriminator;
|
||||
m_timed_invoke_timeout_ms = timed_invoke_timeout_ms;
|
||||
#ifdef CONFIG_ESP_MATTER_ENABLE_MATTER_SERVER
|
||||
chip::Server &server = chip::Server::GetInstance();
|
||||
server.GetCASESessionManager()->FindOrEstablishSession(ScopedNodeId(node_id, get_fabric_index()),
|
||||
&on_device_connected_cb, &on_device_connection_failure_cb);
|
||||
return ESP_OK;
|
||||
#else
|
||||
auto &controller_instance = esp_matter::controller::matter_controller_client::get_instance();
|
||||
#ifdef CONFIG_ESP_MATTER_COMMISSIONER_ENABLE
|
||||
if (CHIP_NO_ERROR ==
|
||||
controller_instance.get_commissioner()->GetConnectedDevice(node_id, &on_device_connected_cb,
|
||||
&on_device_connection_failure_cb)) {
|
||||
return ESP_OK;
|
||||
}
|
||||
#else
|
||||
if (CHIP_NO_ERROR ==
|
||||
controller_instance.get_controller()->GetConnectedDevice(node_id, &on_device_connected_cb,
|
||||
&on_device_connection_failure_cb)) {
|
||||
return ESP_OK;
|
||||
}
|
||||
#endif // CONFIG_ESP_MATTER_COMMISSIONER_ENABLE
|
||||
#endif // CONFIG_ESP_MATTER_ENABLE_MATTER_SERVER
|
||||
return ESP_OK;
|
||||
}
|
||||
static esp_err_t generate_pase_verifier(uint32_t iteration, uint32_t &pincode, chip::MutableByteSpan &salt,
|
||||
chip::Crypto::Spake2pVerifier &verifier)
|
||||
{
|
||||
if (chip::Crypto::DRBG_get_bytes(salt.data(), salt.size()) != CHIP_NO_ERROR) {
|
||||
ESP_LOGE(TAG, "Failed to generate salt");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
if (chip::PASESession::GeneratePASEVerifier(verifier, iteration, salt, true, pincode) != CHIP_NO_ERROR) {
|
||||
ESP_LOGE(TAG, "Failed to generate PASE verifier");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t generate_manual_code(uint32_t pincode, uint16_t discriminator, char *manual_code_buffer,
|
||||
size_t buffer_size)
|
||||
{
|
||||
chip::SetupPayload payload = chip::SetupPayload();
|
||||
payload.setUpPINCode = pincode;
|
||||
payload.version = 0;
|
||||
payload.discriminator.SetLongValue(discriminator);
|
||||
payload.rendezvousInformation.SetValue(chip::RendezvousInformationFlag::kOnNetwork);
|
||||
char payload_buffer[chip::QRCodeBasicSetupPayloadGenerator::kMaxQRCodeBase38RepresentationLength + 1];
|
||||
chip::MutableCharSpan manual_code(payload_buffer);
|
||||
CHIP_ERROR err = chip::ManualSetupPayloadGenerator(payload).payloadDecimalStringRepresentation(manual_code);
|
||||
if (err != CHIP_NO_ERROR || manual_code.size() >= buffer_size) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
strncpy(manual_code_buffer, manual_code.data(), manual_code.size());
|
||||
manual_code_buffer[manual_code.size()] = 0;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void commissioning_window_opener::on_device_connected_fcn(void *context, ExchangeManager &exchangeMgr,
|
||||
const SessionHandle &sessionHandle)
|
||||
{
|
||||
commissioning_window_opener *window_opener = reinterpret_cast<commissioning_window_opener *>(context);
|
||||
if (!window_opener) {
|
||||
return;
|
||||
}
|
||||
if (window_opener->m_is_enhanced) {
|
||||
uint8_t salt_buffer[chip::Crypto::kSpake2p_Max_PBKDF_Salt_Length];
|
||||
chip::MutableByteSpan salt = chip::MutableByteSpan(salt_buffer);
|
||||
chip::Crypto::Spake2pVerifier verifier;
|
||||
if (generate_pase_verifier(window_opener->m_iteration, window_opener->m_pincode, salt, verifier) != ESP_OK) {
|
||||
return;
|
||||
}
|
||||
chip::Spake2pVerifierSerialized serialized_verifier;
|
||||
chip::MutableByteSpan serialized_verifier_span(serialized_verifier);
|
||||
if (verifier.Serialize(serialized_verifier_span) != CHIP_NO_ERROR) {
|
||||
ESP_LOGE(TAG, "Failed to serialize the verifier");
|
||||
return;
|
||||
}
|
||||
AdministratorCommissioning::Commands::OpenCommissioningWindow::Type command_data;
|
||||
command_data.commissioningTimeout = window_opener->m_timout;
|
||||
command_data.PAKEPasscodeVerifier = serialized_verifier_span;
|
||||
command_data.discriminator = window_opener->m_discriminator;
|
||||
command_data.iterations = window_opener->m_iteration;
|
||||
command_data.salt = salt;
|
||||
|
||||
chip::Controller::ClusterBase cluster(exchangeMgr, sessionHandle, window_opener->m_default_remote_endpoint_id);
|
||||
cluster.InvokeCommand(command_data, window_opener, send_command_success_callback, send_command_failure_callback,
|
||||
chip::MakeOptional(window_opener->m_timed_invoke_timeout_ms));
|
||||
} else {
|
||||
AdministratorCommissioning::Commands::OpenBasicCommissioningWindow::Type command_data;
|
||||
command_data.commissioningTimeout = window_opener->m_timout;
|
||||
chip::Controller::ClusterBase cluster(exchangeMgr, sessionHandle, window_opener->m_default_remote_endpoint_id);
|
||||
cluster.InvokeCommand(command_data, window_opener, send_command_success_callback, send_command_failure_callback,
|
||||
chip::MakeOptional(window_opener->m_timed_invoke_timeout_ms));
|
||||
}
|
||||
}
|
||||
|
||||
void commissioning_window_opener::on_device_connection_failure_fcn(void *context, const ScopedNodeId &peerId,
|
||||
CHIP_ERROR error)
|
||||
{
|
||||
commissioning_window_opener *window_opener = reinterpret_cast<commissioning_window_opener *>(context);
|
||||
if (window_opener) {
|
||||
ESP_LOGE(TAG, "Failed to establish CASE session for open %s commisioning window command",
|
||||
window_opener->m_is_enhanced ? "enhanced" : "basic");
|
||||
}
|
||||
}
|
||||
|
||||
void commissioning_window_opener::send_command_success_callback(void *context,
|
||||
const chip::app::DataModel::NullObjectType &data)
|
||||
{
|
||||
commissioning_window_opener *window_opener = reinterpret_cast<commissioning_window_opener *>(context);
|
||||
if (!window_opener) {
|
||||
return;
|
||||
}
|
||||
ESP_LOGI(TAG, "Open %s commissioning window finished", window_opener->m_is_enhanced ? "enhanced" : "basic");
|
||||
if (window_opener->m_is_enhanced) {
|
||||
if (window_opener->m_callback) {
|
||||
char manual_code[22];
|
||||
if (generate_manual_code(window_opener->m_pincode, window_opener->m_discriminator, manual_code,
|
||||
sizeof(manual_code)) == ESP_OK) {
|
||||
window_opener->m_callback(manual_code);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void commissioning_window_opener::send_command_failure_callback(void *context, CHIP_ERROR error)
|
||||
{
|
||||
commissioning_window_opener *window_opener = reinterpret_cast<commissioning_window_opener *>(context);
|
||||
if (window_opener) {
|
||||
ESP_LOGE(TAG, "Failed to send open %s commisioning window command",
|
||||
window_opener->m_is_enhanced ? "enhanced" : "basic");
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace controller
|
||||
} // namespace esp_matter
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
// Copyright 2024 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <esp_matter.h>
|
||||
#include <esp_matter_client.h>
|
||||
#include <esp_matter_mem.h>
|
||||
#include <lib/core/ScopedNodeId.h>
|
||||
#include <messaging/ExchangeMgr.h>
|
||||
#include <transport/Session.h>
|
||||
|
||||
using chip::ScopedNodeId;
|
||||
using chip::SessionHandle;
|
||||
using chip::Messaging::ExchangeManager;
|
||||
|
||||
namespace esp_matter {
|
||||
namespace controller {
|
||||
|
||||
class commissioning_window_opener {
|
||||
public:
|
||||
typedef void (*commissioning_window_open_callback_t)(const char *manual_code);
|
||||
|
||||
static commissioning_window_opener &get_instance()
|
||||
{
|
||||
static commissioning_window_opener instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
void set_callback(commissioning_window_open_callback_t callback) { m_callback = callback; }
|
||||
|
||||
esp_err_t send_open_commissioning_window_command(uint64_t node_id, bool is_enhanced, uint16_t timeout,
|
||||
uint32_t iteration, uint16_t discriminator,
|
||||
uint16_t timed_invoke_timeout_ms);
|
||||
|
||||
uint16_t m_default_remote_endpoint_id = 0;
|
||||
|
||||
private:
|
||||
commissioning_window_opener()
|
||||
: on_device_connected_cb(on_device_connected_fcn, this)
|
||||
, on_device_connection_failure_cb(on_device_connection_failure_fcn, this)
|
||||
{
|
||||
}
|
||||
~commissioning_window_opener() {}
|
||||
|
||||
static void on_device_connected_fcn(void *context, ExchangeManager &exchangeMgr,
|
||||
const SessionHandle &sessionHandle);
|
||||
static void on_device_connection_failure_fcn(void *context, const ScopedNodeId &peerId, CHIP_ERROR error);
|
||||
|
||||
static void send_command_success_callback(void *context, const chip::app::DataModel::NullObjectType &data);
|
||||
|
||||
static void send_command_failure_callback(void *context, CHIP_ERROR error);
|
||||
|
||||
chip::Callback::Callback<chip::OnDeviceConnected> on_device_connected_cb;
|
||||
chip::Callback::Callback<chip::OnDeviceConnectionFailure> on_device_connection_failure_cb;
|
||||
|
||||
uint32_t m_discriminator = 0;
|
||||
bool m_is_enhanced = false;
|
||||
uint32_t m_pincode = 0;
|
||||
uint16_t m_timout = 0;
|
||||
uint32_t m_iteration = 0;
|
||||
uint16_t m_timed_invoke_timeout_ms = 0;
|
||||
commissioning_window_open_callback_t m_callback = nullptr;
|
||||
};
|
||||
|
||||
} // namespace controller
|
||||
} // namespace esp_matter
|
||||
@@ -16,8 +16,9 @@
|
||||
*/
|
||||
|
||||
#include <esp_check.h>
|
||||
#include <esp_matter_controller_cluster_command.h>
|
||||
#include <esp_matter_controller_client.h>
|
||||
#include <esp_matter_controller_cluster_command.h>
|
||||
#include <esp_matter_controller_commissioning_window_opener.h>
|
||||
#include <esp_matter_controller_console.h>
|
||||
#include <esp_matter_controller_group_settings.h>
|
||||
#include <esp_matter_controller_pairing_command.h>
|
||||
@@ -238,13 +239,17 @@ static esp_err_t controller_udc_handler(int argc, char **argv)
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
controller::matter_controller_client::get_instance()
|
||||
.get_commissioner()->GetUserDirectedCommissioningServer()->ResetUDCClientProcessingStates();
|
||||
.get_commissioner()
|
||||
->GetUserDirectedCommissioningServer()
|
||||
->ResetUDCClientProcessingStates();
|
||||
} else if (strncmp(argv[0], "print", sizeof("print")) == 0) {
|
||||
if (argc != 1) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
controller::matter_controller_client::get_instance()
|
||||
.get_commissioner()->GetUserDirectedCommissioningServer()->PrintUDCClients();
|
||||
.get_commissioner()
|
||||
->GetUserDirectedCommissioningServer()
|
||||
->PrintUDCClients();
|
||||
} else if (strncmp(argv[0], "commission", sizeof("commission")) == 0) {
|
||||
if (argc != 3) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
@@ -260,7 +265,9 @@ static esp_err_t controller_udc_handler(int argc, char **argv)
|
||||
|
||||
chip::NodeId gRemoteId = chip::kTestDeviceNodeId;
|
||||
chip::RendezvousParameters params = chip::RendezvousParameters()
|
||||
.SetSetupPINCode(pincode).SetDiscriminator(state->GetLongDiscriminator()).SetPeerAddress(state->GetPeerAddress());
|
||||
.SetSetupPINCode(pincode)
|
||||
.SetDiscriminator(state->GetLongDiscriminator())
|
||||
.SetPeerAddress(state->GetPeerAddress());
|
||||
do {
|
||||
chip::DRBG_get_bytes(reinterpret_cast<uint8_t *>(&gRemoteId), sizeof(gRemoteId));
|
||||
} while (!chip::IsOperationalNodeId(gRemoteId));
|
||||
@@ -342,6 +349,30 @@ static esp_err_t controller_group_settings_handler(int argc, char **argv)
|
||||
}
|
||||
#endif
|
||||
|
||||
static void print_manual_code(const char *manual_code)
|
||||
{
|
||||
ESP_LOGI(TAG,
|
||||
"*************************************Manual Code: [%s]**********************************************",
|
||||
manual_code);
|
||||
}
|
||||
|
||||
static esp_err_t open_commissioning_window_handler(int argc, char **argv)
|
||||
{
|
||||
if (argc != 5) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
uint64_t node_id = string_to_uint64(argv[0]);
|
||||
uint8_t option = string_to_uint8(argv[1]);
|
||||
bool is_enhanced = option == 1;
|
||||
uint16_t window_timeout = string_to_uint16(argv[2]);
|
||||
uint32_t iteration = string_to_uint32(argv[3]);
|
||||
uint16_t discriminator = string_to_uint16(argv[4]);
|
||||
|
||||
controller::commissioning_window_opener::get_instance().set_callback(print_manual_code);
|
||||
return controller::commissioning_window_opener::get_instance().send_open_commissioning_window_command(
|
||||
node_id, is_enhanced, window_timeout, iteration, discriminator, 10000 /* timed_invoke_timeout_ms */);
|
||||
}
|
||||
|
||||
static esp_err_t controller_invoke_command_handler(int argc, char **argv)
|
||||
{
|
||||
if (argc < 4) {
|
||||
@@ -353,6 +384,14 @@ static esp_err_t controller_invoke_command_handler(int argc, char **argv)
|
||||
uint32_t cluster_id = string_to_uint32(argv[2]);
|
||||
uint32_t command_id = string_to_uint32(argv[3]);
|
||||
|
||||
if (argc > 5) {
|
||||
uint16_t timed_invoke_timeout_ms = string_to_uint16(argv[5]);
|
||||
if (timed_invoke_timeout_ms > 0) {
|
||||
return controller::send_invoke_cluster_command(node_id, endpoint_id, cluster_id, command_id, argv[4],
|
||||
chip::MakeOptional(timed_invoke_timeout_ms));
|
||||
}
|
||||
}
|
||||
|
||||
return controller::send_invoke_cluster_command(node_id, endpoint_id, cluster_id, command_id,
|
||||
argc > 4 ? argv[4] : NULL);
|
||||
}
|
||||
@@ -466,98 +505,113 @@ static esp_err_t controller_dispatch(int argc, char **argv)
|
||||
esp_err_t controller_register_commands()
|
||||
{
|
||||
// Subcommands for root command: `controller <subcommand>`
|
||||
const static command_t controller_sub_commands[] =
|
||||
{ {
|
||||
.name = "help",
|
||||
.description = "print this page",
|
||||
.handler = controller_help_handler,
|
||||
},
|
||||
const static command_t controller_sub_commands[] = {
|
||||
{
|
||||
.name = "help",
|
||||
.description = "print this page",
|
||||
.handler = controller_help_handler,
|
||||
},
|
||||
#if CONFIG_ESP_MATTER_COMMISSIONER_ENABLE
|
||||
{
|
||||
.name = "pairing",
|
||||
.description = "Pairing a node.\n"
|
||||
"\tUsage: controller pairing onnetwork [nodeid] [pincode] OR\n"
|
||||
"\tcontroller pairing ble-wifi [nodeid] [ssid] [password] [pincode] [discriminator] OR\n"
|
||||
"\tcontroller pairing ble-thread [nodeid] [dataset] [pincode] [discriminator]",
|
||||
.handler = controller_pairing_handler,
|
||||
},
|
||||
{
|
||||
.name = "group-settings",
|
||||
.description = "Managing the groups and keysets of the controller.\n"
|
||||
"\tUsage: controller group-settings <sub-commands>",
|
||||
.handler = controller_group_settings_handler,
|
||||
},
|
||||
{
|
||||
.name = "pairing",
|
||||
.description = "Pairing a node.\n"
|
||||
"\tUsage: controller pairing onnetwork <nodeid> <pincode> OR\n"
|
||||
"\tcontroller pairing ble-wifi <nodeid> <ssid> <password> <pincode> <discriminator> OR\n"
|
||||
"\tcontroller pairing ble-thread <nodeid> <dataset> <pincode> <discriminator>",
|
||||
.handler = controller_pairing_handler,
|
||||
},
|
||||
{
|
||||
.name = "group-settings",
|
||||
.description = "Managing the groups and keysets of the controller.\n"
|
||||
"\tUsage: controller group-settings <sub-commands>",
|
||||
.handler = controller_group_settings_handler,
|
||||
},
|
||||
#if CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY
|
||||
{
|
||||
.name = "udc",
|
||||
.description = "UDC command.\n"
|
||||
"\tUsage: controller udc reset OR\n"
|
||||
"\tcontroller udc print OR\n"
|
||||
"\tcontroller udc commission [pincode] [udc-entry]",
|
||||
.handler = controller_udc_handler,
|
||||
},
|
||||
{
|
||||
.name = "udc",
|
||||
.description = "UDC command.\n"
|
||||
"\tUsage: controller udc reset OR\n"
|
||||
"\tcontroller udc print OR\n"
|
||||
"\tcontroller udc commission <pincode> <udc-entry>",
|
||||
.handler = controller_udc_handler,
|
||||
},
|
||||
#endif
|
||||
#endif // CONFIG_ESP_MATTER_COMMISSIONER_ENABLE
|
||||
{
|
||||
.name = "invoke-cmd",
|
||||
.description =
|
||||
"Send command to the nodes.\n"
|
||||
"\tUsage: controller invoke-cmd [node-id|group-id] [endpoint-id] [cluster-id] [command-id] [payload]\n"
|
||||
"\tNotes: group-id should start with prefix '0xFFFFFFFFFFFF', endpoint-id will be ignored if the fist "
|
||||
"parameter is group-id.\n"
|
||||
"\tNotes: The payload should be a JSON object that includes all the command data fields defined in the "
|
||||
"SPEC. You can get the format of the payload from "
|
||||
"https://docs.espressif.com/projects/esp-matter/en/latest/esp32/developing.html#cluster-commands",
|
||||
.handler = controller_invoke_command_handler,
|
||||
},
|
||||
{
|
||||
.name = "read-attr",
|
||||
.description = "Read attributes of the nodes.\n"
|
||||
"\tUsage: controller read-attr [node-id] [endpoint-id] [cluster-id] [attr-id]",
|
||||
.handler = controller_read_attr_handler,
|
||||
},
|
||||
{
|
||||
.name = "write-attr",
|
||||
.description =
|
||||
"Write attributes of the nodes.\n"
|
||||
"\tUsage: controller write-attr [node-id|group-id] [endpoint-id] [cluster-id] [attr-id] "
|
||||
"[attr-value]\n"
|
||||
"\tNotes: attr-value should be a JSON object that contains the attribute value JSON item."
|
||||
"You can get the format of the attr-value from "
|
||||
"https://docs.espressif.com/projects/esp-matter/en/latest/esp32/developing.html#write-attribute-commands",
|
||||
.handler = controller_write_attr_handler,
|
||||
},
|
||||
{
|
||||
.name = "read-event",
|
||||
.description = "Read events of the nodes.\n"
|
||||
"\tUsage: controller read-event [node-id] [endpoint-id] [cluster-id] [event-id]",
|
||||
.handler = controller_read_event_handler,
|
||||
},
|
||||
{
|
||||
.name = "subs-attr",
|
||||
.description = "Subscribe attributes of the nodes.\n"
|
||||
"\tUsage: controller subs-attr [node-id] [endpoint-id] [cluster-id] [attr-id] "
|
||||
"[min-interval] [max-interval]",
|
||||
.handler = controller_subscribe_attr_handler,
|
||||
},
|
||||
{
|
||||
.name = "subs-event",
|
||||
.description = "Subscribe events of the nodes.\n"
|
||||
"\tUsage: controller subs-event [node-id] [endpoint-id] [cluster-id] [event-id] "
|
||||
"[min-interval] [max-interval]",
|
||||
.handler = controller_subscribe_event_handler,
|
||||
},
|
||||
{
|
||||
.name = "shutdown-subs",
|
||||
.description = "Shutdown subscription.\n"
|
||||
"\tUsage: controller shutdown-subs [node-id] [subscription-id]",
|
||||
.handler = controller_shutdown_subscription_handler,
|
||||
},
|
||||
{
|
||||
.name = "open-commissioning-window",
|
||||
.description =
|
||||
"Send command to open basic/enhanced commissioning window\n"
|
||||
"\tUsage: controller open-commissioning-window <node-id> <option> <window-timeout> <iteration> "
|
||||
"<discriminator>\n"
|
||||
"\toption: 1 to use enhanced commissioning window. 0 to use basic commissioning window.\n"
|
||||
"\titeration: Number of PBKDF iterations to use to derive the verifier. Ignored if 'option' is 0.\n"
|
||||
"\tdiscriminator: Discriminator to use for advertising. Ignored if 'option' is 0.",
|
||||
.handler = open_commissioning_window_handler,
|
||||
},
|
||||
{
|
||||
.name = "invoke-cmd",
|
||||
.description =
|
||||
"Send command to the nodes.\n"
|
||||
"\tUsage: controller invoke-cmd <node-id|group-id> <endpoint-id> <cluster-id> <command-id> "
|
||||
"[command_data] [timed_invoke_timeout_ms]\n"
|
||||
"\tNotes: group-id should start with prefix '0xFFFFFFFFFFFF', endpoint-id will be ignored if the fist "
|
||||
"parameter is group-id.\n"
|
||||
"\tNotes: The command_data should be a JSON object that includes all the command data fields defined "
|
||||
"in the "
|
||||
"SPEC. You can get the format of the payload from "
|
||||
"https://docs.espressif.com/projects/esp-matter/en/latest/esp32/developing.html#cluster-commands\n"
|
||||
"\tNotes: The timed_invoke_timeout_ms should be used with command_data. If the command has no command "
|
||||
"data field, please use '\"{}\"' as the command_data ",
|
||||
.handler = controller_invoke_command_handler,
|
||||
},
|
||||
{
|
||||
.name = "read-attr",
|
||||
.description = "Read attributes of the nodes.\n"
|
||||
"\tUsage: controller read-attr <node-id> <endpoint-id> <cluster-id> <attr-id>",
|
||||
.handler = controller_read_attr_handler,
|
||||
},
|
||||
{
|
||||
.name = "write-attr",
|
||||
.description =
|
||||
"Write attributes of the nodes.\n"
|
||||
"\tUsage: controller write-attr <node-id> <endpoint-id> <cluster-id> <attr-id> <attr-value>\n"
|
||||
"\tNotes: attr-value should be a JSON object that contains the attribute value JSON item."
|
||||
"You can get the format of the attr-value from "
|
||||
"https://docs.espressif.com/projects/esp-matter/en/latest/esp32/"
|
||||
"developing.html#write-attribute-commands",
|
||||
.handler = controller_write_attr_handler,
|
||||
},
|
||||
{
|
||||
.name = "read-event",
|
||||
.description = "Read events of the nodes.\n"
|
||||
"\tUsage: controller read-event <node-id> <endpoint-id> <cluster-id> <event-id>",
|
||||
.handler = controller_read_event_handler,
|
||||
},
|
||||
{
|
||||
.name = "subs-attr",
|
||||
.description = "Subscribe attributes of the nodes.\n"
|
||||
"\tUsage: controller subs-attr <node-id> <endpoint-id> <cluster-id> <attr-id> "
|
||||
"<min-interval> <max-interval>",
|
||||
.handler = controller_subscribe_attr_handler,
|
||||
},
|
||||
{
|
||||
.name = "subs-event",
|
||||
.description = "Subscribe events of the nodes.\n"
|
||||
"\tUsage: controller subs-attr <node-id> <endpoint-id> <cluster-id> <event-id> "
|
||||
"<min-interval> <max-interval>",
|
||||
.handler = controller_subscribe_event_handler,
|
||||
},
|
||||
{
|
||||
.name = "shutdown-subs",
|
||||
.description = "Shutdown subscription.\n"
|
||||
"\tUsage: controller shutdown-subs <node-id> <subscription-id>",
|
||||
.handler = controller_shutdown_subscription_handler,
|
||||
},
|
||||
};
|
||||
|
||||
const static command_t controller_command = {
|
||||
.name = "controller",
|
||||
.description = "Controller commands. Usage: matter esp controller [command_name]",
|
||||
.description = "Controller commands. Usage: matter esp controller <command_name>",
|
||||
.handler = controller_dispatch,
|
||||
};
|
||||
// Register the controller commands
|
||||
|
||||
Reference in New Issue
Block a user