Files
esp-anchor/components/mqtt_publisher/src/mqtt_publisher.c
T

142 lines
5.1 KiB
C

#include "mqtt_publisher.h"
#include "mqtt_client.h"
#include "esp_log.h"
#include "cJSON.h"
#include <string.h>
#include <stdio.h>
#define TAG "mqtt_publisher"
#define TOPIC_PREFIX "localiser/sensor"
static esp_mqtt_client_handle_t s_client = NULL;
static char s_sensor_id[32];
static EventGroupHandle_t s_evt = NULL;
static mqtt_reconfigure_data_t s_reconfigure_data;
const mqtt_reconfigure_data_t *mqtt_publisher_get_reconfigure_data(void)
{
return &s_reconfigure_data;
}
/* Pre-built topic strings */
static char s_topic_rssi[96];
static char s_topic_announce[96];
static char s_topic_cmd[96];
static void build_topics(void)
{
snprintf(s_topic_rssi, sizeof(s_topic_rssi),
"%s/%s/rssi", TOPIC_PREFIX, s_sensor_id);
snprintf(s_topic_announce, sizeof(s_topic_announce),
"%s/%s/announce", TOPIC_PREFIX, s_sensor_id);
snprintf(s_topic_cmd, sizeof(s_topic_cmd),
"%s/%s/cmd", TOPIC_PREFIX, s_sensor_id);
}
static void handle_cmd(const char *data, int data_len)
{
char *buf = strndup(data, data_len);
if (!buf) return;
cJSON *root = cJSON_Parse(buf);
free(buf);
if (!root) return;
cJSON *action = cJSON_GetObjectItemCaseSensitive(root, "action");
if (cJSON_IsString(action)) {
const char *a = action->valuestring;
if (strcmp(a, "calibrate_start") == 0) xEventGroupSetBits(s_evt, MQTT_CALIBRATE_START);
else if (strcmp(a, "calibrate_stop") == 0) xEventGroupSetBits(s_evt, MQTT_CALIBRATE_STOP);
else if (strcmp(a, "selected") == 0) xEventGroupSetBits(s_evt, MQTT_SELECTED_BIT);
else if (strcmp(a, "deselected") == 0) xEventGroupSetBits(s_evt, MQTT_DESELECTED_BIT);
else if (strcmp(a, "factory_reset") == 0) xEventGroupSetBits(s_evt, MQTT_FACTORY_RESET_BIT);
else if (strcmp(a, "reconfigure_settings") == 0) {
memset(&s_reconfigure_data, 0, sizeof(s_reconfigure_data));
cJSON *ssid_j = cJSON_GetObjectItemCaseSensitive(root, "ssid");
cJSON *pass_j = cJSON_GetObjectItemCaseSensitive(root, "password");
cJSON *host_j = cJSON_GetObjectItemCaseSensitive(root, "mqtt_host");
cJSON *port_j = cJSON_GetObjectItemCaseSensitive(root, "mqtt_port");
if (cJSON_IsString(ssid_j)) strncpy(s_reconfigure_data.ssid, ssid_j->valuestring, sizeof(s_reconfigure_data.ssid) - 1);
if (cJSON_IsString(pass_j)) strncpy(s_reconfigure_data.password, pass_j->valuestring, sizeof(s_reconfigure_data.password) - 1);
if (cJSON_IsString(host_j)) strncpy(s_reconfigure_data.mqtt_host, host_j->valuestring, sizeof(s_reconfigure_data.mqtt_host) - 1);
if (cJSON_IsNumber(port_j)) s_reconfigure_data.mqtt_port = (uint16_t)port_j->valuedouble;
xEventGroupSetBits(s_evt, MQTT_RECONFIGURE_SETTINGS_BIT);
}
else ESP_LOGW(TAG, "Unknown cmd action: %s", a);
}
cJSON_Delete(root);
}
static void mqtt_event_handler(void *arg, esp_event_base_t base,
int32_t id, void *data)
{
esp_mqtt_event_handle_t event = (esp_mqtt_event_handle_t)data;
switch ((esp_mqtt_event_id_t)id) {
case MQTT_EVENT_CONNECTED:
ESP_LOGI(TAG, "Connected to broker");
esp_mqtt_client_subscribe(s_client, s_topic_cmd, 1);
xEventGroupSetBits(s_evt, MQTT_CONNECTED_BIT);
mqtt_publisher_announce();
break;
case MQTT_EVENT_DISCONNECTED:
ESP_LOGW(TAG, "Disconnected from broker");
xEventGroupClearBits(s_evt, MQTT_CONNECTED_BIT);
break;
case MQTT_EVENT_DATA:
if (strncmp(event->topic, s_topic_cmd, event->topic_len) == 0) {
handle_cmd(event->data, event->data_len);
}
break;
case MQTT_EVENT_ERROR:
ESP_LOGE(TAG, "MQTT error");
break;
default:
break;
}
}
esp_err_t mqtt_publisher_init(const char *sensor_id,
const char *broker_uri,
EventGroupHandle_t evt_group)
{
strncpy(s_sensor_id, sensor_id, sizeof(s_sensor_id) - 1);
s_evt = evt_group;
build_topics();
esp_mqtt_client_config_t cfg = {
.broker.address.uri = broker_uri,
.credentials.client_id = sensor_id,
.session.keepalive = 30,
.network.reconnect_timeout_ms = 5000,
};
s_client = esp_mqtt_client_init(&cfg);
if (!s_client) return ESP_FAIL;
ESP_ERROR_CHECK(esp_mqtt_client_register_event(
s_client, ESP_EVENT_ANY_ID, mqtt_event_handler, NULL));
return esp_mqtt_client_start(s_client);
}
void mqtt_publisher_announce(void)
{
if (!s_client) return;
esp_mqtt_client_publish(s_client, s_topic_announce, "", 0, 1, 0);
ESP_LOGI(TAG, "Announced on %s", s_topic_announce);
}
void mqtt_publisher_send_rssi(const char *tag_id, int8_t rssi)
{
if (!s_client) return;
char payload[80];
int len = snprintf(payload, sizeof(payload),
"{\"tag_id\":\"%s\",\"rssi\":%d}", tag_id, (int)rssi);
esp_mqtt_client_publish(s_client, s_topic_rssi, payload, len, 1, 0);
}