// --- 1. CONFIGURAÇÕES OBRIGATÓRIAS DO BLYNK ---
#define BLYNK_TEMPLATE_ID "TMPL2Qeh7sCAb"
#define BLYNK_TEMPLATE_NAME "Irragacao IoT"
#define BLYNK_AUTH_TOKEN "egLmfxCKiM5JKbXZgrtyVz4G4X4RCP60"
#define BLYNK_PRINT Serial
#include <WiFi.h>
#include <WiFiClient.h>
#include <BlynkSimpleEsp32.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <OneWire.h>
#include <DallasTemperature.h>
char auth[] = BLYNK_AUTH_TOKEN;
char ssid[] = "Wokwi-GUEST";
char pass[] = "";
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
#define ONE_WIRE_BUS 4
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
// Mapeamento Estável de Pinos (Idêntico ao KiCad)
const int PIN_PH = 32;
const int PIN_CE = 33;
const int PIN_TURBIDEZ = 39;
const int PIN_RELE = 12;
const int PIN_LED_RED = 25;
const int PIN_LED_YLW = 18;
const int PIN_LED_GRN = 27;
// Variáveis de Controle IoT
bool irrigando = false;
unsigned long ultimoEnvioBlynk = 0;
const unsigned long INTERVALO_BLYNK = 2000;
void setup() {
Serial.begin(115200);
pinMode(PIN_RELE, OUTPUT);
pinMode(PIN_LED_RED, OUTPUT);
pinMode(PIN_LED_YLW, OUTPUT);
pinMode(PIN_LED_GRN, OUTPUT);
// Estado Inicial Seguro: Bomba desligada, LED Vermelho Aceso à espera do telemóvel
digitalWrite(PIN_RELE, LOW);
digitalWrite(PIN_LED_RED, HIGH);
digitalWrite(PIN_LED_YLW, LOW);
digitalWrite(PIN_LED_GRN, LOW);
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println("Erro no OLED");
for(;;);
}
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(0,0);
display.println("Conectando WiFi...");
display.display();
sensors.begin();
// Inicialização de rede estável para simuladores
WiFi.begin(ssid, pass);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\nWiFi Conectado com sucesso!");
Blynk.begin(auth, ssid, pass);
}
void loop() {
Blynk.run();
// --- 1. LEITURA DOS SENSORES ---
sensors.requestTemperatures();
float temperatura = sensors.getTempCByIndex(0);
if(temperatura == -127.00) temperatura = 20.0; // Valor de segurança padrão se falhar
int leituraPH = analogRead(PIN_PH);
float phVal = (leituraPH * 14.0) / 4095.0;
int leituraCE = analogRead(PIN_CE);
float ceVal = (leituraCE * 3.0) / 4095.0; // Escala analógica mapeada para 0 - 3 dS/m
int leituraTurb = analogRead(PIN_TURBIDEZ);
float turbVal = (leituraTurb * 50.0) / 4095.0; // Escala analógica mapeada para 0 - 50 NTU
// --- 2. TRANSMISSÃO DE DADOS PARA A NUVEM (A cada 2 segundos) ---
if (millis() - ultimoEnvioBlynk >= INTERVALO_BLYNK) {
if (Blynk.connected()) {
Blynk.virtualWrite(V1, temperatura);
Blynk.virtualWrite(V2, phVal);
Blynk.virtualWrite(V3, ceVal);
Blynk.virtualWrite(V4, turbVal);
Blynk.virtualWrite(V5, irrigando ? 1 : 0);
}
ultimoEnvioBlynk = millis();
}
// --- 3. MATRIZ DE AVALIAÇÃO DE ESTADOS ---
String estadoAgua = "";
bool criticidadeMal = false;
bool criticidadeNormal = false;
// Verificação de Estado MAL (Falta de parâmetros ideais mínimos)
if (phVal < 6.5 || phVal > 8.4 || ceVal > 1.5 || turbVal > 30.0 || temperatura < 10.0 || temperatura > 35.0) {
criticidadeMal = true;
}
// Verificação de Estado NORMAL (Parâmetros aceitáveis mas fora da faixa excelente)
else if ((phVal >= 7.5 && phVal <= 8.4) || (ceVal >= 0.75 && ceVal <= 1.5) || (turbVal >= 5.0 && turbVal <= 30.0) || (temperatura >= 10.0 && temperatura < 15.0) || (temperatura > 25.0 && temperatura <= 35.0)) {
criticidadeNormal = true;
}
// --- 4. EXECUÇÃO DA LÓGICA DE INDICAÇÃO E SEGURANÇA ---
if (criticidadeMal) {
estadoAgua = "ESTADO: MAL";
irrigando = false; // Bloqueia a rega imediatamente
digitalWrite(PIN_RELE, LOW); // Força o relé a desligar por proteção
digitalWrite(PIN_LED_RED, HIGH); // Ativa indicador físico de Parado/Erro
digitalWrite(PIN_LED_YLW, LOW);
digitalWrite(PIN_LED_GRN, LOW);
if (Blynk.connected()) {
Blynk.virtualWrite(V0, 0); // Atualiza e desliga o botão no smartphone
}
}
else if (irrigando) {
// Se o utilizador mandou irrigar pelo telemóvel e a água não está MAL
estadoAgua = "STATUS: IRRIGANDO";
digitalWrite(PIN_LED_RED, LOW);
digitalWrite(PIN_LED_YLW, LOW);
digitalWrite(PIN_LED_GRN, HIGH); // LED Verde brilha apenas enquanto irriga
}
else {
// Sistema em Standby (Parado), aguardando ordem do telemóvel
if (criticidadeNormal) {
estadoAgua = "ESTADO: NORMAL";
digitalWrite(PIN_LED_RED, LOW);
digitalWrite(PIN_LED_YLW, HIGH); // LED Amarelo avisa que a água está regular
digitalWrite(PIN_LED_GRN, LOW);
} else {
estadoAgua = "ESTADO: BOM";
digitalWrite(PIN_LED_RED, HIGH); // Mantém vermelho de "Parado" mas com o texto BOM na tela
digitalWrite(PIN_LED_YLW, LOW);
digitalWrite(PIN_LED_GRN, LOW);
}
}
// --- 5. EXIBIÇÃO NO VISOR OLED ---
display.clearDisplay();
display.setCursor(0,0);
display.print("Temp: "); display.print(temperatura, 1); display.println(" C");
display.print("pH: "); display.println(phVal, 1);
display.print("CE: "); display.print(ceVal, 2); display.println(" dS/m");
display.print("Turb: "); display.print(turbVal, 1); display.println(" NTU");
display.println("---------------------");
display.println(estadoAgua);
display.display();
delay(100);
}
// --- 6. INTERFACE DE CONTROLO DIRETO PELO SMARTPHONE ---
BLYNK_WRITE(V0) {
int acionamentoRemoto = param.asInt();
// Só permite ligar a irrigação se a água não estiver em estado crítico (MAL)
if (acionamentoRemoto == 1) {
irrigando = true;
digitalWrite(PIN_RELE, HIGH); // Dispara o Módulo Relé físico
} else {
irrigando = false;
digitalWrite(PIN_RELE, LOW); // Corta a energia da bomba
}
}