From 89dd3c9778a6391ae679b5bd12bd9964437386ab Mon Sep 17 00:00:00 2001 From: Nicolas MASSE Date: Tue, 8 Feb 2022 11:45:17 +0100 Subject: [PATCH] format MQTT messages as JSON --- main/Kconfig.projbuild | 12 ++++++++ main/libteleinfo.cpp | 8 +++-- main/mqtt.c | 69 ++++++++++++++++++++++++++++++++---------- main/mqtt.h | 1 - main/tic.c | 7 +---- 5 files changed, 72 insertions(+), 25 deletions(-) diff --git a/main/Kconfig.projbuild b/main/Kconfig.projbuild index fcf22e5..d8c5445 100644 --- a/main/Kconfig.projbuild +++ b/main/Kconfig.projbuild @@ -47,4 +47,16 @@ menu "TIC-to-MQTT Configuration" UART communication port number for the example. See UART documentation for available port numbers. + config MQTT_LWT_TOPIC + string "MQTT Last Will Testament Topic" + default "esp-tic/connected" + help + Topic where to send LWT (Last Will Testament) upon disconnect. + + config MQTT_TIC_VALUE_TOPIC + string "Where to send TIC values" + default "esp-tic/status/tic/%s" + help + Topic where to send regular values received from TIC. + endmenu diff --git a/main/libteleinfo.cpp b/main/libteleinfo.cpp index a004459..0685610 100644 --- a/main/libteleinfo.cpp +++ b/main/libteleinfo.cpp @@ -24,8 +24,12 @@ EXTERNC void libteleinfo_init(libteleinfo_data_callback dcb, libteleinfo_adps_ca // Initialize the LibTeleinfo tinfo.init(ltmode); - tinfo.attachData(_libteleinfo_data_callback); - tinfo.attachADPS(_libteleinfo_adps_callback); + if (dcb != NULL) { + tinfo.attachData(_libteleinfo_data_callback); + } + if (acb != NULL) { + tinfo.attachADPS(_libteleinfo_adps_callback); + } } EXTERNC void libteleinfo_process(uint8_t* buffer, int len) { diff --git a/main/mqtt.c b/main/mqtt.c index 0b07a82..8470a72 100644 --- a/main/mqtt.c +++ b/main/mqtt.c @@ -15,6 +15,8 @@ #include "esp_tls.h" #include "esp_ota_ops.h" #include +#include +#include "cJSON.h" #include "common.h" static esp_mqtt_client_config_t mqtt_cfg; @@ -22,26 +24,54 @@ static esp_mqtt_client_handle_t client; static const char *MQTT_LOGGER = "mqtt"; +#define MQTT_QOS_0 0 +#define MQTT_QOS_1 1 +#define MQTT_QOS_2 2 + +#define MQTT_NO_RETAIN 0 +#define MQTT_RETAIN 1 + +#define JSON_BUFFER_SIZE 128 +#define MQTT_TOPIC_COMPONENT_SIZE 32 + void mqtt_publish_data(char* key, char* value) { - char buffer[128]; - snprintf(buffer, sizeof(buffer), "home/power/tic/%s", key); - int qos = 0; - int retain = 0; - if (strcmp(key, "BASE") == 0 || strcmp(key, "HCHP") == 0 || - strcmp(key, "HCHC") == 0 || strcmp(key, "PTEC") == 0) { - qos = 1; - retain = 1; + char topic[sizeof(CONFIG_MQTT_TIC_VALUE_TOPIC) + MQTT_TOPIC_COMPONENT_SIZE]; + char payload[JSON_BUFFER_SIZE]; + time_t now; + int retain = MQTT_RETAIN; + + // Format the MQTT topic + if (!snprintf(topic, sizeof(CONFIG_MQTT_TIC_VALUE_TOPIC) + MQTT_TOPIC_COMPONENT_SIZE, CONFIG_MQTT_TIC_VALUE_TOPIC, key)) { + ESP_LOGD(MQTT_LOGGER, "mqtt_publish_data: snprintf failed!"); + return; } - int ret = esp_mqtt_client_publish(client, buffer, value, 0, qos, retain); - if (ret == -1) { - ESP_LOGD(MQTT_LOGGER, "MQTT Message discarded!"); + + cJSON *root = cJSON_CreateObject(); + if (root == NULL) { + ESP_LOGD(MQTT_LOGGER, "mqtt_publish_data: cJSON_CreateObject failed!"); + return; } -} -void mqtt_publish_alert(uint8_t value) { - char payload[2] = {'0' + value, 0}; - int ret = esp_mqtt_client_publish(client, "home/power/tic/ADPS", payload, 0, 1, 0); - if (ret == -1) { + // Add the value + cJSON_AddStringToObject(root, "val", value); + + // Add a timestamp + time(&now); + cJSON_AddNumberToObject(root, "ts", (double)now); + + if (!cJSON_PrintPreallocated(root, payload, JSON_BUFFER_SIZE, 0)) { + ESP_LOGD(MQTT_LOGGER, "mqtt_publish_data: cJSON_PrintPreallocated failed!"); + cJSON_Delete(root); + return; + } + cJSON_Delete(root); + + // Short frames (trames courtes) should not be retained as they signal an alert + if (strcmp(key, "ADIR1") == 0 || strcmp(key, "ADIR2") == 0 || strcmp(key, "ADIR3") == 0 || strcmp(key, "ADPS") == 0) { + retain = MQTT_NO_RETAIN; + } + + if (esp_mqtt_client_publish(client, topic, payload, 0, MQTT_QOS_0, retain) == -1) { ESP_LOGD(MQTT_LOGGER, "MQTT Message discarded!"); } } @@ -51,6 +81,9 @@ esp_err_t mqtt_event_handler_cb(esp_mqtt_event_handle_t event) { case MQTT_EVENT_CONNECTED: ESP_LOGI(MQTT_LOGGER, "MQTT_EVENT_CONNECTED"); xEventGroupSetBits(services_event_group, MQTT_CONNECTED_BIT); + if (esp_mqtt_client_publish(client, CONFIG_MQTT_LWT_TOPIC, "1", 0, MQTT_QOS_0, MQTT_RETAIN) == -1) { + ESP_LOGD(MQTT_LOGGER, "MQTT Message discarded!"); + } break; case MQTT_EVENT_DISCONNECTED: ESP_LOGI(MQTT_LOGGER, "MQTT_EVENT_DISCONNECTED"); @@ -115,6 +148,10 @@ void mqtt_init(void) { mqtt_cfg.use_global_ca_store = true; mqtt_cfg.username = get_nvs_string(nvs, "username"); mqtt_cfg.password = get_nvs_string(nvs, "password"); + mqtt_cfg.lwt_topic = CONFIG_MQTT_LWT_TOPIC; + mqtt_cfg.lwt_msg = "0"; + mqtt_cfg.lwt_qos = MQTT_QOS_0; + mqtt_cfg.lwt_retain = MQTT_RETAIN; nvs_close(nvs); diff --git a/main/mqtt.h b/main/mqtt.h index 03f7592..065a556 100644 --- a/main/mqtt.h +++ b/main/mqtt.h @@ -3,6 +3,5 @@ void mqtt_init(); void mqtt_publish_data(char* key, char* value); -void mqtt_publish_alert(uint8_t value); #endif diff --git a/main/tic.c b/main/tic.c index 95be29c..03c4328 100644 --- a/main/tic.c +++ b/main/tic.c @@ -16,11 +16,6 @@ void tic_data_callback(time_t ts, uint8_t flags, char * name, char * value) { mqtt_publish_data(name, value); } -void tic_adps_callback(uint8_t phase) { - ESP_LOGD(TIC_LOGGER, "ALERT phase=%d", phase); - mqtt_publish_alert(phase); -} - static void tic_uart_read(void *pvParameters) { uint8_t* buffer = (uint8_t*) malloc(CONFIG_TIC_UART_READ_BUFFER_SIZE); if (buffer == NULL) { @@ -77,7 +72,7 @@ void tic_uart_init() { ESP_ERROR_CHECK(uart_param_config(CONFIG_TIC_UART_PORT_NUM, &uart_config)); ESP_ERROR_CHECK(uart_set_pin(CONFIG_TIC_UART_PORT_NUM, UART_PIN_NO_CHANGE, CONFIG_TIC_UART_RXD, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE)); - libteleinfo_init(tic_data_callback, tic_adps_callback); + libteleinfo_init(tic_data_callback, NULL); // Create a task to handler UART event from ISR BaseType_t xReturned;