#include <WiFi.h>
#include <Arduino.h>
#include <freertos/FreeRTOS.h>
#include <freertos/queue.h>
#include <freertos/task.h>
#include <freertos/semphr.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include "DHTesp.h"
#include <PubSubClient.h>
const char* ssid = "Wokwi-GUEST"; // SSID / nome da rede WI-FI que deseja se conectar
const char *PASS = ""; // Senha da rede WI-FI que deseja se conectar
float LED_THRESHOLD;
/* defines - LCD */
#define LCD_16X2_CLEAN_LINE " "
#define LCD_16X2_I2C_ADDRESS 0x27
#define LCD_16X2_COLS 16
#define LCD_16X2_ROWS 2
/* defines - LED */
#define LED_PIN 13
#define LED_THRESHOLD 3.58 /* V */
/* defines - ADC */
#define ADC_MAX 4095.0
#define MAX_VOLTAGE_ADC 5.0 /* V */
#define POTENTIOMETER_PIN 34
const int DHTPIN = 25;
DHTesp dhtSensor;
float temperature;
float humidity;
/* tasks */
void task_lcd( void *pvParameters );
void task_potenciometro( void *pvParameters );
void task_led( void *pvParameters );
void task_DHT22( void *pvParameters );
bool flag_callback = true;
/* Variaveis relacionadas ao LCD */
LiquidCrystal_I2C lcd(LCD_16X2_I2C_ADDRESS,
LCD_16X2_COLS,
LCD_16X2_ROWS);
/* filas (queues) */
QueueHandle_t xQueue_LCD, xQueue_LED,xQueue_DHT22;
/* semaforos utilizados */
SemaphoreHandle_t xSerial_semaphore;
#define ID_MQTT "esp32_mqtt_Movimento" // id mqtt (para identificação de sessão)
WiFiClient wifiClient;
PubSubClient cliente;
String topicomqtt = "Led";
WiFiServer server(80);
void callback(char* topic, byte* payload, unsigned int length) {
Serial.println("Nova mensagem recebida: ");
Serial.print(" - Tópico: ");
Serial.println(topic);
Serial.print(" - Mensagem: ");
for (int i = 0; i < length; i++) {
Serial.print((char)payload[i]);
}
Serial.println();
if (strcmp(topic, topicomqtt.c_str()) == 0) {
if ((char)payload[0] == '1') {
flag_callback = true;
Serial.println("Led aceso");
digitalWrite(LED_PIN, HIGH); // adiciona esta linha para ligar o LED
} else if ((char)payload[0] == '0') {
flag_callback = false;
Serial.println("Led apagado");
digitalWrite(LED_PIN, LOW); // adiciona esta linha para desligar o LED
}
}
}
void setup() {
/* Inicializa serial (baudrate 9600) */
Serial.begin(115200);
dhtSensor.setup(DHTPIN, DHTesp::DHT22);
/* Inicializa o LCD, liga o backlight e limpa o LCD */
lcd.begin(20, 4); // Iniciando a variavel que controlara o Display
lcd.init();
lcd.backlight();
// timer.setInterval(500L, task_DHT22); // Configura o intervalo de atualização para 5 segundos
/* Inicializa e configura GPIO do LED */
pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN, LOW);
// Conectar ao Wi-Fi
WiFi.begin("Wokwi-GUEST", "");
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Conectando ao Wi-Fi...");
}
while (!Serial) {
; /* Somente vá em frente quando a serial estiver pronta para funcionar */
}
cliente.setClient(wifiClient);
cliente.setServer("broker.mqttdashboard.com", 1883);
cliente.setCallback(callback);
cliente.connect("Esp32", "ProjetoMQTT", "1234");
cliente.subscribe(topicomqtt.c_str());
cliente.subscribe("Led"); // inscreve-se no tópico "led"
// while (!cliente.connected()) {
// Serial.println("Conectando ao broker MQTT...");
// if (cliente.connect("Esp32", "ProjetoMQTT", "1234")) {
// Serial.println("Conectado ao broker MQTT.");
// cliente.subscribe(topicomqtt.c_str());
// } else {
// Serial.print("Falha ao conectar ao broker MQTT. rc=");
// Serial.print(cliente.state());
// Serial.println(" Tente novamente em 5 segundos...");
// delay(5000);
// }
// }
/* Criação das filas (queues) */
xQueue_LCD = xQueueCreate( 1, sizeof( float ) );
xQueue_LED = xQueueCreate(1, sizeof(float));
xQueue_DHT22 = xQueueCreate( 1, sizeof( float ) );
/* Criação dos semaforos */
xSerial_semaphore = xSemaphoreCreateMutex();
if (xSerial_semaphore == NULL)
{
Serial.println("Erro: nao e possivel criar o semaforo");
while(1); /* Sem semaforo o funcionamento esta comprometido. Nada mais deve ser feito. */
}
/* Criação das tarefas */
xTaskCreatePinnedToCore(
task_potenciometro /* Funcao a qual esta implementado o que a tarefa deve fazer */
, "potenciometro" /* Nome (para fins de debug, se necessário) */
, 4096 /* Tamanho da stack (em words) reservada para essa tarefa */
, NULL /* Parametros passados (nesse caso, não há) */
, 4 /* Prioridade */
, NULL
, APP_CPU_NUM); /* Handle da tarefa, opcional (nesse caso, não há) */
xTaskCreatePinnedToCore(
task_lcd
, "LCD"
, 4096
, NULL
, 1
, NULL
, APP_CPU_NUM);
xTaskCreatePinnedToCore(
task_DHT22, // Função da tarefa
"task_DHT22", // Nome da tarefa
4096, // Tamanho da pilha da tarefa (em bytes)
NULL, // Parâmetro da tarefa (não utilizado)
3, // Prioridade da tarefa
NULL, // Handle da tarefa (não utilizado)
APP_CPU_NUM ); // Núcleo da CPU para executar a tarefa (0 ou 1)
xTaskCreatePinnedToCore(
task_led, // Função da tarefa
"task_led", // Nome da tarefa
4096, // Tamanho da pilha da tarefa (em bytes)
NULL, // Parâmetro da tarefa (não utilizado)
2, // Prioridade da tarefa
NULL, // Handle da tarefa (não utilizado)
APP_CPU_NUM ); // Núcleo da CPU para executar a tarefa (0 ou 1)
/* A partir deste momento, o scheduler de tarefas entra em ação e as tarefas executam */
}
void loop()
{
if (!cliente.connected()) {
cliente.connect("Esp32", "ProjetoMQTT", "1234");
}
cliente.loop();
}
/* --------------------------------------------------*/
/* ---------------------- Tarefas -------------------*/
/* --------------------------------------------------*/
void task_potenciometro( void *pvParameters )
{
(void) pvParameters;
int adc_read= 0;
UBaseType_t uxHighWaterMark;
float voltage = 0.0;
float voltageServo = 0.0;
while(1)
{
adc_read = analogRead(POTENTIOMETER_PIN);
voltage = ((float)adc_read/ADC_MAX) * MAX_VOLTAGE_ADC;
String msg = String(voltage, 2);
int pos = map(voltage, 0, MAX_VOLTAGE_ADC, 0, 180);
cliente.publish("Potenciometro", msg.c_str());
/* Envia tensão lida em A0 para as tarefas a partir de filas */
xQueueOverwrite(xQueue_LCD, (void *)&voltage);
xQueueOverwrite(xQueue_LED, (void *)&voltage);
/* Espera um segundo */
vTaskDelay(pdMS_TO_TICKS(100));
/* Para fins de teste de ocupação de stack, printa na serial o high water mark */
xSemaphoreTake(xSerial_semaphore, portMAX_DELAY );
uxHighWaterMark = uxTaskGetStackHighWaterMark( NULL );
Serial.print("task_potenciometro high water mark (words): ");
Serial.println(voltage);
Serial.println("---");
xSemaphoreGive(xSerial_semaphore);
}
}
void task_lcd( void *pvParameters )
{
(void) pvParameters;
float voltage_rcv = 0.0;
UBaseType_t uxHighWaterMark;
while(1)
{
/* Espera até algo ser recebido na queue */
xQueueReceive(xQueue_LCD, (void *)&voltage_rcv, portMAX_DELAY);
xQueueReceive(xQueue_DHT22, (void *)&temperature,portMAX_DELAY);
xQueueReceive(xQueue_DHT22, (void *)&humidity, portMAX_DELAY);
/* Uma vez recebida a informação na queue, a escreve no display LCD */
lcd.setCursor(0,0);
lcd.print("Voltage: ");
lcd.setCursor(0,1);
lcd.print(LCD_16X2_CLEAN_LINE);
lcd.setCursor(9,0);
lcd.print(voltage_rcv);
lcd.setCursor(14,0);
lcd.print("V");
lcd.print(" ");
// Limpe o LCD
lcd.setCursor(0, 1);
// Escreva os valores lidos do sensor DHT11 no LCD
lcd.print("Temp: ");
lcd.setCursor(0,1);
// Temperatura
lcd.setCursor(9,1);
lcd.print(temperature);
lcd.setCursor(14,1);
lcd.print(" C");
lcd.setCursor(0, 2);
lcd.print("Humidity: ");
lcd.setCursor(0,2);
// Humidade
lcd.setCursor(9,2);
lcd.print(humidity);
lcd.setCursor(14,2);
lcd.print(" %");
vTaskDelay(pdMS_TO_TICKS(1000)); // Aguarde 1 segundo
/* Para fins de teste de ocupação de stack, printa na serial o high water mark */
xSemaphoreTake(xSerial_semaphore, portMAX_DELAY );
uxHighWaterMark = uxTaskGetStackHighWaterMark( NULL );
Serial.print("task_lcd high water mark (words): ");
Serial.println(uxHighWaterMark);
Serial.println("---");
xSemaphoreGive(xSerial_semaphore);
}
}
// Função para ler os valores do sensor DHT22
void task_DHT22(void *pvParameters) {
UBaseType_t uxHighWaterMark;
while (1) {
// Ler os valores do sensor
temperature = dhtSensor.getTemperature();
humidity = dhtSensor.getHumidity();
// Verificar se os valores lidos são válidos
if (isnan(temperature) || isnan(humidity)) {
Serial.println("Falha na leitura do sensor DHT22!");
} else {
String temp_str= String(temperature, 1);
String hum_str= String(humidity, 1);
cliente.publish("Temp", temp_str.c_str());
cliente.publish("Hum", hum_str.c_str());
xQueueSend(xQueue_DHT22, &temperature, 0);
xQueueSend(xQueue_DHT22, &humidity, 0);
}
// Aguardar 2 segundos antes de fazer uma nova leitura
vTaskDelay(500 / portTICK_PERIOD_MS);
/* Para fins de teste de ocupação de stack, printa na serial o high water mark */
xSemaphoreTake(xSerial_semaphore, portMAX_DELAY );
uxHighWaterMark = uxTaskGetStackHighWaterMark( NULL );
Serial.print("task_DHT22 high water mark (words): ");
Serial.println(humidity);
Serial.println("---");
xSemaphoreGive(xSerial_semaphore);
}
}
void task_led( void *pvParameters )
{
(void) pvParameters;
float voltage_rcv = 0.0;
UBaseType_t uxHighWaterMark;
while(1)
{
/* Espera até algo ser recebido na queue */
xQueueReceive(xQueue_LED, (void *)&voltage_rcv, portMAX_DELAY);
/* Uma vez recebida a informação na queue, verifica se o LED deve acender ou não */
if ((voltage_rcv > LED_THRESHOLD)|| flag_callback == true){
digitalWrite(LED_PIN, HIGH );
}
else{
digitalWrite(LED_PIN, LOW);
}
/* Para fins de teste de ocupação de stack, printa na serial o high water mark */
xSemaphoreTake(xSerial_semaphore, portMAX_DELAY );
uxHighWaterMark = uxTaskGetStackHighWaterMark( NULL );
Serial.print("task_led high water mark (words): ");
Serial.println(LED_THRESHOLD);
Serial.println("---");
xSemaphoreGive(xSerial_semaphore);
}
}