From 9e4d1a683e8c4473c8ec409c466dddfe5111af91 Mon Sep 17 00:00:00 2001 From: Piyush Shah Date: Wed, 1 Oct 2025 18:58:03 +0530 Subject: [PATCH 1/3] esp_rmaker_params: Add "Firmware" as a new request source for set-params Useful for identifying set params triggered from the firmware itself, like from the CLI --- components/esp_rainmaker/include/esp_rmaker_core.h | 2 ++ components/esp_rainmaker/src/core/esp_rmaker_param.c | 1 + 2 files changed, 3 insertions(+) diff --git a/components/esp_rainmaker/include/esp_rmaker_core.h b/components/esp_rainmaker/include/esp_rmaker_core.h index f33e351..5753ae5 100644 --- a/components/esp_rainmaker/include/esp_rmaker_core.h +++ b/components/esp_rainmaker/include/esp_rmaker_core.h @@ -163,6 +163,8 @@ typedef enum { ESP_RMAKER_REQ_SRC_LOCAL, /** Request received via command-response framework */ ESP_RMAKER_REQ_SRC_CMD_RESP, + /** Request initiated from firmware/console commands */ + ESP_RMAKER_REQ_SRC_FIRMWARE, /** This will always be the last value. Any value equal to or * greater than this should be considered invalid. */ diff --git a/components/esp_rainmaker/src/core/esp_rmaker_param.c b/components/esp_rainmaker/src/core/esp_rmaker_param.c index 9f350b0..a35da8f 100644 --- a/components/esp_rainmaker/src/core/esp_rmaker_param.c +++ b/components/esp_rainmaker/src/core/esp_rmaker_param.c @@ -54,6 +54,7 @@ static const char *cb_srcs[ESP_RMAKER_REQ_SRC_MAX] = { [ESP_RMAKER_REQ_SRC_SCENE_DEACTIVATE] = "Scene Deactivate", [ESP_RMAKER_REQ_SRC_LOCAL] = "Local", [ESP_RMAKER_REQ_SRC_CMD_RESP] = "Command Response", + [ESP_RMAKER_REQ_SRC_FIRMWARE] = "Firmware", }; const char *esp_rmaker_device_cb_src_to_str(esp_rmaker_req_src_t src) From 33d60a567b35053ecc794f608fffc506a3f04ba6 Mon Sep 17 00:00:00 2001 From: Piyush Shah Date: Wed, 12 Nov 2025 19:50:18 +0530 Subject: [PATCH 2/3] rmaker_console: Add set-param, update-param and get-param commands - Add set-param command to set device parameter values, invoke respective callbacks and report to cloud Usage: set-param - Add update-param command to just report param value to cloud, without invoking callbacks Usage: update-param - Add get-param command to get device parameter values Usage: get-param - Support all parameter types: boolean, integer, float, string This enables easy interaction with ESP RainMaker devices through console interface. --- components/esp_rainmaker/CHANGELOG.md | 5 + components/esp_rainmaker/Kconfig.projbuild | 9 + components/esp_rainmaker/idf_component.yml | 2 +- .../src/console/esp_rmaker_commands.c | 369 +++++++++++++++++- 4 files changed, 382 insertions(+), 3 deletions(-) diff --git a/components/esp_rainmaker/CHANGELOG.md b/components/esp_rainmaker/CHANGELOG.md index b6d6b6a..fcc87fc 100644 --- a/components/esp_rainmaker/CHANGELOG.md +++ b/components/esp_rainmaker/CHANGELOG.md @@ -1,5 +1,10 @@ # Changelog +## 1.7.9 + +### New Feature +- Added set-param, get-param and update-param console commands to assist in some testing + ## 1.7.8 ## Changes diff --git a/components/esp_rainmaker/Kconfig.projbuild b/components/esp_rainmaker/Kconfig.projbuild index 4c28e50..3e01e08 100644 --- a/components/esp_rainmaker/Kconfig.projbuild +++ b/components/esp_rainmaker/Kconfig.projbuild @@ -288,6 +288,15 @@ menu "ESP RainMaker Config" default 0 if ESP_RMAKER_CONSOLE_UART_NUM_0 default 1 if ESP_RMAKER_CONSOLE_UART_NUM_1 + config ESP_RMAKER_CONSOLE_PARAM_CMDS_ENABLE + bool "Enable parameter console commands (set-param, update-param, get-param)" + default n + help + Enable console commands for interacting with device parameters: + - set-param: Set parameter value with callback invocation + - update-param: Update parameter value without callback + - get-param: Get current parameter value + config ESP_RMAKER_USE_CERT_BUNDLE bool "Use Certificate Bundle" default y diff --git a/components/esp_rainmaker/idf_component.yml b/components/esp_rainmaker/idf_component.yml index 049a904..4c98a66 100644 --- a/components/esp_rainmaker/idf_component.yml +++ b/components/esp_rainmaker/idf_component.yml @@ -1,5 +1,5 @@ ## IDF Component Manager Manifest File -version: "1.7.8" +version: "1.7.9" description: ESP RainMaker firmware agent url: https://github.com/espressif/esp-rainmaker/tree/master/components/esp_rainmaker repository: https://github.com/espressif/esp-rainmaker.git diff --git a/components/esp_rainmaker/src/console/esp_rmaker_commands.c b/components/esp_rainmaker/src/console/esp_rmaker_commands.c index d681bf5..67d1167 100644 --- a/components/esp_rainmaker/src/console/esp_rmaker_commands.c +++ b/components/esp_rainmaker/src/console/esp_rmaker_commands.c @@ -14,22 +14,25 @@ #include #include +#include #include #include #include #include -#include #include #include #include #include - #include #include #include +/* Include internal header to access device structure */ +#include "esp_rmaker_internal.h" + static const char *TAG = "esp_rmaker_commands"; + static int user_node_mapping_handler(int argc, char** argv) { if (argc == 3) { @@ -185,6 +188,365 @@ static void register_sign_data_command() esp_console_cmd_register(&cmd); } +#ifdef CONFIG_ESP_RMAKER_CONSOLE_PARAM_CMDS_ENABLE +static int set_param_handler(int argc, char** argv) +{ + if (argc != 4) { + printf("%s: Invalid Usage.\n", TAG); + printf("Usage: set-param \n"); + printf(" Note: This command invokes device callbacks (simulates real parameter changes)\n"); + return ESP_ERR_INVALID_ARG; + } + + const char *device_name = argv[1]; + const char *param_name = argv[2]; + const char *value_str_raw = argv[3]; + + /* Strip surrounding quotes if present */ + char *value_str = strdup(value_str_raw); + if (!value_str) { + printf("%s: Failed to process value string\n", TAG); + return ESP_ERR_NO_MEM; + } + + // Get the device handle + esp_rmaker_device_t *device = esp_rmaker_node_get_device_by_name(esp_rmaker_get_node(), device_name); + if (!device) { + printf("%s: Device %s not found\n", TAG, device_name); + free(value_str); + return ESP_FAIL; + } + + // Get the parameter handle + esp_rmaker_param_t *param = esp_rmaker_device_get_param_by_name(device, param_name); + if (!param) { + printf("%s: Parameter %s not found in device %s\n", TAG, param_name, device_name); + free(value_str); + return ESP_FAIL; + } + + // Get current value to determine type + esp_rmaker_param_val_t *val = esp_rmaker_param_get_val(param); + if (!val) { + printf("%s: Failed to get parameter value\n", TAG); + free(value_str); + return ESP_FAIL; + } + + + // Update value based on type + esp_rmaker_param_val_t new_val; + new_val.type = val->type; + + switch(val->type) { + case RMAKER_VAL_TYPE_BOOLEAN: + new_val.val.b = (strcmp(value_str, "true") == 0 || strcmp(value_str, "1") == 0); + break; + case RMAKER_VAL_TYPE_INTEGER: + new_val.val.i = atoi(value_str); + break; + case RMAKER_VAL_TYPE_FLOAT: + new_val.val.f = atof(value_str); + break; + case RMAKER_VAL_TYPE_STRING: + new_val.val.s = strdup(value_str); // Create a copy to avoid lifetime issues + if (!new_val.val.s) { + printf("%s: Failed to allocate memory for string value\n", TAG); + free(value_str); + return ESP_FAIL; + } + break; + case RMAKER_VAL_TYPE_OBJECT: + new_val.val.s = strdup(value_str); // JSON objects are stored as strings + if (!new_val.val.s) { + printf("%s: Failed to allocate memory for object value\n", TAG); + free(value_str); + return ESP_FAIL; + } + break; + case RMAKER_VAL_TYPE_ARRAY: + new_val.val.s = strdup(value_str); // JSON arrays are stored as strings + if (!new_val.val.s) { + printf("%s: Failed to allocate memory for array value\n", TAG); + free(value_str); + return ESP_FAIL; + } + break; + default: + printf("%s: Unsupported value type\n", TAG); + free(value_str); + return ESP_FAIL; + } + + esp_err_t err = ESP_OK; + + /* Create JSON for esp_rmaker_handle_set_params to invoke callbacks */ + char json_str[1024]; /* Increased buffer size for complex JSON */ + int json_len = 0; + + switch(val->type) { + case RMAKER_VAL_TYPE_BOOLEAN: + json_len = snprintf(json_str, sizeof(json_str), "{\"%s\":{\"%s\":%s}}", + device_name, param_name, new_val.val.b ? "true" : "false"); + break; + case RMAKER_VAL_TYPE_INTEGER: + json_len = snprintf(json_str, sizeof(json_str), "{\"%s\":{\"%s\":%d}}", + device_name, param_name, new_val.val.i); + break; + case RMAKER_VAL_TYPE_FLOAT: + json_len = snprintf(json_str, sizeof(json_str), "{\"%s\":{\"%s\":%f}}", + device_name, param_name, new_val.val.f); + break; + case RMAKER_VAL_TYPE_STRING: + json_len = snprintf(json_str, sizeof(json_str), "{\"%s\":{\"%s\":\"%s\"}}", + device_name, param_name, new_val.val.s); + break; + case RMAKER_VAL_TYPE_OBJECT: + /* JSON objects are embedded directly without quotes */ + json_len = snprintf(json_str, sizeof(json_str), "{\"%s\":{\"%s\":%s}}", + device_name, param_name, new_val.val.s); + break; + case RMAKER_VAL_TYPE_ARRAY: + /* JSON arrays are embedded directly without quotes */ + json_len = snprintf(json_str, sizeof(json_str), "{\"%s\":{\"%s\":%s}}", + device_name, param_name, new_val.val.s); + break; + default: + printf("%s: Unsupported value type for callback\n", TAG); + /* Fall back to direct update */ + err = esp_rmaker_param_update_and_report(param, new_val); + break; + } + + if (json_len > 0 && json_len < sizeof(json_str)) { + /* Use the standard parameter handling function to invoke callbacks */ + err = esp_rmaker_handle_set_params(json_str, json_len, ESP_RMAKER_REQ_SRC_FIRMWARE); + if (err == ESP_OK) { + printf("%s: Successfully set %s.%s with callback\n", TAG, device_name, param_name); + } else { + printf("%s: Callback failed for %s.%s\n", TAG, device_name, param_name); + } + } else { + printf("%s: Failed to create JSON for callback (len=%d, max=%zu)\n", TAG, json_len, sizeof(json_str)); + err = ESP_FAIL; + } + + /* Free allocated string memory if it was a string, object, or array type */ + if ((val->type == RMAKER_VAL_TYPE_STRING || val->type == RMAKER_VAL_TYPE_OBJECT || val->type == RMAKER_VAL_TYPE_ARRAY) && new_val.val.s) { + free(new_val.val.s); + } + + if (err != ESP_OK) { + printf("%s: Failed to update parameter value\n", TAG); + free(value_str); + return err; + } + + printf("%s: Successfully set %s.%s to %s\n", TAG, device_name, param_name, value_str); + + /* Free the processed value string */ + free(value_str); + return ESP_OK; +} + +static int update_param_handler(int argc, char** argv) +{ + if (argc != 4) { + printf("%s: Invalid Usage.\n", TAG); + printf("Usage: update-param \n"); + printf(" Note: This command only updates the value without invoking callbacks\n"); + return ESP_ERR_INVALID_ARG; + } + + const char *device_name = argv[1]; + const char *param_name = argv[2]; + const char *value_str_raw = argv[3]; + + /* Strip surrounding quotes if present */ + char *value_str = strdup(value_str_raw); + if (!value_str) { + printf("%s: Failed to process value string\n", TAG); + return ESP_ERR_NO_MEM; + } + + // Get the device handle + esp_rmaker_device_t *device = esp_rmaker_node_get_device_by_name(esp_rmaker_get_node(), device_name); + if (!device) { + printf("%s: Device %s not found\n", TAG, device_name); + free(value_str); + return ESP_FAIL; + } + + // Get the parameter handle + esp_rmaker_param_t *param = esp_rmaker_device_get_param_by_name(device, param_name); + if (!param) { + printf("%s: Parameter %s not found in device %s\n", TAG, param_name, device_name); + free(value_str); + return ESP_FAIL; + } + + // Get current value to determine type + esp_rmaker_param_val_t *val = esp_rmaker_param_get_val(param); + if (!val) { + printf("%s: Failed to get parameter value\n", TAG); + free(value_str); + return ESP_FAIL; + } + + // Update value based on type + esp_rmaker_param_val_t new_val; + new_val.type = val->type; + + switch(val->type) { + case RMAKER_VAL_TYPE_BOOLEAN: + new_val.val.b = (strcmp(value_str, "true") == 0 || strcmp(value_str, "1") == 0); + break; + case RMAKER_VAL_TYPE_INTEGER: + new_val.val.i = atoi(value_str); + break; + case RMAKER_VAL_TYPE_FLOAT: + new_val.val.f = atof(value_str); + break; + case RMAKER_VAL_TYPE_STRING: + new_val.val.s = strdup(value_str); // Create a copy to avoid lifetime issues + if (!new_val.val.s) { + printf("%s: Failed to allocate memory for string value\n", TAG); + free(value_str); + return ESP_FAIL; + } + break; + case RMAKER_VAL_TYPE_OBJECT: + new_val.val.s = strdup(value_str); // JSON objects are stored as strings + if (!new_val.val.s) { + printf("%s: Failed to allocate memory for object value\n", TAG); + free(value_str); + return ESP_FAIL; + } + break; + case RMAKER_VAL_TYPE_ARRAY: + new_val.val.s = strdup(value_str); // JSON arrays are stored as strings + if (!new_val.val.s) { + printf("%s: Failed to allocate memory for array value\n", TAG); + free(value_str); + return ESP_FAIL; + } + break; + default: + printf("%s: Unsupported value type\n", TAG); + free(value_str); + return ESP_FAIL; + } + + /* Update the parameter value without invoking callback */ + esp_err_t err = esp_rmaker_param_update_and_report(param, new_val); + + /* Free allocated string memory if it was a string, object, or array type */ + if ((val->type == RMAKER_VAL_TYPE_STRING || val->type == RMAKER_VAL_TYPE_OBJECT || val->type == RMAKER_VAL_TYPE_ARRAY) && new_val.val.s) { + free(new_val.val.s); + } + + if (err != ESP_OK) { + printf("%s: Failed to update parameter value\n", TAG); + free(value_str); + return err; + } + + printf("%s: Successfully updated %s.%s to %s (no callback)\n", TAG, device_name, param_name, value_str); + + /* Free the processed value string */ + free(value_str); + return ESP_OK; +} + +static int get_param_handler(int argc, char** argv) +{ + if (argc != 3) { + printf("%s: Invalid Usage.\n", TAG); + printf("Usage: get-param \n"); + return ESP_ERR_INVALID_ARG; + } + + const char *device_name = argv[1]; + const char *param_name = argv[2]; + + // Get the device handle + esp_rmaker_device_t *device = esp_rmaker_node_get_device_by_name(esp_rmaker_get_node(), device_name); + if (!device) { + printf("%s: Device %s not found\n", TAG, device_name); + return ESP_FAIL; + } + + // Get the parameter handle + esp_rmaker_param_t *param = esp_rmaker_device_get_param_by_name(device, param_name); + if (!param) { + printf("%s: Parameter %s not found in device %s\n", TAG, param_name, device_name); + return ESP_FAIL; + } + + // Get the parameter value + esp_rmaker_param_val_t *val = esp_rmaker_param_get_val(param); + if (!val) { + printf("%s: Failed to get parameter value\n", TAG); + return ESP_FAIL; + } + + // Print value based on type + switch(val->type) { + case RMAKER_VAL_TYPE_BOOLEAN: + printf("%s: %s.%s = %s\n", TAG, device_name, param_name, val->val.b ? "true" : "false"); + break; + case RMAKER_VAL_TYPE_INTEGER: + printf("%s: %s.%s = %d\n", TAG, device_name, param_name, val->val.i); + break; + case RMAKER_VAL_TYPE_FLOAT: + printf("%s: %s.%s = %f\n", TAG, device_name, param_name, val->val.f); + break; + case RMAKER_VAL_TYPE_STRING: + printf("%s: %s.%s = %s\n", TAG, device_name, param_name, val->val.s); + break; + case RMAKER_VAL_TYPE_OBJECT: + printf("%s: %s.%s = %s\n", TAG, device_name, param_name, val->val.s); + break; + case RMAKER_VAL_TYPE_ARRAY: + printf("%s: %s.%s = %s\n", TAG, device_name, param_name, val->val.s); + break; + default: + printf("%s: Unsupported value type\n", TAG); + return ESP_FAIL; + } + + return ESP_OK; +} + +static void register_param_commands() +{ + const esp_console_cmd_t set_cmd = { + .command = "set-param", + .help = "Set device parameter value with callback. Usage: set-param ", + .func = &set_param_handler, + }; + ESP_LOGI(TAG, "Registering command: %s", set_cmd.command); + esp_console_cmd_register(&set_cmd); + + const esp_console_cmd_t update_cmd = { + .command = "update-param", + .help = "Update device parameter value without callback. Usage: update-param ", + .func = &update_param_handler, + }; + ESP_LOGI(TAG, "Registering command: %s", update_cmd.command); + esp_console_cmd_register(&update_cmd); + + const esp_console_cmd_t get_cmd = { + .command = "get-param", + .help = "Get device parameter value. Usage: get-param ", + .func = &get_param_handler, + }; + ESP_LOGI(TAG, "Registering command: %s", get_cmd.command); + esp_console_cmd_register(&get_cmd); +} + +#endif /* CONFIG_ESP_RMAKER_CONSOLE_PARAM_CMDS_ENABLE */ + void register_commands() { register_user_node_mapping(); @@ -194,4 +556,7 @@ void register_commands() register_cmd_resp_command(); #endif register_sign_data_command(); +#ifdef CONFIG_ESP_RMAKER_CONSOLE_PARAM_CMDS_ENABLE + register_param_commands(); +#endif } From 2de5cd5a565be805658ba1ee91cac1b744f761ac Mon Sep 17 00:00:00 2001 From: Piyush Shah Date: Wed, 12 Nov 2025 20:15:00 +0530 Subject: [PATCH 3/3] examples: Enable parameter console commands in some examples --- examples/homekit_switch/sdkconfig.defaults | 3 +++ examples/led_light/sdkconfig.defaults | 3 +++ examples/switch/sdkconfig.defaults | 3 +++ 3 files changed, 9 insertions(+) diff --git a/examples/homekit_switch/sdkconfig.defaults b/examples/homekit_switch/sdkconfig.defaults index 6b8262f..d720d1b 100644 --- a/examples/homekit_switch/sdkconfig.defaults +++ b/examples/homekit_switch/sdkconfig.defaults @@ -38,6 +38,9 @@ CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=3120 # For additional security on reset to factory CONFIG_ESP_RMAKER_USER_ID_CHECK=y +# Enable parameter console commands +CONFIG_ESP_RMAKER_CONSOLE_PARAM_CMDS_ENABLE=y + # Application Rollback CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE=y diff --git a/examples/led_light/sdkconfig.defaults b/examples/led_light/sdkconfig.defaults index 6a97bf3..438a394 100644 --- a/examples/led_light/sdkconfig.defaults +++ b/examples/led_light/sdkconfig.defaults @@ -28,6 +28,9 @@ CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=3120 # For additional security on reset to factory CONFIG_ESP_RMAKER_USER_ID_CHECK=y +# Enable parameter console commands +CONFIG_ESP_RMAKER_CONSOLE_PARAM_CMDS_ENABLE=y + # Secure Local Control CONFIG_ESP_RMAKER_LOCAL_CTRL_AUTO_ENABLE=y #CONFIG_ESP_RMAKER_LOCAL_CTRL_ENABLE is deprecated but will continue to work diff --git a/examples/switch/sdkconfig.defaults b/examples/switch/sdkconfig.defaults index 6a97bf3..438a394 100644 --- a/examples/switch/sdkconfig.defaults +++ b/examples/switch/sdkconfig.defaults @@ -28,6 +28,9 @@ CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=3120 # For additional security on reset to factory CONFIG_ESP_RMAKER_USER_ID_CHECK=y +# Enable parameter console commands +CONFIG_ESP_RMAKER_CONSOLE_PARAM_CMDS_ENABLE=y + # Secure Local Control CONFIG_ESP_RMAKER_LOCAL_CTRL_AUTO_ENABLE=y #CONFIG_ESP_RMAKER_LOCAL_CTRL_ENABLE is deprecated but will continue to work