//RODRIGO SERAFIM
//CODIGO FUNCIONAL
//ENVIA OS DADOS PARA O DOJOT
//CONECTADO AO MQTT
// Biblioteca padrão C
#include <stdio.h> // Entrada e saída padrão
#include <string.h> // Manipulação de strings
// Bibliotecas FreeRTOS
#include "freertos/FreeRTOS.h" // Principais cabeçalhos do FreeRTOS
#include "freertos/task.h" // Definições de função relacionadas a tarefas do FreeRTOS
#include "freertos/event_groups.h" // Funcionalidades para grupos de eventos do FreeRTOS
#include <freertos/semphr.h> // Semáforo
// Bibliotecas ESP32
#include "esp_wifi.h" // Funcionalidades para configuração e controle do Wi-Fi no ESP32
#include "esp_event_loop.h" // Definições de função relacionadas ao loop de eventos do ESP32
#include "esp_system.h" // Funcionalidades relacionadas ao sistema ESP32
#include "esp_log.h" // Registro de mensagens de log no sistema
#include "esp_event.h" // Funcionalidades para gerenciamento de eventos, incluindo eventos MQTT
#include "driver/gpio.h" // Funções para configuração e controle de pinos GPIO
#include "nvs_flash.h" // APIs para trabalhar com a memória flash de armazenamento não volátil (NVS) do ESP32
// Bibliotecas LWIP (Lightweight IP)
#include "lwip/err.h" // Definições de códigos de erro utilizados pelo LWIP
#include "lwip/sockets.h" // Criação e gerenciamento de sockets de rede
#include "lwip/sys.h" // Funções de gerenciamento de thread e tempo
#include "lwip/netdb.h" // Operações de banco de dados de rede, como resolução de nome de host
#include "lwip/dns.h" // Operações DNS (Domain Name System) para resolução de nome de host para endereço IP
//Biblioteca MQTT
#include "mqtt_client.h" // Fornece funcionalidades para implementar um cliente MQTT no ESP32
//Outras bibliotecas
#include <Arduino.h>
SemaphoreHandle_t xSemaphore; //Declarando semáforo
esp_mqtt_client_handle_t client; // Declaração global da variável client
// Configurações do sensor de temperatura
#define NTC_PIN A5 //Define porta de entrada do sensor de temperatura como a analógica 5
const float BETA = 3950; // O coeficiente beta do termistor NTC (coeficiente de temperatura negativo)
//(O valor do coeficiente Beta (β) em um termistor NTC (Negative Temperature Coefficient) é uma característica do material do termistor e é utilizado na equação de Steinhart-Hart para calcular a temperatura em função da resistência.)
//Obs.: O valor de 3950 é um valor típico para termistores NTC comumente usado
static float global_temperature = 24; //Valor da temperatura inicial (celsius)
//Configuração de conexão ---------------
#define SSID "Wokwi-GUEST" // SSID da rede Wi-Fi à qual o dispositivo se conectará
#define PASSPHRASE "" // Senha da rede Wi-Fi (deixe vazio se não houver senha)
const int CONNECTED_BIT = BIT0; // Constante que representa o bit indicando conexão bem-sucedida
static const char *TAG = "LOG_MQTT"; // Tag para mensagens de log relacionadas ao MQTT
//---------------------------------------
static EventGroupHandle_t wifi_event_group; //Lidar com eventos relacionados à conexão Wi-Fi
// Esta função é responsável por conectar o dispositivo à rede Wi-Fi
void wifi_connect() {
// Configuração das informações da rede Wi-Fi
wifi_config_t cfg = {
.sta = {
.ssid = SSID, // SSID é o nome da rede Wi-Fi
.password = PASSPHRASE, // PASSPHRASE é a senha da rede Wi-Fi
},
};
// Desconecta o dispositivo Wi-Fi, caso esteja conectado
ESP_ERROR_CHECK(esp_wifi_disconnect());
// Define as configurações de rede Wi-Fi para o modo estação com as informações fornecidas
ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &cfg));
// Inicia o processo de conexão Wi-Fi com as configurações fornecidas
ESP_ERROR_CHECK(esp_wifi_connect());
}
// Esta função é chamada quando eventos relacionados ao Wi-Fi ocorrem
static esp_err_t event_handler(void *ctx, system_event_t *event) {
// Um switch-case é usado para lidar com diferentes tipos de eventos Wi-Fi
switch(event->event_id) {
// Caso o dispositivo Wi-Fi esteja iniciando
case SYSTEM_EVENT_STA_START:
// Chamando a função wifi_connect() para iniciar a conexão Wi-Fi
wifi_connect();
break;
// Caso o dispositivo Wi-Fi tenha obtido um endereço IP com sucesso
case SYSTEM_EVENT_STA_GOT_IP:
// Sinaliza que o dispositivo está conectado, definindo um bit no grupo de eventos
xEventGroupSetBits(wifi_event_group, CONNECTED_BIT);
break;
// Caso o dispositivo Wi-Fi tenha sido desconectado da rede
case SYSTEM_EVENT_STA_DISCONNECTED:
// Tenta reconectar o dispositivo Wi-Fi
esp_wifi_connect();
// Limpa o bit que indica que o dispositivo está conectado
xEventGroupClearBits(wifi_event_group, CONNECTED_BIT);
break;
// Caso contrário, nenhum tratamento específico é necessário para o evento
default:
break;
}
// Retorna ESP_OK para indicar que o tratamento do evento foi bem-sucedido
return ESP_OK;
}
// Esta função é responsável por inicializar o subsistema Wi-Fi do dispositivo
static void initialise_wifi(void) {
// Define o nível de log do driver Wi-Fi como ESP_LOG_NONE para desativar os logs
esp_log_level_set("wifi", ESP_LOG_NONE);
// Inicializa o adaptador TCP/IP do dispositivo
tcpip_adapter_init();
// Inicializa a configuração padrão para a inicialização do Wi-Fi
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
// Inicializa o subsistema Wi-Fi com a configuração fornecida
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
// Configura o modo de operação do dispositivo como STA (Estação)
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
// Inicia o subsistema Wi-Fi
ESP_ERROR_CHECK(esp_wifi_start());
}
//Parte do MQTT: -------------------------------------------------------------------------------
// Esta função é chamada para lidar com eventos relacionados ao cliente MQTT
static void mqtt_event_handler(esp_mqtt_event_handle_t event) {
// Obtém o identificador do cliente MQTT do evento recebido
esp_mqtt_client_handle_t client = event->client;
// Verifica o tipo de evento MQTT recebido e executa ação apropriada
//Deu certo:
if(event->event_id == MQTT_EVENT_CONNECTED) {
// Se o cliente MQTT estiver conectado com sucesso
ESP_LOGD(TAG, "MQTT_EVENT_CONNECTED");
printf("Conectado ao servidor MQTT\n");
}
//Erro:
else if(event->event_id == MQTT_EVENT_DISCONNECTED) {
// Se o cliente MQTT for desconectado
ESP_LOGD(TAG, "MQTT_EVENT_DISCONNECTED");
printf("Desconectado do servidor MQTT\n");
}
//Deu certo:
else if(event->event_id == MQTT_EVENT_SUBSCRIBED) {
// Se o cliente MQTT tiver feito uma subscrição com sucesso
ESP_LOGD(TAG, "MQTT_EVENT_SUBSCRIBED");
}
//Erro:
else if(event->event_id == MQTT_EVENT_UNSUBSCRIBED) {
// Se o cliente MQTT tiver cancelado uma subscrição com sucesso
ESP_LOGD(TAG, "MQTT_EVENT_UNSUBSCRIBED");
}
//Deu certo:
else if(event->event_id == MQTT_EVENT_DATA) {
// Se o cliente MQTT tiver recebido dados
ESP_LOGD(TAG, "MQTT_EVENT_DATA");
printf("Mensagem recebida: %s\n", event->data);
}
//Erro:
else if(event->event_id == MQTT_EVENT_ERROR) {
// Se ocorrer um erro com o cliente MQTT
ESP_LOGD(TAG, "MQTT_EVENT_ERROR");
}
}
// Esta função é responsável por inicializar o cliente MQTT e configurá-lo para se conectar ao servidor MQTT especificado
static void mqtt_initialize(void) {
// Define o nível de log do cliente MQTT como ESP_LOG_VERBOSE para habilitar logs detalhados
esp_log_level_set(TAG, ESP_LOG_VERBOSE);
// Configuração do cliente MQTT com os parâmetros necessários
const esp_mqtt_client_config_t mqtt_cfg = {
.username = "rodrigo_serafim:34ae52",
.host = "200.129.71.138", // Endereço do servidor MQTT
.port = 1883, // Porta padrão para conexões MQTT
.transport = MQTT_TRANSPORT_OVER_TCP, // Método de transporte utilizado (TCP neste caso)
.event_handle = mqtt_event_handler // Função de tratamento de eventos MQTT definida anteriormente
};
// Inicializa o cliente MQTT com a configuração fornecida
client = esp_mqtt_client_init(&mqtt_cfg);
// Inicia o processo do cliente MQTT
esp_mqtt_client_start(client);
// Adiciona a subscrição a um tópico MQTT adicional
int msg_sub_id = esp_mqtt_client_subscribe(client, "rodrigo_serafim:34ae52/config", 1);
if (msg_sub_id < 0) {
ESP_LOGE(TAG, "Failed to subscribe to topic");
}
}
//Parte do Sensor de temperatura: --------------------------------------------------------------
float celsiusGlobal = 0.0;
void generate_data(void*pvParam){
while(1){
//Obtendo dados do sensor
int analogValue = analogRead(NTC_PIN); //AnalogRead pois o sensor ultrapassa valores digitais (0 e 1) e é mais próprio para o contexto!
//printf("Analog: %d \n", analogValue); //Testando leitura analógica
float celsius = 1 / (log(1 / (4095.0 / analogValue - 1)) / BETA + 1.0 / 298.15) - 273.15; //Transforma a leitura analógica/elétrica em um valor visual e conhecido (Celsius).
//Salvar dado em uma variável global
celsiusGlobal = celsius;
//Printa no console a temperatura obtida pelo sensor
printf("Temperatura: %f ℃\n", celsiusGlobal);
//Libera o semáforo binário
if (xSemaphore != NULL) {
xSemaphoreGive(xSemaphore);
}
//Delay
vTaskDelay(pdMS_TO_TICKS(1000)); // Use vTaskDelay em vez de delay
}
}
// Esta função é responsável por enviar mensagens periodicamente para um tópico MQTT
char tx_buffer[128]; // Buffer para armazenar a mensagem a ser enviada
void send_messages(void *pvParam) {
// Loop infinito para enviar dados continuamente
while (1) {
// Aguarda o semáforo binário
if (xSemaphore != NULL && xSemaphoreTake(xSemaphore, pdMS_TO_TICKS(3000))) {
// Obtém o valor da temperatura global
float value = (float)celsiusGlobal;
// Converte o valor da temperatura para uma string JSON
sprintf(tx_buffer, "{\"Temperatura\": %.2f}", value);
// Imprime o valor da temperatura no console
printf("Enviando o valor %s\n", tx_buffer);
// Publica a temperatura no tópico MQTT
esp_mqtt_client_publish(client, "rodrigo_serafim:34ae52/attrs", tx_buffer, 0, 0, 0);
// Os parâmetros adicionais (QoS, retain, etc.) são definidos como 0
// Aguarda 2 segundos antes de enviar a próxima mensagem
vTaskDelay(2000 / portTICK_RATE_MS);
}
}
}
void setup() {
// Configuração do loop de eventos e inicialização do Wi-Fi
ESP_ERROR_CHECK(esp_event_loop_init(event_handler, NULL)); // Inicializa o loop de eventos e define a função de tratamento de eventos
wifi_event_group = xEventGroupCreate(); // Cria um grupo de eventos para lidar com eventos relacionados ao Wi-Fi
esp_err_t ret = nvs_flash_init(); // Inicializa a memória flash de armazenamento não volátil (NVS)
if (ret == ESP_ERR_NVS_NO_FREE_PAGES) { // Verifica se há páginas livres na memória flash NVS
ESP_ERROR_CHECK(nvs_flash_erase()); // Apaga a memória flash NVS se não houver páginas livres suficientes
ret = nvs_flash_init(); // Tenta inicializar a memória flash NVS novamente após a exclusão
}
ESP_ERROR_CHECK( ret ); // Verifica se a inicialização da memória flash NVS foi bem-sucedida
initialise_wifi(); // Inicializa a conexão Wi-Fi
// Aguarda até que o dispositivo esteja conectado à rede Wi-Fi
xEventGroupWaitBits(wifi_event_group, CONNECTED_BIT, false, true, portMAX_DELAY);
// Inicialização do cliente MQTT
mqtt_initialize(); // Inicializa o cliente MQTT
}
void app_main() {// Função principal da aplicação
xSemaphore = xSemaphoreCreateBinary();
// Executa a configuração inicial do dispositivo
setup();
// Adiciona um atraso após o setup (por exemplo, 5 segundo)
vTaskDelay(pdMS_TO_TICKS(5000));
//Gerar dados do sensor de temperatura
xTaskCreate(generate_data, "Task para ler", 4096, NULL, 5 , NULL);
// Cria uma nova tarefa para enviar mensagens periodicamente
xTaskCreate(&send_messages, "send messages", 2048, NULL, 5, NULL);
}