Skip to content

Commit 33e7b0e

Browse files
committed
Merge branch 'feature/notify' into 'master'
esp_rmaker_core: Add support for triggering phone app notifications See merge request app-frameworks/esp-rainmaker!256
2 parents dcfecc3 + 036e2da commit 33e7b0e

File tree

5 files changed

+124
-9
lines changed

5 files changed

+124
-9
lines changed

components/esp_rainmaker/include/esp_rmaker_core.h

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ extern "C"
2424

2525
#define ESP_RMAKER_CONFIG_VERSION "2020-03-20"
2626

27-
#define MAX_VERSION_STRING_LEN 16
27+
/* Maximum length of the alert message that can be passed to esp_rmaker_raise_alert() */
28+
#define ESP_RMAKER_MAX_ALERT_LEN 100
2829

2930
/** @cond **/
3031
/** ESP RainMaker Event Base */
@@ -741,6 +742,46 @@ esp_err_t esp_rmaker_param_add_array_max_count(const esp_rmaker_param_t *param,
741742
*/
742743
esp_err_t esp_rmaker_param_update_and_report(const esp_rmaker_param_t *param, esp_rmaker_param_val_t val);
743744

745+
/** Update and notify a parameter
746+
*
747+
* Calling this API will update the parameter and report it to ESP RainMaker cloud similar to
748+
* esp_rmaker_param_update_and_report(). However, additionally, it will also trigger a notification
749+
* on the phone apps (if enabled).
750+
*
751+
* @note This should be used only when some local change requires explicit notification even when the
752+
* phone app is in background, not otherwise.
753+
* Eg. Alarm got triggered, temperature exceeded some threshold, etc.
754+
*
755+
* Alternatively, the esp_rmaker_raise_alert() API can also be used to trigger notification
756+
* on the phone apps with pre-formatted text.
757+
*
758+
* @param[in] param Parameter handle.
759+
* @param[in] val New value of the parameter.
760+
*
761+
* @return ESP_OK if the parameter was updated successfully.
762+
* @return error in case of failure.
763+
*/
764+
esp_err_t esp_rmaker_param_update_and_notify(const esp_rmaker_param_t *param, esp_rmaker_param_val_t val);
765+
766+
/** Trigger an alert on the phone app
767+
*
768+
* This API will trigger a notification alert on the phone apps (if enabled) using the formatted text
769+
* provided. Note that this does not send a notification directly to the phone, but reports the alert
770+
* to the ESP RainMaker cloud which then uses the Notification framework to send notifications to the
771+
* phone apps. The value does not get stored anywhere, nor is it linked to any node parameters.
772+
*
773+
* @note This should be used only if some event requires explicitly alerting the user even when the
774+
* phone app is in background, not otherwise.
775+
* Eg. "Motion Detected", "Fire alarm triggered"
776+
*
777+
* @param[in] alert_str NULL terminated pre-formatted alert string.
778+
* Maximum length can be ESP_RMAKER_MAX_ALERT_LEN, excluding NULL character.
779+
*
780+
* @return ESP_OK on success.
781+
* @return error in case of failure.
782+
*/
783+
esp_err_t esp_rmaker_raise_alert(const char *alert_str);
784+
744785
/** Get parameter name from handle
745786
*
746787
* @param[in] param Parameter handle.

components/esp_rainmaker/src/core/esp_rmaker_internal.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@
1818
#include <json_generator.h>
1919
#include <esp_rmaker_core.h>
2020

21-
#define RMAKER_PARAM_FLAG_VALUE_CHANGE 0x01
21+
#define RMAKER_PARAM_FLAG_VALUE_CHANGE (1 << 0)
22+
#define RMAKER_PARAM_FLAG_VALUE_NOTIFY (1 << 1)
2223
#define ESP_RMAKER_NVS_PART_NAME "nvs"
2324

2425
typedef enum {
@@ -100,7 +101,6 @@ esp_err_t esp_rmaker_report_node_state(void);
100101
_esp_rmaker_device_t *esp_rmaker_node_get_first_device(const esp_rmaker_node_t *node);
101102
esp_rmaker_attr_t *esp_rmaker_node_get_first_attribute(const esp_rmaker_node_t *node);
102103
esp_err_t esp_rmaker_params_mqtt_init(void);
103-
esp_err_t esp_rmaker_report_param_internal(void);
104104
esp_err_t esp_rmaker_param_get_stored_value(_esp_rmaker_param_t *param, esp_rmaker_param_val_t *val);
105105
esp_err_t esp_rmaker_param_store_value(_esp_rmaker_param_t *param);
106106
esp_err_t esp_rmaker_node_delete(const esp_rmaker_node_t *node);

components/esp_rainmaker/src/core/esp_rmaker_param.c

Lines changed: 54 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,13 @@
3030
#define NODE_PARAMS_LOCAL_INIT_TOPIC_SUFFIX "params/local/init"
3131
#define NODE_PARAMS_REMOTE_TOPIC_SUFFIX "params/remote"
3232
#define TIME_SERIES_DATA_TOPIC_SUFFIX "params/ts_data"
33+
#define NODE_PARAMS_ALERT_TOPIC_SUFFIX "alert"
34+
35+
#define ESP_RMAKER_ALERT_KEY "esp.alert.str"
3336

3437
#define MAX_PUBLISH_TOPIC_LEN 64
35-
#define RMAKER_PARAMS_SIZE_MARGIN 50
38+
#define RMAKER_PARAMS_SIZE_MARGIN 50 /* To accommodate for changes in param values while creating JSON */
39+
#define RMAKER_ALERT_STR_MARGIN 25 /* To accommodate rest of the alert payload {"esp.alert.str":""} */
3640

3741
static size_t max_node_params_size = CONFIG_ESP_RMAKER_MAX_PARAM_DATA_SIZE;
3842
/* This buffer will be allocated once and will be reused for all param updates.
@@ -210,17 +214,25 @@ static esp_err_t esp_rmaker_allocate_and_populate_params(uint8_t flags, bool res
210214
return err;
211215
}
212216

213-
esp_err_t esp_rmaker_report_param_internal(void)
217+
static esp_err_t esp_rmaker_report_param_internal(uint8_t flags)
214218
{
215219
esp_err_t err = esp_rmaker_allocate_and_populate_params(RMAKER_PARAM_FLAG_VALUE_CHANGE, true);
216220
if (err == ESP_OK) {
217221
/* Just checking if there are indeed any params to report by comparing with a decent enough
218222
* length as even the smallest possible data, Eg. '{"d":{"p":0}}' will be > 10 bytes.
219223
*/
220224
if (strlen(node_params_buf) > 10) {
221-
snprintf(publish_topic, sizeof(publish_topic), "node/%s/%s",
222-
esp_rmaker_get_node_id(), NODE_PARAMS_LOCAL_TOPIC_SUFFIX);
223-
ESP_LOGI(TAG, "Reporting params: %s", node_params_buf);
225+
if (flags == RMAKER_PARAM_FLAG_VALUE_CHANGE) {
226+
snprintf(publish_topic, sizeof(publish_topic), "node/%s/%s",
227+
esp_rmaker_get_node_id(), NODE_PARAMS_LOCAL_TOPIC_SUFFIX);
228+
ESP_LOGI(TAG, "Reporting params: %s", node_params_buf);
229+
} else if (flags == RMAKER_PARAM_FLAG_VALUE_NOTIFY) {
230+
snprintf(publish_topic, sizeof(publish_topic), "node/%s/%s",
231+
esp_rmaker_get_node_id(), NODE_PARAMS_ALERT_TOPIC_SUFFIX);
232+
ESP_LOGI(TAG, "Notifying params: %s", node_params_buf);
233+
} else {
234+
return ESP_FAIL;
235+
}
224236
if (esp_rmaker_params_mqtt_init_done) {
225237
esp_rmaker_mqtt_publish(publish_topic, node_params_buf, strlen(node_params_buf), RMAKER_MQTT_QOS1, NULL);
226238
} else {
@@ -688,7 +700,21 @@ esp_err_t esp_rmaker_param_report(const esp_rmaker_param_t *param)
688700
return ESP_ERR_INVALID_ARG;
689701
}
690702
((_esp_rmaker_param_t *)param)->flags |= RMAKER_PARAM_FLAG_VALUE_CHANGE;
691-
return esp_rmaker_report_param_internal();
703+
return esp_rmaker_report_param_internal(RMAKER_PARAM_FLAG_VALUE_CHANGE);
704+
}
705+
706+
esp_err_t esp_rmaker_param_notify(const esp_rmaker_param_t *param)
707+
{
708+
if (!param) {
709+
ESP_LOGE(TAG, "Param handle cannot be NULL.");
710+
return ESP_ERR_INVALID_ARG;
711+
}
712+
((_esp_rmaker_param_t *)param)->flags |= (RMAKER_PARAM_FLAG_VALUE_CHANGE | RMAKER_PARAM_FLAG_VALUE_NOTIFY);
713+
esp_err_t err = esp_rmaker_report_param_internal(RMAKER_PARAM_FLAG_VALUE_NOTIFY);
714+
if (err != ESP_OK) {
715+
ESP_LOGW(TAG, "Failed to report parameter");
716+
}
717+
return esp_rmaker_report_param_internal(RMAKER_PARAM_FLAG_VALUE_CHANGE);
692718
}
693719

694720
esp_err_t esp_rmaker_param_update_and_report(const esp_rmaker_param_t *param, esp_rmaker_param_val_t val)
@@ -701,6 +727,16 @@ esp_err_t esp_rmaker_param_update_and_report(const esp_rmaker_param_t *param, es
701727
return err;
702728
}
703729

730+
esp_err_t esp_rmaker_param_update_and_notify(const esp_rmaker_param_t *param, esp_rmaker_param_val_t val)
731+
{
732+
esp_err_t err = esp_rmaker_param_update(param, val);
733+
/** Report parameter only if the RainMaker has started */
734+
if ((err == ESP_OK) && (esp_rmaker_get_state() == ESP_RMAKER_STATE_STARTED)) {
735+
err = esp_rmaker_param_notify(param);
736+
}
737+
return err;
738+
}
739+
704740
char *esp_rmaker_param_get_name(const esp_rmaker_param_t *param)
705741
{
706742
if (!param) {
@@ -718,3 +754,15 @@ char *esp_rmaker_param_get_type(const esp_rmaker_param_t *param)
718754
}
719755
return ((_esp_rmaker_param_t *)param)->type;
720756
}
757+
758+
esp_err_t esp_rmaker_raise_alert(const char *alert_str)
759+
{
760+
char msg[ESP_RMAKER_MAX_ALERT_LEN + 1]; /* + 1 for NULL terminattion */
761+
strlcpy(msg, alert_str, sizeof(msg));
762+
char buf[ESP_RMAKER_MAX_ALERT_LEN + RMAKER_ALERT_STR_MARGIN];
763+
snprintf(buf, sizeof(buf), "{\"%s\":\"%s\"}", ESP_RMAKER_ALERT_KEY, msg);
764+
snprintf(publish_topic, sizeof(publish_topic), "node/%s/%s",
765+
esp_rmaker_get_node_id(), NODE_PARAMS_ALERT_TOPIC_SUFFIX);
766+
ESP_LOGI(TAG, "Reporting alert: %s", buf);
767+
return esp_rmaker_mqtt_publish(publish_topic, buf, strlen(buf), RMAKER_MQTT_QOS1, NULL);
768+
}

examples/switch/main/Kconfig.projbuild

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,12 @@ menu "Example Configuration"
88
GPIO number on which the "Boot" button is connected. This is generally used
99
by the application for custom operations like toggling states, resetting to defaults, etc.
1010

11+
config EXAMPLE_ENABLE_TEST_NOTIFICATIONS
12+
bool "Test Notifications"
13+
default n
14+
help
15+
Enable this option to test mobile push notifications. When enabled, turning on the switch using
16+
push button will trigger a parameter notification {"Switch":{"Power":true}} and turning off will
17+
trigger an alert "Switch was turned off".
18+
1119
endmenu

examples/switch/main/app_driver.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,27 @@ static void push_btn_cb(void *arg)
5151
{
5252
bool new_state = !g_power_state;
5353
app_driver_set_state(new_state);
54+
#ifdef CONFIG_EXAMPLE_ENABLE_TEST_NOTIFICATIONS
55+
/* This snippet has been added just to demonstrate how the APIs esp_rmaker_param_update_and_notify()
56+
* and esp_rmaker_raise_alert() can be used to trigger push notifications on the phone apps.
57+
* Normally, there should not be a need to use these APIs for such simple operations. Please check
58+
* API documentation for details.
59+
*/
60+
if (new_state) {
61+
esp_rmaker_param_update_and_notify(
62+
esp_rmaker_device_get_param_by_name(switch_device, ESP_RMAKER_DEF_POWER_NAME),
63+
esp_rmaker_bool(new_state));
64+
} else {
65+
esp_rmaker_param_update_and_report(
66+
esp_rmaker_device_get_param_by_name(switch_device, ESP_RMAKER_DEF_POWER_NAME),
67+
esp_rmaker_bool(new_state));
68+
esp_rmaker_raise_alert("Switch was turned off");
69+
}
70+
#else
5471
esp_rmaker_param_update_and_report(
5572
esp_rmaker_device_get_param_by_name(switch_device, ESP_RMAKER_DEF_POWER_NAME),
5673
esp_rmaker_bool(new_state));
74+
#endif
5775
}
5876

5977
static void set_power_state(bool target)

0 commit comments

Comments
 (0)