app_rainmaker: Add support for custom rainmaker cluster

This also adds the custom attribute and custom command for required user node association.
sdkconfig.defauls: Setting self claim by default. This does not get set for esp32, since the config option is not valid for esp32.
This commit is contained in:
Chirag Atal
2022-03-14 19:30:51 +05:30
parent e1d328e109
commit 11d0bb9733
10 changed files with 198 additions and 26 deletions
+21 -6
View File
@@ -35,7 +35,7 @@ export ESP_RMAKER_PATH=/path/to/esp-rainmaker
### RainMaker Claiming
This need to be done before flashing the firmware. Note the mac address of the device.
If self-claiming is not enabled/supported, this need to be done before flashing the firmware.
RainMaker CLI:
```
@@ -45,19 +45,34 @@ $ rainmaker.py claim --addr 0x3E0000 $ESPPORT
### RainMaker User-Node Association
This need to be done after commissioning.
This needs to be done after commissioning.
Check if the device already has user node association done, using the custom RainMaker cluster (cluster_id: 0xc00):
```
$ ./out/debug/chip-tool any read-by-id 0xc00 0x0 0x1 0x0
```
* If the above custom status attribute (attribute_id: 0x0) returns true, the association has already been done.
* If the attribute returns false, the association has not been done. And the below custom configuration command
(command_id: 0x0) can be used to do the association.
RainMaker CLI:
Get the details: This will print the user_id and secret_key (do not close this):
```
$ rainmaker.py test --addnode <node-id>
>> add-user <user-id> <secret-key>
```
This will print the console command to be run on the device:
Prepare the command payload: Use the above details.
```
add-user <user-id> <secret-key>
payload: <user_id>::<secret_key>
```
Use these details in the below command on the device console.
Now use the payload to run the RainMaker configuration command from chip-tool:
```
matter esp rainmaker add-user <user-id> <secret-key>
$ ./out/debug/chip-tool any command-by-id 0xc00 0x0 '"<user_id>::<secret_key>"' 0x1 0x0
```
The device/node should now be associated with the user.
+14 -2
View File
@@ -55,6 +55,14 @@ static esp_err_t app_attribute_update_cb(esp_matter_callback_type_t type, int en
return err;
}
esp_err_t app_command_callback(int endpoint_id, int cluster_id, int command_id, TLVReader &tlv_data, void *priv_data)
{
esp_err_t err = ESP_OK;
/* Pass all the commands to all the ecosystems, if their command callbacks exist */
err = app_rainmaker_command_callback(endpoint_id, cluster_id, command_id, tlv_data, priv_data);
return err;
}
extern "C" void app_main()
{
esp_err_t err = ESP_OK;
@@ -81,6 +89,10 @@ extern "C" void app_main()
/* Initialize driver */
app_driver_init();
/* Initialize rainmaker */
esp_matter_command_set_custom_callback(app_command_callback, NULL);
app_rainmaker_init();
/* Matter start */
err = esp_matter_start(app_event_cb);
if (err != ESP_OK) {
@@ -88,8 +100,8 @@ extern "C" void app_main()
}
app_qrcode_print();
/* Initialize rainmaker */
app_rainmaker_init();
/* Start rainmaker */
app_rainmaker_start();
#if CONFIG_ENABLE_CHIP_SHELL
esp_matter_console_diagnostics_register_commands();
@@ -334,7 +334,124 @@ static void app_rainmaker_device_create()
}
}
#define ESP_MATTER_RAINMAKER_ENDPOINT_ID 0x0 /* Same as root node endpoint. This will always be endpoint_id 0. */
#define ESP_MATTER_RAINMAKER_CLUSTER_ID 0x131B0000 /* 0x131B == manufacturer code */
#define ESP_MATTER_RAINMAKER_STATUS_ATTRIBUTE_ID 0x0
#define ESP_MATTER_RAINMAKER_CONFIGURATION_COMMAND_ID 0x0
#define ESP_MATTER_RAINMAKER_CLUSTER_REVISION 1
#define ESP_MATTER_RAINMAKER_COMMAND_LIMIT 5 /* This command can be called 5 times per reboot */
#define ESP_MATTER_RAINMAKER_MAX_DATA_LEN 40
static esp_err_t app_rainmaker_status_attribute_update(bool status)
{
int endpoint_id = ESP_MATTER_RAINMAKER_ENDPOINT_ID;
int cluster_id = ESP_MATTER_RAINMAKER_CLUSTER_ID;
int attribute_id = ESP_MATTER_RAINMAKER_STATUS_ATTRIBUTE_ID;
esp_matter_attr_val_t val = esp_matter_bool(status);
return esp_matter_attribute_update(endpoint_id, cluster_id, attribute_id, &val);
}
static void app_rainmaker_user_node_association_event_handler(void* arg, esp_event_base_t event_base, int32_t event_id,
void* event_data)
{
/* This event handler is only for user node association status */
if (event_base == RMAKER_EVENT) {
if (event_id == RMAKER_EVENT_USER_NODE_MAPPING_DONE) {
ESP_LOGI(TAG, "User node association complete. Updating the status attribute.");
app_rainmaker_status_attribute_update(true);
} else if (event_id == RMAKER_EVENT_USER_NODE_MAPPING_RESET) {
ESP_LOGI(TAG, "User node association reset. Updating the status attribute.");
app_rainmaker_status_attribute_update(false);
}
}
}
esp_err_t app_rainmaker_command_callback(int endpoint_id, int cluster_id, int command_id, TLVReader &tlv_data,
void *priv_data)
{
/* Return if this is not the rainmaker configuration command */
if (endpoint_id != ESP_MATTER_RAINMAKER_ENDPOINT_ID || cluster_id != ESP_MATTER_RAINMAKER_CLUSTER_ID
|| command_id != ESP_MATTER_RAINMAKER_CONFIGURATION_COMMAND_ID) {
return ESP_OK;
}
ESP_LOGI(TAG, "RainMaker configuration command callback");
static int command_count = ESP_MATTER_RAINMAKER_COMMAND_LIMIT;
if (command_count <= 0) {
ESP_LOGE(TAG, "This command has reached a limit. Please reboot to try again.");
return ESP_FAIL;
}
command_count--;
/* Parse the tlv data */
chip::CharSpan config_value;
chip::app::DataModel::Decode(tlv_data, config_value);
const char *data = config_value.data();
int size = config_value.size();
/* The expected format of the data is "<user_id>::<secret_key>" */
char ch = ':';
char *check = strchr(data, (int)ch);
if (check == NULL) {
ESP_LOGE(TAG, "':' not found in the received data: %.*s. The expected format is \"<user_id>::<secret_key>\"",
size, data);
return ESP_FAIL;
}
/* Get sizes */
int user_id_index = 0;
int user_id_len = (int)(strchr(data, (int)ch) - data); /* (first ':') - (start of string) */
int secret_key_index = (int)(strrchr(data, (int)ch) - data) + 1; /* (last ':') - (start of string) + 1 */
int secret_key_len = size - secret_key_index;
if (user_id_len <= 0 || user_id_len >= ESP_MATTER_RAINMAKER_MAX_DATA_LEN || secret_key_len <= 0
|| secret_key_len >= ESP_MATTER_RAINMAKER_MAX_DATA_LEN) {
ESP_LOGE(TAG, "User id or secret key length invalid: user_id_len: %d, secret_key_len: %d", user_id_len,
secret_key_len);
return ESP_FAIL;
}
/* Copy the data. This done to make the strings NULL terminated. */
char user_id[ESP_MATTER_RAINMAKER_MAX_DATA_LEN] = {0};
char secret_key[ESP_MATTER_RAINMAKER_MAX_DATA_LEN] = {0};
strncpy(user_id, &data[user_id_index], user_id_len);
strncpy(secret_key, &data[secret_key_index], secret_key_len);
ESP_LOGI(TAG, "user_id: %s, secret_key: %s", user_id, secret_key);
/* Call the rainmaker API */
if (strlen(user_id) > 0 && strlen(secret_key) > 0) {
esp_rmaker_start_user_node_mapping(user_id, secret_key);
}
return ESP_OK;
}
esp_err_t app_rainmaker_custom_cluster_create()
{
/* Get the endpoint */
esp_matter_node_t *node = esp_matter_node_get();
esp_matter_endpoint_t *endpoint = esp_matter_endpoint_get(node, ESP_MATTER_RAINMAKER_ENDPOINT_ID);
/* Create custom rainmaker cluster */
esp_matter_cluster_t *cluster = esp_matter_cluster_create(endpoint, ESP_MATTER_RAINMAKER_CLUSTER_ID, ESP_MATTER_CLUSTER_FLAG_SERVER);
esp_matter_attribute_create(cluster, ZCL_CLUSTER_REVISION_SERVER_ATTRIBUTE_ID, ESP_MATTER_ATTRIBUTE_FLAG_NONE,
esp_matter_uint16(ESP_MATTER_RAINMAKER_CLUSTER_REVISION));
/* Create custom status attribute */
/* Update the value of the attribute after esp_rmaker_node_init() is done */
esp_matter_attribute_create(cluster, ESP_MATTER_RAINMAKER_STATUS_ATTRIBUTE_ID, ESP_MATTER_ATTRIBUTE_FLAG_NONE,
esp_matter_bool(false));
/* Create custom configuration command */
esp_matter_command_create(cluster, ESP_MATTER_RAINMAKER_CONFIGURATION_COMMAND_ID,
ESP_MATTER_COMMAND_FLAG_CLIENT_GENERATED | ESP_MATTER_COMMAND_FLAG_CUSTOM, NULL);
return ESP_OK;
}
esp_err_t app_rainmaker_init()
{
/* Add custom rainmaker cluster */
return app_rainmaker_custom_cluster_create();
}
esp_err_t app_rainmaker_start()
{
/* Initialize the ESP RainMaker Agent.
* Note that this should be called after app_wifi_init() but before app_wifi_start()
@@ -368,6 +485,16 @@ esp_err_t app_rainmaker_init()
/* Enable scheduling. */
esp_rmaker_schedule_enable();
/* Check user node association */
if (esp_rmaker_user_node_mapping_get_state() == ESP_RMAKER_USER_MAPPING_DONE) {
app_rainmaker_status_attribute_update(true);
}
/* Register an event handler and update the state later */
esp_event_handler_register(RMAKER_EVENT, RMAKER_EVENT_USER_NODE_MAPPING_DONE,
&app_rainmaker_user_node_association_event_handler, NULL);
esp_event_handler_register(RMAKER_EVENT, RMAKER_EVENT_USER_NODE_MAPPING_RESET,
&app_rainmaker_user_node_association_event_handler, NULL);
/* Start the ESP RainMaker Agent */
esp_rmaker_start();
+14 -2
View File
@@ -17,16 +17,28 @@ extern "C" {
/** Initialize ESP RainMaker
*
* This initializes the devices and params for RainMaker, corresponding to the endpoint and attributes. It also adds
* RainMaker features like OTA, Scheduling, etc.
* This adds the custom RainMaker cluster.
*
* @return ESP_OK on success.
* @return error in case of failure.
*/
esp_err_t app_rainmaker_init(void);
/** Start ESP RainMaker
*
* This initializes the devices and params for RainMaker, corresponding to the endpoint and attributes. It also adds
* RainMaker features like OTA, Scheduling, etc.
*
* @return ESP_OK on success.
* @return error in case of failure.
*/
esp_err_t app_rainmaker_start(void);
esp_err_t app_rainmaker_attribute_update(int endpoint_id, int cluster_id, int attribute_id, esp_matter_attr_val_t *val);
esp_err_t app_rainmaker_command_callback(int endpoint_id, int cluster_id, int command_id, TLVReader &tlv_data,
void *priv_data);
#ifdef __cplusplus
}
#endif
@@ -33,3 +33,7 @@ CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=3120
#enable lwIP route hooks
CONFIG_LWIP_HOOK_IP6_ROUTE_DEFAULT=y
CONFIG_LWIP_HOOK_ND6_GET_GW_DEFAULT=y
# ESP RainMaker
CONFIG_ESP_RMAKER_USER_ID_CHECK=y
CONFIG_ESP_RMAKER_SELF_CLAIM=y
@@ -30,5 +30,8 @@ CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=3120
CONFIG_LWIP_HOOK_IP6_ROUTE_DEFAULT=y
CONFIG_LWIP_HOOK_ND6_GET_GW_DEFAULT=y
# ESP RainMaker
CONFIG_ESP_RMAKER_USER_ID_CHECK=y
# Disable BLE
CONFIG_ENABLE_CHIPOBLE=n