Skip to content

Commit

Permalink
esp_rmaker_core: Add mqtt based support for command-response
Browse files Browse the repository at this point in the history
  • Loading branch information
shahpiyushv committed Jul 18, 2022
1 parent 9f87e12 commit c77d27a
Show file tree
Hide file tree
Showing 9 changed files with 164 additions and 5 deletions.
2 changes: 1 addition & 1 deletion cli
4 changes: 3 additions & 1 deletion components/esp_rainmaker/CMakeLists.txt
Expand Up @@ -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)

Expand Down
20 changes: 20 additions & 0 deletions components/esp_rainmaker/Kconfig.projbuild
Expand Up @@ -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
14 changes: 14 additions & 0 deletions components/esp_rainmaker/include/esp_rmaker_core.h
Expand Up @@ -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
113 changes: 113 additions & 0 deletions components/esp_rainmaker/src/core/esp_rmaker_cmd_resp_manager.c
@@ -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 */
8 changes: 7 additions & 1 deletion components/esp_rainmaker/src/core/esp_rmaker_core.c
Expand Up @@ -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();
}
}

Expand Down Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions components/esp_rainmaker/src/core/esp_rmaker_internal.h
Expand Up @@ -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);
2 changes: 1 addition & 1 deletion components/rmaker_common
5 changes: 4 additions & 1 deletion docs/Doxyfile
Expand Up @@ -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 \
Expand All @@ -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
##
Expand Down

0 comments on commit c77d27a

Please sign in to comment.