Add client-only controller and commissioner

This commit is contained in:
WanqQixiang
2024-01-29 18:17:11 +08:00
parent 2418e6696f
commit e39a21e770
39 changed files with 1154 additions and 554 deletions
+9 -4
View File
@@ -22,6 +22,7 @@
#if CONFIG_ESP_MATTER_ENABLE_DATA_MODEL
#include <zap-generated/CHIPClusters.h>
#include "app/CASESessionManager.h"
#include "app/CommandSender.h"
#include "app/InteractionModelEngine.h"
#endif // CONFIG_ESP_MATTER_ENABLE_DATA_MODEL
@@ -242,7 +243,8 @@ esp_err_t send_command(void *ctx, peer_device_t *remote_device, const CommandPat
ESP_LOGE(TAG, "No memory for command sender");
return ESP_ERR_NO_MEM;
}
if (command_sender->PrepareCommand(command_path, /* aStartDataStruct */ false) != CHIP_NO_ERROR) {
chip::app::CommandSender::PrepareCommandParameters prepare_command_params;
if (command_sender->PrepareCommand(command_path, prepare_command_params) != CHIP_NO_ERROR) {
ESP_LOGE(TAG, "Failed to prepare command");
return ESP_FAIL;
}
@@ -256,7 +258,8 @@ esp_err_t send_command(void *ctx, peer_device_t *remote_device, const CommandPat
ESP_LOGE(TAG, "Failed to convert json string to TLV");
return err;
}
if (command_sender->FinishCommand(timed_invoke_timeout_ms) != CHIP_NO_ERROR) {
chip::app::CommandSender::FinishCommandParameters finish_command_params(timed_invoke_timeout_ms);
if (command_sender->FinishCommand(finish_command_params) != CHIP_NO_ERROR) {
ESP_LOGE(TAG, "Failed to finish command");
return ESP_FAIL;
}
@@ -284,7 +287,8 @@ esp_err_t send_group_command(const uint8_t fabric_index, const CommandPathParams
ESP_LOGE(TAG, "No memory for command sender");
return ESP_ERR_NO_MEM;
}
if (command_sender->PrepareCommand(command_path, /* aStartDataStruct */ false) != CHIP_NO_ERROR) {
chip::app::CommandSender::PrepareCommandParameters prepare_command_params;
if (command_sender->PrepareCommand(command_path, prepare_command_params) != CHIP_NO_ERROR) {
ESP_LOGE(TAG, "Failed to prepare command");
return ESP_FAIL;
}
@@ -298,7 +302,8 @@ esp_err_t send_group_command(const uint8_t fabric_index, const CommandPathParams
ESP_LOGE(TAG, "Failed to convert json string to TLV");
return err;
}
if (command_sender->FinishCommand(chip::NullOptional) != CHIP_NO_ERROR) {
chip::app::CommandSender::FinishCommandParameters finish_command_params;
if (command_sender->FinishCommand(finish_command_params) != CHIP_NO_ERROR) {
ESP_LOGE(TAG, "Failed to finish command");
return ESP_FAIL;
}
@@ -1037,6 +1037,7 @@ static esp_err_t chip_init(event_callback_t callback, intptr_t callback_arg)
// Wait for the matter stack to be initialized
xTaskNotifyWait(0, 0, NULL, portMAX_DELAY);
#endif // CONFIG_ESP_MATTER_ENABLE_MATTER_SERVER
return ESP_OK;
}
@@ -1068,11 +1069,14 @@ esp_err_t start(event_callback_t callback, intptr_t callback_arg)
return err;
}
esp_matter_started = true;
#ifdef CONFIG_ESP_MATTER_ENABLE_MATTER_SERVER
// If Matter server is not enabled. we will never use minimum unused endpoint id.
err = node::read_min_unused_endpoint_id();
// If the min_unused_endpoint_id is not found, we will write the current min_unused_endpoint_id in nvs.
if (err == ESP_ERR_NVS_NOT_FOUND) {
err = node::store_min_unused_endpoint_id();
}
#endif
return err;
}
@@ -3,18 +3,29 @@ set(include_dirs_list )
set(exclude_srcs_list )
if (CONFIG_ESP_MATTER_CONTROLLER_ENABLE)
list(APPEND src_dirs_list "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/logger/zap-generated")
list(APPEND include_dirs_list "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/logger")
list(APPEND src_dirs_list "${CMAKE_CURRENT_SOURCE_DIR}/core"
"${CMAKE_CURRENT_SOURCE_DIR}/commands"
"${CMAKE_CURRENT_SOURCE_DIR}/logger/zap-generated")
list(APPEND include_dirs_list "${CMAKE_CURRENT_SOURCE_DIR}/core"
"${CMAKE_CURRENT_SOURCE_DIR}/commands"
"${CMAKE_CURRENT_SOURCE_DIR}/logger")
if (CONFIG_ESP_MATTER_CONTROLLER_CUSTOM_CLUSTER_ENABLE)
list(APPEND src_dirs_list "${CMAKE_CURRENT_SOURCE_DIR}/controller_custom_cluster")
list(APPEND include_dirs_list "${CMAKE_CURRENT_SOURCE_DIR}/controller_custom_cluster")
endif()
if (NOT CONFIG_ESP_MATTER_COMMISSIONER_ENABLE)
list(APPEND exclude_srcs_list "${CMAKE_CURRENT_SOURCE_DIR}/esp_matter_commissioner.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/esp_matter_controller_pairing_command.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/esp_matter_attestation_trust_store.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/esp_matter_controller_group_settings.cpp")
if (CONFIG_ESP_MATTER_ENABLE_MATTER_SERVER)
list(APPEND exclude_srcs_list "${CMAKE_CURRENT_SOURCE_DIR}/core/esp_matter_controller_client.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/core/esp_matter_controller_credentials_issuer.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/core/esp_matter_controller_group_settings.cpp")
endif()
if (CONFIG_ESP_MATTER_COMMISSIONER_ENABLE)
list(APPEND src_dirs_list "${CMAKE_CURRENT_SOURCE_DIR}/attestation_store")
list(APPEND include_dirs_list "${CMAKE_CURRENT_SOURCE_DIR}/attestation_store")
else()
list(APPEND exclude_srcs_list "${CMAKE_CURRENT_SOURCE_DIR}/commands/esp_matter_controller_pairing_command.cpp")
endif()
endif()
+34 -10
View File
@@ -6,20 +6,20 @@ menu "ESP Matter Controller"
help
Enable the controller.
config ESP_MATTER_CONTROLLER_VENDOR_ID
int "Matter Controller Vendor ID"
depends on ESP_MATTER_CONTROLLER_ENABLE && !ESP_MATTER_ENABLE_MATTER_SERVER
default 4891
help
Vendor ID for the controller
config ESP_MATTER_COMMISSIONER_ENABLE
bool "Enable matter commissioner"
depends on ESP_MATTER_CONTROLLER_ENABLE
depends on ESP_MATTER_CONTROLLER_ENABLE && !ESP_MATTER_ENABLE_MATTER_SERVER
default y
help
Enable the matter commissioner in the ESP Matter controller.
config ESP_MATTER_COMMISSIONER_MAX_ACTIVE_DEVICES
int "Max active device"
depends on ESP_MATTER_COMMISSIONER_ENABLE
default 5
help
Maximum number of active device the commissioner supports.
config ESP_MATTER_CONTROLLER_JSON_STRING_BUFFER_LEN
int "Max JSON string buffer length"
depends on ESP_MATTER_CONTROLLER_ENABLE
@@ -30,8 +30,8 @@ menu "ESP Matter Controller"
config ESP_MATTER_CONTROLLER_CUSTOM_CLUSTER_ENABLE
bool "Enable controller custom cluster"
depends on ESP_MATTER_CONTROLLER_ENABLE && !ESP_MATTER_COMMISSIONER_ENABLE
default y
depends on ESP_MATTER_CONTROLLER_ENABLE && ESP_MATTER_ENABLE_MATTER_SERVER
default n
help
Enable the custom cluster of matter controller in the ESP Matter controller for Rainmaker Fabric suppport.
@@ -52,6 +52,30 @@ menu "ESP Matter Controller"
help
Read the PAA root certificates from the spiffs partition
config CUSTOM_ATTESTATION_TRUST_STORE
bool "Attestation Trust Store - Custom"
help
Use the custom Attestation Trust Store
endchoice
choice ESP_MATTER_COMMISSIONER_OPERATIONAL_CREDS_ISSUER
prompt "Operational Credentials Issuer"
depends on !ESP_MATTER_ENABLE_MATTER_SERVER
default TEST_OPERATIONAL_CREDS_ISSUER
help
This option determines how the commissioner generates the NOC chains for the end-devices and itself.
config TEST_OPERATIONAL_CREDS_ISSUER
bool "Operational Credentials Issuer - Test"
help
Use the ExampleOperationalCredentialsIssuer from Matter controller Code
config CUSTOM_OPERATIONAL_CREDS_ISSUER
bool "Operational Credentials Issuer - Custom"
help
Use the custom OperationalCredentialsIssuer
endchoice
endmenu
@@ -14,17 +14,14 @@
#include <DataModelLogger.h>
#include <controller/CommissioneeDeviceProxy.h>
#if CONFIG_ESP_MATTER_COMMISSIONER_ENABLE
#include <esp_matter_commissioner.h>
#else
#include <app/server/Server.h>
#endif
#include <esp_check.h>
#include <esp_matter_controller_client.h>
#include <esp_matter_controller_cluster_command.h>
#include <esp_matter_controller_utils.h>
#include <esp_matter_mem.h>
#include <json_parser.h>
#include <app/server/Server.h>
#include <crypto/CHIPCryptoPAL.h>
#include <setup_payload/ManualSetupPayloadGenerator.h>
#include <setup_payload/QRCodeSetupPayloadGenerator.h>
@@ -101,7 +98,8 @@ void decode_response(const ConcreteCommandPath &command_path, TLVReader *reader)
} else if (command_path.mCommandId == ScenesManagement::Commands::StoreSceneResponse::Id) {
decode_command_response<ScenesManagement::Commands::StoreScene::Type::ResponseType>(command_path, reader);
} else if (command_path.mCommandId == ScenesManagement::Commands::GetSceneMembershipResponse::Id) {
decode_command_response<ScenesManagement::Commands::GetSceneMembership::Type::ResponseType>(command_path, reader);
decode_command_response<ScenesManagement::Commands::GetSceneMembership::Type::ResponseType>(command_path,
reader);
}
}
@@ -209,11 +207,15 @@ esp_err_t cluster_command::dispatch_group_command(void *context)
esp_err_t err = ESP_OK;
cluster_command *cmd = reinterpret_cast<cluster_command *>(context);
uint16_t group_id = cmd->m_destination_id & 0xFFFF;
#if CONFIG_ESP_MATTER_COMMISSIONER_ENABLE
uint8_t fabric_index = commissioner::get_device_commissioner()->GetFabricIndex();
#else
#ifdef CONFIG_ESP_MATTER_ENABLE_MATTER_SERVER
uint8_t fabric_index = get_fabric_index();
#endif
#else
#ifdef CONFIG_ESP_MATTER_COMMISSIONER_ENABLE
uint8_t fabric_index = matter_controller_client::get_instance().get_commissioner()->GetFabricIndex();
#else
uint8_t fabric_index = matter_controller_client::get_instance().get_controller()->GetFabricIndex();
#endif // CONFIG_ESP_MATTER_COMMISSIONER_ENABLE
#endif // CONFIG_ESP_MATTER_ENABLE_MATTER_SERVER
chip::app::CommandPathParams command_path = {cmd->m_endpoint_id, group_id, cmd->m_cluster_id, cmd->m_command_id,
chip::app::CommandPathFlags::kGroupIdValid};
err = custom::command::send_group_command(fabric_index, command_path, cmd->m_command_data_field);
@@ -226,18 +228,27 @@ esp_err_t cluster_command::send_command()
if (is_group_command()) {
return dispatch_group_command(reinterpret_cast<void *>(this));
}
#if CONFIG_ESP_MATTER_COMMISSIONER_ENABLE
#ifdef CONFIG_ESP_MATTER_ENABLE_MATTER_SERVER
chip::Server &server = chip::Server::GetInstance();
server.GetCASESessionManager()->FindOrEstablishSession(ScopedNodeId(m_destination_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 ==
commissioner::get_device_commissioner()->GetConnectedDevice(m_destination_id, &on_device_connected_cb,
&on_device_connection_failure_cb)) {
controller_instance.get_commissioner()->GetConnectedDevice(m_destination_id, &on_device_connected_cb,
&on_device_connection_failure_cb)) {
return ESP_OK;
}
#else
chip::Server *server = &(chip::Server::GetInstance());
server->GetCASESessionManager()->FindOrEstablishSession(ScopedNodeId(m_destination_id, get_fabric_index()),
&on_device_connected_cb, &on_device_connection_failure_cb);
return ESP_OK;
#endif
if (CHIP_NO_ERROR ==
controller_instance.get_controller()->GetConnectedDevice(m_destination_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
chip::Platform::Delete(this);
return ESP_FAIL;
}
@@ -34,6 +34,7 @@ using esp_matter::cluster::custom::command::custom_command_callback;
constexpr char k_empty_command_data_field[] = "{}";
constexpr size_t k_command_data_field_buffer_size = CONFIG_ESP_MATTER_CONTROLLER_JSON_STRING_BUFFER_LEN;
/** Cluster command class to send an invoke interaction command to a server **/
class cluster_command {
public:
cluster_command(uint64_t destination_id, uint16_t endpoint_id, uint32_t cluster_id, uint32_t command_id,
@@ -89,8 +90,23 @@ private:
custom_command_callback::on_error_callback_t on_error_cb;
};
esp_err_t send_invoke_cluster_command(uint64_t node_id, uint16_t endpoint_id, uint32_t cluster_id, uint32_t command_id,
const char *command_data_field);
/** Send cluster invoke command
*
* @note When the destination_id is a Matter GroupId, the endpoint_id parameter will be ignored.
* @note When the command has no data field, command_data_field can be NULL.
*
* @param[in] destination_id NodeId or GroupId
* @param[in] endpoint_id EndpointId
* @param[in] cluster_id ClusterId
* @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)
*
* @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);
} // namespace controller
} // namespace esp_matter
@@ -12,20 +12,18 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include <esp_matter_commissioner.h>
#include <esp_log.h>
#include <esp_matter_controller_client.h>
#include <esp_matter_controller_pairing_command.h>
static const char *TAG = "pairing_command";
using namespace esp_matter::commissioner;
using namespace chip;
using namespace chip::Controller;
namespace esp_matter {
namespace controller {
pairing_command pairing_command::instance;
void pairing_command::OnStatusUpdate(DevicePairingDelegate::Status status)
{
switch (status) {
@@ -60,14 +58,11 @@ void pairing_command::OnCommissioningComplete(NodeId nodeId, CHIP_ERROR err)
{
if (err == CHIP_NO_ERROR) {
ESP_LOGI(TAG, "Device commissioning completed with success - getting OperationalDeviceProxy");
esp_matter::commissioner::get_device_commissioner()->GetConnectedDevice(nodeId, &mOnDeviceConnectedCallback,
&mOnDeviceConnectionFailureCallback);
auto &controller_instance = esp_matter::controller::matter_controller_client::get_instance();
controller_instance.get_commissioner()->GetConnectedDevice(nodeId, &mOnDeviceConnectedCallback,
&mOnDeviceConnectionFailureCallback);
} else {
ESP_LOGI(TAG, "Device commissioning Failure: Matter%s", ErrorStr(err));
CommissionerDiscoveryController *cdc = esp_matter::commissioner::get_discovery_controller();
if (cdc != nullptr) {
cdc->CommissioningFailed(err);
}
}
}
@@ -75,24 +70,11 @@ void pairing_command::OnDeviceConnectedFn(void *context, ExchangeManager &exchan
const SessionHandle &sessionHandle)
{
ESP_LOGI(TAG, "OnDeviceConnectedFn");
CommissionerDiscoveryController *cdc = esp_matter::commissioner::get_discovery_controller();
if (cdc != nullptr) {
uint16_t vendorId = get_auto_commissioner()->GetCommissioningParameters().GetRemoteVendorId().Value();
uint16_t productId = get_auto_commissioner()->GetCommissioningParameters().GetRemoteProductId().Value();
ESP_LOGI(TAG, " ----- AutoCommissioner -- Commissionee vendorId=0x%04X productId=0x%04X", vendorId, productId);
cdc->CommissioningSucceeded(vendorId, productId, get_instance().m_remote_node_id, exchangeMgr, sessionHandle);
}
}
void pairing_command::OnDeviceConnectionFailureFn(void *context, const ScopedNodeId &peerId, CHIP_ERROR err)
{
ESP_LOGI(TAG, "OnDeviceConnectionFailureFn - attempt to get OperationalDeviceProxy failed");
CommissionerDiscoveryController *cdc = esp_matter::commissioner::get_discovery_controller();
if (cdc != nullptr) {
cdc->CommissioningFailed(err);
}
}
CommissioningParameters pairing_command::get_commissioning_params()
@@ -111,6 +93,7 @@ CommissioningParameters pairing_command::get_commissioning_params()
void pairing_command::OnDiscoveredDevice(const chip::Dnssd::DiscoveredNodeData &nodeData)
{
auto &controller_instance = esp_matter::controller::matter_controller_client::get_instance();
// Ignore nodes with closed comissioning window
VerifyOrReturn(nodeData.commissionData.commissioningMode != 0);
const uint16_t port = nodeData.resolutionData.port;
@@ -119,7 +102,7 @@ void pairing_command::OnDiscoveredDevice(const chip::Dnssd::DiscoveredNodeData &
ESP_LOGI(TAG, "Discovered Device: %s:%u", buf, port);
// Stop Mdns discovery. TODO: Check whether it is a right method
get_device_commissioner()->RegisterDeviceDiscoveryDelegate(nullptr);
controller_instance.get_commissioner()->RegisterDeviceDiscoveryDelegate(nullptr);
Inet::InterfaceId interfaceId = nodeData.resolutionData.ipAddress[0].IsIPv6LinkLocal()
? nodeData.resolutionData.interfaceId
@@ -127,18 +110,19 @@ void pairing_command::OnDiscoveredDevice(const chip::Dnssd::DiscoveredNodeData &
PeerAddress peerAddress = PeerAddress::UDP(nodeData.resolutionData.ipAddress[0], port, interfaceId);
RendezvousParameters params = RendezvousParameters().SetSetupPINCode(m_setup_pincode).SetPeerAddress(peerAddress);
CommissioningParameters commissioning_params = get_commissioning_params();
get_device_commissioner()->PairDevice(m_remote_node_id, params, commissioning_params);
controller_instance.get_commissioner()->PairDevice(m_remote_node_id, params, commissioning_params);
}
esp_err_t pairing_on_network(NodeId node_id, uint32_t pincode)
{
Dnssd::DiscoveryFilter filter(chip::Dnssd::DiscoveryFilterType::kNone);
get_device_commissioner()->RegisterDeviceDiscoveryDelegate(&pairing_command::get_instance());
auto &controller_instance = esp_matter::controller::matter_controller_client::get_instance();
controller_instance.get_commissioner()->RegisterDeviceDiscoveryDelegate(&pairing_command::get_instance());
pairing_command::get_instance().m_pairing_mode = PAIRING_MODE_ONNETWORK;
pairing_command::get_instance().m_setup_pincode = pincode;
pairing_command::get_instance().m_remote_node_id = node_id;
pairing_command::get_instance().m_pairing_network_type = NETWORK_TYPE_NONE;
if (CHIP_NO_ERROR != get_device_commissioner()->DiscoverCommissionableNodes(filter)) {
if (CHIP_NO_ERROR != controller_instance.get_commissioner()->DiscoverCommissionableNodes(filter)) {
ESP_LOGE(TAG, "Failed to discover commissionable nodes");
return ESP_FAIL;
}
@@ -155,19 +139,21 @@ esp_err_t pairing_ble_wifi(NodeId node_id, uint32_t pincode, uint16_t disc, cons
chip::ByteSpan pwdSpan(reinterpret_cast<const uint8_t *>(pwd), strlen(pwd));
CommissioningParameters commissioning_params =
CommissioningParameters().SetWiFiCredentials(Controller::WiFiCredentials(nameSpan, pwdSpan));
get_device_commissioner()->PairDevice(node_id, params, commissioning_params);
auto &controller_instance = esp_matter::controller::matter_controller_client::get_instance();
controller_instance.get_commissioner()->PairDevice(node_id, params, commissioning_params);
return ESP_OK;
}
esp_err_t pairing_ble_thread(NodeId node_id, uint32_t pincode, uint16_t disc, uint8_t *dataset_tlvs, uint8_t dataset_len)
esp_err_t pairing_ble_thread(NodeId node_id, uint32_t pincode, uint16_t disc, uint8_t *dataset_tlvs,
uint8_t dataset_len)
{
RendezvousParameters params = RendezvousParameters().SetSetupPINCode(pincode).SetDiscriminator(disc).SetPeerAddress(
chip::Transport::PeerAddress::BLE());
chip::ByteSpan dataset_span(dataset_tlvs, dataset_len);
CommissioningParameters commissioning_params =
CommissioningParameters().SetThreadOperationalDataset(dataset_span);
get_device_commissioner()->PairDevice(node_id, params, commissioning_params);
CommissioningParameters commissioning_params = CommissioningParameters().SetThreadOperationalDataset(dataset_span);
auto &controller_instance = esp_matter::controller::matter_controller_client::get_instance();
controller_instance.get_commissioner()->PairDevice(node_id, params, commissioning_params);
return ESP_OK;
}
#endif
@@ -42,15 +42,10 @@ typedef enum pairing_mode {
PAIRING_MODE_ONNETWORK,
} pairing_mode_t;
/** Pairing command class to finish commissioning with Matter end-devices **/
class pairing_command : public chip::Controller::DevicePairingDelegate,
public chip::Controller::DeviceDiscoveryDelegate {
public:
pairing_command()
: mOnDeviceConnectedCallback(OnDeviceConnectedFn, this)
, mOnDeviceConnectionFailureCallback(OnDeviceConnectionFailureFn, this)
{
}
/****************** DevicePairingDelegate Interface *****************/
void OnStatusUpdate(DevicePairingDelegate::Status status) override;
void OnPairingComplete(CHIP_ERROR error) override;
@@ -60,7 +55,11 @@ public:
/****************** DeviceDiscoveryDelegate Interface ***************/
void OnDiscoveredDevice(const chip::Dnssd::DiscoveredNodeData &nodeData) override;
static pairing_command &get_instance() { return instance; }
static pairing_command &get_instance()
{
static pairing_command s_instance;
return s_instance;
}
NodeId m_remote_node_id;
uint32_t m_setup_pincode;
@@ -69,19 +68,57 @@ public:
pairing_mode_t m_pairing_mode;
private:
static pairing_command instance;
pairing_command()
: mOnDeviceConnectedCallback(OnDeviceConnectedFn, this)
, mOnDeviceConnectionFailureCallback(OnDeviceConnectionFailureFn, this)
{
}
CommissioningParameters get_commissioning_params();
static void OnDeviceConnectedFn(void *context, ExchangeManager &exchangeMgr, const SessionHandle &sessionHandle);
static void OnDeviceConnectionFailureFn(void *context, const ScopedNodeId &peerId, CHIP_ERROR error);
CommissioningParameters get_commissioning_params();
chip::Callback::Callback<chip::OnDeviceConnected> mOnDeviceConnectedCallback;
chip::Callback::Callback<chip::OnDeviceConnectionFailure> mOnDeviceConnectionFailureCallback;
};
/**
* Pairing a Matter end-device on the same IP network
*
* @param[in] node_id NodeId assigned to the Matter end-device.
* @param[in] pincode Setup PIN code of the Matter end-device.
*
* @return ESP_OK on success
* @return error in case of failure
*/
esp_err_t pairing_on_network(NodeId node_id, uint32_t pincode);
#if CONFIG_ENABLE_ESP32_BLE_CONTROLLER
/**
* Pairing a Matter over Wi-Fi end-device with BLE
*
* @param[in] node_id NodeId assigned to the Matter end-device.
* @param[in] pincode Setup PIN code of the Matter end-device.
* @param[in] disc Discriminator of the Matter end-device.
* @param[in] ssid SSID of the Wi-Fi AP.
* @param[in] pwd Password of the Wi-Fi AP.
*
* @return ESP_OK on success
* @return error in case of failure
*/
esp_err_t pairing_ble_wifi(NodeId node_id, uint32_t pincode, uint16_t disc, const char *ssid, const char *pwd);
/**
* Pairing a Matter over Thread end-device with BLE
*
* @param[in] node_id NodeId assigned to the Matter end-device.
* @param[in] pincode Setup PIN code of the Matter end-device.
* @param[in] disc Discriminator of the Matter end-device.
* @param[in] dataset_tlvs Dataset TLV string of the Thread network.
* @param[in] dataset_len Length of the dataset TLV string.
*
* @return ESP_OK on success
* @return error in case of failure
*/
esp_err_t pairing_ble_thread(NodeId node_id, uint32_t pincode, uint16_t disc, uint8_t *dataset_tlvs,
uint8_t dataset_len);
#endif
@@ -12,13 +12,10 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include <app/server/Server.h>
#include <controller/CommissioneeDeviceProxy.h>
#include <esp_log.h>
#if CONFIG_ESP_MATTER_COMMISSIONER_ENABLE
#include <esp_matter_commissioner.h>
#else
#include <app/server/Server.h>
#endif
#include <esp_matter_controller_client.h>
#include <esp_matter_controller_read_command.h>
#include "DataModelLogger.h"
@@ -76,18 +73,27 @@ void read_command::on_device_connection_failure_fcn(void *context, const ScopedN
esp_err_t read_command::send_command()
{
#if CONFIG_ESP_MATTER_COMMISSIONER_ENABLE
#ifdef CONFIG_ESP_MATTER_ENABLE_MATTER_SERVER
chip::Server &server = chip::Server::GetInstance();
server.GetCASESessionManager()->FindOrEstablishSession(ScopedNodeId(m_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 ==
commissioner::get_device_commissioner()->GetConnectedDevice(m_node_id, &on_device_connected_cb,
&on_device_connection_failure_cb)) {
controller_instance.get_commissioner()->GetConnectedDevice(m_node_id, &on_device_connected_cb,
&on_device_connection_failure_cb)) {
return ESP_OK;
}
#else
chip::Server *server = &(chip::Server::GetInstance());
server->GetCASESessionManager()->FindOrEstablishSession(ScopedNodeId(m_node_id, get_fabric_index()),
&on_device_connected_cb, &on_device_connection_failure_cb);
return ESP_OK;
#endif
if (CHIP_NO_ERROR ==
controller_instance.get_controller()->GetConnectedDevice(m_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
chip::Platform::Delete(this);
return ESP_FAIL;
@@ -188,8 +194,8 @@ esp_err_t send_read_attr_command(uint64_t node_id, ScopedMemoryBufferWithSize<ui
attr_paths[i] = AttributePathParams(endpoint_ids[i], cluster_ids[i], attribute_ids[i]);
}
read_command *cmd =
chip::Platform::New<read_command>(node_id, std::move(attr_paths), std::move(event_paths), nullptr, nullptr, nullptr);
read_command *cmd = chip::Platform::New<read_command>(node_id, std::move(attr_paths), std::move(event_paths),
nullptr, nullptr, nullptr);
if (!cmd) {
ESP_LOGE(TAG, "Failed to alloc memory for read_command");
return ESP_ERR_NO_MEM;
@@ -219,8 +225,8 @@ esp_err_t send_read_event_command(uint64_t node_id, ScopedMemoryBufferWithSize<u
event_paths[i] = EventPathParams(endpoint_ids[i], cluster_ids[i], event_ids[i]);
}
read_command *cmd =
chip::Platform::New<read_command>(node_id, std::move(attr_paths), std::move(event_paths), nullptr, nullptr, nullptr);
read_command *cmd = chip::Platform::New<read_command>(node_id, std::move(attr_paths), std::move(event_paths),
nullptr, nullptr, nullptr);
if (!cmd) {
ESP_LOGE(TAG, "Failed to alloc memory for read_command");
return ESP_ERR_NO_MEM;
@@ -38,8 +38,10 @@ typedef enum {
READ_EVENT,
} read_command_type_t;
/** Read command class to send a read interaction command to a server **/
class read_command : public ReadClient::Callback {
public:
/** Constructor for command with multiple paths**/
read_command(uint64_t node_id, ScopedMemoryBufferWithSize<AttributePathParams> &&attr_paths,
ScopedMemoryBufferWithSize<EventPathParams> &&event_paths, attribute_report_cb_t attribute_cb,
read_done_cb_t read_cb_done, event_report_cb_t event_cb)
@@ -54,7 +56,10 @@ public:
, event_data_cb(event_cb)
{
}
/** Constructor for command with single path.
* @note 0xFFFF could be used as wildcard EndpointId
* @note 0xFFFFFFFF could be used as wildcard ClusterId/AttributeId/EventId
*/
read_command(uint64_t node_id, uint16_t endpoint_id, uint32_t cluster_id, uint32_t attribute_or_event_id,
read_command_type_t command_type, attribute_report_cb_t attribute_cb, read_done_cb_t read_cb_done,
event_report_cb_t event_cb)
@@ -113,19 +118,70 @@ private:
attribute_report_cb_t attribute_data_cb;
read_done_cb_t read_done_cb;
event_report_cb_t event_data_cb;
};
/** Send read command with multiple attribute paths
*
* @note The three arrays should has the same size and the order of the three arrays should be the same as
* the attribute paths.
*
* @param[in] node_id Remote NodeId
* @param[in] endpoint_ids EndpointId array of the multiple attribute paths
* @param[in] cluster_ids ClusterId array of the multiple attribute paths
* @param[in] attribute_ids AttributeId array of the multiple attribute paths
*
* @return ESP_OK on success.
* @return error in case of failure.
*/
esp_err_t send_read_attr_command(uint64_t node_id, ScopedMemoryBufferWithSize<uint16_t> &endpoint_ids,
ScopedMemoryBufferWithSize<uint32_t> &cluster_ids,
ScopedMemoryBufferWithSize<uint32_t> &attribute_ids);
/** Send read command with multiple event paths
*
* @note The three arrays should has the same size and the order of the three arrays should be the same as
* the event paths.
*
* @param[in] node_id Remote NodeId
* @param[in] endpoint_ids EndpointId array of the multiple event paths
* @param[in] cluster_ids ClusterId array of the multiple event paths
* @param[in] event_ids EventId array of the multiple event paths
*
* @return ESP_OK on success.
* @return error in case of failure.
*/
esp_err_t send_read_event_command(uint64_t node_id, ScopedMemoryBufferWithSize<uint16_t> &endpoint_ids,
ScopedMemoryBufferWithSize<uint32_t> &cluster_ids,
ScopedMemoryBufferWithSize<uint32_t> &event_ids);
/** Send read command with single attribute path
*
* @note 0xFFFF could be used as wildcard EndpointId
* @note 0xFFFFFFFF could be used as wildcard ClusterId/AttributeId/EventId
*
* @param[in] node_id Remote NodeId
* @param[in] endpoint_id EndpointId
* @param[in] cluster_id ClusterId
* @param[in] attribute_id AttributeId
*
* @return ESP_OK on success.
* @return error in case of failure.
*/
esp_err_t send_read_attr_command(uint64_t node_id, uint16_t endpoint_id, uint32_t cluster_id, uint32_t attribute_id);
/** Send read command with single event path
*
* @note 0xFFFF could be used as wildcard EndpointId
* @note 0xFFFFFFFF could be used as wildcard ClusterId/AttributeId/EventId
*
* @param[in] node_id Remote NodeId
* @param[in] endpoint_id EndpointId
* @param[in] cluster_id ClusterId
* @param[in] event_id EventId
*
* @return ESP_OK on success.
* @return error in case of failure.
*/
esp_err_t send_read_event_command(uint64_t node_id, uint16_t endpoint_id, uint32_t cluster_id, uint32_t event_id);
} // namespace controller
@@ -12,13 +12,10 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include <app/server/Server.h>
#include <controller/CommissioneeDeviceProxy.h>
#include <esp_log.h>
#if CONFIG_ESP_MATTER_COMMISSIONER_ENABLE
#include <esp_matter_commissioner.h>
#else
#include <app/server/Server.h>
#endif
#include <esp_matter_controller_client.h>
#include <esp_matter_controller_subscribe_command.h>
#include "DataModelLogger.h"
@@ -92,18 +89,27 @@ void subscribe_command::on_device_connection_failure_fcn(void *context, const Sc
esp_err_t subscribe_command::send_command()
{
#if CONFIG_ESP_MATTER_COMMISSIONER_ENABLE
if (CHIP_NO_ERROR ==
commissioner::get_device_commissioner()->GetConnectedDevice(m_node_id, &on_device_connected_cb,
&on_device_connection_failure_cb)) {
return ESP_OK;
}
#else
#ifdef CONFIG_ESP_MATTER_ENABLE_MATTER_SERVER
chip::Server *server = &(chip::Server::GetInstance());
server->GetCASESessionManager()->FindOrEstablishSession(ScopedNodeId(m_node_id, get_fabric_index()),
&on_device_connected_cb, &on_device_connection_failure_cb);
return ESP_OK;
#endif
#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(m_node_id, &on_device_connected_cb,
&on_device_connection_failure_cb)) {
return ESP_OK;
}
#else
if (CHIP_NO_ERROR ==
controller_instance.get_controller()->GetConnectedDevice(m_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
chip::Platform::Delete(this);
return ESP_FAIL;
}
@@ -304,7 +310,8 @@ esp_err_t send_shutdown_subscription(uint64_t node_id, uint32_t subscription_id)
if (CHIP_NO_ERROR !=
InteractionModelEngine::GetInstance()->ShutdownSubscription(
#if CONFIG_ESP_MATTER_COMMISSIONER_ENABLE
ScopedNodeId(node_id, commissioner::get_device_commissioner()->GetFabricIndex()), subscription_id)) {
ScopedNodeId(node_id, matter_controller_client::get_instance().get_commissioner()->GetFabricIndex()),
subscription_id)) {
#else
ScopedNodeId(node_id, /* fabric index */ 1), subscription_id)) {
#endif
@@ -38,8 +38,10 @@ typedef enum {
SUBSCRIBE_EVENT,
} subscribe_command_type_t;
/** Subscribe command class to send a subscribe interaction command to a server **/
class subscribe_command : public ReadClient::Callback {
public:
/** Constructor for command with multiple paths**/
subscribe_command(uint64_t node_id, ScopedMemoryBufferWithSize<AttributePathParams> &&attr_paths,
ScopedMemoryBufferWithSize<EventPathParams> &&event_paths, uint16_t min_interval,
uint16_t max_interval, bool auto_resubscribe = true, attribute_report_cb_t attribute_cb = nullptr,
@@ -61,6 +63,10 @@ public:
{
}
/** Constructor for command with single path.
* @note 0xFFFF could be used as wildcard EndpointId
* @note 0xFFFFFFFF could be used as wildcard ClusterId/AttributeId/EventId
*/
subscribe_command(uint64_t node_id, uint16_t endpoint_id, uint32_t cluster_id, uint32_t attribute_or_event_id,
subscribe_command_type_t command_type, uint16_t min_interval, uint16_t max_interval,
bool auto_resubscribe = true, attribute_report_cb_t attribute_cb = nullptr,
@@ -135,20 +141,84 @@ private:
subscribe_failure_cb_t subscribe_failure_cb;
};
/** Send subscribe command with multiple attribute paths
*
* @note The three arrays should has the same size and the order of the three arrays should be the same as
* the attribute paths.
*
* @param[in] node_id Remote NodeId
* @param[in] endpoint_ids EndpointId array of the multiple attribute paths
* @param[in] cluster_ids ClusterId array of the multiple attribute paths
* @param[in] attribute_ids AttributeId array of the multiple attribute paths
* @param[in] min_interval Minimum interval of the subscription
* @param[in] max_interval Maximum interval of the subscription
* @param[in] auto_resubscribe Auto re-subscribe flag
*
* @return ESP_OK on success.
* @return error in case of failure.
*/
esp_err_t send_subscribe_attr_command(uint64_t node_id, ScopedMemoryBufferWithSize<uint16_t> &endpoint_ids,
ScopedMemoryBufferWithSize<uint32_t> &cluster_ids,
ScopedMemoryBufferWithSize<uint32_t> &attribute_ids, uint16_t min_interval,
uint16_t max_interval, bool auto_resubscribe = true);
/** Send subscribe command with multiple event paths
*
* @note The three arrays should has the same size and the order of the three arrays should be the same as
* the event paths.
*
* @param[in] node_id Remote NodeId
* @param[in] endpoint_ids EndpointId array of the multiple event paths
* @param[in] cluster_ids ClusterId array of the multiple event paths
* @param[in] event_ids EventId array of the multiple event paths
* @param[in] min_interval Minimum interval of the subscription
* @param[in] max_interval Maximum interval of the subscription
* @param[in] auto_resubscribe Auto re-subscribe flag
*
* @return ESP_OK on success.
* @return error in case of failure.
*/
esp_err_t send_subscribe_event_command(uint64_t node_id, ScopedMemoryBufferWithSize<uint16_t> &endpoint_ids,
ScopedMemoryBufferWithSize<uint32_t> &cluster_ids,
ScopedMemoryBufferWithSize<uint32_t> &event_ids, uint16_t min_interval,
uint16_t max_interval, bool auto_resubscribe = true);
/** Send subscribe command with single attribute path
*
* @note 0xFFFF could be used as wildcard EndpointId
* @note 0xFFFFFFFF could be used as wildcard ClusterId/AttributeId/EventId
*
* @param[in] node_id Remote NodeId
* @param[in] endpoint_id EndpointId of the attribute path
* @param[in] cluster_id ClusterId of the attribute path
* @param[in] attribute_id AttributeId of the attribue path
* @param[in] min_interval Minimum interval of the subscription
* @param[in] max_interval Maximum interval of the subscription
* @param[in] auto_resubscribe Auto re-subscribe flag
*
* @return ESP_OK on success.
* @return error in case of failure.
*/
esp_err_t send_subscribe_attr_command(uint64_t node_id, uint16_t endpoint_id, uint32_t cluster_id,
uint32_t attribute_id, uint16_t min_interval, uint16_t max_interval,
bool auto_resubscribe = true);
/** Send subscribe command with single event path
*
* @note 0xFFFF could be used as wildcard EndpointId
* @note 0xFFFFFFFF could be used as wildcard ClusterId/AttributeId/EventId
*
* @param[in] node_id Remote NodeId
* @param[in] endpoint_id EndpointId of the event path
* @param[in] cluster_id ClusterId of the event path
* @param[in] event_id AttributeId of the event path
* @param[in] min_interval Minimum interval of the subscription
* @param[in] max_interval Maximum interval of the subscription
* @param[in] auto_resubscribe Auto re-subscribe flag
*
* @return ESP_OK on success.
* @return error in case of failure.
*/
esp_err_t send_subscribe_event_command(uint64_t node_id, uint16_t endpoint_id, uint32_t cluster_id, uint32_t event_id,
uint16_t min_interval, uint16_t max_interval, bool auto_resubscribe = true);
@@ -13,14 +13,12 @@
// limitations under the License.
#include <esp_check.h>
#include <esp_matter_controller_client.h>
#include <esp_matter_controller_utils.h>
#include <esp_matter_controller_write_command.h>
#include <json_to_tlv.h>
#if CONFIG_ESP_MATTER_COMMISSIONER_ENABLE
#include <esp_matter_commissioner.h>
#else
#include <app/server/Server.h>
#endif
using namespace chip::app::Clusters;
using chip::ByteSpan;
@@ -117,18 +115,27 @@ void write_command::on_device_connection_failure_fcn(void *context, const Scoped
esp_err_t write_command::send_command()
{
#if CONFIG_ESP_MATTER_COMMISSIONER_ENABLE
#ifdef CONFIG_ESP_MATTER_ENABLE_MATTER_SERVER
chip::Server &server = chip::Server::GetInstance();
server.GetCASESessionManager()->FindOrEstablishSession(ScopedNodeId(m_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 ==
commissioner::get_device_commissioner()->GetConnectedDevice(m_node_id, &on_device_connected_cb,
&on_device_connection_failure_cb)) {
controller_instance.get_commissioner()->GetConnectedDevice(m_node_id, &on_device_connected_cb,
&on_device_connection_failure_cb)) {
return ESP_OK;
}
#else
chip::Server *server = &(chip::Server::GetInstance());
server->GetCASESessionManager()->FindOrEstablishSession(ScopedNodeId(m_node_id, get_fabric_index()),
&on_device_connected_cb, &on_device_connection_failure_cb);
return ESP_OK;
#endif
if (CHIP_NO_ERROR ==
controller_instance.get_controller()->GetConnectedDevice(m_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
chip::Platform::Delete(this);
return ESP_FAIL;
}
@@ -37,8 +37,10 @@ using esp_matter::client::peer_device_t;
constexpr char *k_null_attribute_val_str = "null";
constexpr size_t k_attr_val_str_buf_size = CONFIG_ESP_MATTER_CONTROLLER_JSON_STRING_BUFFER_LEN;
/** Write command class to send a write interaction command to a server **/
class write_command : public WriteClient::Callback {
public:
/** Constructor for command with an attribute path**/
write_command(uint64_t node_id, uint16_t endpoint_id, uint32_t cluster_id, uint32_t attribute_id,
const char *attribute_val_str)
: m_node_id(node_id)
@@ -98,6 +100,18 @@ private:
chip::Callback::Callback<chip::OnDeviceConnectionFailure> on_device_connection_failure_cb;
};
/** Send write attribute command
*
* @param[in] node_id Remote NodeId
* @param[in] endpoint_id EndpointId
* @param[in] cluster_id ClusterId
* @param[in] attribute_id AttributeId
* @param[in] attr_val_json_str Attribute value string with JSON format
* (https://docs.espressif.com/projects/esp-matter/en/latest/esp32/developing.html#write-attribute-commands)
*
* @return ESP_OK on success.
* @return error in case of failure.
*/
esp_err_t send_write_attr_command(uint64_t node_id, uint16_t endpoint_id, uint32_t cluster_id, uint32_t attribute_id,
const char *attr_val_json_str);
@@ -416,7 +416,7 @@ static esp_err_t fetch_rainmaker_group_id(uint16_t endpoint_id, ScopedMemoryBuff
http_len = esp_http_client_fetch_headers(client);
http_status_code = esp_http_client_get_status_code(client);
if ((http_len > 0) && (http_status_code == 200)) {
http_len = esp_http_client_read_response(client, http_payload.Get(), http_payload.AllocatedSize() - 1 );
http_len = esp_http_client_read_response(client, http_payload.Get(), http_payload.AllocatedSize() - 1);
http_payload[http_len] = 0;
} else {
http_len = esp_http_client_read_response(client, http_payload.Get(), http_payload.AllocatedSize() - 1);
@@ -89,6 +89,7 @@ void print_device_list(matter_device_t *dev_list)
ESP_LOGI(TAG, " {");
ESP_LOGI(TAG, " endpoint_id: %d,", dev->endpoints[i].endpoint_id);
ESP_LOGI(TAG, " device_type_id: 0x%lx,", dev->endpoints[i].device_type_id);
ESP_LOGI(TAG, " device_name: %s,", dev->endpoints[i].device_name);
ESP_LOGI(TAG, " },");
}
ESP_LOGI(TAG, " ]");
@@ -195,6 +196,13 @@ static esp_err_t get_metadata(jparse_ctx_t *jctx, matter_device_t *dev)
json_obj_leave_array(jctx);
}
dev->endpoint_count = 1;
int device_name_len = ESP_MATTER_CONTROLLER_MAX_DEVICE_NAME_LEN;
if (json_obj_get_strlen(jctx, "deviceName", &device_name_len) == 0 &&
device_name_len < ESP_MATTER_CONTROLLER_MAX_DEVICE_NAME_LEN) {
json_obj_get_string(jctx, "deviceName", dev->endpoints[0].device_name,
ESP_MATTER_CONTROLLER_MAX_DEVICE_NAME_LEN);
dev->endpoints[0].device_name[device_name_len] = 0;
}
}
json_obj_get_bool(jctx, "isRainmaker", &(dev->is_rainmaker_device));
json_obj_leave_object(jctx);
@@ -21,10 +21,12 @@ namespace controller {
namespace device_mgr {
#define ESP_MATTER_DEVICE_MAX_ENDPOINT 8
#define ESP_MATTER_CONTROLLER_MAX_DEVICE_NAME_LEN 32
typedef struct endpoint_entry {
uint16_t endpoint_id;
uint32_t device_type_id;
char device_name[ESP_MATTER_CONTROLLER_MAX_DEVICE_NAME_LEN];
} endpoint_entry_t;
typedef struct matter_device {
@@ -0,0 +1,236 @@
// 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 <sdkconfig.h>
#include <esp_check.h>
#include <esp_err.h>
#include <esp_matter_controller_client.h>
#include <esp_matter_controller_credentials_issuer.h>
#include <esp_matter_controller_pairing_command.h>
#include <controller/CHIPDeviceControllerFactory.h>
#include <controller/OperationalCredentialsDelegate.h>
#include <credentials/GroupDataProvider.h>
#include <credentials/attestation_verifier/DefaultDeviceAttestationVerifier.h>
#include <credentials/attestation_verifier/DeviceAttestationVerifier.h>
#include <crypto/CHIPCryptoPAL.h>
#include <lib/core/CHIPError.h>
#include <lib/core/DataModelTypes.h>
#include <lib/support/CHIPMem.h>
#include <lib/support/ScopedBuffer.h>
#include <lib/support/Span.h>
#include <lib/support/TestGroupData.h>
#include <stdint.h>
#ifdef CONFIG_ESP_MATTER_COMMISSIONER_ENABLE
#include <esp_matter_attestation_trust_store.h>
#endif
#if CONFIG_ENABLE_ESP32_BLE_CONTROLLER
#include <platform/ESP32/BLEManagerImpl.h>
#include <platform/internal/BLEManager.h>
#endif
#define TAG "MatterController"
using chip::Platform::ScopedMemoryBufferWithSize;
namespace esp_matter {
namespace controller {
esp_err_t matter_controller_client::init(NodeId node_id, FabricId fabric_id, uint16_t listen_port)
{
chip::Controller::FactoryInitParams factory_init_params;
ESP_RETURN_ON_FALSE(m_operational_keystore.Init(&m_default_storage) == CHIP_NO_ERROR, ESP_FAIL, TAG,
"Failed to initialize operational keystore");
ESP_RETURN_ON_FALSE(m_operational_cert_store.Init(&m_default_storage) == CHIP_NO_ERROR, ESP_FAIL, TAG,
"Failed to initialize operational cert store");
// ESP_RETURN_ON_FALSE(m_icd_client_storage.Init(&m_default_storage, &m_session_key_store) == CHIP_NO_ERROR,
// ESP_FAIL, TAG, "Failed to initialize ICD client store");
factory_init_params.listenPort = listen_port;
factory_init_params.fabricIndependentStorage = &m_default_storage;
factory_init_params.operationalKeystore = &m_operational_keystore;
factory_init_params.opCertStore = &m_operational_cert_store;
factory_init_params.enableServerInteractions = m_operational_advertising;
factory_init_params.sessionKeystore = &m_session_key_store;
m_controller_node_id = node_id;
m_controller_fabric_id = fabric_id;
m_group_data_provider.SetStorageDelegate(&m_default_storage);
m_group_data_provider.SetSessionKeystore(factory_init_params.sessionKeystore);
ESP_RETURN_ON_FALSE(m_group_data_provider.Init() == CHIP_NO_ERROR, ESP_FAIL, TAG,
"Failed to initialize group data provider");
factory_init_params.groupDataProvider =
reinterpret_cast<chip::Credentials::GroupDataProvider *>(&m_group_data_provider);
chip::Credentials::SetGroupDataProvider(factory_init_params.groupDataProvider);
ESP_RETURN_ON_FALSE(chip::Controller::DeviceControllerFactory::GetInstance().Init(factory_init_params) ==
CHIP_NO_ERROR,
ESP_FAIL, TAG, "Failed to initialize DeviceControllerFactory");
return ESP_OK;
}
#ifdef CONFIG_ESP_MATTER_COMMISSIONER_ENABLE
esp_err_t matter_controller_client::setup_commissioner()
{
#if CONFIG_ENABLE_ESP32_BLE_CONTROLLER
CHIP_ERROR err = chip::DeviceLayer::Internal::BLEMgr().Init();
// This function will return CHIP_ERROR_INCORRECT_STATE if BLE Manager is already initialized.
ESP_RETURN_ON_FALSE(err == CHIP_NO_ERROR || err == CHIP_ERROR_INCORRECT_STATE, ESP_FAIL, TAG,
"Failed to initialze the BLE manager");
ESP_RETURN_ON_FALSE(chip::DeviceLayer::Internal::BLEMgrImpl().ConfigureBle(0, true) == CHIP_NO_ERROR, ESP_FAIL, TAG,
"Failed to configure BLEManager");
#endif
chip::Controller::SetupParams commissioner_params;
const chip::Credentials::AttestationTrustStore *trust_store = chip::Credentials::get_attestation_trust_store();
chip::Credentials::DeviceAttestationVerifier *dac_verifier = chip::Credentials::GetDefaultDACVerifier(trust_store);
chip::Credentials::SetDeviceAttestationVerifier(dac_verifier);
commissioner_params.deviceAttestationVerifier = dac_verifier;
m_credentials_issuer = get_credentials_issuer();
ESP_RETURN_ON_FALSE(m_credentials_issuer, ESP_FAIL, TAG,
"Please set the custom credentials_issuer before calling setup_commissioner");
ESP_RETURN_ON_ERROR(m_credentials_issuer->initialize_credentials_issuer(m_default_storage), TAG,
"Failed to initialize credentials_issuer");
commissioner_params.operationalCredentialsDelegate = m_credentials_issuer->get_delegate();
commissioner_params.controllerVendorId = chip::VendorId((uint16_t)CONFIG_ESP_MATTER_CONTROLLER_VENDOR_ID);
// Commissioner NOC chain
ScopedMemoryBufferWithSize<uint8_t> noc;
noc.Calloc(chip::Controller::kMaxCHIPDERCertLength);
ESP_RETURN_ON_FALSE(noc.Get(), ESP_ERR_NO_MEM, TAG, "Failed allocate memory for noc");
chip::MutableByteSpan noc_span(noc.Get(), chip::Controller::kMaxCHIPDERCertLength);
ScopedMemoryBufferWithSize<uint8_t> icac;
icac.Calloc(chip::Controller::kMaxCHIPDERCertLength);
ESP_RETURN_ON_FALSE(icac.Get(), ESP_ERR_NO_MEM, TAG, "Failed allocate memory for icac");
chip::MutableByteSpan icac_span(icac.Get(), chip::Controller::kMaxCHIPDERCertLength);
ScopedMemoryBufferWithSize<uint8_t> rcac;
rcac.Calloc(chip::Controller::kMaxCHIPDERCertLength);
ESP_RETURN_ON_FALSE(rcac.Get(), ESP_ERR_NO_MEM, TAG, "Failed allocate memory for rcac");
chip::MutableByteSpan rcac_span(rcac.Get(), chip::Controller::kMaxCHIPDERCertLength);
// NOC Keypair
chip::Crypto::P256Keypair ephemeral_key;
ESP_RETURN_ON_FALSE(ephemeral_key.Initialize(chip::Crypto::ECPKeyTarget::ECDSA) == CHIP_NO_ERROR, ESP_FAIL, TAG,
"Failed to initialize ephemeral_key pair");
ESP_RETURN_ON_ERROR(m_credentials_issuer->generate_controller_noc_chain(m_controller_node_id,
m_controller_fabric_id, ephemeral_key,
rcac_span, icac_span, noc_span),
TAG, "Failed to generate NOC chain");
commissioner_params.operationalKeypair = &ephemeral_key;
commissioner_params.controllerRCAC = rcac_span;
commissioner_params.controllerICAC = icac_span;
commissioner_params.controllerNOC = noc_span;
commissioner_params.defaultCommissioner = &m_auto_commissioner;
commissioner_params.enableServerInteractions = m_operational_advertising;
auto &factory = chip::Controller::DeviceControllerFactory::GetInstance();
ESP_RETURN_ON_FALSE(factory.SetupCommissioner(commissioner_params, m_device_commissioner) == CHIP_NO_ERROR,
ESP_FAIL, TAG, "Failed to setup commissioner");
// Initialize Group Data, including IPK
chip::FabricIndex fabric_index = m_device_commissioner.GetFabricIndex();
ESP_RETURN_ON_FALSE(fabric_index != chip::kUndefinedFabricIndex, ESP_FAIL, TAG, "Invalid Fabric Index");
uint8_t compressed_fabric_id[sizeof(uint64_t)] = {0};
chip::MutableByteSpan compressed_fabric_id_span(compressed_fabric_id);
ESP_RETURN_ON_FALSE(m_device_commissioner.GetCompressedFabricIdBytes(compressed_fabric_id_span) == CHIP_NO_ERROR,
ESP_FAIL, TAG, "Failed to get compressed_fabric_id");
chip::Credentials::GroupDataProvider *group_data_provider =
reinterpret_cast<chip::Credentials::GroupDataProvider *>(&m_group_data_provider);
ESP_RETURN_ON_FALSE(chip::GroupTesting::InitData(group_data_provider, fabric_index, compressed_fabric_id_span) ==
CHIP_NO_ERROR,
ESP_FAIL, TAG, "Failed to initialize group data");
chip::ByteSpan default_ipk = chip::GroupTesting::DefaultIpkValue::GetDefaultIpk();
ESP_RETURN_ON_FALSE(chip::Credentials::SetSingleIpkEpochKey(group_data_provider, fabric_index, default_ipk,
compressed_fabric_id_span) == CHIP_NO_ERROR,
ESP_FAIL, TAG, "Failed to set ipk for commissioner fabric");
// m_icd_client_storage.UpdateFabricList(fabric_index);
m_device_commissioner.RegisterPairingDelegate(&controller::pairing_command::get_instance());
return ESP_OK;
}
#else
esp_err_t matter_controller_client::setup_controller(chip::MutableByteSpan &ipk)
{
chip::Controller::SetupParams controller_params;
// Controller doesn't need to verify device attestation. Set deviceAttestationVerifier to null.
controller_params.deviceAttestationVerifier = nullptr;
m_credentials_issuer = get_credentials_issuer();
ESP_RETURN_ON_FALSE(m_credentials_issuer, ESP_FAIL, TAG,
"Please set the custom credentials_issuer before calling setup_controller");
ESP_RETURN_ON_ERROR(m_credentials_issuer->initialize_credentials_issuer(m_default_storage), TAG,
"Failed to initialize credentials_issuer");
controller_params.operationalCredentialsDelegate = m_credentials_issuer->get_delegate();
controller_params.controllerVendorId = chip::VendorId((uint16_t)CONFIG_ESP_MATTER_CONTROLLER_VENDOR_ID);
// Commissioner NOC chain
ScopedMemoryBufferWithSize<uint8_t> noc;
noc.Calloc(chip::Controller::kMaxCHIPDERCertLength);
ESP_RETURN_ON_FALSE(noc.Get(), ESP_ERR_NO_MEM, TAG, "Failed allocate memory for noc");
chip::MutableByteSpan noc_span(noc.Get(), chip::Controller::kMaxCHIPDERCertLength);
ScopedMemoryBufferWithSize<uint8_t> icac;
icac.Calloc(chip::Controller::kMaxCHIPDERCertLength);
ESP_RETURN_ON_FALSE(icac.Get(), ESP_ERR_NO_MEM, TAG, "Failed allocate memory for icac");
chip::MutableByteSpan icac_span(icac.Get(), chip::Controller::kMaxCHIPDERCertLength);
ScopedMemoryBufferWithSize<uint8_t> rcac;
rcac.Calloc(chip::Controller::kMaxCHIPDERCertLength);
ESP_RETURN_ON_FALSE(rcac.Get(), ESP_ERR_NO_MEM, TAG, "Failed allocate memory for rcac");
chip::MutableByteSpan rcac_span(rcac.Get(), chip::Controller::kMaxCHIPDERCertLength);
chip::Crypto::P256Keypair ephemeral_key;
ESP_RETURN_ON_ERROR(m_credentials_issuer->generate_controller_noc_chain(m_controller_node_id,
m_controller_fabric_id, ephemeral_key,
rcac_span, icac_span, noc_span),
TAG, "Failed to generate NOC chain");
// Check whether the keypair is initialized in generate_controller_noc_chain
bool is_keypair_initialized = false;
{
chip::Crypto::P256ECDSASignature signature;
is_keypair_initialized = ephemeral_key.ECDSA_sign_msg(NULL, 0, signature) != CHIP_ERROR_UNINITIALIZED;
}
// If not initialized, use an empty keypair.
controller_params.operationalKeypair = is_keypair_initialized ? &ephemeral_key : nullptr;
controller_params.controllerRCAC = rcac_span;
controller_params.controllerICAC = icac_span;
controller_params.controllerNOC = noc_span;
controller_params.defaultCommissioner = nullptr;
controller_params.enableServerInteractions = m_operational_advertising;
controller_params.permitMultiControllerFabrics = false;
auto &factory = chip::Controller::DeviceControllerFactory::GetInstance();
ESP_RETURN_ON_FALSE(factory.SetupController(controller_params, m_device_controller) == CHIP_NO_ERROR, ESP_FAIL, TAG,
"Failed to setup controller");
chip::FabricIndex fabric_index = m_device_controller.GetFabricIndex();
if (fabric_index != chip::kUndefinedFabricIndex && !ipk.empty()) {
// If we have created fabric in SetupController and IPK input is not empty, initialize Group Data with IPK.
// Otherwise we will initialize Group Data with IPK later.
uint8_t compressed_fabric_id[sizeof(uint64_t)] = {0};
chip::MutableByteSpan compressed_fabric_id_span(compressed_fabric_id);
ESP_RETURN_ON_FALSE(m_device_controller.GetCompressedFabricIdBytes(compressed_fabric_id_span) == CHIP_NO_ERROR,
ESP_FAIL, TAG, "Failed to get compressed_fabric_id");
chip::Credentials::GroupDataProvider *group_data_provider =
reinterpret_cast<chip::Credentials::GroupDataProvider *>(&m_group_data_provider);
chip::Credentials::GroupDataProvider::KeySet keyset;
keyset.keyset_id = chip::Credentials::GroupDataProvider::kIdentityProtectionKeySetId;
keyset.policy = chip::app::Clusters::GroupKeyManagement::GroupKeySecurityPolicyEnum::kTrustFirst;
keyset.num_keys_used = 1;
keyset.epoch_keys[0].start_time = 0;
memcpy(keyset.epoch_keys[0].key, ipk.data(), chip::Crypto::CHIP_CRYPTO_SYMMETRIC_KEY_LENGTH_BYTES);
ESP_RETURN_ON_FALSE(group_data_provider->SetKeySet(fabric_index, compressed_fabric_id_span, keyset) ==
CHIP_NO_ERROR,
ESP_FAIL, TAG, "Failed to set ipk for commissioner fabric");
}
return ESP_OK;
}
#endif // CONFIG_ESP_MATTER_COMMISSIONER_ENABLE
} // namespace controller
} // namespace esp_matter
@@ -0,0 +1,125 @@
// Copyright 2022 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_log.h>
#include <esp_matter_controller_credentials_issuer.h>
#include <app/icd/client/DefaultICDClientStorage.h>
#include <controller/AutoCommissioner.h>
#include <controller/CHIPDeviceController.h>
#include <controller/CommissionerDiscoveryController.h>
#include <controller/ExampleOperationalCredentialsIssuer.h>
#include <controller/OperationalCredentialsDelegate.h>
#include <credentials/DeviceAttestationCredsProvider.h>
#include <credentials/GroupDataProviderImpl.h>
#include <credentials/PersistentStorageOpCertStore.h>
#include <credentials/attestation_verifier/DeviceAttestationVerifier.h>
#include <crypto/PersistentStorageOperationalKeystore.h>
#include <crypto/RawKeySessionKeystore.h>
#include <lib/core/CHIPError.h>
#include <lib/core/CHIPPersistentStorageDelegate.h>
#include <lib/core/DataModelTypes.h>
#include <lib/support/Span.h>
#include <platform/CHIPDeviceLayer.h>
#include <platform/KeyValueStoreManager.h>
#include <platform/PlatformManager.h>
#include <stdint.h>
#include <transport/TransportMgr.h>
namespace esp_matter {
namespace controller {
#ifndef CONFIG_ESP_MATTER_ENABLE_MATTER_SERVER
class matter_controller_client {
public:
class controller_storage_delegate : public chip::PersistentStorageDelegate {
CHIP_ERROR SyncGetKeyValue(const char *key, void *buffer, uint16_t &size) override
{
ESP_LOGD("MatterController", "Retrieving value from controller storage.");
size_t bytesRead = 0;
CHIP_ERROR err = chip::DeviceLayer::PersistedStorage::KeyValueStoreMgr().Get(key, buffer, size, &bytesRead);
if (err == CHIP_NO_ERROR) {
ESP_LOGD("MatterController", "Retrieved value from controller storage.");
}
size = static_cast<uint16_t>(bytesRead);
return err;
}
CHIP_ERROR SyncSetKeyValue(const char *key, const void *value, uint16_t size) override
{
ESP_LOGD("MatterController", "Stored value in controller storage");
return chip::DeviceLayer::PersistedStorage::KeyValueStoreMgr().Put(key, value, size);
}
CHIP_ERROR SyncDeleteKeyValue(const char *key) override
{
ESP_LOGD("MatterController", "Delete value in controller storage");
return chip::DeviceLayer::PersistedStorage::KeyValueStoreMgr().Delete(key);
}
};
using NodeId = ::chip::NodeId;
using FabricId = ::chip::FabricId;
using MatterDeviceCommissioner = ::chip::Controller::DeviceCommissioner;
using MatterDeviceController = ::chip::Controller::DeviceController;
static constexpr uint16_t k_max_groups_per_fabric = 50;
static constexpr uint16_t k_max_group_keys_per_fabric = 25;
static matter_controller_client &get_instance()
{
static matter_controller_client s_instance;
return s_instance;
}
esp_err_t init(NodeId node_id, FabricId fabric_id, uint16_t listen_port);
#ifdef CONFIG_ESP_MATTER_COMMISSIONER_ENABLE
esp_err_t setup_commissioner();
MatterDeviceCommissioner *get_commissioner() { return &m_device_commissioner; }
#else
esp_err_t setup_controller(chip::MutableByteSpan &ipk);
MatterDeviceController *get_controller() { return &m_device_controller; }
#endif
private:
matter_controller_client() {}
bool m_operational_advertising = true;
controller_storage_delegate m_default_storage;
chip::PersistentStorageOperationalKeystore m_operational_keystore;
chip::Credentials::PersistentStorageOpCertStore m_operational_cert_store;
chip::Crypto::RawKeySessionKeystore m_session_key_store;
chip::Credentials::GroupDataProviderImpl m_group_data_provider{k_max_groups_per_fabric,
k_max_group_keys_per_fabric};
credentials_issuer *m_credentials_issuer;
NodeId m_controller_node_id;
FabricId m_controller_fabric_id;
// TODO: Enable ICD client from ESP32 platform
// chip::app::DefaultICDClientStorage s_icd_client_storage;
#ifdef CONFIG_ESP_MATTER_COMMISSIONER_ENABLE
chip::Controller::AutoCommissioner m_auto_commissioner;
MatterDeviceCommissioner m_device_commissioner;
#else
MatterDeviceController m_device_controller;
#endif
};
#endif // CONFIG_ESP_MATTER_ENABLE_MATTER_SERVER
} // namespace controller
} // namespace esp_matter
@@ -36,8 +36,8 @@
#include <protocols/secure_channel/RendezvousParameters.h>
using chip::NodeId;
using chip::Platform::ScopedMemoryBufferWithSize;
using chip::Inet::IPAddress;
using chip::Platform::ScopedMemoryBufferWithSize;
using chip::Transport::PeerAddress;
const static char *TAG = "controller_console";
@@ -50,7 +50,7 @@ static size_t get_array_size(const char *str)
return 0;
}
size_t ret = 1;
for (size_t i = 0; i < strlen(str); ++ i) {
for (size_t i = 0; i < strlen(str); ++i) {
if (str[i] == ',') {
ret++;
}
@@ -133,7 +133,7 @@ static esp_err_t controller_help_handler(int argc, char **argv)
return ESP_OK;
}
#if CONFIG_ENABLE_ESP32_BLE_CONTROLLER
#if defined(CONFIG_ENABLE_ESP32_BLE_CONTROLLER) && defined(CONFIG_ESP_MATTER_COMMISSIONER_ENABLE)
static int char_to_int(char ch)
{
if ('A' <= ch && ch <= 'F') {
@@ -166,7 +166,7 @@ static bool convert_hex_str_to_bytes(const char *hex_str, uint8_t *bytes, uint8_
}
return true;
}
#endif // CONFIG_ENABLE_ESP32_BLE_CONTROLLER
#endif // defined(CONFIG_ENABLE_ESP32_BLE_CONTROLLER) && defined(CONFIG_ESP_MATTER_COMMISSIONER_ENABLE)
#if CONFIG_ESP_MATTER_COMMISSIONER_ENABLE
static esp_err_t controller_pairing_handler(int argc, char **argv)
@@ -225,7 +225,9 @@ static esp_err_t controller_pairing_handler(int argc, char **argv)
}
return ESP_ERR_INVALID_ARG;
}
#endif // CONFIG_ESP_MATTER_COMMISSIONER_ENABLE
#ifndef CONFIG_ESP_MATTER_ENABLE_MATTER_SERVER
static esp_err_t controller_group_settings_handler(int argc, char **argv)
{
if (argc >= 1) {
@@ -290,7 +292,7 @@ static esp_err_t controller_group_settings_handler(int argc, char **argv)
ESP_LOGI(TAG, "Unbind keyset : controller group-settings unbind-keyset <group_id> <ketset_id>");
return ESP_OK;
}
#endif // CONFIG_ESP_MATTER_COMMISSIONER_ENABLE
#endif
static esp_err_t controller_invoke_command_handler(int argc, char **argv)
{
@@ -416,82 +418,83 @@ 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,
},
#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-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,
},
{
.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-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 = {
@@ -0,0 +1,62 @@
// 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_check.h>
#include <esp_err.h>
#include <esp_matter_controller_credentials_issuer.h>
namespace esp_matter {
namespace controller {
class example_credentials_issuer : public credentials_issuer {
esp_err_t initialize_credentials_issuer(chip::PersistentStorageDelegate &storage) override
{
return m_operational_creds_issuer.Initialize(storage) == CHIP_NO_ERROR ? ESP_OK : ESP_FAIL;
}
chip::Controller::OperationalCredentialsDelegate *get_delegate() override { return &m_operational_creds_issuer; }
esp_err_t generate_controller_noc_chain(chip::NodeId node_id, chip::FabricId fabric_id,
chip::Crypto::P256Keypair &keypair, chip::MutableByteSpan &rcac,
chip::MutableByteSpan &icac, chip::MutableByteSpan &noc) override
{
CHIP_ERROR err = m_operational_creds_issuer.GenerateNOCChainAfterValidation(
node_id, fabric_id, chip::kUndefinedCATs, keypair.Pubkey(), rcac, icac, noc);
return err == CHIP_NO_ERROR ? ESP_OK : ESP_FAIL;
}
private:
chip::Controller::ExampleOperationalCredentialsIssuer m_operational_creds_issuer;
};
static credentials_issuer *s_custom_credentials_issuer = nullptr;
void set_custom_credentials_issuer(credentials_issuer *issuer)
{
s_custom_credentials_issuer = issuer;
}
credentials_issuer *get_credentials_issuer()
{
#ifdef CONFIG_TEST_OPERATIONAL_CREDS_ISSUER
static example_credentials_issuer s_creds_issuer;
return &s_creds_issuer;
#elif defined(CONFIG_CUSTOM_OPERATIONAL_CREDS_ISSUER)
return s_custom_credentials_issuer;
#endif
return nullptr;
}
} // namespace controller
} // namespace esp_matter
@@ -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_check.h>
#include <esp_err.h>
#include <controller/ExampleOperationalCredentialsIssuer.h>
#include <controller/OperationalCredentialsDelegate.h>
#include <crypto/CHIPCryptoPAL.h>
#include <lib/core/CHIPPersistentStorageDelegate.h>
#include <lib/core/DataModelTypes.h>
#include <lib/core/NodeId.h>
#include <lib/support/Span.h>
namespace esp_matter {
namespace controller {
class credentials_issuer {
public:
virtual ~credentials_issuer() {}
/**
* This function is used to initialize the Credentials Issuer, if needed.
*
* @param[in] storage A reference to the storage, where the Credentials Issuer can optionally use to access the
* keypair in storage.
* @return ESP_OK on success
* @return error in case of failure.
*/
virtual esp_err_t initialize_credentials_issuer(chip::PersistentStorageDelegate &storage) = 0;
/**
* This function is used to get the OperationalCredentialsDelegate which is used to generate NOC chains for End
* Devices
*
* @return OperationalCredentialsDelegate of the Controller/Commissioner
*/
virtual chip::Controller::OperationalCredentialsDelegate *get_delegate() = 0;
/**
* This function is used to Generate NOC Chain for the Controller/Commissioner.
*
* @param[in] nodeId The desired NodeId for the generated NOC Chain - May be optional/unused in some
* implementations.
* @param[in] fabricId The desired FabricId for the generated NOC Chain - May be optional/unused in some
* implementations.
* @param[in] keypair The desired Keypair for the generated NOC Chain - May be optional/unused in some
* implementations.
* @param[in,out] rcac Buffer to hold the Root Certificate of the generated NOC Chain.
* @param[in,out] icac Buffer to hold the Intermediate Certificate of the generated NOC Chain.
* @param[in,out] noc Buffer to hold the Leaf Certificate of the generated NOC Chain.
*
* @return ESP_OK on success
* @return error in case of failure.
*/
virtual esp_err_t generate_controller_noc_chain(chip::NodeId node_id, chip::FabricId fabric,
chip::Crypto::P256Keypair &keypair, chip::MutableByteSpan &rcac,
chip::MutableByteSpan &icac, chip::MutableByteSpan &noc) = 0;
};
void set_custom_credentials_issuer(credentials_issuer *issuer);
credentials_issuer *get_credentials_issuer();
} // namespace controller
} // namespace esp_matter
@@ -13,7 +13,7 @@
// limitations under the License.
#include <esp_check.h>
#include <esp_matter_commissioner.h>
#include <esp_matter_controller_client.h>
#include <esp_matter_controller_group_settings.h>
#include <esp_matter_controller_utils.h>
@@ -49,7 +49,12 @@ esp_err_t show_groups()
ESP_LOGI(TAG, " | Available Groups : |");
ESP_LOGI(TAG, " +-------------------------------------------------------------------------------------+");
ESP_LOGI(TAG, " | Group Id | KeySet Id | Group Name |");
FabricIndex fabric_index = commissioner::get_device_commissioner()->GetFabricIndex();
FabricIndex fabric_index =
#ifdef CONFIG_ESP_MATTER_COMMISSIONER_ENABLE
esp_matter::controller::matter_controller_client::get_instance().get_commissioner()->GetFabricIndex();
#else
esp_matter::controller::matter_controller_client::get_instance().get_controller()->GetFabricIndex();
#endif
GroupDataProvider *group_data_provider = chip::Credentials::GetGroupDataProvider();
auto iter = group_data_provider->IterateGroupInfo(fabric_index);
GroupDataProvider::GroupInfo group_info;
@@ -74,7 +79,12 @@ esp_err_t add_group(char *group_name, uint16_t group_id)
return ESP_ERR_INVALID_ARG;
}
FabricIndex fabric_index = commissioner::get_device_commissioner()->GetFabricIndex();
FabricIndex fabric_index =
#ifdef CONFIG_ESP_MATTER_COMMISSIONER_ENABLE
esp_matter::controller::matter_controller_client::get_instance().get_commissioner()->GetFabricIndex();
#else
esp_matter::controller::matter_controller_client::get_instance().get_controller()->GetFabricIndex();
#endif
GroupDataProvider *group_data_provider = chip::Credentials::GetGroupDataProvider();
GroupDataProvider::GroupInfo group_info;
@@ -91,7 +101,12 @@ esp_err_t remove_group(uint16_t group_id)
return ESP_ERR_INVALID_ARG;
}
FabricIndex fabric_index = commissioner::get_device_commissioner()->GetFabricIndex();
FabricIndex fabric_index =
#ifdef CONFIG_ESP_MATTER_COMMISSIONER_ENABLE
esp_matter::controller::matter_controller_client::get_instance().get_commissioner()->GetFabricIndex();
#else
esp_matter::controller::matter_controller_client::get_instance().get_controller()->GetFabricIndex();
#endif
GroupDataProvider *group_data_provider = chip::Credentials::GetGroupDataProvider();
ESP_RETURN_ON_FALSE(CHIP_NO_ERROR == group_data_provider->RemoveGroupInfo(fabric_index, group_id), ESP_FAIL, TAG,
"Failed to remove the group info");
@@ -100,7 +115,12 @@ esp_err_t remove_group(uint16_t group_id)
esp_err_t show_keysets()
{
FabricIndex fabric_index = commissioner::get_device_commissioner()->GetFabricIndex();
FabricIndex fabric_index =
#ifdef CONFIG_ESP_MATTER_COMMISSIONER_ENABLE
esp_matter::controller::matter_controller_client::get_instance().get_commissioner()->GetFabricIndex();
#else
esp_matter::controller::matter_controller_client::get_instance().get_controller()->GetFabricIndex();
#endif
GroupDataProvider *group_data_provider = chip::Credentials::GetGroupDataProvider();
GroupDataProvider::KeySet keyset;
@@ -125,7 +145,12 @@ esp_err_t show_keysets()
esp_err_t bind_keyset(uint16_t group_id, uint16_t keyset_id)
{
size_t current_count = 0;
FabricIndex fabric_index = commissioner::get_device_commissioner()->GetFabricIndex();
FabricIndex fabric_index =
#ifdef CONFIG_ESP_MATTER_COMMISSIONER_ENABLE
esp_matter::controller::matter_controller_client::get_instance().get_commissioner()->GetFabricIndex();
#else
esp_matter::controller::matter_controller_client::get_instance().get_controller()->GetFabricIndex();
#endif
GroupDataProvider *group_data_provider = chip::Credentials::GetGroupDataProvider();
auto iter = group_data_provider->IterateGroupKeys(fabric_index);
@@ -144,7 +169,12 @@ esp_err_t bind_keyset(uint16_t group_id, uint16_t keyset_id)
esp_err_t unbind_keyset(uint16_t group_id, uint16_t keyset_id)
{
size_t index = 0;
FabricIndex fabric_index = commissioner::get_device_commissioner()->GetFabricIndex();
FabricIndex fabric_index =
#ifdef CONFIG_ESP_MATTER_COMMISSIONER_ENABLE
esp_matter::controller::matter_controller_client::get_instance().get_commissioner()->GetFabricIndex();
#else
esp_matter::controller::matter_controller_client::get_instance().get_controller()->GetFabricIndex();
#endif
GroupDataProvider *group_data_provider = chip::Credentials::GetGroupDataProvider();
auto iter = group_data_provider->IterateGroupKeys(fabric_index);
@@ -165,12 +195,23 @@ esp_err_t unbind_keyset(uint16_t group_id, uint16_t keyset_id)
esp_err_t add_keyset(uint16_t keyset_id, uint8_t key_policy, uint64_t validity_time, char *epoch_key_oct_str)
{
FabricIndex fabric_index = commissioner::get_device_commissioner()->GetFabricIndex();
auto &controller_instance = esp_matter::controller::matter_controller_client::get_instance();
FabricIndex fabric_index =
#ifdef CONFIG_ESP_MATTER_COMMISSIONER_ENABLE
controller_instance.get_commissioner()->GetFabricIndex();
#else
controller_instance.get_controller()->GetFabricIndex();
#endif
GroupDataProvider *group_data_provider = chip::Credentials::GetGroupDataProvider();
uint8_t compressed_fabric_id[sizeof(uint64_t)];
chip::MutableByteSpan compressed_fabric_id_span(compressed_fabric_id);
if (CHIP_NO_ERROR !=
commissioner::get_device_commissioner()->GetCompressedFabricIdBytes(compressed_fabric_id_span)) {
#ifdef CONFIG_ESP_MATTER_COMMISSIONER_ENABLE
controller_instance.get_commissioner()->GetCompressedFabricIdBytes(compressed_fabric_id_span)) {
#else
controller_instance.get_controller()->GetCompressedFabricIdBytes(compressed_fabric_id_span)) {
#endif
ESP_LOGE(TAG, "Failed to get the compressed fabric_id");
return ESP_FAIL;
}
@@ -197,7 +238,12 @@ esp_err_t add_keyset(uint16_t keyset_id, uint8_t key_policy, uint64_t validity_t
esp_err_t remove_keyset(uint16_t keyset_id)
{
FabricIndex fabric_index = commissioner::get_device_commissioner()->GetFabricIndex();
FabricIndex fabric_index =
#ifdef CONFIG_ESP_MATTER_COMMISSIONER_ENABLE
esp_matter::controller::matter_controller_client::get_instance().get_commissioner()->GetFabricIndex();
#else
esp_matter::controller::matter_controller_client::get_instance().get_controller()->GetFabricIndex();
#endif
GroupDataProvider *group_data_provider = chip::Credentials::GetGroupDataProvider();
size_t index = 0;
@@ -18,21 +18,82 @@
namespace esp_matter {
namespace controller {
namespace group_settings {
/** Group management functions for the client only controller **/
/**
* Print groups information
*/
esp_err_t show_groups();
/**
* Add a group
*
* @param[in] group_name Group name
* @param[in] group_id Group ID
*
* @return ESP_OK on success
* @return error in case of failure
*/
esp_err_t add_group(char *group_name, uint16_t group_id);
/**
* Leave a group
*
* @param[in] group_id Group ID
*
* @return ESP_OK on success
* @return error in case of failure
*/
esp_err_t remove_group(uint16_t group_id);
/**
* Print group keysets
*/
esp_err_t show_keysets();
/**
* Bind a group keyset to a group
*
* @param[in] group_id Group ID
* @param[in] keyset_id Group Keyset ID
*
* @return ESP_OK on success
* @return error in case of failure
*/
esp_err_t bind_keyset(uint16_t group_id, uint16_t keyset_id);
/**
* Unbind a group keyset to a group
*
* @param[in] group_id Group ID
* @param[in] keyset_id Group Keyset ID
*
* @return ESP_OK on success
* @return error in case of failure
*/
esp_err_t unbind_keyset(uint16_t group_id, uint16_t keyset_id);
/**
* Add a group keyset
*
* @param[in] keyset_id Group Keyset ID
* @param[in] key_policy Key policy
* @param[in] validity_time Validity time for the keyset in second
* @param[in] epoch_key_oct_str Octet string of the Epoch key
*
* @return ESP_OK on success
* @return error in case of failure
*/
esp_err_t add_keyset(uint16_t keyset_id, uint8_t key_policy, uint64_t validity_time, char *epoch_key_oct_str);
/**
* Remove a group keyset
*
* @param[in] keyset_id Group Keyset ID
*
* @return ESP_OK on success
* @return error in case of failure
*/
esp_err_t remove_keyset(uint16_t keyset_id);
} // namespace group_settings
@@ -18,7 +18,7 @@
namespace esp_matter {
namespace controller {
#if !CONFIG_ESP_MATTER_COMMISSIONER_ENABLE
#ifdef CONFIG_ESP_MATTER_ENABLE_MATTER_SERVER
uint8_t s_controller_fabric_index = chip::kUndefinedFabricIndex;
void set_fabric_index(uint8_t fabric_index)
@@ -30,7 +30,7 @@ uint8_t get_fabric_index(void)
{
return s_controller_fabric_index;
}
#endif // !CONFIG_ESP_MATTER_COMMISSIONER_ENABLE
#endif // CONFIG_ESP_MATTER_ENABLE_MATTER_SERVER
} // namespace controller
} // namespace esp_matter
@@ -16,14 +16,14 @@
#include <stdint.h>
#include <app/ConcreteAttributePath.h>
#include <app/AttributePathParams.h>
#include <app/ConcreteAttributePath.h>
#include <app/EventHeader.h>
#include <lib/core/TLVReader.h>
using chip::Platform::ScopedMemoryBufferWithSize;
using chip::app::AttributePathParams;
using chip::app::EventPathParams;
using chip::Platform::ScopedMemoryBufferWithSize;
namespace esp_matter {
namespace controller {
@@ -33,15 +33,16 @@ using event_report_cb_t = void (*)(uint64_t remote_node_id, const chip::app::Eve
chip::TLV::TLVReader *data);
using subscribe_done_cb_t = void (*)(uint64_t remote_node_id, uint32_t subscription_id);
using subscribe_failure_cb_t = void (*)(void *subscribe_command);
using read_done_cb_t = void (*)(uint64_t remote_node_id, const ScopedMemoryBufferWithSize<AttributePathParams> &attr_paths,
using read_done_cb_t = void (*)(uint64_t remote_node_id,
const ScopedMemoryBufferWithSize<AttributePathParams> &attr_paths,
const ScopedMemoryBufferWithSize<EventPathParams> &EventPathParams);
#if !CONFIG_ESP_MATTER_COMMISSIONER_ENABLE
#if CONFIG_ESP_MATTER_ENABLE_MATTER_SERVER
/**
* @brief Set the fabric index of the controller.
* The controller should be able to send commands to the devices on this fabric.
*
* This should be called after the controller is added to the fabric.
* If Matter server is enabled on the controller, the controller could join multiple fabrics.
* We should choose one on which the controller is able to send commands to other end-devices.
* This should be called after the controller server is added to the fabric.
*/
void set_fabric_index(uint8_t fabric_index);
@@ -50,7 +51,7 @@ void set_fabric_index(uint8_t fabric_index);
*
*/
uint8_t get_fabric_index();
#endif // !CONFIG_ESP_MATTER_COMMISSIONER_ENABLE
#endif // CONFIG_ESP_MATTER_ENABLE_MATTER_SERVER
} // namespace controller
} // namespace esp_matter
@@ -1,247 +0,0 @@
// Copyright 2022 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 <app/clusters/network-commissioning/network-commissioning.h>
#include <app/server/Dnssd.h>
#include <app/server/OnboardingCodesUtil.h>
#include <app/server/Server.h>
#include <controller/CHIPDeviceControllerFactory.h>
#include <controller/ExampleOperationalCredentialsIssuer.h>
#include <credentials/GroupDataProviderImpl.h>
#include <credentials/attestation_verifier/DefaultDeviceAttestationVerifier.h>
#include <crypto/CHIPCryptoPAL.h>
#include <esp_heap_caps.h>
#include <esp_matter_attestation_trust_store.h>
#include <esp_matter_commissioner.h>
#include <esp_matter_controller_pairing_command.h>
#include <lib/support/TestGroupData.h>
#include <platform/DeviceInstanceInfoProvider.h>
#include <platform/DiagnosticDataProvider.h>
#if CONFIG_ENABLE_ESP32_BLE_CONTROLLER
#include <platform/internal/BLEManager.h>
#include <platform/ESP32/BLEManagerImpl.h>
#endif
using namespace chip;
using namespace chip::Credentials;
using namespace chip::DeviceLayer;
using namespace chip::Inet;
using namespace chip::Transport;
using namespace chip::app::Clusters;
using namespace chip::Controller;
using namespace chip::Messaging;
using namespace esp_matter::controller;
class ControllerServerStorageDelegate : public PersistentStorageDelegate {
CHIP_ERROR SyncGetKeyValue(const char *key, void *buffer, uint16_t &size) override
{
ChipLogProgress(AppServer, "Retrieving value from controller server storage.");
size_t bytesRead = 0;
CHIP_ERROR err = PersistedStorage::KeyValueStoreMgr().Get(key, buffer, size, &bytesRead);
if (err == CHIP_NO_ERROR) {
ChipLogProgress(AppServer, "Retrieved value from server storage.");
}
size = static_cast<uint16_t>(bytesRead);
return err;
}
CHIP_ERROR SyncSetKeyValue(const char *key, const void *value, uint16_t size) override
{
ChipLogProgress(AppServer, "Stored value in server storage");
return PersistedStorage::KeyValueStoreMgr().Put(key, value, size);
}
CHIP_ERROR SyncDeleteKeyValue(const char *key) override
{
ChipLogProgress(AppServer, "Delete value in server storage");
return PersistedStorage::KeyValueStoreMgr().Delete(key);
}
};
constexpr uint64_t LOCAL_NODE_ID = 112233;
ControllerServerStorageDelegate controller_server_storage;
ExampleOperationalCredentialsIssuer op_creds_issuer;
NodeId local_node_id = LOCAL_NODE_ID;
Credentials::GroupDataProviderImpl group_data_provider;
AutoCommissioner auto_commissioner;
class ESPCommissionerCallback : public CommissionerCallback {
void ReadyForCommissioning(uint32_t pincode, uint16_t discriminator, PeerAddress peerAddress) override
{
esp_matter::controller::pairing_on_network(pincode, pairing_command::get_instance().m_remote_node_id);
}
};
ESPCommissionerCallback commissioner_callback;
DeviceCommissioner device_commissioner;
CommissionerDiscoveryController commissioner_discovery_controller;
Crypto::RawKeySessionKeystore session_keystore;
constexpr uint16_t kUdcListenPort = 5560;
namespace esp_matter {
namespace commissioner {
esp_err_t init(uint16_t commissioner_port)
{
#if CONFIG_ENABLE_ESP32_BLE_CONTROLLER
CHIP_ERROR err = chip::DeviceLayer::Internal::BLEMgr().Init();
err = chip::DeviceLayer::Internal::BLEMgrImpl().ConfigureBle(0, true);
if (err != CHIP_NO_ERROR) {
ChipLogError(DeviceLayer, "BLEManager initialization failed: %s", ErrorStr(err));
return ESP_FAIL;
}
#endif
Controller::FactoryInitParams factoryParams;
Controller::SetupParams setupParams;
// use a different listen port for the commissioner
factoryParams.listenPort = commissioner_port;
factoryParams.fabricIndependentStorage = &controller_server_storage;
factoryParams.fabricTable = &Server::GetInstance().GetFabricTable();
factoryParams.sessionKeystore = &session_keystore;
group_data_provider.SetStorageDelegate(&controller_server_storage);
group_data_provider.SetSessionKeystore(factoryParams.sessionKeystore);
if (group_data_provider.Init() != CHIP_NO_ERROR) {
return ESP_FAIL;
}
factoryParams.groupDataProvider = reinterpret_cast<Credentials::GroupDataProvider *>(&group_data_provider);
setupParams.operationalCredentialsDelegate = &op_creds_issuer;
uint16_t vendor_id;
DeviceLayer::GetDeviceInstanceInfoProvider()->GetVendorId(vendor_id);
ChipLogProgress(Support, " ----- Commissioner using vendorId 0x%04X", vendor_id);
setupParams.controllerVendorId = static_cast<VendorId>(vendor_id);
if (op_creds_issuer.Initialize(controller_server_storage) != CHIP_NO_ERROR) {
return ESP_FAIL;
}
ChipLogProgress(Support, " ----- UDC listening on port %d", kUdcListenPort);
if (device_commissioner.SetUdcListenPort(kUdcListenPort) != CHIP_NO_ERROR) {
return ESP_FAIL;
}
const Credentials::AttestationTrustStore *testingRootStore = Credentials::get_attestation_trust_store();
SetDeviceAttestationVerifier(GetDefaultDACVerifier(testingRootStore));
Platform::ScopedMemoryBuffer<uint8_t> noc;
if (!noc.Alloc(Controller::kMaxCHIPDERCertLength)) {
return ESP_ERR_NO_MEM;
}
MutableByteSpan nocSpan(noc.Get(), Controller::kMaxCHIPDERCertLength);
Platform::ScopedMemoryBuffer<uint8_t> icac;
if (!icac.Alloc(Controller::kMaxCHIPDERCertLength)) {
return ESP_ERR_NO_MEM;
}
MutableByteSpan icacSpan(icac.Get(), Controller::kMaxCHIPDERCertLength);
Platform::ScopedMemoryBuffer<uint8_t> rcac;
if (!rcac.Alloc(Controller::kMaxCHIPDERCertLength)) {
return ESP_ERR_NO_MEM;
}
MutableByteSpan rcacSpan(rcac.Get(), Controller::kMaxCHIPDERCertLength);
Crypto::P256Keypair ephemeralKey;
if (ephemeralKey.Initialize(Crypto::ECPKeyTarget::ECDSA) != CHIP_NO_ERROR) {
return ESP_FAIL;
}
if (op_creds_issuer.GenerateNOCChainAfterValidation(local_node_id, /* fabricId = */ 1, chip::kUndefinedCATs,
ephemeralKey.Pubkey(), rcacSpan, icacSpan,
nocSpan) != CHIP_NO_ERROR) {
return ESP_FAIL;
}
setupParams.operationalKeypair = &ephemeralKey;
setupParams.controllerRCAC = rcacSpan;
setupParams.controllerICAC = icacSpan;
setupParams.controllerNOC = nocSpan;
setupParams.defaultCommissioner = &auto_commissioner;
auto &factory = Controller::DeviceControllerFactory::GetInstance();
if (factory.Init(factoryParams) != CHIP_NO_ERROR) {
return ESP_FAIL;
}
if (factory.SetupCommissioner(setupParams, *get_device_commissioner()) != CHIP_NO_ERROR) {
return ESP_FAIL;
}
FabricIndex fabricIndex = device_commissioner.GetFabricIndex();
if (fabricIndex == kUndefinedFabricIndex) {
return ESP_FAIL;
}
uint8_t compressedFabricId[sizeof(uint64_t)] = {0};
MutableByteSpan compressedFabricIdSpan(compressedFabricId);
if (device_commissioner.GetCompressedFabricIdBytes(compressedFabricIdSpan) != CHIP_NO_ERROR) {
return ESP_FAIL;
}
ChipLogProgress(Support, "Setting up group data for Fabric Index %u with Compressed Fabric ID:",
static_cast<unsigned>(fabricIndex));
ChipLogByteSpan(Support, compressedFabricIdSpan);
// TODO: Once ExampleOperationalCredentialsIssuer has support, set default IPK on it as well so
// that commissioned devices get the IPK set from real values rather than "test-only" internal hookups.
ByteSpan defaultIpk = chip::GroupTesting::DefaultIpkValue::GetDefaultIpk();
if (CHIP_NO_ERROR !=
chip::Credentials::SetSingleIpkEpochKey(reinterpret_cast<GroupDataProvider *>(&group_data_provider),
fabricIndex, defaultIpk, compressedFabricIdSpan)) {
return ESP_FAIL;
}
get_discovery_controller()->SetUserDirectedCommissioningServer(
get_device_commissioner()->GetUserDirectedCommissioningServer());
get_discovery_controller()->SetCommissionerCallback(&commissioner_callback);
get_device_commissioner()->RegisterPairingDelegate(&pairing_command::get_instance());
ChipLogProgress(Support, "InitCommissioner nodeId=0x" ChipLogFormatX64 " fabricIndex=0x%x",
ChipLogValueX64(get_device_commissioner()->GetNodeId()), static_cast<unsigned>(fabricIndex));
return ESP_OK;
}
void shutdown()
{
UserDirectedCommissioningServer *udcServer = get_device_commissioner()->GetUserDirectedCommissioningServer();
if (udcServer != nullptr) {
udcServer->SetUserConfirmationProvider(nullptr);
}
get_device_commissioner()->Shutdown();
}
DeviceCommissioner *get_device_commissioner()
{
return &device_commissioner;
}
CommissionerDiscoveryController *get_discovery_controller()
{
return &commissioner_discovery_controller;
}
AutoCommissioner *get_auto_commissioner()
{
return &auto_commissioner;
}
} // namespace commissioner
} // namespace esp_matter
@@ -1,43 +0,0 @@
// Copyright 2022 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 <controller/CHIPDeviceController.h>
#include <controller/CommissionerDiscoveryController.h>
#include <credentials/DeviceAttestationCredsProvider.h>
#include <lib/core/CHIPError.h>
#include <platform/CHIPDeviceLayer.h>
#include <platform/PlatformManager.h>
#include <transport/TransportMgr.h>
#if CONFIG_ESP_MATTER_COMMISSIONER_ENABLE
using chip::NodeId;
using chip::Controller::AutoCommissioner;
using chip::Controller::DeviceCommissioner;
using chip::Controller::DevicePairingDelegate;
using chip::Transport::PeerAddress;
namespace esp_matter {
namespace commissioner {
esp_err_t init(uint16_t commissioner_port);
void shutdown();
DeviceCommissioner *get_device_commissioner();
CommissionerDiscoveryController *get_discovery_controller();
AutoCommissioner *get_auto_commissioner();
} // namespace commissioner
} // namespace esp_matter
#endif // CONFIG_ESP_MATTER_COMMISSIONER_ENABLE
-5
View File
@@ -37,11 +37,6 @@ project(controller)
idf_build_set_property(CXX_COMPILE_OPTIONS "-std=gnu++17;-Os;-DCHIP_HAVE_CONFIG_H" APPEND)
idf_build_set_property(C_COMPILE_OPTIONS "-Os" APPEND)
if (CONFIG_ESP_MATTER_COMMISSIONER_ENABLE)
idf_build_set_property(CXX_COMPILE_OPTIONS "-DCHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY=1;-DCHIP_CONFIG_CONTROLLER_MAX_ACTIVE_DEVICES=${CONFIG_ESP_MATTER_COMMISSIONER_MAX_ACTIVE_DEVICES}" APPEND)
idf_build_set_property(C_COMPILE_OPTIONS "-DCHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY=1;-DCHIP_CONFIG_CONTROLLER_MAX_ACTIVE_DEVICES=${CONFIG_ESP_MATTER_COMMISSIONER_MAX_ACTIVE_DEVICES}" APPEND)
endif()
# For RISCV chips, project_include.cmake sets -Wno-format, but does not clear various
# flags that depend on -Wformat
idf_build_set_property(COMPILE_OPTIONS "-Wno-format-nonliteral;-Wno-format-security" APPEND)
+5 -6
View File
@@ -38,10 +38,10 @@ idf.py -p <PORT> erase-flash flash monitor
### 4.3 Pair and Control
- Pairing the controller with chip-tool
- Connect the controller to Wi-Fi network with the device console
```
./chip-tool pairing ble-wifi 0x7483 <ssid> <password> 20202021 3840
matter esp wifi connect {ssid} {password}
```
- Initializing a new Thread network dataset and commit it as the active one
@@ -64,17 +64,16 @@ matter esp ot_cli ifconfig up
matter esp ot_cli thread start
```
- Pairing the Thread end-device with chip-tool and write the ACL
- Pairing the Thread end-device
```
./chip-tool pairing ble-thread 0x7484 hex:<dataset_tlvs> 20202021 3840
./chip-tool accesscontrol write acl '[{"fabricIndex": 1, "privilege": 5, "authMode": 2, "subjects": [112233, 25731], "targets":null}]' 0x7484 0
matter esp controller pairing ble-thread 1234 <dataset_tlvs> 20202021 3840
```
- Control the Thread end-device on the device console (On/Off cluster Toggle command)
```
matter esp controller invoke-cmd 0x7484 1 6 2
matter esp controller invoke-cmd 1234 1 6 2
```
## A1 Appendix FAQs
+4 -22
View File
@@ -11,15 +11,11 @@
#include <nvs_flash.h>
#include <esp_matter.h>
#include <esp_matter_commissioner.h>
#include <esp_matter_controller_client.h>
#include <esp_matter_console.h>
#include <esp_matter_controller_console.h>
#include <esp_matter_controller_utils.h>
#include <esp_matter_ota.h>
#if CONFIG_ESP_MATTER_CONTROLLER_CUSTOM_CLUSTER_ENABLE
#include <matter_controller_cluster.h>
#include <matter_controller_device_mgr.h>
#endif // CONFIG_ESP_MATTER_CONTROLLER_CUSTOM_CLUSTER_ENABLE
#if CONFIG_OPENTHREAD_BORDER_ROUTER
#include <esp_matter_thread_br_console.h>
#include <esp_matter_thread_br_launcher.h>
@@ -53,14 +49,8 @@ static void app_event_cb(const ChipDeviceEvent *event, intptr_t arg)
.host_config = ESP_OPENTHREAD_DEFAULT_HOST_CONFIG(),
.port_config = ESP_OPENTHREAD_DEFAULT_PORT_CONFIG(),
};
printf("init thread br\n");
esp_matter::thread_br_init(&config);
#endif
#if !CONFIG_ESP_MATTER_COMMISSIONER_ENABLE
// Check whether fabric exists at index 1, if yes, set the controller fabric index to 1.
// If you controller works on other fabrics, please set the fabric index to another value.
if (chip::Server::GetInstance().GetFabricTable().FindFabricWithIndex(1)) {
esp_matter::controller::set_fabric_index(1);
}
#endif
}
break;
@@ -86,22 +76,14 @@ extern "C" void app_main()
esp_matter::console::thread_br_cli_register_command();
#endif // CONFIG_OPENTHREAD_BORDER_ROUTER && CONFIG_OPENTHREAD_CLI
#endif // CONFIG_ENABLE_CHIP_SHELL
#if !CONFIG_ESP_MATTER_COMMISSIONER_ENABLE
// If there is no commissioner in the controller, we need a default node so that the controller can be commissioned
// to a specific fabric.
node::config_t node_config;
node_t *node = node::create(&node_config, NULL, NULL);
ABORT_APP_ON_FAILURE(node != nullptr, ESP_LOGE(TAG, "Failed to create Matter node"));
#endif // !CONFIG_ESP_MATTER_COMMISSIONER_ENABLE
/* Matter start */
err = esp_matter::start(app_event_cb);
ABORT_APP_ON_FAILURE(err == ESP_OK, ESP_LOGE(TAG, "Failed to start Matter, err:%d", err));
#if CONFIG_ESP_MATTER_COMMISSIONER_ENABLE
esp_matter::lock::chip_stack_lock(portMAX_DELAY);
esp_matter::commissioner::init(5580);
esp_matter::controller::matter_controller_client::get_instance().init(112233, 1, 5580);
esp_matter::controller::matter_controller_client::get_instance().setup_commissioner();
esp_matter::lock::chip_stack_unlock();
#endif // CONFIG_ESP_MATTER_COMMISSIONER_ENABLE
}
+1 -1
View File
@@ -28,7 +28,7 @@
{ \
.radio_mode = RADIO_MODE_UART_RCP, \
.radio_uart_config = { \
.port = 1, \
.port = UART_NUM_1, \
.uart_config = \
{ \
.baud_rate = 460800, \
@@ -0,0 +1,15 @@
#pragma once
#include <sdkconfig.h>
#ifndef CONFIG_ESP_MATTER_ENABLE_MATTER_SERVER
#ifdef CONFIG_ESP_MATTER_COMMISSIONER_ENABLE
// Enable or disable whether this device advertises as a commissioner.
#define CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONER_DISCOVERY 1
#endif // CONFIG_ESP_MATTER_COMMISSIONER_ENABLE
// Number of devices a controller can be simultaneously connected to
#define CHIP_CONFIG_CONTROLLER_MAX_ACTIVE_DEVICES 8
#endif // CONFIG_ESP_MATTER_ENABLE_MATTER_SERVER
+3
View File
@@ -50,3 +50,6 @@ CONFIG_MBEDTLS_HKDF_C=y
# Increase LwIP IPv6 address number to 6 (MAX_FABRIC + 1)
# unique local addresses for fabrics(MAX_FABRIC), a link local address(1)
CONFIG_LWIP_IPV6_NUM_ADDRESSES=6
# Enable project configurations
CONFIG_CHIP_PROJECT_CONFIG="main/matter_project_config.h"
@@ -5,3 +5,6 @@ CONFIG_ENABLE_ESP32_BLE_CONTROLLER=y
# Disable using ble for commissioning
CONFIG_USE_BLE_ONLY_FOR_COMMISSIONING=n
# Disable Matter server
CONFIG_ESP_MATTER_ENABLE_MATTER_SERVER=n
+19 -2
View File
@@ -44,9 +44,10 @@ CONFIG_MDNS_MULTIPLE_INSTANCE=y
# Enable chip shell
CONFIG_ENABLE_CHIP_SHELL=y
CONFIG_ESP_MATTER_CONSOLE_TASK_STACK=4096
CONFIG_CHIP_SHELL_CMD_LINE_BUF_MAX_LENGTH=512
# Increase Stack size
CONFIG_CHIP_TASK_STACK_SIZE=10240
CONFIG_CHIP_TASK_STACK_SIZE=15360
CONFIG_ESP_MAIN_TASK_STACK_SIZE=8192
# Wi-Fi Settings
@@ -54,8 +55,10 @@ CONFIG_ENABLE_WIFI_STATION=y
CONFIG_ENABLE_WIFI_AP=n
# Enable Controller and disable commissioner
CONFIG_ESP_MATTER_ENABLE_MATTER_SERVER=n
CONFIG_ENABLE_CHIP_CONTROLLER_BUILD=y
CONFIG_ESP_MATTER_CONTROLLER_ENABLE=y
CONFIG_ESP_MATTER_COMMISSIONER_ENABLE=n
CONFIG_ESP_MATTER_COMMISSIONER_ENABLE=y
CONFIG_ESP_MATTER_CONTROLLER_CUSTOM_CLUSTER_ENABLE=n
# Disable chip test build
@@ -72,3 +75,17 @@ CONFIG_ENABLE_ROUTE_HOOK=n
# Use USB Jtag Console
CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG=y
# Enable project configurations
CONFIG_CHIP_PROJECT_CONFIG="main/matter_project_config.h"
# Enable ble controller
CONFIG_ENABLE_ESP32_BLE_CONTROLLER=y
# SPIRAM
CONFIG_SPIRAM=y
CONFIG_SPIRAM_SPEED_80M=y
CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL=512
CONFIG_SPIRAM_MALLOC_RESERVE_INTERNAL=8192
CONFIG_SPIRAM_ALLOW_BSS_SEG_EXTERNAL_MEMORY=y
CONFIG_SPIRAM_TRY_ALLOCATE_WIFI_LWIP=y