/* Ejercicio entregable 011
Deben de utilizar este archivo los alumnos con c<5, d<5, u>=5
siendo c,d,u las tres últimas cifras del DNI 22000cdu -W
Luminosidad y motor continua con potenciometro
Para cambiar Luminosidad o haz click sobre el sensor durante la simulacion
NOMBRE ALUMNO: Cristina Vidal Herrero
DNI: 26600086 B
ENLACE WOKWI: XXXXXXX
*/
#include <Arduino.h>
#include <WiFi.h>
#include <PubSubClient.h>
#include <ArduinoJson.h>
const int luxPin = 35; // Pin analógico para el sensor de luminosidad
const int potPin = 34; // Pin analógico para el sensor de posición
const uint8_t PIN_PWM = 26;
const uint32_t FREQ = 1000; // Hz
const uint8_t RES = 10; // bits (0..1023)
// WiFi Wokwi
const char* WIFI_SSID = "Wokwi-GUEST";
const char* WIFI_PASS = "";
// MQTT
const char* MQTT_HOST = "broker.emqx.io";
const int MQTT_PORT = 1883;
const char* DNI_3ULT = "086";
String topicLuz;
String topicHistorico;
WiFiClient espClient;
PubSubClient mqtt(espClient);
static const int ADC_MIN = 0;
static const int ADC_MAX = 4095;
// Histórico 5 horas
float historico[5] = {0, 0, 0, 0, 0};
uint32_t lastPublishLuz = 0;
uint32_t lastHourTick = 0;
static const uint32_t LUZ_PUBLISH_MS = 2000;
static const uint32_t HOUR_MS = 3600000;
double sumLuzHour = 0.0;
uint32_t cntLuzHour = 0;
int adcToPercent(int adc)
{
adc = constrain(adc, ADC_MIN, ADC_MAX);
return map(adc, ADC_MIN, ADC_MAX, 0, 100);
}
float percentToAngle(int percent)
{
percent = constrain(percent, 0, 100);
return (percent * 90.0f) / 100.0f;
}
float potAdcToAngle(int adc)
{
adc = constrain(adc, ADC_MIN, ADC_MAX);
float angle = (float)adc * 90.0f / (float)ADC_MAX;
return constrain(angle, 0.0f, 90.0f);
}
void pushHistorico(float nuevaMedia)
{
for (int i = 0; i < 4; i++) historico[i] = historico[i + 1];
historico[4] = nuevaMedia;
}
void ensureWiFi()
{
if (WiFi.status() == WL_CONNECTED) return;
WiFi.mode(WIFI_STA);
WiFi.begin(WIFI_SSID, WIFI_PASS);
uint32_t t0 = millis();
while (WiFi.status() != WL_CONNECTED && millis() - t0 < 15000) {
delay(250);
}
if (WiFi.status() == WL_CONNECTED) {
Serial.print("WiFi OK. IP: ");
Serial.println(WiFi.localIP());
} else {
Serial.println("WiFi NO conectado (reintentando).");
}
}
void ensureMQTT()
{
if (mqtt.connected()) return;
if (WiFi.status() != WL_CONNECTED) return;
String clientId = String("esp32-invernadero-") + DNI_3ULT + "-" + String((uint32_t)ESP.getEfuseMac(), HEX);
if (mqtt.connect(clientId.c_str())) {
Serial.println("MQTT OK");
}
}
void publishLuz(int luzPercent)
{
if (!mqtt.connected()) return;
char payload[8];
snprintf(payload, sizeof(payload), "%d", luzPercent);
mqtt.publish(topicLuz.c_str(), payload, true);
}
void publishHistorico()
{
if (!mqtt.connected()) return;
StaticJsonDocument<128> doc;
JsonArray arr = doc.to<JsonArray>();
for (int i = 0; i < 5; i++) arr.add((int)round(historico[i]));
char out[128];
serializeJson(arr, out, sizeof(out));
mqtt.publish(topicHistorico.c_str(), out, true);
}
void setup()
{
// put your setup code here, to run once:
Serial.begin(115200);
Serial.println("Hello, ESP32!");
delay(200);
//ledcAttachPin(26, 0);
//ledcSetup(0, 1000, 10); // frecuencia 1KHz y resolucion 2^10
ledcAttach(PIN_PWM, FREQ, RES);
mqtt.setServer(MQTT_HOST, MQTT_PORT);
topicLuz = String("sja003/invernadero/") + DNI_3ULT + "/luz";
topicHistorico = String("sja003/invernadero/") + DNI_3ULT + "/historico";
ensureWiFi();
ensureMQTT();
lastPublishLuz = 0;
lastHourTick = millis();
Serial.println(topicLuz);
Serial.println(topicHistorico);
}
void loop()
{
// put your main code here, to run repeatedly:
ensureWiFi();
ensureMQTT();
mqtt.loop();
int luxAdc = analogRead(luxPin);
int potAdc = analogRead(potPin);
int luzPercent = adcToPercent(luxAdc);
float targetAngle = percentToAngle(luzPercent);
float actualAngle = potAdcToAngle(potAdc);
int pwmCmd = map((int)round(targetAngle * 10), 0, 900, 0, 1023);
pwmCmd = constrain(pwmCmd, 0, 1023);
ledcWrite(PIN_PWM, pwmCmd);
sumLuzHour += luzPercent;
cntLuzHour++;
if (millis() - lastPublishLuz >= LUZ_PUBLISH_MS) {
lastPublishLuz = millis();
publishLuz(luzPercent);
Serial.print("Luz%=");
Serial.print(luzPercent);
Serial.print(" target=");
Serial.print(targetAngle, 1);
Serial.print(" actual=");
Serial.print(actualAngle, 1);
Serial.print(" pwm=");
Serial.print(pwmCmd);
Serial.print(" luxADC=");
Serial.print(luxAdc);
Serial.print(" potADC=");
Serial.println(potAdc);
}
if (millis() - lastHourTick >= HOUR_MS) {
lastHourTick += HOUR_MS;
float media = 0.0f;
if (cntLuzHour > 0) media = (float)(sumLuzHour / (double)cntLuzHour);
pushHistorico(media);
publishHistorico();
sumLuzHour = 0.0;
cntLuzHour = 0;
Serial.print("Media 1h: ");
Serial.print(media, 1);
Serial.println(" -> historico publicado");
}
delay(20);
}