(I apologize if this forum is not the appropriate place for these questions)
I would like to know if there is any kind of limitation.
In multiple connections wifi connections.
I have a product that connects to the internet via wifi.
I can make two MQTT connections with different or the same brokers work perfectly.
This is a requirement of my application.
However, I need to send an email. However, if mqtt is enabled, there are many errors generated when mqtt is enabled.
I use the ESP IDF 5 and MQTT Library, my code for the email is changed for the esp idf sample
My code the MQTT is:
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <ctype.h>
#include <float.h>
#include "esp_log.h"
#include "cJSON.h"
#include "mqtt_client.h"
#include "f_mqtt.h"
#include "f_config.h"
#include "f_licenca.h"
#include "f_nvs.h"
#include "f_configfile.h"
#include "f_wifi.h"
#include "f_ota.h"
EventGroupHandle_t xEventGroupMQTT_In;
EventGroupHandle_t xEventGroupMQTT_Out;
#define MQTT_In_BIT (1 << 0)
#define MQTT_Out_BIT (1 << 0)
//const int MQTT_CONNECTED_BIT = BIT0;
static const char *TAG = "MQTT";
esp_mqtt_client_handle_t cMqttIn;
esp_mqtt_client_handle_t cMqttOut;
static void log_error_if_nonzero(const char *message, int error_code){if (error_code != 0) {ESP_LOGE(TAG, "Last error %s: 0x%x", message, error_code);}}
//-----------------------------------------------------------------------------------------------------------------------
//--------------------------------MQTT In (Usuario)----------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------
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;
switch ((esp_mqtt_event_id_t)event_id) {
case MQTT_EVENT_CONNECTED:
ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED - MQTT-IN(Usuario)");
xEventGroupSetBits(xEventGroupMQTT_In, MQTT_In_BIT);
if (xEventGroupMQTT_In != NULL) {xEventGroupSetBits(xEventGroupMQTT_In, MQTT_In_BIT);}
break;
case MQTT_EVENT_DISCONNECTED:
ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED - MQTT-IN(Usuario)");
xEventGroupClearBits(xEventGroupMQTT_In, MQTT_In_BIT);
break;
case MQTT_EVENT_DATA:
f_SendDataMqtt(strndup(event->topic, event->topic_len), strndup(event->data, event->data_len), false);
break;
case MQTT_EVENT_ERROR:
ESP_LOGI(TAG, "MQTT_EVENT_ERROR - MQTT-IN(Usuario)");
if (event->error_handle->error_type == MQTT_ERROR_TYPE_TCP_TRANSPORT) {
log_error_if_nonzero("(MQTT-IN Usuario) - reported from esp-tls", event->error_handle->esp_tls_last_esp_err);
log_error_if_nonzero("(MQTT-IN Usuario) - reported from tls stack", event->error_handle->esp_tls_stack_err);
log_error_if_nonzero("(MQTT-IN Usuario) - captured as transport's socket errno", event->error_handle->esp_transport_sock_errno);
ESP_LOGI(TAG, "(MQTT-IN Usuario) - Last errno string (%s)", strerror(event->error_handle->esp_transport_sock_errno));
}
break;
default:
ESP_LOGI(TAG, "(MQTT-IN Usuario) - Other event id:%d - MQTT-IN(Usuario)", event->event_id);
break;
}
}
//-----------------------------------------------------------------------------------------------------------------------
//---MQTT OUT(LICENCA DA ENERVISION)-------------------------------------------------------------------------------------
//-----------------------------------------------------------------------------------------------------------------------
static void mqtt_event_handler_out(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;
switch ((esp_mqtt_event_id_t)event_id) {
case MQTT_EVENT_CONNECTED:
ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED - MQTT-OUT(Licenca Enervision)");
esp_mqtt_client_subscribe(client, TOPICO_OTA, 0);
esp_mqtt_client_subscribe(client, f_topico(TOPICO_LICENCA), 0);
f_mqttPublica(f_topico(zMQTT_sufixo), f_prepJsonConfig(mqtt_ON), cMqttOut);
f_mqttPublica(f_topico(zMQTT_sufixo_Config), f_prepJsonConfig(mqtt_Config), cMqttOut);
xEventGroupSetBits(xEventGroupMQTT_Out, MQTT_Out_BIT);
break;
case MQTT_EVENT_DISCONNECTED:
ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED - MQTT-OUT(Licenca Enervision)");
xEventGroupClearBits(xEventGroupMQTT_Out, MQTT_Out_BIT);
break;
case MQTT_EVENT_DATA:
ESP_LOGI(TAG, "MQTT_EVENT_DATA - MQTT-OUT(Licenca Enervision)");
printf("TOPIC=%.*s\r\n", event->topic_len, event->topic);
printf("DATA=%.*s\r\n", event->data_len, event->data);
//Testa qual tópico foi recebido e começa a fazer as coisas conforme o tópico
if (strncmp(event->topic, TOPICO_OTA, event->topic_len) == 0) {
f_otaMQTT(event->topic, event->topic_len, event->data, event->data_len);
}
if (strncmp(event->topic, f_topico(TOPICO_LICENCA), event->topic_len) == 0) {
cJSON *token = cJSON_GetObjectItem(cJSON_Parse((char *)event->data), "token");
if (!cJSON_IsString(token)){ESP_LOGE(TAG, "Erro na leitura do json");}
f_nvsSet(zTokenTemp, token->valuestring, false);
xTaskCreatePinnedToCore(v_InsertLicenca, "v_InsertLicenca", 8000, NULL, tskIDLE_PRIORITY, NULL, tskNO_AFFINITY);
}
break;
case MQTT_EVENT_ERROR:
ESP_LOGI(TAG, "MQTT_EVENT_ERROR - MQTT-OUT(Licenca Enervision)");
if (event->error_handle->error_type == MQTT_ERROR_TYPE_TCP_TRANSPORT) {
log_error_if_nonzero("(MQTT-OUT Licenca Enervision) - reported from esp-tls", event->error_handle->esp_tls_last_esp_err);
log_error_if_nonzero("r(MQTT-OUT Licenca Enervision) - eported from tls stack", event->error_handle->esp_tls_stack_err);
log_error_if_nonzero("(MQTT-OUT Licenca Enervision) - captured as transport's socket errno", event->error_handle->esp_transport_sock_errno);
ESP_LOGI(TAG, "(MQTT-OUT Licenca Enervision) - Last errno string (%s)", strerror(event->error_handle->esp_transport_sock_errno));
}
break;
default:
ESP_LOGI(TAG, "Other event id:%d - MQTT-OUT(Licenca Enervision)", event->event_id);
break;
}
}
void f_mqttPublica(const char * topico, const char * payload, esp_mqtt_client_handle_t handle){
EventBits_t bits = xEventGroupWaitBits(xEventGroupWifi, WIFI_BIT_0, pdFALSE, pdFALSE, 200);
if((bits & WIFI_BIT_0)){
int len = strlen(payload);
int resp = esp_mqtt_client_publish(handle, topico, payload, len, 0, 0);
if (resp==0){
// ESP_LOGI(TAG, "JSON publicado via MQTT. Com sucesso");
}else if(resp<0){
ESP_LOGE(TAG, "Publicação não enviada. Erro");
}
}
}
void f_setupMQTT_In(void *pvParameters){
xEventGroupMQTT_In = xEventGroupCreate();
Dados_Mqtt_t DadosMqtt;
if(f_DadosMqtt(&DadosMqtt, mqtt_IN) == ESP_OK){
bool is_secure = strstr(DadosMqtt.mqtt_server, "mqtts://") == DadosMqtt.mqtt_server;
esp_mqtt_client_config_t mqtt_cfg = {
.broker.address.uri = DadosMqtt.mqtt_server,
.broker.address.port = DadosMqtt.mqtt_port,
.credentials.username = DadosMqtt.mqtt_user,
.credentials.authentication.password = DadosMqtt.mqtt_pass,
.credentials.client_id = f_mqttId_In(),
.session.last_will.msg = f_prepJsonConfig(mqtt_OFF),
.session.last_will.msg_len = strlen(f_prepJsonConfig(mqtt_OFF)),
.session.last_will.topic = f_topico(zMQTT_sufixo),
.session.last_will.retain = true,
.session.last_will.qos = 1,
.session.keepalive = 120, // DadosMqtt.mqtt_keepalive
//.task.stack_size = 3200,
//.task.priority = tskIDLE_PRIORITY + 1
};
if (is_secure) {
char *cert_data = f_lerCertificado(DadosMqtt.mqtt_cert);
if (cert_data != NULL) {
mqtt_cfg.broker.verification.certificate = cert_data;
mqtt_cfg.broker.verification.certificate_len = strlen(cert_data) + 1;
} else {
ESP_LOGE("MQTT", "Falha ao carregar o certificado: %s", DadosMqtt.mqtt_cert);
}
}
EventBits_t bits = xEventGroupWaitBits(xEventGroupWifi, WIFI_BIT_0, pdFALSE, pdFALSE, portMAX_DELAY);
if((bits & WIFI_BIT_0)){
cMqttIn = esp_mqtt_client_init(&mqtt_cfg);
esp_mqtt_client_register_event(cMqttIn, ESP_EVENT_ANY_ID, mqtt_event_handler, NULL);
esp_mqtt_client_start(cMqttIn);
}
}
vTaskDelete(NULL);
}
void f_setupMQTT_Out(void *pvParameters){
xEventGroupMQTT_Out = xEventGroupCreate();
Dados_Mqtt_t DadosMqttout;
if(f_DadosMqtt(&DadosMqttout, mqtt_OUT) == ESP_OK){
bool is_secure = strstr(DadosMqttout.mqtt_server, "mqtts://") == DadosMqttout.mqtt_server;
esp_mqtt_client_config_t mqtt_cfg_out = {
.broker.address.uri = DadosMqttout.mqtt_server,
.broker.address.port = DadosMqttout.mqtt_port,
.credentials.username = DadosMqttout.mqtt_user,
.credentials.authentication.password = DadosMqttout.mqtt_pass,
.credentials.client_id = f_mqttId_Out(),
.session.last_will.msg = f_prepJsonConfig(mqtt_OFF),
.session.last_will.msg_len = strlen(f_prepJsonConfig(mqtt_OFF)),
.session.last_will.topic = f_topico(zMQTT_sufixo),
.session.last_will.retain = true,
.session.last_will.qos = 1,
.session.keepalive = 120, // DadosMqttout.mqtt_keepalive
//.task.stack_size = 3200,
//.task.priority = tskIDLE_PRIORITY + 1
};
if (is_secure) {
char *cert_data_out = f_lerCertificado(DadosMqttout.mqtt_cert);
if (cert_data_out != NULL) {
mqtt_cfg_out.broker.verification.certificate = cert_data_out;
mqtt_cfg_out.broker.verification.certificate_len = strlen(cert_data_out) + 1;
} else {
ESP_LOGE("MQTT", "Falha ao carregar o certificado: %s", DadosMqttout.mqtt_cert);
}
}
EventBits_t bits = xEventGroupWaitBits(xEventGroupWifi, WIFI_BIT_0, pdFALSE, pdFALSE, portMAX_DELAY);
if((bits & WIFI_BIT_0)){
cMqttOut = esp_mqtt_client_init(&mqtt_cfg_out);
esp_mqtt_client_register_event(cMqttOut, ESP_EVENT_ANY_ID, mqtt_event_handler_out, NULL);
esp_mqtt_client_start(cMqttOut);
}
}
vTaskDelete(NULL);
}
void f_startRestartMQTT_In() {xTaskCreate(f_restartMQTT_In, "f_setupMQTT_In", 3000, NULL, tskIDLE_PRIORITY, NULL);}
void f_startRestartMQTT_Out() {xTaskCreate(f_restartMQTT_Out, "f_setupMQTT_Out", 3000, NULL, tskIDLE_PRIORITY, NULL);}
void f_restartMQTT_In(void *pvParameters){
ESP_LOGI(TAG, "Reiniciando MQTT_In");
if (xEventGroupGetBits(xEventGroupMQTT_In) & MQTT_In_BIT) {
esp_mqtt_client_stop(cMqttIn); // Para o cliente MQTT
ESP_LOGI(TAG, "Stop MQTT_In");
}
ESP_LOGI(TAG, "Aguardando...Stop MQTT");
xEventGroupWaitBits(xEventGroupMQTT_In, MQTT_In_BIT, pdFALSE, pdFALSE, portMAX_DELAY);
xTaskCreate(f_setupMQTT_In, "f_setupMQTT_In", 3000, NULL, tskIDLE_PRIORITY, NULL);
ESP_LOGI(TAG, "Startado MQTT_In");
vTaskDelete(NULL); // Exclui a task após a execução
}
void f_restartMQTT_Out(void *pvParameters){
ESP_LOGI(TAG, "Reiniciando MQTT_Out");
if (xEventGroupGetBits(xEventGroupMQTT_Out) & MQTT_Out_BIT) {
esp_mqtt_client_stop(cMqttOut); // Para o cliente MQTT
ESP_LOGI(TAG, "Stop MQTT_Out");
}
ESP_LOGI(TAG, "Aguardando...Stop MQTT Out");
xEventGroupWaitBits(xEventGroupMQTT_Out, MQTT_Out_BIT, pdFALSE, pdFALSE, portMAX_DELAY);
xTaskCreate(f_setupMQTT_Out, "f_setupMQTT_Out", 3000, NULL, tskIDLE_PRIORITY, NULL);
ESP_LOGI(TAG, "Startado MQTT_Out");
vTaskDelete(NULL); // Exclui a task após a execução
}
void f_startMQTT_In(){
xTaskCreate(f_setupMQTT_In, "f_setupMQTT_In", 3000, NULL, tskIDLE_PRIORITY, NULL);
ESP_LOGI(TAG, "Startado MQTT_In");
}
void f_startMQTT_Out(){
xTaskCreate(f_setupMQTT_Out, "f_setupMQTT_Out", 3000, NULL, tskIDLE_PRIORITY, NULL);
ESP_LOGI(TAG, "Startado MQTT_Out");
}
void f_stopMQTT_In(){
ESP_LOGI(TAG, "Stopando MQTT_In");
if (xEventGroupGetBits(xEventGroupMQTT_In) & MQTT_In_BIT) {
esp_mqtt_client_disconnect(cMqttIn);
esp_mqtt_client_stop(cMqttIn);
esp_mqtt_client_destroy(cMqttIn);
ESP_LOGI(TAG, "Procedimentos de Stop do MQTT_In - Realizado");
}
}
void f_stopMQTT_Out(){
ESP_LOGI(TAG, "Stopando MQTT_Out");
if (xEventGroupGetBits(xEventGroupMQTT_Out) & MQTT_Out_BIT) {
esp_mqtt_client_disconnect(cMqttOut);
esp_mqtt_client_stop(cMqttOut);
esp_mqtt_client_destroy(cMqttOut);
ESP_LOGI(TAG, "Procedimentos de Stop do MQTT_Out - Realizado");
}
}
char* f_topico(const char* sufixo) {
int tamanho = snprintf(NULL, 0, "%s/%s/%s", TOPICO_PREFIXO, f_serialNumber(), sufixo);
char* topico = (char*)malloc(tamanho + 1);
if (topico == NULL) {return NULL;}
snprintf(topico, tamanho + 1, "%s/%s/%s", TOPICO_PREFIXO, f_serialNumber(), sufixo);
return topico;
}
void f_otaMQTT(char * topico, int tam_Topico, char * payload, int tam_Payload){
ESP_LOGW(TAG, "Recebi um pedido para atualizar o software");
char *url_dynamic = (char *)malloc(tam_Payload + 1);
if (url_dynamic != NULL) {
strncpy(url_dynamic, payload, tam_Payload);
url_dynamic[tam_Payload] = '\0';
f_startOTA(url_dynamic);
} else {
ESP_LOGE(TAG, "Failed to allocate memory for URL");
}
}
char * f_prepJsonConfig(prepMQTT_t tipo){
Dados_Licenca_t DadosLicenca;
f_DadosLicenca(&DadosLicenca);
cJSON *json = cJSON_CreateObject();
cJSON_AddStringToObject(json, "serial", f_serialNumber());
if (tipo == mqtt_Config){
cJSON_AddStringToObject(json, "versao-firmware", DadosLicenca.VersaoFirmware ? DadosLicenca.VersaoFirmware : "");
cJSON_AddStringToObject(json, "data-update", DadosLicenca.DataFirmware ? DadosLicenca.DataFirmware : "");
cJSON_AddStringToObject(json, "listen-topic", TOPICO_OTA);
cJSON_AddStringToObject(json, "hardware", Serial_Prefix);
cJSON_AddStringToObject(json, "usuario", DadosLicenca.Usuario);
cJSON_AddStringToObject(json, "tipo-licenca", DadosLicenca.TipoLicenca);
cJSON_AddNumberToObject(json, "tempo-validade", DadosLicenca.tempovalidade);
cJSON_AddNumberToObject(json, "licence-count", DadosLicenca.licencecount);
}
if(tipo == mqtt_ON) {cJSON_AddStringToObject(json, "status", "ON");}
if(tipo == mqtt_OFF){cJSON_AddStringToObject(json, "status", "OFF");}
char *json_str = cJSON_PrintUnformatted(json);
cJSON_Delete(json);
return json_str;
}
esp_err_t f_DadosMqtt(Dados_Mqtt_t *data, connMQTT_t conn){
cJSON *oJson;
if (conn == mqtt_IN){
oJson = read_json_file(FILE_MQTT_JSON);
} else{
oJson = read_json_file(FILE_MQTT_OUT_JSON);
}
if (oJson!=NULL){
data->mqtt_server = cJSON_GetStringValue(cJSON_GetObjectItem(oJson, "mqtt_server"));
data->mqtt_port = strtoul(cJSON_GetStringValue(cJSON_GetObjectItem(oJson, "mqtt_port")), NULL, 10);
data->mqtt_user = cJSON_GetStringValue(cJSON_GetObjectItem(oJson, "mqtt_user"));
data->mqtt_pass = cJSON_GetStringValue(cJSON_GetObjectItem(oJson, "mqtt_pass"));
data->mqtt_cert = cJSON_GetStringValue(cJSON_GetObjectItem(oJson, "mqtt_cert"));
data->mqtt_cert_len = data->mqtt_cert ? strlen(data->mqtt_cert) : 0;
if (data->mqtt_server == NULL) {ESP_LOGW(TAG, "Chave não encontrada (mqtt_server)");return ESP_FAIL;}
if (data->mqtt_port == 0) {ESP_LOGW(TAG, "Chave não encontrada (mqtt_port)"); return ESP_FAIL;}
if (data->mqtt_user == NULL) {ESP_LOGW(TAG, "Chave não encontrada (mqtt_user)");return ESP_FAIL;}
if (data->mqtt_pass == NULL) {ESP_LOGW(TAG, "Chave não encontrada (mqtt_pass)");return ESP_FAIL;}
bool is_secure = strstr(data->mqtt_server, "mqtts://") == data->mqtt_server;
if(is_secure){
if (data->mqtt_cert == NULL) {ESP_LOGW(TAG, "Conteudo vazio ou chave não encontrada (mqtt_cert)");return ESP_FAIL;}
if (data->mqtt_cert_len < 10) {ESP_LOGW(TAG, "Conteudo vazio ou chave não encontrada (mqtt_cert_len)");return ESP_FAIL;}
}
return ESP_OK;
}
return ESP_FAIL;
}
bool f_ValidaTopico(const char *topic) {
if (topic == NULL || strlen(topic) == 0) {return false;}
int len = strlen(topic);
if (len > 65535) {return false;}
for (int i = 0; i < len; i++) {
if (iscntrl((unsigned char)topic[i])) {
return false;
}
}
// Verificar regras específicas de MQTT para os caracteres '+' e '#'
for (int i = 0; i < len; i++) {
if (topic[i] == '+') {
// O caractere '+' deve estar sozinho em um nível
if (i > 0 && topic[i-1] != '/') return false;
if (i < len - 1 && topic[i+1] != '/') return false;
} else if (topic[i] == '#') {
// O caractere '#' só pode estar no final do tópico
if (i != len - 1) return false;
if (i > 0 && topic[i-1] != '/') return false;
} else if (topic[i] == '/' && i < len - 1 && topic[i+1] == '/') {
// Verificar se há dois '/' consecutivos
return false;
}
}
return true;
}
void f_subscribe(char * topico){
esp_mqtt_client_subscribe(cMqttIn, topico, 0);
ESP_LOGW(TAG, "Topico[%s] assinado", topico);
}
char *strndup(const char *src, size_t len) {
char *dst = (char *)malloc(len + 1);
if (dst) {
memcpy(dst, src, len);
dst[len] = '\0';
}
return dst;
}
char* f_mqttId_In() {
int tamanho = snprintf(NULL, 0, "%s:%s", "user", f_serialNumber());
char* msg = (char*)malloc(tamanho + 1);
if (msg == NULL) {return NULL;}
snprintf(msg, tamanho + 1, "%s:%s", "user", f_serialNumber());
return msg;
}
char* f_mqttId_Out() {
int tamanho = snprintf(NULL, 0, "%s:%s", "enervision", f_serialNumber());
char* msg = (char*)malloc(tamanho + 1);
if (msg == NULL) {return NULL;}
snprintf(msg, tamanho + 1, "%s:%s", "enervision", f_serialNumber());
return msg;
}
void f_SendDataMqtt(char *topico, char *payload, bool Print) {
}
and my code for send mail is:
#include <string.h>
#include <stdlib.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_event.h"
#include "esp_log.h"
#include "esp_system.h"
#include "nvs_flash.h"
#include "mbedtls/platform.h"
#include "mbedtls/net_sockets.h"
#include "mbedtls/esp_debug.h"
#include "mbedtls/ssl.h"
#include "mbedtls/entropy.h"
#include "mbedtls/ctr_drbg.h"
#include "mbedtls/error.h"
#include <mbedtls/base64.h>
#include <sys/param.h>
#include "f_email.h"
#include "f_wifi.h"
#include "f_validaemail.h"
#include "f_configfile.h"
#include "cJSON.h"
#include <stdio.h>
#include "f_mqtt.h"
static const char *TAG = "EMAIL";
#define VALIDATE_MBEDTLS_RETURN(ret, min_valid_ret, max_valid_ret, goto_label) \
do { \
if (ret < min_valid_ret || ret > max_valid_ret) { \
goto goto_label; \
} \
} while (0) \
static int write_ssl_and_get_response(mbedtls_ssl_context *ssl, unsigned char *buf, size_t len){
int ret;
const size_t DATA_SIZE = 128;
unsigned char data[DATA_SIZE];
char code[4];
size_t i, idx = 0;
if (len) {ESP_LOGD(TAG, "%s", buf);}
while (len && (ret = mbedtls_ssl_write(ssl, buf, len)) <= 0) {
if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {ESP_LOGE(TAG, "mbedtls_ssl_write failed with error -0x%x", -ret);
goto exit;
}
}
do {
len = DATA_SIZE - 1;
memset(data, 0, DATA_SIZE);
ret = mbedtls_ssl_read(ssl, data, len);
if (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE) {
continue;
}
if (ret <= 0) {
ESP_LOGE(TAG, "mbedtls_ssl_read failed with error -0x%x", -ret);
goto exit;
}
ESP_LOGD(TAG, "%s", data);
len = ret;
for (i = 0; i < len; i++) {
if (data[i] != '\n') {
if (idx < 4) {
code[idx++] = data[i];
}
continue;
}
if (idx == 4 && code[0] >= '0' && code[0] <= '9' && code[3] == ' ') {
code[3] = '\0';
ret = atoi(code);
goto exit;
}
idx = 0;
}
} while (1);
exit:
return ret;
}
static int perform_tls_handshake(mbedtls_ssl_context *ssl) {
int ret = -1;
uint32_t flags;
char *buf = NULL;
size_t buf_size = 0;
ESP_LOGI(TAG, "Performing the SSL/TLS handshake...");
fflush(stdout);
while ((ret = mbedtls_ssl_handshake(ssl)) != 0) {
if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
ESP_LOGE(TAG, "mbedtls_ssl_handshake returned -0x%x", -ret);
return ret; // Retorna imediatamente em caso de erro
}
}
ESP_LOGI(TAG, "Verifying peer X.509 certificate...");
flags = mbedtls_ssl_get_verify_result(ssl);
if (flags != 0) {
ESP_LOGW(TAG, "Failed to verify peer certificate!");
// Calcula o tamanho necessário para o buffer
buf_size = mbedtls_x509_crt_verify_info(NULL, 0, " ! ", flags) + 1; // +1 para o caractere nulo
buf = (char *)malloc(buf_size);
if (buf == NULL) {
ESP_LOGE(TAG, "Falha ao alocar memória para o buffer de verificação do certificado.");
return -1; // Retorna imediatamente em caso de falha de alocação
}
// Preenche o buffer com as informações de verificação
mbedtls_x509_crt_verify_info(buf, buf_size, " ! ", flags);
ESP_LOGW(TAG, "Verification info: %s", buf);
// Libera o buffer após o uso
free(buf);
} else {
ESP_LOGI(TAG, "Certificate verified.");
}
ESP_LOGI(TAG, "Cipher suite is %s", mbedtls_ssl_get_ciphersuite(ssl));
return 0; // Nenhum erro
}
mbedtls_entropy_context entropy;
mbedtls_ctr_drbg_context ctr_drbg;
mbedtls_ssl_context ssl;
mbedtls_ssl_config conf;
mbedtls_net_context server_fd;
bool f_conecta(email_params_t *params) {
char *buf = NULL;
int ret, len;
mbedtls_ssl_init(&ssl);
mbedtls_ctr_drbg_init(&ctr_drbg);
mbedtls_ssl_config_init(&conf);
mbedtls_entropy_init(&entropy);
ESP_LOGI(TAG, "Seeding the random number generator");
ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, NULL, 0);
if (ret != 0) {ESP_LOGE(TAG, "mbedtls_ctr_drbg_seed returned -0x%x", -ret);return false;}
ESP_LOGI(TAG, "Setting up the SSL/TLS structure...");
ret = mbedtls_ssl_config_defaults(&conf, MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT);
if (ret != 0) {ESP_LOGE(TAG, "mbedtls_ssl_config_defaults returned -0x%x", -ret);return false;}
mbedtls_ssl_conf_authmode(&conf, MBEDTLS_SSL_VERIFY_NONE); // Desativa a verificação do certificado
mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &ctr_drbg);
ret = mbedtls_ssl_setup(&ssl, &conf);
if (ret != 0) {ESP_LOGE(TAG, "mbedtls_ssl_setup returned -0x%x", -ret);return false;}
mbedtls_net_init(&server_fd);
ESP_LOGI(TAG, "Connecting to %s:%s...", params->server, params->port);
ret = mbedtls_net_connect(&server_fd, params->server, params->port, MBEDTLS_NET_PROTO_TCP);
if (ret != 0) {ESP_LOGE(TAG, "mbedtls_net_connect returned -0x%x", -ret);return false;}
ESP_LOGI(TAG, "Connected.");
mbedtls_ssl_set_bio(&ssl, &server_fd, mbedtls_net_send, mbedtls_net_recv, NULL);
ret = perform_tls_handshake(&ssl);
if (ret != 0) {return false;}
ret = write_ssl_and_get_response(&ssl, NULL, 0);
if (ret < 200 || ret > 299) {return false;}
ESP_LOGI(TAG, "Writing EHLO to server...");
len = snprintf(NULL, 0, "EHLO %s\r\n", "ESP32");
if (len < 0) {ESP_LOGE(TAG, "Erro ao calcular tamanho para EHLO.");return false;}
buf = (char *)malloc(len + 1); // +1 para o caractere nulo
if (buf == NULL) {ESP_LOGE(TAG, "Falha ao alocar memória.");return false;}
snprintf(buf, len + 1, "EHLO %s\r\n", "ESP32");
ret = write_ssl_and_get_response(&ssl, (unsigned char *)buf, len);
free(buf); // Libera o buffer após uso
if (ret < 200 || ret > 299) {return false;}
return true;
}
bool f_autentica(email_params_t *params) {
int ret, len;
unsigned char base64_buffer[128];
size_t base64_len;
char *buf = NULL;
ESP_LOGI(TAG, "Authentication...");
// Calcula o tamanho necessário para "AUTH LOGIN" e aloca o buffer
len = snprintf(NULL, 0, "AUTH LOGIN\r\n");
if (len < 0) {
ESP_LOGE(TAG, "Erro ao calcular o tamanho para AUTH LOGIN.");
return false;
}
buf = (char *)malloc(len + 1); // +1 para o caractere nulo
if (buf == NULL) {
ESP_LOGE(TAG, "Falha ao alocar memória.");
return false;
}
// Preenche o buffer com o comando "AUTH LOGIN"
snprintf(buf, len + 1, "AUTH LOGIN\r\n");
// Envia o comando "AUTH LOGIN"
ret = write_ssl_and_get_response(&ssl, (unsigned char *)buf, len);
free(buf); // Libera o buffer após uso
if (ret < 200 || ret > 399) {
return false;
}
ESP_LOGI(TAG, "Write USER NAME");
// Codifica o e-mail em Base64
ret = mbedtls_base64_encode(base64_buffer, sizeof(base64_buffer), &base64_len, (unsigned char *)params->authorEmail, strlen(params->authorEmail));
if (ret != 0) {
ESP_LOGE(TAG, "Erro ao codificar o nome de usuário! ret = -0x%x", -ret);
return false;
}
// Calcula o tamanho necessário para o nome de usuário codificado e aloca o buffer
len = snprintf(NULL, 0, "%s\r\n", base64_buffer);
if (len < 0) {
ESP_LOGE(TAG, "Erro ao calcular o tamanho para o nome de usuário.");
return false;
}
buf = (char *)malloc(len + 1);
if (buf == NULL) {
ESP_LOGE(TAG, "Falha ao alocar memória.");
return false;
}
// Preenche o buffer com o nome de usuário codificado
snprintf(buf, len + 1, "%s\r\n", base64_buffer);
// Envia o nome de usuário codificado
ret = write_ssl_and_get_response(&ssl, (unsigned char *)buf, len);
free(buf); // Libera o buffer após uso
if (ret < 300 || ret > 399) {
return false;
}
ESP_LOGI(TAG, "Write PASSWORD");
// Codifica a senha em Base64
ret = mbedtls_base64_encode(base64_buffer, sizeof(base64_buffer), &base64_len, (unsigned char *)params->password, strlen(params->password));
if (ret != 0) {
ESP_LOGE(TAG, "Erro ao codificar a senha! ret = -0x%x", -ret);
return false;
}
// Calcula o tamanho necessário para a senha codificada e aloca o buffer
len = snprintf(NULL, 0, "%s\r\n", base64_buffer);
if (len < 0) {
ESP_LOGE(TAG, "Erro ao calcular o tamanho para a senha.");
return false;
}
buf = (char *)malloc(len + 1);
if (buf == NULL) {
ESP_LOGE(TAG, "Falha ao alocar memória.");
return false;
}
// Preenche o buffer com a senha codificada
snprintf(buf, len + 1, "%s\r\n", base64_buffer);
// Envia a senha codificada
ret = write_ssl_and_get_response(&ssl, (unsigned char *)buf, len);
free(buf); // Libera o buffer após uso
if (ret < 200 || ret > 399) {
return false;
}
ESP_LOGI(TAG, "Autenticacao concluida com sucesso.");
return true;
}
bool f_ComporEmail(email_params_t *params) {
int ret, len;
char *buf = NULL;
ESP_LOGI(TAG, "Write MAIL FROM");
// Calcula o tamanho necessário para o comando "MAIL FROM"
len = snprintf(NULL, 0, "MAIL FROM:<%s>\r\n", params->authorEmail);
if (len < 0) {
ESP_LOGE(TAG, "Erro ao calcular tamanho para MAIL FROM.");
return false;
}
// Aloca buffer para "MAIL FROM"
buf = (char *)malloc(len + 1); // +1 para o caractere nulo
if (buf == NULL) {
ESP_LOGE(TAG, "Falha ao alocar memória.");
return false;
}
// Preenche o buffer com o comando "MAIL FROM"
snprintf(buf, len + 1, "MAIL FROM:<%s>\r\n", params->authorEmail);
// Envia o comando "MAIL FROM"
ret = write_ssl_and_get_response(&ssl, (unsigned char *)buf, len);
free(buf); // Libera o buffer após uso
if (ret < 200 || ret > 299) {
ESP_LOGE(TAG, "Falha ao enviar MAIL FROM");
return false;
}
ESP_LOGI(TAG, "Write RCPT");
// Calcula o tamanho necessário para o comando "RCPT TO"
len = snprintf(NULL, 0, "RCPT TO:<%s>\r\n", params->toEmail);
if (len < 0) {
ESP_LOGE(TAG, "Erro ao calcular tamanho para RCPT TO.");
return false;
}
// Aloca buffer para "RCPT TO"
buf = (char *)malloc(len + 1);
if (buf == NULL) {
ESP_LOGE(TAG, "Falha ao alocar memória.");
return false;
}
// Preenche o buffer com o comando "RCPT TO"
snprintf(buf, len + 1, "RCPT TO:<%s>\r\n", params->toEmail);
// Envia o comando "RCPT TO"
ret = write_ssl_and_get_response(&ssl, (unsigned char *)buf, len);
free(buf); // Libera o buffer após uso
if (ret < 200 || ret > 299) {
ESP_LOGE(TAG, "Falha ao enviar RCPT TO");
return false;
}
ESP_LOGI(TAG, "Write DATA");
// Calcula o tamanho necessário para o comando "DATA"
len = snprintf(NULL, 0, "DATA\r\n");
if (len < 0) {
ESP_LOGE(TAG, "Erro ao calcular tamanho para DATA.");
return false;
}
// Aloca buffer para o comando "DATA"
buf = (char *)malloc(len + 1);
if (buf == NULL) {
ESP_LOGE(TAG, "Falha ao alocar memória.");
return false;
}
// Preenche o buffer com o comando "DATA"
snprintf(buf, len + 1, "DATA\r\n");
// Envia o comando "DATA"
ret = write_ssl_and_get_response(&ssl, (unsigned char *)buf, len);
free(buf); // Libera o buffer após uso
if (ret < 300 || ret > 399) {
ESP_LOGE(TAG, "Falha ao enviar DATA");
return false;
}
ESP_LOGI(TAG, "Escrevendo conteúdo do email em HTML...");
// Calcula o tamanho necessário para o conteúdo do e-mail
len = snprintf(NULL, 0,
"From: \"%s\" <%s>\r\n"
"To: \"%s\" <%s>\r\n"
"Subject: %s\r\n"
"MIME-Version: 1.0\r\n"
"Content-Type: text/html; charset=\"UTF-8\"\r\n\r\n"
"%s\r\n.\r\n",
params->authorName, params->authorEmail, params->toName, params->toEmail, params->subject, params->msgBody);
if (len < 0) {
ESP_LOGE(TAG, "Erro ao calcular tamanho para o conteúdo do email.");
return false;
}
// Aloca buffer para o conteúdo do e-mail
buf = (char *)malloc(len + 1);
if (buf == NULL) {
ESP_LOGE(TAG, "Falha ao alocar memória.");
return false;
}
// Preenche o buffer com o conteúdo do e-mail
snprintf(buf, len + 1,
"From: \"%s\" <%s>\r\n"
"To: \"%s\" <%s>\r\n"
"Subject: %s\r\n"
"MIME-Version: 1.0\r\n"
"Content-Type: text/html; charset=\"UTF-8\"\r\n\r\n"
"%s\r\n.\r\n",
params->authorName, params->authorEmail, params->toName, params->toEmail, params->subject, params->msgBody);
// Envia o conteúdo do e-mail
ret = write_ssl_and_get_response(&ssl, (unsigned char *)buf, len);
free(buf); // Libera o buffer após uso
if (ret < 200 || ret > 299) {
ESP_LOGE(TAG, "Falha ao enviar conteúdo do email.");
return false;
}
ESP_LOGI(TAG, "Email composto com sucesso");
return true;
}
char* allocate_buffer(size_t size) {
char *buf = (char *)malloc(size);
if (buf == NULL) {
ESP_LOGE(TAG, "Falha ao alocar memória.");
}
return buf;
}
char* f_prepFilename(char *filename) {
if (filename[0] == '/') {
return filename + 1; // Retorna o ponteiro para o segundo caractere da string
}
return filename; // Se não houver barra, retorna o nome original
}
char* f_generateEmailHeader(email_params_t *params, char* attachment_path, size_t *buf_len) {
if (params->toEmail2 != NULL && strlen(params->toEmail2) > 0) {
*buf_len = snprintf(NULL, 0,
"From: \"%s\" <%s>\r\n"
"To: \"%s\" <%s>\r\n"
"Cc: \"%s\" <%s>\r\n"
"Subject: %s\r\n"
"MIME-Version: 1.0\r\n"
"Content-Type: multipart/mixed; boundary=\"XYZabcd1234\"\r\n\r\n"
"--XYZabcd1234\r\n"
"Content-Type: text/html; charset=\"UTF-8\"\r\n\r\n"
"%s\r\n"
"--XYZabcd1234\r\n"
"Content-Type: text/csv\r\n"
"Content-Disposition: attachment; filename=\"%s\"\r\n"
"Content-Transfer-Encoding: base64\r\n\r\n",
params->authorName, params->authorEmail, params->toName, params->toEmail, params->toName2, params->toEmail2,
params->subject, params->msgBody, f_prepFilename(attachment_path));
char *buf = (char *)malloc(*buf_len + 1);
if (!buf) {
ESP_LOGE("EMAIL", "Falha ao alocar memória para o cabeçalho do email.");
return NULL;
}
snprintf(buf, *buf_len + 1,
"From: \"%s\" <%s>\r\n"
"To: \"%s\" <%s>\r\n"
"Cc: \"%s\" <%s>\r\n"
"Subject: %s\r\n"
"MIME-Version: 1.0\r\n"
"Content-Type: multipart/mixed; boundary=\"XYZabcd1234\"\r\n\r\n"
"--XYZabcd1234\r\n"
"Content-Type: text/html; charset=\"UTF-8\"\r\n\r\n"
"%s\r\n"
"--XYZabcd1234\r\n"
"Content-Type: text/csv\r\n"
"Content-Disposition: attachment; filename=\"%s\"\r\n"
"Content-Transfer-Encoding: base64\r\n\r\n",
params->authorName, params->authorEmail, params->toName, params->toEmail, params->toName2, params->toEmail2,
params->subject, params->msgBody, f_prepFilename(attachment_path));
return buf;
} else { // Email sem cópia
*buf_len = snprintf(NULL, 0,
"From: \"%s\" <%s>\r\n"
"To: \"%s\" <%s>\r\n"
"Subject: %s\r\n"
"MIME-Version: 1.0\r\n"
"Content-Type: multipart/mixed; boundary=\"XYZabcd1234\"\r\n\r\n"
"--XYZabcd1234\r\n"
"Content-Type: text/html; charset=\"UTF-8\"\r\n\r\n"
"%s\r\n"
"--XYZabcd1234\r\n"
"Content-Type: text/csv\r\n"
"Content-Disposition: attachment; filename=\"%s\"\r\n"
"Content-Transfer-Encoding: base64\r\n\r\n",
params->authorName, params->authorEmail, params->toName, params->toEmail,
params->subject, params->msgBody, f_prepFilename(attachment_path));
char *buf = (char *)malloc(*buf_len + 1);
if (!buf) {
ESP_LOGE("EMAIL", "Falha ao alocar memória para o cabeçalho do email.");
return NULL;
}
snprintf(buf, *buf_len + 1,
"From: \"%s\" <%s>\r\n"
"To: \"%s\" <%s>\r\n"
"Subject: %s\r\n"
"MIME-Version: 1.0\r\n"
"Content-Type: multipart/mixed; boundary=\"XYZabcd1234\"\r\n\r\n"
"--XYZabcd1234\r\n"
"Content-Type: text/html; charset=\"UTF-8\"\r\n\r\n"
"%s\r\n"
"--XYZabcd1234\r\n"
"Content-Type: text/csv\r\n"
"Content-Disposition: attachment; filename=\"%s\"\r\n"
"Content-Transfer-Encoding: base64\r\n\r\n",
params->authorName, params->authorEmail, params->toName, params->toEmail,
params->subject, params->msgBody, f_prepFilename(attachment_path));
return buf;
}
return NULL; // Nunca deve chegar aqui...
}
static int write_ssl_data(mbedtls_ssl_context *ssl, unsigned char *buf, size_t len) {
int ret = 0; // Inicializa 'ret' com zero
while (len && (ret = mbedtls_ssl_write(ssl, buf, len)) <= 0) {
if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
ESP_LOGE("SSL_DATA", "mbedtls_ssl_write falhou com erro -0x%x ao enviar %d bytes", -ret, len);
return ret; // Retorna o erro diretamente se não for MBEDTLS_ERR_SSL_WANT_READ ou MBEDTLS_ERR_SSL_WANT_WRITE
}
}
return ret; // Retorna o número de bytes escritos ou o erro
}
bool f_ComporEmailAttachedFile(email_params_t *params, char* attachment_path) {
int ret, len;
char *buf = NULL;
unsigned char file_buffer[128];
unsigned char base64_buffer[200];
size_t base64_len;
FILE *file;
size_t read_bytes;
len = snprintf(NULL, 0, "MAIL FROM:<%s>\r\n", params->authorEmail);
buf = allocate_buffer(len + 1);
if (!buf) return false;
snprintf(buf, len + 1, "MAIL FROM:<%s>\r\n", params->authorEmail);
ret = write_ssl_and_get_response(&ssl, (unsigned char *)buf, len);
free(buf);
if (ret < 200 || ret > 299) return false;
ESP_LOGI(TAG, "Write RCPT - 1");
len = snprintf(NULL, 0, "RCPT TO:<%s>\r\n", params->toEmail);
buf = allocate_buffer(len + 1);
if (!buf) return false;
snprintf(buf, len + 1, "RCPT TO:<%s>\r\n", params->toEmail);
ret = write_ssl_and_get_response(&ssl, (unsigned char *)buf, len);
free(buf);
if (ret < 200 || ret > 299) return false;
// Envia o comando "RCPT TO" para o destinatário de cópia (CC)
if (params->toEmail2 != NULL && strlen(params->toEmail2) > 0) {
ESP_LOGI(TAG, "Write RCPT - 2");
len = snprintf(NULL, 0, "RCPT TO:<%s>\r\n", params->toEmail2);
buf = allocate_buffer(len + 1);
if (!buf) return false;
snprintf(buf, len + 1, "RCPT TO:<%s>\r\n", params->toEmail2);
ret = write_ssl_and_get_response(&ssl, (unsigned char *)buf, len);
free(buf);
if (ret < 200 || ret > 299) return false;
}
ESP_LOGI(TAG, "Write DATA");
len = snprintf(NULL, 0, "DATA\r\n");
buf = allocate_buffer(len + 1);
if (!buf) return false;
snprintf(buf, len + 1, "DATA\r\n");
ret = write_ssl_and_get_response(&ssl, (unsigned char *)buf, len);
free(buf);
if (ret < 300 || ret > 399) return false;
ESP_LOGI(TAG, "Compondo corpo do e-mail com anexo...");
size_t header_len;
char *email_header = f_generateEmailHeader(params, attachment_path, &header_len);
if (!email_header) {return false;}
ret = write_ssl_data(&ssl, (unsigned char *)email_header, header_len);
free(email_header); // Libera a memória após o envio
if (ret < 0) {ESP_LOGE(TAG, "Erro ao enviar os cabeçalhos.");return false;}
ESP_LOGI(TAG, "Enviando anexo em Base64...");
file = fopen(attachment_path, "rb");
if (!file) {ESP_LOGE(TAG, "Falha ao abrir o arquivo: %s", attachment_path);return false;}
int count=0;
while ((read_bytes = fread(file_buffer, 1, sizeof(file_buffer), file)) > 0) {
ret = mbedtls_base64_encode(base64_buffer, sizeof(base64_buffer), &base64_len, file_buffer, read_bytes);
if (ret != 0) {ESP_LOGE(TAG, "Erro na codificação Base64: -0x%x", -ret);fclose(file);return false;}
ret = write_ssl_data(&ssl, (unsigned char *)base64_buffer, base64_len);
if (ret < 0) {ESP_LOGE(TAG, "Erro ao enviar o chunk do anexo.");fclose(file);return false;}
count++;
}
ESP_LOGI(TAG, "Arquivo enviado em %d partes", count);
fclose(file);
ESP_LOGI(TAG, "Finalizando envio do e-mail...");
const char *end_of_email = "\r\n--XYZabcd1234--\r\n.\r\n";
ret = write_ssl_and_get_response(&ssl, (unsigned char *)end_of_email, strlen(end_of_email));
if (ret < 200 || ret > 299) {
ESP_LOGE(TAG, "Falha ao finalizar envio do e-mail.");
return false;
}
ESP_LOGI(TAG, "Email com anexo enviado com sucesso.");
return true;
}
void f_EnviaEmail(void *args) {
ESP_LOGW(TAG, "Ponto A");
EventBits_t bitsMQTT_In = xEventGroupGetBits(xEventGroupMQTT_In);
EventBits_t bitsMQTT_Out = xEventGroupGetBits(xEventGroupMQTT_Out);
if (bitsMQTT_In & MQTT_In_BIT) {
ESP_LOGI(TAG, "Parando MQTT In...");
f_stopMQTT_In();
xEventGroupWaitBits(xEventGroupMQTT_In, MQTT_In_BIT, pdFALSE, pdFALSE, portMAX_DELAY);
} else {
ESP_LOGI(TAG, "MQTT In não está rodando, ignorando stop.");
}
if (bitsMQTT_Out & MQTT_Out_BIT) {
ESP_LOGI(TAG, "Parando MQTT Out...");
f_stopMQTT_Out();
xEventGroupWaitBits(xEventGroupMQTT_Out, MQTT_Out_BIT, pdFALSE, pdFALSE, portMAX_DELAY);
} else {
ESP_LOGI(TAG, "MQTT Out não está rodando, ignorando stop.");
}
email_params_t *params = (email_params_t *)args;
bool success = true;
if (f_conecta(params)) {
ESP_LOGI(TAG, "SMTP Conectado");
} else {
ESP_LOGE(TAG, "Erro de Conexão. Encerrando envio de e-mail.");
success = false;
}
if (success && f_autentica(params)) {
ESP_LOGI(TAG, "SMTP Autenticado");
} else if (success) {
ESP_LOGE(TAG, "Erro de Autenticação. Encerrando envio de e-mail.");
success = false;
}
bool file_exists = f_fileCheck(params->attachment_file); // Verifica se o arquivo existe
if (success) {
if (file_exists) {
ESP_LOGI(TAG, "Arquivo encontrado(%s). Enviando e-mail com anexo.", params->attachment_file);
success = f_ComporEmailAttachedFile(params, params->attachment_file); // Com anexo
} else {
ESP_LOGI(TAG, "Arquivo não encontrado. Enviando e-mail sem anexo.");
success = f_ComporEmail(params); // Sem anexo
}
}
if (success) {
ESP_LOGI(TAG, "Email composto e enviado com sucesso!");
} else {
ESP_LOGE(TAG, "Erro ao compor ou enviar o e-mail.");
}
// Libera recursos do mbedtls
mbedtls_ssl_close_notify(&ssl);
mbedtls_net_free(&server_fd);
mbedtls_ssl_free(&ssl);
mbedtls_ssl_config_free(&conf);
mbedtls_ctr_drbg_free(&ctr_drbg);
mbedtls_entropy_free(&entropy);
UBaseType_t highWaterMark = uxTaskGetStackHighWaterMark(NULL);
ESP_LOGI(TAG, "Uso de memoria da tarefa f_EnviaEmail: %d bytes", highWaterMark * sizeof(StackType_t));
if (params) {
free(params);
}
f_startMQTT_In(NULL);
f_startMQTT_Out(NULL);
vTaskDelete(NULL);
}
When I turn off the wifi the email is sent perfectly.
I can do this as many times as I want.
But was if the enable MQTT Tasks, is wrong send mail.
Generate this error: mbedtls_ssl_setup returned -0x7f00
As an alternative, I decided to implement a stop and termination of MQTT actions so that it frees up the memory and/or items that occupy the connections.
This alternative partially worked, because it really works, I can stop MQTT sending the email and then start MQTT.
However, if I repeat this operation more than 3 times, I get some kind of crash.
This First send:
The second send:
The third submission stops the task
When I make this third attempt it freezes and does not start the task.
If I try to log into the webserver, it responds with an error.
My unhappiness is that when I restart everything goes back to normal and again I can send at least 2 emails.
Remembering that this is a complex product with several tasks involved:
Does anyone have any idea what problem I might be experiencing?