#include <DHT.h>
#include <Wire.h>
#include <WiFi.h>
#include <ESP32Servo.h>
#include <PubSubClient.h>
#include <LiquidCrystal_I2C.h> // Inicializa o display no endereço 0x27
// ================= DEFINICAO DE PINOS IO =================
#define DHTPIN 4
#define DHTTYPE DHT22
#define LDR_PIN 34
#define EC_PIN 35
#define FAN_PIN 5
#define IRRIGATION_PIN 18
#define LIGHT_PWM_PIN 23
// ================= DEFINICAO DE CONSTANTES PWM =================
//#define VENT_PWM_CHANNEL 0
//#define VENT_PWM_FREQ 20000 // 20 kHz
//#define VENT_PWM_RESOLUTION 8 // 8 bits -> 0 a 255
#define LIGHT_PWM_CHANNEL 1
#define LIGHT_PWM_FREQ 5000 // 5 kHz
#define LIGHT_PWM_RESOLUTION 8 // 0–255
// ================= CONFIGURACOES DE EXECUCAO =================
const unsigned int bit_rate = 115200;
const unsigned int wait_exec_code = 1000;
unsigned long lastMsg = 0;
// ================= CONFIGURACAO DA WIFI =================
const unsigned int wait_connect_wifi = 500;
const char* ssidWiFi = "Wokwi-GUEST";
const char* passwordWiFi = "";
// ================= CONFIGURACAO DO SERVIDOR MQTT - MQQTX =================
/*
const unsigned int wait_connect_mqtt = 2000;
const char* serverMQTT = "broker.emqx.io";
const int portMQTT = 1883;
const char* clientIDMQTT = "estufa_esp32_iot";
const char* tokenMQTT = "";
const char* subtopicMQTT = "iot/estufa/setor1/#";
const char* pubtopicMQTT = "iot/estufa/setor1/";
char msg[255];
*/
// ================= CONFIGURACAO DO SERVIDOR MQTT - UBIDOTS =================
const unsigned int wait_connect_mqtt = 2000;
const char* serverMQTT = "industrial.api.ubidots.com";
const int portMQTT = 1883;
const char* clientIDMQTT = "estufa_esp32_iot";
const char* tokenMQTT = "BBUS-aPruCqbd55BX0xKLekoIFZ3cqYtY6v";
const char* devicelabelMQTT = "esp32-estufa";
const char* subtopicMQTT = "/v1.6/devices/esp32-estufa";
const char* pubtopicMQTT = "/v1.6/devices/esp32-estufa";
char msg[255];
// ================= CONFIGURACAO DO LCD =================
LiquidCrystal_I2C lcd (0x27, 16, 2);
// ================= CONFIGURACAO DO VENTILADOR =================
const float temperature_min = 15.0;
const float temperature_max = 40.0;
// ================= CONFIGURACAO DA COBERTURA =================
const float luminosity_min = 400.0; // lux (liga luz)
const float luminosity_max = 1200.0; // lux (desliga luz)
// ================= MODULOS =================
WiFiClient espClient;
PubSubClient clientMQTT(espClient);
DHT dht(DHTPIN, DHTTYPE);
// ================= CALLBACKS =================
void callbackMQTT(char* topic, byte* payload, unsigned int length) {
Serial.print("[MQTT] Mensagem em ["); Serial.print(topic);
Serial.print("]: ");
for (unsigned int i = 0; i < length; i++) {
Serial.print((char)payload[i]);
}
Serial.println();
}
// ================= FUNÇÕES DE CONFIGURACAO =================
void setupWiFi() {
Serial.println("[WiFi] Conectando...");
WiFi.begin(ssidWiFi, passwordWiFi);
while (WiFi.status() != WL_CONNECTED) {
delay(wait_connect_wifi);
}
Serial.print("[WiFi] IP: ");
Serial.println(WiFi.localIP());
Serial.print("[WiFi] Gateway: ");
Serial.println(WiFi.gatewayIP());
Serial.println("[WiFi] WiFi Conectado!");
}
void setupDHT(){
dht.begin();
Serial.println("[DHT] Sensor inicializado");
}
void setupMQTT(){
clientMQTT.setServer(serverMQTT, portMQTT);
clientMQTT.setCallback(callbackMQTT);
while (!clientMQTT.connected()) {
Serial.println("[MQTT] Conectando...");
if (clientMQTT.connect(clientIDMQTT,tokenMQTT,"")) {
Serial.println("[MQTT] Conectado!");
clientMQTT.subscribe(subtopicMQTT);
} else {
Serial.print("[MQTT] falhou (rc=");
Serial.print(clientMQTT.state());
Serial.println("). Tentando novamente em 2s...");
delay(wait_connect_mqtt);
}
}
}
void setupLightPWM(){
// PWM da iluminação artificial
ledcAttach(LIGHT_PWM_PIN, LIGHT_PWM_FREQ, LIGHT_PWM_RESOLUTION);
ledcWrite(LIGHT_PWM_PIN, 0); // luz desligada
}
void setupLCD() {
// Configuração do número de linhas e colunas do LCD
lcd.begin(16, 2); // Nº de Colunas e Linhas do Display
lcd.init();
lcd.backlight();
}
void setupVentPWM(){
// Configura PWM no ESP32
//ledcSetup(VENT_PWM_CHANNEL, VENT_PWM_FREQ, VENT_PWM_RESOLUTION);
//ledcAttachPin(MOTOR_PWM_PIN, VENT_PWM_CHANNEL);
}
// ================= FUNCOES GERAIS =================
float dataLDRConvert(int ldr_analog_value){
// Conversao das medições do sensor de luminosidade
const float vcc_esp32 = 3.3;
const float GAMMA = 0.7;
const float RL10 = 50;
float voltage = ldr_analog_value / 4095. * vcc_esp32;
float resistance = 3025 * voltage / (1 - voltage / vcc_esp32);
float luminosity = pow(RL10 * 1e3 * pow(10, GAMMA) / resistance, (1 / GAMMA));
return luminosity;
}
float readSoilEC() {
int adc = analogRead(EC_PIN);
float voltage = adc * 3.3 / 4095.0;
// Modelo EC (dS/m)
float ec = 2.5 * voltage;
return ec;
}
void publishMQTTx(const char* suffix, const String& payload) {
char topic[150];
snprintf(topic, sizeof(topic), "%s%s", pubtopicMQTT, suffix);
clientMQTT.publish(topic, payload.c_str());
}
void publishMQTTUbidots(float temperature, float humidity, float luminosity, float soil_ec, float duty_cycle_vent, float duty_cycle_ilum, bool vent_status, bool irrig_status, bool ilum_status) {
String payload = "{";
payload += "\"temperatura\":" + String(temperature, 2) + ",";
payload += "\"umidade\":" + String(humidity, 2) + ",";
payload += "\"luminosidade\":" + String(luminosity, 2) + ",";
payload += "\"condutividade_solo\":" + String(soil_ec, 2) + ",";
payload += "\"duty_cycle_vent\":" + String(duty_cycle_vent, 2) + ",";
payload += "\"duty_cycle_ilum\":" + String(duty_cycle_ilum, 2) + ",";
payload += "\"vent_status\":" + String(vent_status, 2) + ",";
payload += "\"irrig_status\":" + String(irrig_status, 2) + ",";
payload += "\"ilum_status\":" + String(ilum_status, 2);
payload += "}";
Serial.println("[MQTT] Variáveis publicadas: " + payload);
clientMQTT.publish(pubtopicMQTT, payload.c_str());
}
void reconnectMQTT() {
Serial.println("[MQTT] Conexão com o servidor MQTT perdida. Tentando conexão novamente...");
while (!clientMQTT.connected()) {
if (clientMQTT.connect(clientIDMQTT,tokenMQTT,"")) {
clientMQTT.subscribe(subtopicMQTT);
}
Serial.println("[MQTT] Tentando conexão novamente...");
delay(wait_connect_mqtt);
}
Serial.println("[MQTT] Conexão reestabelescida...");
}
// ================= FUNÇÕES DE CONTROLE =================
float ventControl(float temperature){
float dutyPercent;
if (temperature <= temperature_min) {
dutyPercent = 0;
}
else if (temperature >= temperature_max) {
dutyPercent = 100;
}
else {
dutyPercent = 100.0 * (temperature - temperature_min) / (temperature_max - temperature_min);
}
// Converte % para 0–255
//duty_cycle_value = map(dutyPercent, 0, 100, 0, 255);
// Aplica PWM
//ledcWrite(VENT_PWM_CHANNEL, duty_cycle_value);
// ===== Serial =====
//Serial.print("[PWM] Duty Cycle: " + String(dutyPercent) + " %");
// ===== LCD =====
//lcd.setCursor(0, 0);
//lcd.print("Velocidade:");
lcd.setCursor(0, 0);
lcd.print("Controle PWM");
lcd.setCursor(0, 1);
lcd.print("DutyCyc: ");
lcd.print(dutyPercent);
lcd.print(" % ");
return dutyPercent;
}
bool irrigControl(float humidity){
const float humidity_lim = 60.00;
digitalWrite(IRRIGATION_PIN, (humidity < humidity_lim) ? HIGH : LOW);
return (humidity < humidity_lim) ? true : false;
}
float lightControl(float luminosity) {
float dutyPercent;
if (luminosity <= luminosity_min) {
dutyPercent = 100;
}
else if (luminosity >= luminosity_max) {
dutyPercent = 0;
}
else {
dutyPercent = 100.0 * (luminosity_max - luminosity) /
(luminosity_max - luminosity_min);
}
dutyPercent = constrain(dutyPercent, 0, 100);
int dutyPWM = map(dutyPercent, 0, 100, 0, 255);
ledcWrite(LIGHT_PWM_PIN, dutyPWM);
return dutyPercent;
}
// ================= INICIALIZACAO DE MODULOS =================
void setup() {
// Configuracao da serial
Serial.begin(bit_rate);
// Inicializacao do WiFi
setupWiFi();
// Inicializacao do DHT
setupDHT();
// Inicializacao do Servidor MQTT
setupMQTT();
// Inicializacao da Iluminacao Artificial
setupLightPWM();
// Inicializacao do Ventilador
setupVentPWM();
// Inicializacao do LCD
setupLCD();
// Configuracao do pino do sistema de irrigacao
pinMode(IRRIGATION_PIN, OUTPUT);
Serial.println();
}
// ================= FUNCAO PRINCIPAL =================
void loop() {
if (!clientMQTT.connected()) {
reconnectMQTT();
}
clientMQTT.loop();
// ===== COLETA DE DADOS =====
float humidity = dht.readHumidity();
float temperature = dht.readTemperature();
int ldr_analog_value = analogRead(LDR_PIN);
float soil_ec = readSoilEC();
float luminosity = dataLDRConvert(ldr_analog_value);
unsigned long actualMsg = millis();
if (actualMsg - lastMsg > wait_exec_code){
lastMsg = actualMsg;
// ===== PUBLICACAO DAS LEITURAS =====
Serial.println();
if (isnan(humidity) || isnan(temperature) || isnan(luminosity)){
Serial.println("[MEAS] Erro nas leituras!");
return;
}
else{
// ===== CONTROLE DO VENTILADOR =====
float duty_cycle_vent = ventControl(temperature);
bool vent_status = (duty_cycle_vent != 0) ? true : false;
// ===== CONTROLE DA IRRIGAÇÃO =====
bool irrig_status = irrigControl(humidity);
// ===== CONTROLE DE ILUMINACAO =====
float duty_cycle_ilum = lightControl(luminosity);
bool ilum_status = (duty_cycle_ilum != 0) ? true : false;
// ===== PRINT NA SERIAL =====
Serial.println("[MEAS] Temperatura Ambiente: " + String(temperature) + " °C");
Serial.println("[MEAS] Umidade: " + String(humidity) + " %");
Serial.println("[MEAS] Luminosidade no Ambiente: " + String(luminosity) + " lux");
Serial.println("[MEAS] Condutividade do Solo: " + String(soil_ec, 2) + " dS/m");
Serial.print("[Status] Ventilador: ");
Serial.println(vent_status ? "ON" : "OFF");
Serial.println("[Status] Duty Cycle (Ventilador): " + String(duty_cycle_vent) + " %");
Serial.print("[Status] Irrigacao: ");
Serial.println(irrig_status ? "ON" : "OFF");
Serial.print("[Status] Ilumincao Artificial: ");
Serial.println(ilum_status ? "ON" : "OFF");
Serial.println("[Status] Duty Cycle (Iluminação): " + String(duty_cycle_ilum) + " %");
// ===== PUBLICAÇÃO NO SERVIDOR MQTT =====
//publishMQTTx("sensores/temperatura", String(temperature));
//publishMQTTx("sensores/umidade_ar", String(humidity));
//publishMQTTx("sensores/luminosidade", String(luminosity));
//publishMQTTx("atuadores/ventilador/status", vent_status ? "ON" : "OFF");
//publishMQTTx("atuadores/ventilador/duty_cycle_vent", String(duty_cycle_vent).c_str());
//publishMQTTx("atuadores/irrigacao/status", irrig_status ? "ON" : "OFF");
//publishMQTTx("atuadores/sombreamento/status", ilum_status ? "ON" : "OFF");
//publishMQTTx("atuadores/ventilador/duty_cycle_vent", String(duty_cycle_ilum).c_str());
publishMQTTUbidots(temperature, humidity, luminosity, soil_ec, duty_cycle_vent, duty_cycle_ilum, vent_status, irrig_status, ilum_status);
}
}
}