mirror of
https://github.com/espressif/esp-rainmaker.git
synced 2026-01-15 14:35:30 +00:00
Merge branch 'task/cmd_response' into 'master'
esp_rmaker_core: Add framework for command-response workflow See merge request app-frameworks/esp-rainmaker!207
This commit is contained in:
2
cli
2
cli
Submodule cli updated: e61d9528c1...85e7124161
@@ -10,7 +10,9 @@ set(core_srcs "src/core/esp_rmaker_core.c"
|
||||
"src/core/esp_rmaker_user_mapping.pb-c.c"
|
||||
"src/core/esp_rmaker_user_mapping.c"
|
||||
"src/core/esp_rmaker_schedule.c"
|
||||
"src/core/esp_rmaker_scenes.c")
|
||||
"src/core/esp_rmaker_scenes.c"
|
||||
"src/core/esp_rmaker_cmd_resp_manager.c"
|
||||
)
|
||||
|
||||
set(priv_req protobuf-c json_parser json_generator wifi_provisioning nvs_flash esp_http_client app_update esp-tls mbedtls esp_https_ota console esp_local_ctrl esp_https_server mdns esp_schedule efuse)
|
||||
|
||||
|
||||
@@ -242,4 +242,24 @@ menu "ESP RainMaker Config"
|
||||
|
||||
endmenu
|
||||
|
||||
menu "ESP RainMaker Command-Response"
|
||||
|
||||
config ESP_RMAKER_CMD_RESP_ENABLE
|
||||
bool "Enable Command-Response Module"
|
||||
default y
|
||||
help
|
||||
Enable the ESP RainMaker Command-Response module for semi-synchronous communication. Please refer the RainMaker documents
|
||||
for additional information.
|
||||
|
||||
config ESP_RMAKER_CMD_RESP_TEST_ENABLE
|
||||
bool "Enable Command-Response Testing"
|
||||
default n
|
||||
depends on ESP_RMAKER_CMD_RESP_ENABLE
|
||||
help
|
||||
Enable testing for Command-Response module. This enables triggering commands and parsing response from the node itself,
|
||||
rather than receiving the commands from cloud. C API or the serial console can be used to trigger the commands.
|
||||
This should be enabled only while testing commands, but should always be disabled in production firmware.
|
||||
|
||||
endmenu
|
||||
|
||||
endmenu
|
||||
|
||||
@@ -931,6 +931,20 @@ bool esp_rmaker_local_ctrl_service_started(void);
|
||||
* @return error on failure
|
||||
*/
|
||||
esp_err_t esp_rmaker_ota_enable_default(void);
|
||||
|
||||
/*
|
||||
* Send a command to self (TESTING only)
|
||||
*
|
||||
* This is to be passed as an argument to esp_rmaker_cmd_resp_test_send().
|
||||
*
|
||||
* @param[in] cmd The TLV encoded command data.
|
||||
* @param[in] cmd_len Length of the command data.
|
||||
* @param[in] priv_data Private data passed to esp_rmaker_cmd_resp_test_send().
|
||||
*
|
||||
* @return ESP_OK on success
|
||||
* @return error on failure
|
||||
*/
|
||||
esp_err_t esp_rmaker_test_cmd_resp(const void *cmd, size_t cmd_len, void *priv_data);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
#include <esp_rmaker_core.h>
|
||||
#include <esp_rmaker_user_mapping.h>
|
||||
#include <esp_rmaker_utils.h>
|
||||
#include <esp_rmaker_cmd_resp.h>
|
||||
|
||||
#include <esp_rmaker_console_internal.h>
|
||||
|
||||
@@ -402,6 +403,31 @@ static void register_time_commands()
|
||||
esp_console_cmd_register(&tz_set_cmd);
|
||||
}
|
||||
|
||||
static int cmd_resp_cli_handler(int argc, char *argv[])
|
||||
{
|
||||
if (argc != 5) {
|
||||
printf("Usage: cmd <req_id> <user_role> <cmd> <data>\n");
|
||||
return -1;
|
||||
}
|
||||
char *req_id = argv[1];
|
||||
uint8_t user_role = atoi(argv[2]);
|
||||
uint16_t cmd = atoi(argv[3]);
|
||||
esp_rmaker_cmd_resp_test_send(req_id, user_role, cmd, (void *)argv[4], strlen(argv[4]), esp_rmaker_test_cmd_resp, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void register_cmd_resp_command()
|
||||
{
|
||||
const esp_console_cmd_t cmd_resp_cmd = {
|
||||
.command = "cmd",
|
||||
.help = "Send command to command-response module. Usage cmd <req_id> <cmd> <user_role> <data>",
|
||||
.func = &cmd_resp_cli_handler,
|
||||
};
|
||||
ESP_LOGI(TAG, "Registering command: %s", cmd_resp_cmd.command);
|
||||
esp_console_cmd_register(&cmd_resp_cmd);
|
||||
}
|
||||
|
||||
|
||||
void register_commands()
|
||||
{
|
||||
register_generic_debug_commands();
|
||||
@@ -410,4 +436,5 @@ void register_commands()
|
||||
register_get_node_id();
|
||||
register_wifi_prov();
|
||||
register_time_commands();
|
||||
register_cmd_resp_command();
|
||||
}
|
||||
|
||||
113
components/esp_rainmaker/src/core/esp_rmaker_cmd_resp_manager.c
Normal file
113
components/esp_rainmaker/src/core/esp_rmaker_cmd_resp_manager.c
Normal file
@@ -0,0 +1,113 @@
|
||||
// Copyright 2020 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_log.h>
|
||||
#include <string.h>
|
||||
#include <esp_rmaker_mqtt.h>
|
||||
#include <esp_rmaker_cmd_resp.h>
|
||||
#include "esp_rmaker_internal.h"
|
||||
|
||||
#define TO_NODE_TOPIC_SUFFIX "to-node"
|
||||
#define FROM_NODE_TOPIC_SUFFIX "from-node"
|
||||
|
||||
static const char *TAG = "esp_rmaker_cmd_resp";
|
||||
|
||||
#ifdef CONFIG_ESP_RMAKER_CMD_RESP_TEST_ENABLE
|
||||
|
||||
/* These are for testing purpose only */
|
||||
static void esp_rmaker_resp_callback(const char *topic, void *payload, size_t payload_len, void *priv_data)
|
||||
{
|
||||
esp_rmaker_cmd_resp_parse_response(payload, payload_len, priv_data);
|
||||
|
||||
}
|
||||
|
||||
esp_err_t esp_rmaker_test_cmd_resp(const void *cmd, size_t cmd_len, void *priv_data)
|
||||
{
|
||||
if (!cmd) {
|
||||
ESP_LOGE(TAG, "No command data to send.");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
char publish_topic[100];
|
||||
snprintf(publish_topic, sizeof(publish_topic), "node/%s/%s", esp_rmaker_get_node_id(), TO_NODE_TOPIC_SUFFIX);
|
||||
return esp_rmaker_mqtt_publish(publish_topic, cmd, cmd_len, RMAKER_MQTT_QOS1, NULL);
|
||||
}
|
||||
|
||||
static esp_err_t esp_rmaker_cmd_resp_test_enable(void)
|
||||
{
|
||||
char subscribe_topic[100];
|
||||
snprintf(subscribe_topic, sizeof(subscribe_topic), "node/%s/%s",
|
||||
esp_rmaker_get_node_id(), FROM_NODE_TOPIC_SUFFIX);
|
||||
esp_err_t err = esp_rmaker_mqtt_subscribe(subscribe_topic, esp_rmaker_resp_callback, RMAKER_MQTT_QOS1, NULL);
|
||||
if(err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to subscribe to %s. Error %d", subscribe_topic, err);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
ESP_LOGI(TAG, "Command-Response test support enabled.");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
#else
|
||||
esp_err_t esp_rmaker_test_cmd_resp(const void *cmd, size_t cmd_len, void *priv_data)
|
||||
{
|
||||
ESP_LOGE(TAG, "Please enable CONFIG_ESP_RMAKER_CMD_RESP_TEST_ENABLE to use this.");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
#endif /* !CONFIG_ESP_RMAKER_CMD_RESP_TEST_ENABLE */
|
||||
|
||||
#ifdef CONFIG_ESP_RMAKER_CMD_RESP_ENABLE
|
||||
|
||||
static void esp_rmaker_cmd_callback(const char *topic, void *payload, size_t payload_len, void *priv_data)
|
||||
{
|
||||
void *output = NULL;
|
||||
size_t output_len = 0;
|
||||
/* Any command data received is directly sent to the command response framework and on success,
|
||||
* the response (if any) is sent back to the MQTT Broker.
|
||||
*/
|
||||
if (esp_rmaker_cmd_response_handler(payload, payload_len, &output, &output_len) == ESP_OK) {
|
||||
if (output) {
|
||||
char publish_topic[100];
|
||||
snprintf(publish_topic, sizeof(publish_topic), "node/%s/%s", esp_rmaker_get_node_id(), FROM_NODE_TOPIC_SUFFIX);
|
||||
if (esp_rmaker_mqtt_publish(publish_topic, output, output_len, RMAKER_MQTT_QOS1, NULL) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to publish reponse.");
|
||||
}
|
||||
free(output);
|
||||
} else {
|
||||
ESP_LOGE(TAG, "No output generated by command-response handler.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t esp_rmaker_cmd_response_enable(void)
|
||||
{
|
||||
ESP_LOGI(TAG, "Enabling Command-Response Module.");
|
||||
char subscribe_topic[100];
|
||||
snprintf(subscribe_topic, sizeof(subscribe_topic), "node/%s/%s",
|
||||
esp_rmaker_get_node_id(), TO_NODE_TOPIC_SUFFIX);
|
||||
esp_err_t err = esp_rmaker_mqtt_subscribe(subscribe_topic, esp_rmaker_cmd_callback, RMAKER_MQTT_QOS1, NULL);
|
||||
if(err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to subscribe to %s. Error %d", subscribe_topic, err);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
#ifdef CONFIG_ESP_RMAKER_CMD_RESP_TEST_ENABLE
|
||||
esp_rmaker_cmd_resp_test_enable();
|
||||
#endif /* CONFIG_ESP_RMAKER_CMD_RESP_TEST_ENABLE */
|
||||
return ESP_OK;
|
||||
}
|
||||
#else
|
||||
esp_err_t esp_rmaker_cmd_response_enable(void)
|
||||
{
|
||||
ESP_LOGW(TAG, "Command-Response Module not enabled. Set CONFIG_ESP_RMAKER_CMD_RESP_ENABLE=y to use this.");
|
||||
return ESP_OK;
|
||||
}
|
||||
#endif /* !CONFIG_ESP_RMAKER_CMD_RESP_ENABLE */
|
||||
@@ -137,8 +137,9 @@ static void esp_rmaker_event_handler(void* arg, esp_event_base_t event_base,
|
||||
} else if (event_base == RMAKER_EVENT &&
|
||||
(event_id == RMAKER_EVENT_USER_NODE_MAPPING_DONE ||
|
||||
event_id == RMAKER_EVENT_USER_NODE_MAPPING_RESET)) {
|
||||
esp_rmaker_params_mqtt_init();
|
||||
esp_event_handler_unregister(RMAKER_EVENT, event_id, &esp_rmaker_event_handler);
|
||||
esp_rmaker_params_mqtt_init();
|
||||
esp_rmaker_cmd_response_enable();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -324,6 +325,11 @@ static void esp_rmaker_task(void *data)
|
||||
ESP_LOGE(TAG, "Aborting!!!");
|
||||
goto rmaker_end;
|
||||
}
|
||||
err = esp_rmaker_cmd_response_enable();
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Aborting!!!");
|
||||
goto rmaker_end;
|
||||
}
|
||||
} else {
|
||||
/* If network is connected without even starting the user-node mapping workflow,
|
||||
* it could mean that some incorrect app was used to provision the device. Even
|
||||
|
||||
@@ -116,3 +116,4 @@ static inline esp_err_t esp_rmaker_post_event(esp_rmaker_event_t event_id, void*
|
||||
return esp_event_post(RMAKER_EVENT, event_id, data, data_size, portMAX_DELAY);
|
||||
}
|
||||
esp_rmaker_state_t esp_rmaker_get_state(void);
|
||||
esp_err_t esp_rmaker_cmd_response_enable(void);
|
||||
|
||||
Submodule components/rmaker_common updated: b40a39e06f...96374c52ee
@@ -25,6 +25,7 @@ INPUT = \
|
||||
../components/esp_rainmaker/include/esp_rmaker_core.h \
|
||||
../components/esp_rainmaker/include/esp_rmaker_user_mapping.h \
|
||||
../components/esp_rainmaker/include/esp_rmaker_schedule.h \
|
||||
../components/esp_rainmaker/include/esp_rmaker_scenes.h \
|
||||
## RainMaker Standard Types
|
||||
../components/esp_rainmaker/include/esp_rmaker_standard_types.h \
|
||||
../components/esp_rainmaker/include/esp_rmaker_standard_params.h \
|
||||
@@ -40,7 +41,9 @@ INPUT = \
|
||||
../components/rmaker_common/include/esp_rmaker_common_events.h \
|
||||
../components/rmaker_common/include/esp_rmaker_factory.h \
|
||||
../components/rmaker_common/include/esp_rmaker_work_queue.h \
|
||||
../components/rmaker_common/include/esp_rmaker_utils.h
|
||||
../components/rmaker_common/include/esp_rmaker_utils.h \
|
||||
../components/rmaker_common/include/esp_rmaker_cmd_resp.h \
|
||||
../components/rmaker_common/include/esp_rmaker_mqtt_glue.h
|
||||
|
||||
## Get warnings for functions that have no documentation for their parameters or return value
|
||||
##
|
||||
|
||||
Reference in New Issue
Block a user