#include <WiFi.h>
#include <HTTPClient.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <time.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <LittleFS.h>
#include <ArduinoJson.h>
// --- CONFIG Wi-Fi ---
const char* ssid = "Wokwi-GUEST";
const char* password = "";
const char* ntpServer = "pool.ntp.org";
const long gmtOffset_sec = -10800;
const int daylightOffset_sec = 0;
// --- ThingSpeak ---
const char* server = "http://api.thingspeak.com/update";
String apiKey1 = "4YP76XVULK2B1OC3"; // Canal 1 - Umidade
String apiKey2 = "85VTFD3OY2ZC61TK"; // Canal 2 - Temperatura
// --- OLED ---
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
TwoWire wireOled = TwoWire(1); // SDA 25, SCL 26
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &wireOled, -1);
// --- Switch slide ---
#define SWITCH_PIN 14
bool oledLigado = true;
// --- Sensores ---
const int soilPins[8] = {32, 33, 34, 35, 36, 39, 4, 15};
const int tempPins[8] = {21, 19, 18, 5, 17, 16, 23, 22};
OneWire oneWires[8] = {
OneWire(tempPins[0]), OneWire(tempPins[1]), OneWire(tempPins[2]), OneWire(tempPins[3]),
OneWire(tempPins[4]), OneWire(tempPins[5]), OneWire(tempPins[6]), OneWire(tempPins[7])
};
DallasTemperature temps[8] = {
DallasTemperature(&oneWires[0]), DallasTemperature(&oneWires[1]),
DallasTemperature(&oneWires[2]), DallasTemperature(&oneWires[3]),
DallasTemperature(&oneWires[4]), DallasTemperature(&oneWires[5]),
DallasTemperature(&oneWires[6]), DallasTemperature(&oneWires[7])
};
// --- Tela Wi-Fi ---
void mostrarTelaWiFi(bool conectado) {
if (!oledLigado) return;
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 5);
display.println("Inicializacao Completa");
display.setCursor(0, 25);
display.println(conectado ? "Wi-Fi Conectado" : "Wi-Fi Desconectado");
display.display();
}
// --- Envia para ThingSpeak ---
bool enviarParaThingSpeak(String apiKey, JsonArray dados, String tipo) {
HTTPClient http;
String url = String(server) + "?api_key=" + apiKey;
for (int i = 0; i < dados.size(); i++) {
url += "&field" + String(i + 1) + "=" + String(dados[i].as<float>(), 2);
}
http.begin(url);
int httpCode = http.GET();
if (httpCode > 0) {
Serial.printf("Enviado %s ao ThingSpeak! Codigo: %d\n", tipo.c_str(), httpCode);
http.end();
return true;
} else {
Serial.printf("Erro HTTP (%s): %s\n", tipo.c_str(), http.errorToString(httpCode).c_str());
http.end();
return false;
}
}
void setup() {
Serial.begin(115200);
pinMode(SWITCH_PIN, INPUT_PULLUP);
wireOled.begin(25, 26);
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println("Erro ao iniciar OLED");
}
// --- Inicializa LittleFS ---
if (!LittleFS.begin()) {
Serial.println("❌ Falha ao montar LittleFS. Verifique a partição!");
} else {
Serial.println("✅ LittleFS montado com sucesso.");
}
// Inicializa sensores
for (int i = 0; i < 8; i++) temps[i].begin();
// Conexão Wi-Fi
WiFi.begin(ssid, password);
Serial.print("Conectando ao WiFi");
int tentativas = 0;
while (WiFi.status() != WL_CONNECTED && tentativas < 20) {
delay(500); Serial.print("."); tentativas++;
}
bool conectado = WiFi.status() == WL_CONNECTED;
Serial.println(conectado ? "\nWi-Fi Conectado" : "\nFalha Wi-Fi");
if (conectado) configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
mostrarTelaWiFi(conectado);
}
void loop() {
// --- Controle OLED ---
bool switchDesligado = digitalRead(SWITCH_PIN) == HIGH;
if (switchDesligado && oledLigado) {
oledLigado = false;
display.clearDisplay();
display.display();
display.ssd1306_command(SSD1306_DISPLAYOFF);
Serial.println("OLED Desligado");
} else if (!switchDesligado && !oledLigado) {
oledLigado = true;
display.ssd1306_command(SSD1306_DISPLAYON);
mostrarTelaWiFi(WiFi.status() == WL_CONNECTED);
Serial.println("OLED Ligado");
}
// --- A cada 15 segundos ---
static unsigned long ultimaLeitura = 0;
if (millis() - ultimaLeitura > 15000) {
ultimaLeitura = millis();
float umidade[8];
float temperatura[8];
for (int i = 0; i < 8; i++) {
int raw = analogRead(soilPins[i]);
umidade[i] = map(raw, 0, 4095, 100, 0);
}
for (int i = 0; i < 8; i++) {
temps[i].requestTemperatures();
delay(100); // necessário para estabilidade da leitura
temperatura[i] = temps[i].getTempCByIndex(0);
}
for (int i = 0; i < 8; i++) Serial.printf("Umidade %d: %.1f%%\n", i + 1, umidade[i]);
for (int i = 0; i < 8; i++) Serial.printf("Temperatura %d: %.2f C\n", i + 1, temperatura[i]);
DynamicJsonDocument doc(1024);
JsonArray arrUm = doc.createNestedArray("umidade");
JsonArray arrTemp = doc.createNestedArray("temperatura");
for (int i = 0; i < 8; i++) arrUm.add(umidade[i]);
for (int i = 0; i < 8; i++) arrTemp.add(temperatura[i]);
if (WiFi.status() == WL_CONNECTED) {
bool ok1 = enviarParaThingSpeak(apiKey1, arrUm, "umidade");
bool ok2 = enviarParaThingSpeak(apiKey2, arrTemp, "temperatura");
if (ok1 && ok2 && LittleFS.exists("/pendentes.txt")) {
File file = LittleFS.open("/pendentes.txt", "r");
while (file.available()) {
String linha = file.readStringUntil('\n');
DynamicJsonDocument json(1024);
if (deserializeJson(json, linha) == DeserializationError::Ok) {
enviarParaThingSpeak(apiKey1, json["umidade"], "umidade");
enviarParaThingSpeak(apiKey2, json["temperatura"], "temperatura");
}
}
file.close();
LittleFS.remove("/pendentes.txt");
Serial.println("Backup enviado e removido.");
}
} else {
File file = LittleFS.open("/pendentes.txt", "a");
if (file) {
serializeJson(doc, file);
file.println();
file.close();
Serial.println("WiFi offline. Dados salvos localmente.");
} else {
Serial.println("Erro ao salvar backup no LittleFS.");
}
}
}
}