Files
iot-bedroom-environment-con…/main/mqtt_manager.c

1179 lines
61 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#include "mqtt_manager.h"
#include "esp_log.h"
#include "mqtt_client.h"
#include "cJSON.h"
#include "esp_mac.h"
#include "esp_err.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include <time.h>
#include <math.h>
#include <string.h>
#include <inttypes.h>
#include "sensors.h"
#include "common.h"
#include "time_alarm.h"
#include "app_state.h"
#include "vars.h"
static const char *TAG = "mqtt_manager";
// MQTT 配置
#define MQTT_BROKER_URL "mqtt://beihong.wang:1883"
#define MQTT_USERNAME "esp_mqtt_client"
#define MQTT_CLIENT_ID "esp_mqtt_client"
#define MQTT_PASSWORD "664hd78gas97"
#define MQTT_PUBLISH_TOPIC_QOS0 "topic/sensor/esp32_iothome_001"
#define MQTT_NOTIFY_TOPIC "topic/control/esp32_iothome_001"
#define MQTT_UNSUBSCRIBE_TOPIC "topic/control/esp32_iothome_001"
#define MQTT_MAX_RETRY_COUNT 5
#define MQTT_RETRY_DELAY_MS 5000
esp_mqtt_client_handle_t g_mqtt_client = NULL;
// 全局静态 JSON 缓冲区4KB用于所有 JSON 打印,防止堆碎片化
static char GLOBAL_MQTT_JSON_BUFFER[4096];
static bool g_mqtt_connected = false;
static int g_mqtt_retry_count = 0;
// 静态任务缓冲区:使用静态创建避免在堆上分配任务栈/TCB
// app_state.h 提供共享状态的 extern 声明;保留跨模块函数声明
extern sensor_data_t g_sensor_data;
extern void alarm_set_time(uint8_t alarm_idx, uint8_t hour, uint8_t minute, uint8_t second);
extern void alarm_set_enable(uint8_t alarm_idx, bool enable);
// MQTT 发布任务:构建 JSON 并发布到 broker
void mqtt_publish_task(void *pvParameters)
{
TickType_t last_wake_time = xTaskGetTickCount();
// 初始化设备消息
if (xMqttMessageMutex != NULL && xSemaphoreTake(xMqttMessageMutex, portMAX_DELAY) == pdTRUE)
{
strcpy(g_device_message.device_id, "esp32_bedroom_001");
strcpy(g_device_message.device_type, "bedroom_controller");
time_t now;
time(&now);
g_device_message.timestamp = (uint64_t)(now * 1000ULL);
g_device_message.state.online = true;
strcpy(g_device_message.state.current_mode, "night_mode");
g_device_message.state.home_status = true;
g_device_message.state.standby_mode = false;
g_device_message.state.error_code = 0;
g_device_message.state.auto_mode = false; // 默认手动模式
set_var_mode("Manual"); // 初始化屏幕模式显示
g_device_message.telemetry.temperature = 0;
g_device_message.telemetry.humidity = 0;
g_device_message.telemetry.light_intensity = 0;
strcpy(g_device_message.telemetry.curtain_state, "close");
strcpy(g_device_message.telemetry.led_state, "close");
g_device_message.telemetry.led_power = 0;
strcpy(g_device_message.telemetry.fan_state, "close");
strcpy(g_device_message.telemetry.buzzer_state, "close");
xSemaphoreGive(xMqttMessageMutex);
}
while (1)
{
// 只有在MQTT连接时才更新传感器数据并生成JSON消息
if (g_mqtt_connected)
{
if (xSensorDataMutex != NULL && xSemaphoreTake(xSensorDataMutex, portMAX_DELAY) == pdTRUE)
{
if (xMqttMessageMutex != NULL && xSemaphoreTake(xMqttMessageMutex, portMAX_DELAY) == pdTRUE)
{
if (g_sensor_data.ahtxx_valid)
{
g_device_message.telemetry.temperature = g_sensor_data.temperature;
g_device_message.telemetry.humidity = g_sensor_data.humidity;
}
if (g_sensor_data.bh1750_valid)
{
g_device_message.telemetry.light_intensity = g_sensor_data.lux;
}
if (g_sensor_data.sgp30_valid)
{
g_device_message.telemetry.co2_ppm = g_sensor_data.co2_ppm;
g_device_message.telemetry.tvoc_ppb = g_sensor_data.tvoc_ppb;
}
xSemaphoreGive(xMqttMessageMutex);
}
xSemaphoreGive(xSensorDataMutex);
}
}
char *json_message = NULL;
bool json_heap_alloc = false;
// 只有在MQTT连接时才生成JSON消息
if (g_mqtt_connected && xMqttMessageMutex != NULL && xSemaphoreTake(xMqttMessageMutex, portMAX_DELAY) == pdTRUE)
{
time_t now;
time(&now);
g_device_message.timestamp = (uint64_t)(now * 1000ULL);
cJSON *root = cJSON_CreateObject();
cJSON_AddStringToObject(root, "type", "device_message");
cJSON_AddStringToObject(root, "device_id", g_device_message.device_id);
cJSON_AddStringToObject(root, "device_type", g_device_message.device_type);
// 使用字符串表示时间戳,避免浮点数转换的栈溢出问题
char timestamp_str[32];
snprintf(timestamp_str, sizeof(timestamp_str), "%llu", g_device_message.timestamp);
cJSON_AddStringToObject(root, "timestamp", timestamp_str);
cJSON_AddStringToObject(root, "message_type", "sensor_data");
cJSON *data_obj = cJSON_CreateObject();
cJSON_AddItemToObject(root, "data", data_obj);
cJSON *state_obj = cJSON_CreateObject();
cJSON_AddBoolToObject(state_obj, "online", g_device_message.state.online);
cJSON_AddStringToObject(state_obj, "current_mode", g_device_message.state.current_mode);
cJSON_AddBoolToObject(state_obj, "standby_mode", g_device_message.state.standby_mode);
cJSON_AddNumberToObject(state_obj, "error_code", g_device_message.state.error_code);
cJSON_AddBoolToObject(state_obj, "auto_mode", g_device_message.state.auto_mode);
cJSON_AddItemToObject(data_obj, "state", state_obj);
cJSON *telemetry_obj = cJSON_CreateObject();
// 使用字符串表示浮点数,避免栈溢出问题
char temp_str[16];
char humidity_str[16];
char light_str[16];
snprintf(temp_str, sizeof(temp_str), "%.2f", roundf(g_device_message.telemetry.temperature * 100) / 100);
snprintf(humidity_str, sizeof(humidity_str), "%.2f", roundf(g_device_message.telemetry.humidity * 100) / 100);
snprintf(light_str, sizeof(light_str), "%.2f", roundf(g_device_message.telemetry.light_intensity * 100) / 100);
cJSON_AddStringToObject(telemetry_obj, "temperature", temp_str);
cJSON_AddStringToObject(telemetry_obj, "humidity", humidity_str);
cJSON_AddStringToObject(telemetry_obj, "light_intensity", light_str);
cJSON_AddStringToObject(telemetry_obj, "curtain_state", g_device_message.telemetry.curtain_state);
cJSON_AddStringToObject(telemetry_obj, "led_state", g_device_message.telemetry.led_state);
cJSON_AddNumberToObject(telemetry_obj, "led_power", g_device_message.telemetry.led_power);
cJSON_AddStringToObject(telemetry_obj, "fan_state", g_device_message.telemetry.fan_state);
cJSON_AddStringToObject(telemetry_obj, "buzzer_state", g_device_message.telemetry.buzzer_state);
// 添加 SGP30 传感器数据
cJSON_AddNumberToObject(telemetry_obj, "co2_ppm", g_device_message.telemetry.co2_ppm);
cJSON_AddNumberToObject(telemetry_obj, "tvoc_ppb", g_device_message.telemetry.tvoc_ppb);
cJSON_AddItemToObject(data_obj, "telemetry", telemetry_obj);
// 优先将 JSON 打印到全局静态缓冲区,避免堆分配;若缓冲不足再回退到 cJSON_Print
bool printed = cJSON_PrintPreallocated(root, GLOBAL_MQTT_JSON_BUFFER, sizeof(GLOBAL_MQTT_JSON_BUFFER), 0);
if (printed)
{
json_message = GLOBAL_MQTT_JSON_BUFFER; // 直接使用全局内存
json_heap_alloc = false;
}
else
{
json_message = cJSON_Print(root);
json_heap_alloc = (json_message != NULL);
}
cJSON_Delete(root);
xSemaphoreGive(xMqttMessageMutex);
}
if (json_message != NULL)
{
ESP_LOGI(TAG, "准备发布MQTT消息:");
ESP_LOGI(TAG, "Topic: %s", MQTT_PUBLISH_TOPIC_QOS0);
if (g_mqtt_client != NULL && g_mqtt_connected)
{
int msg_id = esp_mqtt_client_publish(g_mqtt_client, MQTT_PUBLISH_TOPIC_QOS0, json_message, 0, 0, 0);
ESP_LOGI(TAG, "MQTT消息已发布, msg_id=%d", msg_id);
}
else
{
ESP_LOGW(TAG, "MQTT客户端未连接跳过发布");
}
if (json_heap_alloc)
{
free(json_message);
}
}
uint32_t delay_ms = 3000;
if (xMqttMessageMutex != NULL && xSemaphoreTake(xMqttMessageMutex, 10) == pdTRUE)
{
if (!g_device_message.state.home_status)
{
delay_ms = 50000;
}
xSemaphoreGive(xMqttMessageMutex);
}
vTaskDelayUntil(&last_wake_time, pdMS_TO_TICKS(delay_ms));
}
}
void mqtt_manager_publish_feedback(void)
{
if (g_mqtt_client == NULL || !g_mqtt_connected)
return;
if (xMqttMessageMutex != NULL && xSemaphoreTake(xMqttMessageMutex, portMAX_DELAY) == pdTRUE)
{
time_t now;
time(&now);
g_device_message.timestamp = (uint64_t)(now * 1000ULL);
cJSON *root = cJSON_CreateObject();
cJSON_AddStringToObject(root, "type", "device_message");
cJSON_AddStringToObject(root, "device_id", g_device_message.device_id);
cJSON_AddStringToObject(root, "device_type", g_device_message.device_type);
// 使用字符串表示时间戳,避免浮点数转换的栈溢出问题
char timestamp_str[32];
snprintf(timestamp_str, sizeof(timestamp_str), "%llu", g_device_message.timestamp);
cJSON_AddStringToObject(root, "timestamp", timestamp_str);
cJSON_AddStringToObject(root, "message_type", "control_feedback");
cJSON *data_obj = cJSON_CreateObject();
cJSON_AddItemToObject(root, "data", data_obj);
cJSON *state_obj = cJSON_CreateObject();
cJSON_AddBoolToObject(state_obj, "online", g_device_message.state.online);
cJSON_AddStringToObject(state_obj, "current_mode", g_device_message.state.current_mode);
cJSON_AddBoolToObject(state_obj, "standby_mode", g_device_message.state.standby_mode);
cJSON_AddNumberToObject(state_obj, "error_code", g_device_message.state.error_code);
cJSON_AddBoolToObject(state_obj, "auto_mode", g_device_message.state.auto_mode);
cJSON_AddItemToObject(data_obj, "state", state_obj);
cJSON *telemetry_obj = cJSON_CreateObject();
cJSON_AddStringToObject(telemetry_obj, "fan_state", g_device_message.telemetry.fan_state);
cJSON_AddStringToObject(telemetry_obj, "led_state", g_device_message.telemetry.led_state);
cJSON_AddNumberToObject(telemetry_obj, "led_power", g_device_message.telemetry.led_power);
cJSON_AddStringToObject(telemetry_obj, "curtain_state", g_device_message.telemetry.curtain_state);
cJSON_AddStringToObject(telemetry_obj, "buzzer_state", g_device_message.telemetry.buzzer_state);
// 添加 SGP30 传感器数据
cJSON_AddNumberToObject(telemetry_obj, "co2_ppm", g_device_message.telemetry.co2_ppm);
cJSON_AddNumberToObject(telemetry_obj, "tvoc_ppb", g_device_message.telemetry.tvoc_ppb);
cJSON_AddItemToObject(data_obj, "telemetry", telemetry_obj);
// 添加闹钟状态信息
cJSON *alarms_obj = cJSON_CreateArray();
for (int i = 0; i < ALARM_MAX_NUM; i++)
{
uint8_t hour, minute, second;
bool enabled, triggered;
alarm_get_status(i, &hour, &minute, &second, &enabled, &triggered);
cJSON *alarm_obj = cJSON_CreateObject();
char alarm_name[32]; // 增加缓冲区大小以避免截断
snprintf(alarm_name, sizeof(alarm_name), "alarm%d", i + 1);
cJSON_AddStringToObject(alarm_obj, "name", alarm_name);
char time_str[32]; // 增加缓冲区大小以避免截断
snprintf(time_str, sizeof(time_str), "%02d:%02d:%02d", hour, minute, second);
cJSON_AddStringToObject(alarm_obj, "time", time_str);
cJSON_AddBoolToObject(alarm_obj, "enabled", enabled);
cJSON_AddBoolToObject(alarm_obj, "triggered", triggered);
cJSON_AddItemToArray(alarms_obj, alarm_obj);
}
cJSON_AddItemToObject(data_obj, "alarms", alarms_obj);
// 优先写入静态缓冲,减少堆分配
char *json_message_fb = NULL;
bool json_fb_heap = false;
bool printed_fb = cJSON_PrintPreallocated(root, GLOBAL_MQTT_JSON_BUFFER, sizeof(GLOBAL_MQTT_JSON_BUFFER), 0);
if (printed_fb)
{
json_message_fb = GLOBAL_MQTT_JSON_BUFFER;
json_fb_heap = false;
}
else
{
json_message_fb = cJSON_Print(root);
json_fb_heap = (json_message_fb != NULL);
}
cJSON_Delete(root);
if (json_message_fb)
{
esp_mqtt_client_publish(g_mqtt_client, MQTT_PUBLISH_TOPIC_QOS0, json_message_fb, 0, 0, 0);
if (json_fb_heap)
{
free(json_message_fb);
}
}
xSemaphoreGive(xMqttMessageMutex);
}
}
// 发布闹钟状态消息
void mqtt_manager_publish_alarm_status(int alarm_idx, const char *alarm_status, bool triggered)
{
if (g_mqtt_client == NULL || !g_mqtt_connected)
return;
if (xMqttMessageMutex != NULL && xSemaphoreTake(xMqttMessageMutex, portMAX_DELAY) == pdTRUE)
{
time_t now;
time(&now);
g_device_message.timestamp = (uint64_t)(now * 1000ULL);
cJSON *root = cJSON_CreateObject();
cJSON_AddStringToObject(root, "type", "device_message");
cJSON_AddStringToObject(root, "device_id", g_device_message.device_id);
cJSON_AddStringToObject(root, "device_type", g_device_message.device_type);
// 使用字符串表示时间戳,避免浮点数转换的栈溢出问题
char timestamp_str[32];
snprintf(timestamp_str, sizeof(timestamp_str), "%llu", g_device_message.timestamp);
cJSON_AddStringToObject(root, "timestamp", timestamp_str);
cJSON_AddStringToObject(root, "message_type", "alarm_status");
cJSON *data_obj = cJSON_CreateObject();
cJSON_AddItemToObject(root, "data", data_obj);
cJSON *alarm_obj = cJSON_CreateObject();
char alarm_name[32]; // 增加缓冲区大小以避免截断
snprintf(alarm_name, sizeof(alarm_name), "alarm%d", alarm_idx + 1);
cJSON_AddStringToObject(alarm_obj, "alarm_name", alarm_name);
cJSON_AddStringToObject(alarm_obj, "status", alarm_status);
cJSON_AddBoolToObject(alarm_obj, "triggered", triggered);
cJSON_AddItemToObject(data_obj, "alarm", alarm_obj);
// 包含当前设备状态
cJSON *state_obj = cJSON_CreateObject();
cJSON_AddBoolToObject(state_obj, "online", g_device_message.state.online);
cJSON_AddStringToObject(state_obj, "current_mode", g_device_message.state.current_mode);
cJSON_AddBoolToObject(state_obj, "standby_mode", g_device_message.state.standby_mode);
cJSON_AddNumberToObject(state_obj, "error_code", g_device_message.state.error_code);
cJSON_AddBoolToObject(state_obj, "auto_mode", g_device_message.state.auto_mode);
cJSON_AddItemToObject(data_obj, "state", state_obj);
// 包含当前设备遥测数据
cJSON *telemetry_obj = cJSON_CreateObject();
cJSON_AddStringToObject(telemetry_obj, "fan_state", g_device_message.telemetry.fan_state);
cJSON_AddStringToObject(telemetry_obj, "led_state", g_device_message.telemetry.led_state);
cJSON_AddNumberToObject(telemetry_obj, "led_power", g_device_message.telemetry.led_power);
cJSON_AddStringToObject(telemetry_obj, "curtain_state", g_device_message.telemetry.curtain_state);
cJSON_AddStringToObject(telemetry_obj, "buzzer_state", g_device_message.telemetry.buzzer_state);
cJSON_AddItemToObject(data_obj, "telemetry", telemetry_obj);
// 优先写入静态缓冲,减少堆分配
char *json_message_alarm = NULL;
bool json_alarm_heap = false;
bool printed_alarm = cJSON_PrintPreallocated(root, GLOBAL_MQTT_JSON_BUFFER, sizeof(GLOBAL_MQTT_JSON_BUFFER), 0);
if (printed_alarm)
{
json_message_alarm = GLOBAL_MQTT_JSON_BUFFER;
json_alarm_heap = false;
}
else
{
json_message_alarm = cJSON_Print(root);
json_alarm_heap = (json_message_alarm != NULL);
}
cJSON_Delete(root);
if (json_message_alarm)
{
ESP_LOGI(TAG, "发布闹钟状态: alarm%d %s (triggered=%d)", alarm_idx + 1, alarm_status, triggered);
esp_mqtt_client_publish(g_mqtt_client, MQTT_PUBLISH_TOPIC_QOS0, json_message_alarm, 0, 0, 0);
if (json_alarm_heap)
{
free(json_message_alarm);
}
}
xSemaphoreGive(xMqttMessageMutex);
}
}
static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data)
{
ESP_LOGD(TAG, "Event dispatched from event loop base=%s, event_id=%" PRIi32 "", base, event_id);
esp_mqtt_event_handle_t event = event_data;
esp_mqtt_client_handle_t client = event->client;
int msg_id;
switch ((esp_mqtt_event_id_t)event_id)
{
case MQTT_EVENT_CONNECTED:
ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED");
g_mqtt_connected = true;
g_mqtt_retry_count = 0; // 重置重试计数器
msg_id = esp_mqtt_client_subscribe(client, MQTT_NOTIFY_TOPIC, 2);
ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);
break;
case MQTT_EVENT_DISCONNECTED:
ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED");
g_mqtt_connected = false;
// 如果不是手动停止,尝试重连
if (g_mqtt_client != NULL && g_mqtt_retry_count < MQTT_MAX_RETRY_COUNT)
{
g_mqtt_retry_count++;
ESP_LOGI(TAG, "MQTT断开连接%d秒后尝试重连 (第%d次)",
MQTT_RETRY_DELAY_MS/1000, g_mqtt_retry_count);
// 延迟后重连
vTaskDelay(pdMS_TO_TICKS(MQTT_RETRY_DELAY_MS));
esp_mqtt_client_reconnect(g_mqtt_client);
}
else if (g_mqtt_retry_count >= MQTT_MAX_RETRY_COUNT)
{
ESP_LOGW(TAG, "MQTT重连次数已达上限(%d次),停止重试", MQTT_MAX_RETRY_COUNT);
}
break;
case MQTT_EVENT_SUBSCRIBED:
ESP_LOGI(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d", event->msg_id);
msg_id = esp_mqtt_client_publish(client, MQTT_PUBLISH_TOPIC_QOS0, "data", 0, 0, 0);
ESP_LOGI(TAG, "sent publish successful, msg_id=%d", msg_id);
break;
case MQTT_EVENT_UNSUBSCRIBED:
ESP_LOGI(TAG, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id);
break;
case MQTT_EVENT_PUBLISHED:
ESP_LOGI(TAG, "MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id);
break;
case MQTT_EVENT_DATA:
ESP_LOGI(TAG, "MQTT_EVENT_DATA");
printf("TOPIC=%.*s\r\n", event->topic_len, event->topic);
printf("DATA=%.*s\r\n", event->data_len, event->data);
if (strncmp(event->topic, MQTT_NOTIFY_TOPIC, event->topic_len) == 0)
{
cJSON *root = cJSON_ParseWithLength(event->data, event->data_len);
if (root == NULL)
{
ESP_LOGE(TAG, "Failed to parse JSON data");
break;
}
cJSON *type_obj = cJSON_GetObjectItem(root, "type");
if (type_obj != NULL && cJSON_IsString(type_obj) && strcmp(type_obj->valuestring, "status") == 0)
{
cJSON *subtype_obj = cJSON_GetObjectItem(root, "subtype");
cJSON *status_obj = cJSON_GetObjectItem(root, "status");
const char *status_str = NULL;
if (subtype_obj != NULL && cJSON_IsString(subtype_obj))
{
status_str = cJSON_GetStringValue(subtype_obj);
}
else if (status_obj != NULL && cJSON_IsString(status_obj))
{
status_str = cJSON_GetStringValue(status_obj);
}
if (status_str != NULL && strcmp(status_str, "online") == 0)
{
ESP_LOGI(TAG, "Received status online message, starting reporting");
if (xMqttMessageMutex != NULL && xSemaphoreTake(xMqttMessageMutex, portMAX_DELAY) == pdTRUE)
{
g_device_message.state.online = true;
g_device_message.state.home_status = true;
xSemaphoreGive(xMqttMessageMutex);
}
mqtt_manager_publish_feedback();
}
cJSON_Delete(root);
break;
}
if (type_obj == NULL || !cJSON_IsString(type_obj))
{
ESP_LOGE(TAG, "Invalid message type");
cJSON_Delete(root);
break;
}
cJSON *device_id_obj = cJSON_GetObjectItem(root, "device_id");
cJSON *device_type_obj = cJSON_GetObjectItem(root, "device_type");
if (device_id_obj == NULL || !cJSON_IsString(device_id_obj) ||
device_type_obj == NULL || !cJSON_IsString(device_type_obj))
{
ESP_LOGE(TAG, "Missing device identification");
cJSON_Delete(root);
break;
}
if (strcmp(cJSON_GetStringValue(device_id_obj), "esp32_bedroom_001") != 0 ||
strcmp(cJSON_GetStringValue(device_type_obj), "bedroom_controller") != 0)
{
ESP_LOGE(TAG, "Device identification does not match");
cJSON_Delete(root);
break;
}
if (strcmp(type_obj->valuestring, "control_command") == 0)
{
cJSON *request_id_obj = cJSON_GetObjectItem(root, "request_id");
if (request_id_obj != NULL && cJSON_IsString(request_id_obj))
{
ESP_LOGI(TAG, "Received request_id: %s", request_id_obj->valuestring);
}
cJSON *message_type_obj = cJSON_GetObjectItem(root, "message_type");
if (message_type_obj != NULL && cJSON_IsString(message_type_obj))
{
const char *message_type = cJSON_GetStringValue(message_type_obj);
if (strcmp(message_type, "presence_request") == 0)
{
cJSON *data_obj = cJSON_GetObjectItem(root, "data");
if (data_obj != NULL && cJSON_IsObject(data_obj))
{
cJSON *presence_obj = cJSON_GetObjectItem(data_obj, "presence");
if (presence_obj != NULL && cJSON_IsString(presence_obj))
{
const char *presence_status = cJSON_GetStringValue(presence_obj);
ESP_LOGI(TAG, "Received presence status: %s", presence_status);
if (xMqttMessageMutex != NULL && xSemaphoreTake(xMqttMessageMutex, portMAX_DELAY) == pdTRUE)
{
if (strcmp(presence_status, "home") == 0)
{
g_device_message.state.home_status = true;
led_backlight_on = true;
ESP_LOGI(TAG, "Device is present at home");
}
else if (strcmp(presence_status, "away") == 0)
{
g_device_message.state.home_status = false;
led_backlight_on = false;
ESP_LOGI(TAG, "Device is away from home");
}
xSemaphoreGive(xMqttMessageMutex);
}
}
}
}
else if (strcmp(message_type, "control_request") == 0)
{
ESP_LOGI(TAG, "Received control_request message");
// 首先检查是否有config对象用于设置自动/手动模式
cJSON *data_obj = cJSON_GetObjectItem(root, "data");
if (data_obj != NULL && cJSON_IsObject(data_obj))
{
// 检查是否有config.auto_mode字段
cJSON *config_obj = cJSON_GetObjectItem(data_obj, "config");
if (config_obj != NULL && cJSON_IsObject(config_obj))
{
cJSON *auto_mode_obj = cJSON_GetObjectItem(config_obj, "auto_mode");
if (auto_mode_obj != NULL && cJSON_IsBool(auto_mode_obj))
{
bool auto_mode = cJSON_IsTrue(auto_mode_obj);
ESP_LOGI(TAG, "Setting auto_mode to: %s", auto_mode ? "true (Auto)" : "false (Manual)");
if (xMqttMessageMutex != NULL && xSemaphoreTake(xMqttMessageMutex, portMAX_DELAY) == pdTRUE)
{
g_device_message.state.auto_mode = auto_mode;
if (auto_mode) {
strcpy(g_device_message.state.current_mode, "auto");
set_var_mode("Auto");
} else {
strcpy(g_device_message.state.current_mode, "manual");
set_var_mode("Manual");
}
xSemaphoreGive(xMqttMessageMutex);
}
// 自动/手动模式联动自动功能
if (auto_mode) {
g_cooling_mode_enabled = true;
g_use_time_period = true;
cooling_mode_save_to_nvs();
time_period_save_to_nvs();
ESP_LOGI(TAG, "自动模式: 已开启降温、时间段等自动功能");
} else {
g_cooling_mode_enabled = false;
g_use_time_period = false;
cooling_mode_save_to_nvs();
time_period_save_to_nvs();
ESP_LOGI(TAG, "手动模式: 已关闭降温、时间段等自动功能");
}
// 发布反馈消息
mqtt_manager_publish_feedback();
}
else
{
ESP_LOGW(TAG, "auto_mode field not found or not boolean in config");
}
}
else
{
// 如果没有config对象检查是否有controls对象
// 这样control_request消息也可以用于设备控制
cJSON *controls_obj = cJSON_GetObjectItem(data_obj, "controls");
if (controls_obj != NULL && cJSON_IsObject(controls_obj))
{
ESP_LOGI(TAG, "Processing control command in control_request");
// 直接在这里处理controls对象避免goto带来的作用域问题
// 处理风扇控制
cJSON *fan_power_obj = cJSON_GetObjectItem(controls_obj, "fan_state");
if (fan_power_obj != NULL && cJSON_IsString(fan_power_obj))
{
const char *fan_power_str = cJSON_GetStringValue(fan_power_obj);
if (strcmp(fan_power_str, "open") == 0)
{
strcpy(g_device_message.telemetry.fan_state, "open");
if (xControlFlagMutex != NULL && xSemaphoreTake(xControlFlagMutex, portMAX_DELAY) == pdTRUE)
{
fan_control_flag = true;
xSemaphoreGive(xControlFlagMutex);
}
ESP_LOGI(TAG, "Fan turned OPEN");
}
else if (strcmp(fan_power_str, "close") == 0 || strcmp(fan_power_str, "closed") == 0)
{
strcpy(g_device_message.telemetry.fan_state, "close");
if (xControlFlagMutex != NULL && xSemaphoreTake(xControlFlagMutex, portMAX_DELAY) == pdTRUE)
{
fan_control_flag = false;
xSemaphoreGive(xControlFlagMutex);
}
ESP_LOGI(TAG, "Fan turned CLOSE");
}
mqtt_manager_publish_feedback();
}
// 处理窗帘控制
cJSON *curtain_obj = cJSON_GetObjectItem(controls_obj, "curtain_state");
if (curtain_obj != NULL && cJSON_IsString(curtain_obj))
{
const char *curtain_str = cJSON_GetStringValue(curtain_obj);
if (strcmp(curtain_str, "open") == 0)
{
strcpy(g_device_message.telemetry.curtain_state, "open");
if (xControlFlagMutex != NULL && xSemaphoreTake(xControlFlagMutex, portMAX_DELAY) == pdTRUE)
{
servo_control_flag = true;
xSemaphoreGive(xControlFlagMutex);
}
ESP_LOGI(TAG, "Curtain opened");
}
else if (strcmp(curtain_str, "close") == 0 || strcmp(curtain_str, "closed") == 0)
{
strcpy(g_device_message.telemetry.curtain_state, "close");
if (xControlFlagMutex != NULL && xSemaphoreTake(xControlFlagMutex, portMAX_DELAY) == pdTRUE)
{
servo_control_flag = false;
xSemaphoreGive(xControlFlagMutex);
}
ESP_LOGI(TAG, "Curtain closed");
}
mqtt_manager_publish_feedback();
}
// 处理蜂鸣器控制
cJSON *buzzer_power_obj = cJSON_GetObjectItem(controls_obj, "buzzer_state");
if (buzzer_power_obj != NULL && cJSON_IsString(buzzer_power_obj))
{
const char *buzzer_power_str = cJSON_GetStringValue(buzzer_power_obj);
if (strcmp(buzzer_power_str, "open") == 0)
{
strcpy(g_device_message.telemetry.buzzer_state, "open");
if (xControlFlagMutex != NULL && xSemaphoreTake(xControlFlagMutex, portMAX_DELAY) == pdTRUE)
{
buzzer_control_flag = true;
xSemaphoreGive(xControlFlagMutex);
}
ESP_LOGI(TAG, "Buzzer turned OPEN");
}
else if (strcmp(buzzer_power_str, "close") == 0 || strcmp(buzzer_power_str, "closed") == 0)
{
strcpy(g_device_message.telemetry.buzzer_state, "close");
if (xControlFlagMutex != NULL && xSemaphoreTake(xControlFlagMutex, portMAX_DELAY) == pdTRUE)
{
buzzer_control_flag = false;
xSemaphoreGive(xControlFlagMutex);
}
ESP_LOGI(TAG, "Buzzer turned CLOSE");
}
mqtt_manager_publish_feedback();
}
// 处理LED控制
cJSON *led_state_obj = cJSON_GetObjectItem(controls_obj, "led_state");
cJSON *led_power_obj = cJSON_GetObjectItem(controls_obj, "led_power");
bool led_changed = false;
if (led_power_obj != NULL && cJSON_IsNumber(led_power_obj))
{
int power = cJSON_GetNumberValue(led_power_obj);
if (power < 0)
power = 0;
if (power > 100)
power = 100;
g_device_message.telemetry.led_power = (uint8_t)power;
strcpy(g_device_message.telemetry.led_state, power > 0 ? "open" : "close");
led_brightness_value = (uint8_t)power;
light_source_control_flag = (power > 0);
ESP_LOGI(TAG, "LED power set to %d", power);
led_changed = true;
}
else if (led_state_obj != NULL && cJSON_IsString(led_state_obj))
{
const char *state = cJSON_GetStringValue(led_state_obj);
if (strcmp(state, "open") == 0)
{
strcpy(g_device_message.telemetry.led_state, "open");
g_device_message.telemetry.led_power = 100;
if (xControlFlagMutex != NULL && xSemaphoreTake(xControlFlagMutex, portMAX_DELAY) == pdTRUE)
{
led_brightness_value = 100;
light_source_control_flag = true;
xSemaphoreGive(xControlFlagMutex);
}
ESP_LOGI(TAG, "LED turned OPEN");
led_changed = true;
}
else if (strcmp(state, "close") == 0 || strcmp(state, "closed") == 0)
{
strcpy(g_device_message.telemetry.led_state, "close");
g_device_message.telemetry.led_power = 0;
if (xControlFlagMutex != NULL && xSemaphoreTake(xControlFlagMutex, portMAX_DELAY) == pdTRUE)
{
led_brightness_value = 0;
light_source_control_flag = false;
xSemaphoreGive(xControlFlagMutex);
}
ESP_LOGI(TAG, "LED turned CLOSE");
led_changed = true;
}
}
if (led_changed)
{
mqtt_manager_publish_feedback();
}
// 处理闹钟设置
ESP_LOGI(TAG, "Starting alarm processing in control_request");
for (int ai = 1; ai <= ALARM_MAX_NUM; ai++)
{
char key_time[32];
char key_enable[32];
snprintf(key_time, sizeof(key_time), "alarm%d_time", ai);
snprintf(key_enable, sizeof(key_enable), "alarm%d_enable", ai);
ESP_LOGI(TAG, "Checking for alarm keys: %s, %s", key_time, key_enable);
cJSON *alarm_time_obj = cJSON_GetObjectItem(controls_obj, key_time);
if (alarm_time_obj != NULL && cJSON_IsString(alarm_time_obj))
{
const char *time_str = cJSON_GetStringValue(alarm_time_obj);
ESP_LOGI(TAG, "Found alarm%d_time: %s", ai, time_str);
int hh = 0, mm = 0, ss = 0;
int parts = 0;
parts = sscanf(time_str, "%d:%d:%d", &hh, &mm, &ss);
ESP_LOGI(TAG, "Parsed time: parts=%d, hh=%d, mm=%d, ss=%d", parts, hh, mm, ss);
if (parts >= 2)
{
if (parts == 2)
ss = 0;
ESP_LOGI(TAG, "Set alarm%d time to %02d:%02d:%02d", ai, hh, mm, ss);
alarm_set_time(ai - 1, hh, mm, ss);
}
else
{
ESP_LOGW(TAG, "Failed to parse alarm time: %s", time_str);
}
}
else
{
ESP_LOGI(TAG, "No alarm%d_time found or not a string", ai);
}
cJSON *alarm_enable_obj = cJSON_GetObjectItem(controls_obj, key_enable);
if (alarm_enable_obj != NULL && cJSON_IsString(alarm_enable_obj))
{
const char *enable_str = cJSON_GetStringValue(alarm_enable_obj);
ESP_LOGI(TAG, "Found alarm%d_enable: %s", ai, enable_str);
bool enable = false;
if (strcasecmp(enable_str, "on") == 0 || strcasecmp(enable_str, "true") == 0 || strcasecmp(enable_str, "enable") == 0)
enable = true;
else
enable = false;
ESP_LOGI(TAG, "Set alarm%d enable = %s", ai, enable ? "true" : "false");
alarm_set_enable(ai - 1, enable);
}
else
{
ESP_LOGI(TAG, "No alarm%d_enable found or not a string", ai);
}
if ((alarm_time_obj != NULL && cJSON_IsString(alarm_time_obj)) || (alarm_enable_obj != NULL && cJSON_IsString(alarm_enable_obj)))
{
ESP_LOGI(TAG, "Alarm settings changed, publishing feedback");
mqtt_manager_publish_feedback();
}
}
}
else
{
ESP_LOGW(TAG, "Neither config nor controls object found in data");
}
}
}
else
{
ESP_LOGW(TAG, "data object not found in control_request");
}
}
else
{
// 对于其他类型的消息假设是control_command类型
cJSON *data_obj = cJSON_GetObjectItem(root, "data");
if (data_obj != NULL && cJSON_IsObject(data_obj))
{
cJSON *controls_obj = cJSON_GetObjectItem(data_obj, "controls");
if (controls_obj != NULL && cJSON_IsObject(controls_obj))
{
ESP_LOGI(TAG, "Processing control command");
// 处理风扇控制
cJSON *fan_power_obj = cJSON_GetObjectItem(controls_obj, "fan_state");
if (fan_power_obj != NULL && cJSON_IsString(fan_power_obj))
{
const char *fan_power_str = cJSON_GetStringValue(fan_power_obj);
if (strcmp(fan_power_str, "open") == 0)
{
strcpy(g_device_message.telemetry.fan_state, "open");
if (xControlFlagMutex != NULL && xSemaphoreTake(xControlFlagMutex, portMAX_DELAY) == pdTRUE)
{
fan_control_flag = true;
xSemaphoreGive(xControlFlagMutex);
}
ESP_LOGI(TAG, "Fan turned OPEN");
}
else if (strcmp(fan_power_str, "close") == 0 || strcmp(fan_power_str, "closed") == 0)
{
strcpy(g_device_message.telemetry.fan_state, "close");
if (xControlFlagMutex != NULL && xSemaphoreTake(xControlFlagMutex, portMAX_DELAY) == pdTRUE)
{
fan_control_flag = false;
xSemaphoreGive(xControlFlagMutex);
}
ESP_LOGI(TAG, "Fan turned CLOSE");
}
mqtt_manager_publish_feedback();
}
cJSON *curtain_obj = cJSON_GetObjectItem(controls_obj, "curtain_state");
if (curtain_obj != NULL && cJSON_IsString(curtain_obj))
{
const char *curtain_str = cJSON_GetStringValue(curtain_obj);
if (strcmp(curtain_str, "open") == 0)
{
strcpy(g_device_message.telemetry.curtain_state, "open");
if (xControlFlagMutex != NULL && xSemaphoreTake(xControlFlagMutex, portMAX_DELAY) == pdTRUE)
{
servo_control_flag = true;
xSemaphoreGive(xControlFlagMutex);
}
ESP_LOGI(TAG, "Curtain opened");
}
else if (strcmp(curtain_str, "close") == 0 || strcmp(curtain_str, "closed") == 0)
{
strcpy(g_device_message.telemetry.curtain_state, "close");
if (xControlFlagMutex != NULL && xSemaphoreTake(xControlFlagMutex, portMAX_DELAY) == pdTRUE)
{
servo_control_flag = false;
xSemaphoreGive(xControlFlagMutex);
}
ESP_LOGI(TAG, "Curtain closed");
}
mqtt_manager_publish_feedback();
}
cJSON *buzzer_power_obj = cJSON_GetObjectItem(controls_obj, "buzzer_state");
if (buzzer_power_obj != NULL && cJSON_IsString(buzzer_power_obj))
{
const char *buzzer_power_str = cJSON_GetStringValue(buzzer_power_obj);
if (strcmp(buzzer_power_str, "open") == 0)
{
strcpy(g_device_message.telemetry.buzzer_state, "open");
if (xControlFlagMutex != NULL && xSemaphoreTake(xControlFlagMutex, portMAX_DELAY) == pdTRUE)
{
buzzer_control_flag = true;
xSemaphoreGive(xControlFlagMutex);
}
ESP_LOGI(TAG, "Buzzer turned OPEN");
}
else if (strcmp(buzzer_power_str, "close") == 0 || strcmp(buzzer_power_str, "closed") == 0)
{
strcpy(g_device_message.telemetry.buzzer_state, "close");
if (xControlFlagMutex != NULL && xSemaphoreTake(xControlFlagMutex, portMAX_DELAY) == pdTRUE)
{
buzzer_control_flag = false;
xSemaphoreGive(xControlFlagMutex);
}
ESP_LOGI(TAG, "Buzzer turned CLOSE");
}
mqtt_manager_publish_feedback();
}
cJSON *led_state_obj = cJSON_GetObjectItem(controls_obj, "led_state");
cJSON *led_power_obj = cJSON_GetObjectItem(controls_obj, "led_power");
if (led_power_obj != NULL && cJSON_IsNumber(led_power_obj))
{
int power = cJSON_GetNumberValue(led_power_obj);
if (power < 0)
power = 0;
if (power > 100)
power = 100;
g_device_message.telemetry.led_power = (uint8_t)power;
strcpy(g_device_message.telemetry.led_state, power > 0 ? "open" : "close");
led_brightness_value = (uint8_t)power;
light_source_control_flag = (power > 0);
ESP_LOGI(TAG, "LED power set to %d", power);
}
else if (led_state_obj != NULL && cJSON_IsString(led_state_obj))
{
const char *state = cJSON_GetStringValue(led_state_obj);
if (strcmp(state, "open") == 0)
{
strcpy(g_device_message.telemetry.led_state, "open");
g_device_message.telemetry.led_power = 100;
if (xControlFlagMutex != NULL && xSemaphoreTake(xControlFlagMutex, portMAX_DELAY) == pdTRUE)
{
led_brightness_value = 100;
light_source_control_flag = true;
xSemaphoreGive(xControlFlagMutex);
}
ESP_LOGI(TAG, "LED turned OPEN");
}
else if (strcmp(state, "close") == 0 || strcmp(state, "closed") == 0)
{
strcpy(g_device_message.telemetry.led_state, "close");
g_device_message.telemetry.led_power = 0;
if (xControlFlagMutex != NULL && xSemaphoreTake(xControlFlagMutex, portMAX_DELAY) == pdTRUE)
{
led_brightness_value = 0;
light_source_control_flag = false;
xSemaphoreGive(xControlFlagMutex);
}
ESP_LOGI(TAG, "LED turned CLOSE");
}
else
{
ESP_LOGW(TAG, "Invalid LED command: %s", state);
}
}
cJSON *day_period_start_obj = cJSON_GetObjectItem(controls_obj, "day_period_start");
cJSON *day_period_end_obj = cJSON_GetObjectItem(controls_obj, "day_period_end");
cJSON *night_period_start_obj = cJSON_GetObjectItem(controls_obj, "night_period_start");
cJSON *night_period_end_obj = cJSON_GetObjectItem(controls_obj, "night_period_end");
bool period_changed = false;
if (day_period_start_obj != NULL && cJSON_IsString(day_period_start_obj) &&
day_period_end_obj != NULL && cJSON_IsString(day_period_end_obj))
{
const char *start_str = cJSON_GetStringValue(day_period_start_obj);
const char *end_str = cJSON_GetStringValue(day_period_end_obj);
int start_hh = 0, start_mm = 0, end_hh = 0, end_mm = 0;
if (sscanf(start_str, "%d:%d", &start_hh, &start_mm) >= 2 &&
sscanf(end_str, "%d:%d", &end_hh, &end_mm) >= 2)
{
ESP_LOGI(TAG, "Set day period: %02d:%02d - %02d:%02d",
start_hh, start_mm, end_hh, end_mm);
time_period_set(TIME_PERIOD_DAY, start_hh, start_mm, end_hh, end_mm);
period_changed = true;
}
}
if (night_period_start_obj != NULL && cJSON_IsString(night_period_start_obj) &&
night_period_end_obj != NULL && cJSON_IsString(night_period_end_obj))
{
const char *start_str = cJSON_GetStringValue(night_period_start_obj);
const char *end_str = cJSON_GetStringValue(night_period_end_obj);
int start_hh = 0, start_mm = 0, end_hh = 0, end_mm = 0;
if (sscanf(start_str, "%d:%d", &start_hh, &start_mm) >= 2 &&
sscanf(end_str, "%d:%d", &end_hh, &end_mm) >= 2)
{
ESP_LOGI(TAG, "Set night period: %02d:%02d - %02d:%02d",
start_hh, start_mm, end_hh, end_mm);
time_period_set(TIME_PERIOD_NIGHT, start_hh, start_mm, end_hh, end_mm);
period_changed = true;
}
}
if (period_changed)
{
mqtt_manager_publish_feedback();
}
// 处理时间段启用控制
cJSON *use_time_period_obj = cJSON_GetObjectItem(controls_obj, "use_time_period");
if (use_time_period_obj != NULL && cJSON_IsBool(use_time_period_obj))
{
g_use_time_period = cJSON_IsTrue(use_time_period_obj) ? true : false;
time_period_save_to_nvs();
ESP_LOGI(TAG, "时间段控制 %s", g_use_time_period ? "启用" : "禁用");
mqtt_manager_publish_feedback();
}
cJSON *temp_threshold_obj = cJSON_GetObjectItem(controls_obj, "temperature_threshold");
if (temp_threshold_obj != NULL && cJSON_IsNumber(temp_threshold_obj))
{
float threshold = (float)cJSON_GetNumberValue(temp_threshold_obj);
if (threshold < 10.0f)
threshold = 10.0f;
if (threshold > 40.0f)
threshold = 40.0f;
g_temperature_threshold = threshold;
g_cooling_mode_enabled = true;
cooling_mode_save_to_nvs();
ESP_LOGI(TAG, "Cooling mode temperature threshold set to %.1f°C", g_temperature_threshold);
mqtt_manager_publish_feedback();
}
}
}
}
}
cJSON_Delete(root);
}
}
break;
case MQTT_EVENT_ERROR:
ESP_LOGI(TAG, "MQTT_EVENT_ERROR");
if (event->error_handle->error_type == MQTT_ERROR_TYPE_TCP_TRANSPORT)
{
ESP_LOGI(TAG, "Last error code reported from esp-tls: 0x%x", event->error_handle->esp_tls_last_esp_err);
ESP_LOGI(TAG, "Last tls stack error number: 0x%x", event->error_handle->esp_tls_stack_err);
ESP_LOGI(TAG, "Last captured errno : %d (%s)", event->error_handle->esp_transport_sock_errno,
strerror(event->error_handle->esp_transport_sock_errno));
// 检查是否是DNS解析错误
if (event->error_handle->esp_tls_last_esp_err == 0x8002 || // ESP_ERR_ESP_TLS_CANNOT_RESOLVE_HOSTNAME
event->error_handle->esp_transport_sock_errno == 202 || // EAI_NONAME
event->error_handle->esp_transport_sock_errno == 203) // EAI_SERVICE
{
ESP_LOGE(TAG, "DNS解析失败请检查MQTT服务器地址: %s", MQTT_BROKER_URL);
ESP_LOGE(TAG, "可能的解决方案:");
ESP_LOGE(TAG, "1. 检查域名 %s 是否正确", "beihong.wang");
ESP_LOGE(TAG, "2. 检查网络连接");
ESP_LOGE(TAG, "3. 尝试使用IP地址代替域名");
}
}
else if (event->error_handle->error_type == MQTT_ERROR_TYPE_CONNECTION_REFUSED)
{
ESP_LOGI(TAG, "Connection refused error: 0x%x", event->error_handle->connect_return_code);
ESP_LOGI(TAG, "Possible reasons: wrong username/password, server refused connection");
}
else
{
ESP_LOGW(TAG, "Unknown error type: 0x%x", event->error_handle->error_type);
}
// 记录错误后尝试重连
if (g_mqtt_client != NULL && g_mqtt_retry_count < MQTT_MAX_RETRY_COUNT)
{
g_mqtt_retry_count++;
ESP_LOGI(TAG, "MQTT error, will retry in %d seconds (attempt %d/%d)",
MQTT_RETRY_DELAY_MS/1000, g_mqtt_retry_count, MQTT_MAX_RETRY_COUNT);
vTaskDelay(pdMS_TO_TICKS(MQTT_RETRY_DELAY_MS));
esp_mqtt_client_reconnect(g_mqtt_client);
}
break;
case MQTT_EVENT_ANY:
ESP_LOGI(TAG, "MQTT_EVENT_ANY");
break;
case MQTT_EVENT_BEFORE_CONNECT:
ESP_LOGI(TAG, "MQTT_EVENT_BEFORE_CONNECT");
break;
case MQTT_EVENT_DELETED:
ESP_LOGI(TAG, "MQTT_EVENT_DELETED");
break;
case MQTT_USER_EVENT:
ESP_LOGI(TAG, "MQTT_USER_EVENT");
break;
default:
ESP_LOGI(TAG, "Other event id:%d", event->event_id);
break;
}
}
esp_err_t mqtt_manager_init(void)
{
ESP_LOGI(TAG, "mqtt_manager_init");
return ESP_OK;
}
esp_err_t mqtt_manager_start(void)
{
// 生成基于MAC地址的唯一客户端ID
char client_id[32];
uint8_t mac[6];
esp_read_mac(mac, ESP_MAC_WIFI_STA);
sprintf(client_id, "esp32_%02x%02x%02x", mac[3], mac[4], mac[5]);
ESP_LOGI(TAG, "Generated Client ID: %s", client_id);
esp_mqtt_client_config_t mqtt_cfg = {
.broker.address.uri = MQTT_BROKER_URL,
.credentials.username = MQTT_USERNAME,
.credentials.client_id = client_id,
.credentials.authentication.password = MQTT_PASSWORD,
};
esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt_cfg);
esp_mqtt_client_register_event(client, ESP_EVENT_ANY_ID, mqtt_event_handler, NULL);
esp_mqtt_client_start(client);
g_mqtt_client = client;
xTaskCreate(mqtt_publish_task, "mqtt_publish_task", 3046, NULL, 5, NULL);
return ESP_OK;
}
esp_err_t mqtt_manager_stop(void)
{
if (g_mqtt_client != NULL)
{
esp_mqtt_client_stop(g_mqtt_client);
esp_mqtt_client_destroy(g_mqtt_client);
g_mqtt_client = NULL;
}
return ESP_OK;
}