#include "DHTSensor.h"
#include "Display.h"
#include "LedControl.h"
#include "PotentiometerSensor.h"
#include <HTTPClient.h>
#include <ArduinoJson.h>
#include <WiFi.h>
#include <time.h>
#define DHTPIN 4
#define DHTTYPE DHT22
#define LED_RIEGO 12
#define LED_FERTILIZANTE 13
#define PH_PIN 32
#define RAIN_PIN 34
#define SUNLIGHT_PIN 33
// Umbrales
const float HUMEDAD_MINIMA = 40.0;
const int LLUVIA_MINIMA = 30; // mm
const float PH_MAXIMO = 8.0; // pH aceptable para fertilizar
// Objetos
DHTSensor dhtSensor(DHTPIN, DHTTYPE);
Display display;
LedControl ledRiego(LED_RIEGO);
LedControl ledFertilizante(LED_FERTILIZANTE);
PotentiometerSensor sensorPH(PH_PIN);
PotentiometerSensor sensorLluvia(RAIN_PIN);
PotentiometerSensor sensorLuz(SUNLIGHT_PIN);
// Sensor IDs
#define SENSOR_ID_TEMP 101
#define SENSOR_ID_HUM 102
#define SENSOR_ID_LUZ 103
#define SENSOR_ID_LLUVIA 104
#define SENSOR_ID_PH 105
#define SENSOR_ID_NUTRIENTES 106
#define CREATED_USER 104
// Variables de tiempo
unsigned long lastPageChange = 0;
const unsigned long pageInterval = 12000;
int currentPage = 0;
unsigned long lastSend = 0;
const unsigned long sendInterval = 50000;
// Configuración NTP
const char* ntpServer = "pool.ntp.org";
const long gmtOffset_sec = -5 * 3600;
const int daylightOffset_sec = 0;
String getCurrentTimestampISO8601() {
struct tm timeinfo;
if (!getLocalTime(&timeinfo)) {
Serial.println("[ERROR] No se pudo obtener la hora");
return "2025-01-01T00:00:00";
}
char buf[25];
strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S", &timeinfo);
return String(buf);
}
void enviarLecturaSensor(int sensorId, float valor) {
if (WiFi.status() != WL_CONNECTED) {
Serial.println("[Reading] No WiFi connection");
return;
}
HTTPClient http;
http.begin("https://api-edge-gqgmetakfceda8dc.brazilsouth-01.azurewebsites.net/api/v1/sensor-readings");
http.addHeader("Content-Type", "application/json");
http.setTimeout(10000);
JsonDocument doc;
doc["sensor_id"] = sensorId;
doc["value"] = valor;
doc["created_user"] = CREATED_USER;
String json;
serializeJson(doc, json);
Serial.printf("[Reading] Enviando sensor %d: %.2f\n", sensorId, valor);
int httpResponseCode = http.POST(json);
Serial.printf("[Reading] HTTP Response code: %d\n", httpResponseCode);
if (httpResponseCode > 0) {
Serial.println("[Reading] Registro enviado correctamente");
} else {
Serial.println("[Reading] Error al enviar registro");
}
http.end();
}
void setup() {
Serial.begin(115200);
delay(100);
Serial.println("[DEBUG] Setup iniciado");
// Inicializar sensores y actuadores
dhtSensor.begin();
display.begin();
ledRiego.begin();
ledFertilizante.begin();
sensorPH.begin();
sensorLluvia.begin();
sensorLuz.begin();
// Conexión WiFi
Serial.println("[WiFi] Conectando a Wokwi-GUEST...");
WiFi.begin("Wokwi-GUEST", "");
int wifiAttempts = 0;
while (WiFi.status() != WL_CONNECTED && wifiAttempts < 20) {
delay(500);
Serial.print(".");
wifiAttempts++;
}
if (WiFi.status() == WL_CONNECTED) {
Serial.println("\n[WiFi] Conectado. IP: " + WiFi.localIP().toString());
// Configurar y sincronizar hora NTP
configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
Serial.println("[TIME] Sincronizando tiempo...");
struct tm timeinfo;
int retries = 0;
while (!getLocalTime(&timeinfo) && retries < 10) {
Serial.println("[TIME] Esperando sincronización NTP...");
delay(1000);
retries++;
}
if (retries < 10) {
Serial.println("[TIME] Tiempo sincronizado correctamente");
} else {
Serial.println("[ERROR] No se pudo sincronizar la hora con el servidor NTP");
}
} else {
Serial.println("\n[WiFi] Error: No se pudo conectar");
}
lastSend = millis();
Serial.println("[DEBUG] Setup completado");
}
void loop() {
float temp = dhtSensor.readTemperature();
float hum = dhtSensor.readHumidity();
// Simula pH de 3.5 a 9.0
float phValue = sensorPH.readMapped(35, 90) / 10.0;
// Fórmula realista: concentración inversamente proporcional al pH neutro
// Menor pH => más nutrientes disponibles
int nutrientes = (int)(1000 / (abs(phValue - 6.5) + 1));
// Lluvia simulada en mm
int lluvia = sensorLluvia.readMapped(0, 100);
// Luz simulada en Lux
int luz = sensorLuz.readMapped(0, 100000);
Serial.println("===== Lecturas =====");
Serial.printf("Temperatura: %.2f °C\n", temp);
Serial.printf("Humedad: %.2f %%\n", hum);
Serial.printf("pH: %.1f\n", phValue);
Serial.printf("Nutrientes (estimado): %d ppm\n", nutrientes);
Serial.printf("Lluvia: %d mm\n", lluvia);
Serial.printf("Luz solar: %d lux\n", luz);
Serial.printf("Timestamp: %s\n", getCurrentTimestampISO8601().c_str());
Serial.println("====================");
unsigned long now = millis();
if (now - lastPageChange >= pageInterval) {
currentPage = (currentPage + 1) % 2;
lastPageChange = now;
}
if (currentPage == 0) {
display.showDataPage1(temp, hum, nutrientes);
} else {
display.showDataPage2(phValue, lluvia, luz);
}
// Lógica para RIEGO
if (hum < HUMEDAD_MINIMA && lluvia < LLUVIA_MINIMA && luz > 70000) {
ledRiego.turnOn();
Serial.println("[CONTROL] LED Riego: ON");
} else {
ledRiego.turnOff();
}
// Lógica para FERTILIZACIÓN
if (phValue < PH_MAXIMO && temp > 15 && temp < 35) {
ledFertilizante.turnOn();
Serial.println("[CONTROL] LED Fertilizante: ON");
} else {
ledFertilizante.turnOff();
}
if (now - lastSend >= sendInterval && WiFi.status() == WL_CONNECTED) {
Serial.println("[DEBUG] Enviando datos periódicos...");
enviarLecturaSensor(SENSOR_ID_TEMP, temp);
enviarLecturaSensor(SENSOR_ID_HUM, hum);
enviarLecturaSensor(SENSOR_ID_NUTRIENTES, nutrientes);
enviarLecturaSensor(SENSOR_ID_PH, phValue);
enviarLecturaSensor(SENSOR_ID_LLUVIA, lluvia);
enviarLecturaSensor(SENSOR_ID_LUZ, luz);
lastSend = now;
}
delay(2000);
}