import machine
import time
from machine import Pin, ADC
import dht
# ========================================
# CONFIGURACION WIFI - MQTT
# ========================================
import network
import ujson
try:
from umqtt.simple import MQTTClient
MQTT_AVAILABLE = True
except ImportError:
MQTT_AVAILABLE = False
print("Advertencia: librería umqtt no disponible")
# Configuración WiFi y MQTT
WIFI_SSID = "Wokwi-GUEST"
WIFI_PASSWORD = ""
MQTT_CLIENT_ID = "galpon-automatizado"
MQTT_BROKER = "broker.mqttdashboard.com"
MQTT_USER = ""
MQTT_PASSWORD = ""
MQTT_TOPIC_SENSORS = "galpon/sensores"
MQTT_TOPIC_CLIMA = "galpon/clima"
MQTT_TOPIC_LUCES = "galpon/luces"
MQTT_TOPIC_SEGURIDAD = "galpon/seguridad"
# ========================================
# LIBRERIA PARA LCD 16X2 I2C
# ========================================
class I2cLcd:
def __init__(self, i2c, addr, cols, rows):
self.i2c = i2c
self.addr = addr
self.cols = cols
self.rows = rows
self.buf = bytearray(1)
self._init()
def _write_byte(self, byte, mode=0):
"""Envía un byte al LCD con el pulso de enable"""
# mode: 0 = comando, 1 = dato
# Formato: [D7 D6 D5 D4 BL EN RW RS]
# BL = backlight (bit 3), EN = enable (bit 2), RW = write (bit 1), RS = select (bit 0)
en = 0x04 # Enable
rs = mode & 0x01
# Enviar nibble alto
high = (byte & 0xF0) | rs | en
low = (byte & 0xF0) | rs
self.i2c.writeto(self.addr, bytes([high | 0x08])) # Con backlight
time.sleep_ms(1)
self.i2c.writeto(self.addr, bytes([low | 0x08])) # Sin enable
time.sleep_ms(1)
# Enviar nibble bajo
high = ((byte << 4) & 0xF0) | rs | en
low = ((byte << 4) & 0xF0) | rs
self.i2c.writeto(self.addr, bytes([high | 0x08]))
time.sleep_ms(1)
self.i2c.writeto(self.addr, bytes([low | 0x08]))
time.sleep_ms(1)
def _init(self):
"""Inicializa el LCD 16x2 en modo 4 bits"""
time.sleep_ms(50)
# Secuencia de inicialización 4-bit
self._write_byte(0x33, 0)
time.sleep_ms(5)
self._write_byte(0x32, 0)
time.sleep_ms(5)
self._write_byte(0x28, 0) # 4-bit, 2 líneas, font 5x8
time.sleep_ms(5)
self._write_byte(0x0C, 0) # Display ON, cursor OFF, blink OFF
time.sleep_ms(5)
self._write_byte(0x06, 0) # Incremento automático
time.sleep_ms(5)
self.clear()
def clear(self):
"""Limpia el LCD"""
self._write_byte(0x01, 0)
time.sleep_ms(2)
def move_to(self, col, row):
"""Mueve el cursor a la posición especificada"""
if row == 0:
self._write_byte(0x80 | col, 0)
else:
self._write_byte(0xC0 | col, 0)
time.sleep_ms(1)
def putstr(self, s):
"""Escribe una cadena en el LCD"""
for char in s:
self._write_byte(ord(char), 1) # 1 = modo dato
time.sleep_ms(1)
#----------------------------------------
class ChickenCoopLighting:
def __init__(self):
# Configuración de pines
self.ldr_pin = ADC(Pin(36)) # Sensor LDR en GPIO36 (VP)
self.ldr_pin.atten(ADC.ATTN_11DB) # Configurar para rango 0-3.3V
# Inicializar MQTT
self.mqtt_connected = False
self.mqtt_client = None
self.last_mqtt_send = time.time()
self.mqtt_interval = 5 # Enviar datos cada 5 segundos
# Relés conectados a los pines correctos
self.relay1 = Pin(25, Pin.OUT) # Primer relé en GPIO25
self.relay2 = Pin(26, Pin.OUT) # Segundo relé en GPIO26
self.relay3 = Pin(27, Pin.OUT) # Tercer relé en GPIO27
# Relés para luces del pasillo (independientes del criadero)
self.pasillo_relay1 = Pin(13, Pin.OUT) # Luz entrada pasillo
self.pasillo_relay2 = Pin(32, Pin.OUT) # Luz salida pasillo
# Apagar luces del pasillo al inicio
self.pasillo_relay1.value(0)
self.pasillo_relay2.value(0)
self.pasillo_luz1_on = False
self.pasillo_luz2_on = False
# Botón para cambiar a Fase 2
self.phase_button = Pin(4, Pin.IN, Pin.PULL_UP) # Botón en GPIO4 con pull-up
# Sensores PIR para pasillo
self.pir1 = Pin(15, Pin.IN) # PIR entrada pasillo
self.pir2 = Pin(16, Pin.IN) # PIR salida pasillo
# PIR exterior y alerta
self.pir_exterior = Pin(5, Pin.IN) # PIR exterior
self.alert_light = Pin(2, Pin.OUT) # Luz de alerta
# Apagar al inicio
self.alert_light.value(0)
self.alert_active = False
# Sensor de temperatura DHT22
self.dht_sensor = dht.DHT22(Pin(14))
# Relés del sistema de climatización
self.cooling_relay = Pin(12, Pin.OUT) # Modo frío
self.heating_relay = Pin(33, Pin.OUT) # Modo calor
# Asegurar que ambos estén apagados al inicio
self.cooling_relay.value(0)
self.heating_relay.value(0)
self.cooling_on = False
self.heating_on = False
# Inicializar LCD 16x2 (SDA=22, SCL=21)
from machine import I2C
i2c = I2C(0, scl=Pin(21), sda=Pin(22), freq=400000)
# Prueba con 0x27 o 0x3F según tu módulo
self.display = I2cLcd(i2c, 0x27, 16, 2)
time.sleep(0.5) # Retraso para estabilizar
self.display.clear()
self.display.putstr("Sistema iniciado")
# Sensor de puerta/ventana abierta (simulado con pulsador en GPIO17)
self.door_sensor = Pin(17, Pin.IN, Pin.PULL_UP) # 0 = cerrada, 1 = abierta
self.door_open = False
# Variables del sistema
self.phase = 1 # Fase inicial
self.day_count = 1 # Contador de días
self.start_time = time.time()
self.last_button_state = self.phase_button.value() # Leer estado inicial del botón
# Estado de las luces
self.lights_on = [False, False, False]
# IMPORTANTE: Re-inicializar relés apagados DESPUÉS de configurar variables
# LOW (0) = apagado
self.relay1.value(0)
self.relay2.value(0)
self.relay3.value(0)
time.sleep(0.1) # Pequeña pausa para estabilizar
# Leer valor inicial para debug y verificación
initial_reading = self.read_light_intensity()
initial_lux = self.calculate_lux(initial_reading)
print("Sistema de iluminación iniciado")
print(f"Fase {self.phase} - Día {self.day_count}")
print(f"DEBUG - Lectura inicial ADC: {initial_reading}")
print(f"DEBUG - Lux aproximado inicial: {initial_lux}")
print(f"DEBUG - Estado inicial botón: {self.last_button_state} (1=no presionado, 0=presionado)")
print(f"DEBUG - Estado inicial luces: {self.lights_on}")
print("Presiona el botón para cambiar a Fase 2")
print()
#----------------------
def connect_wifi(self):
"""Conecta el ESP32 a la red WiFi"""
print("Conectando a WiFi...", end="")
sta_if = network.WLAN(network.STA_IF)
sta_if.active(True)
sta_if.connect(WIFI_SSID, WIFI_PASSWORD)
timeout = 0
while not sta_if.isconnected() and timeout < 20:
print(".", end="")
time.sleep(0.5)
timeout += 1
if sta_if.isconnected():
print(" ¡Conectado!")
print(f"IP: {sta_if.ifconfig()[0]}")
return True
else:
print(" No se pudo conectar")
return False
def connect_mqtt(self):
"""Conecta al broker MQTT"""
if not MQTT_AVAILABLE:
print("MQTT no disponible")
return False
try:
print("Conectando a MQTT...", end="")
self.mqtt_client = MQTTClient(
MQTT_CLIENT_ID,
MQTT_BROKER,
user=MQTT_USER,
password=MQTT_PASSWORD
)
self.mqtt_client.connect()
print(" ¡Conectado!")
self.mqtt_connected = True
return True
except Exception as e:
print(f" Error: {e}")
self.mqtt_connected = False
return False
def publish_mqtt(self, topic, message):
"""Publica un mensaje en MQTT de forma segura"""
if not self.mqtt_connected:
return False
try:
self.mqtt_client.publish(topic, message)
return True
except Exception as e:
print(f"Error publicando en MQTT: {e}")
self.mqtt_connected = False
return False
def send_sensor_data(self):
"""Envía datos de sensores por MQTT"""
if not self.mqtt_connected:
return
# Leer datos actuales
light_reading = self.read_light_intensity()
lux = self.calculate_lux(light_reading)
temp = self.read_temperature()
# Construir payload
sensor_data = {
"timestamp": time.time(),
"lux": lux,
"adc": light_reading,
"temperatura": temp if temp else 0,
"fase": self.phase,
"dia": self.day_count
}
message = ujson.dumps(sensor_data)
self.publish_mqtt(MQTT_TOPIC_SENSORS, message)
print(f"[MQTT] Datos de sensores enviados: {message}")
def send_lighting_status(self):
"""Envía estado de iluminación por MQTT"""
if not self.mqtt_connected:
return
lights_status = {
"fase": self.phase,
"luces_encendidas": sum(self.lights_on),
"luz1": self.lights_on[0],
"luz2": self.lights_on[1],
"luz3": self.lights_on[2],
"pasillo_luz1": self.pasillo_luz1_on,
"pasillo_luz2": self.pasillo_luz2_on
}
message = ujson.dumps(lights_status)
self.publish_mqtt(MQTT_TOPIC_LUCES, message)
def send_climate_status(self):
"""Envía estado de climatización por MQTT"""
if not self.mqtt_connected:
return
temp = self.read_temperature()
climate_data = {
"temperatura": temp if temp else 0,
"cooling": self.cooling_on,
"heating": self.heating_on
}
message = ujson.dumps(climate_data)
self.publish_mqtt(MQTT_TOPIC_CLIMA, message)
def send_security_status(self):
"""Envía estado de seguridad por MQTT"""
if not self.mqtt_connected:
return
security_data = {
"alerta_exterior": self.alert_active,
"puerta_abierta": self.door_open
}
message = ujson.dumps(security_data)
self.publish_mqtt(MQTT_TOPIC_SEGURIDAD, message)
#----------------------
def read_light_intensity(self):
"""Lee el valor del sensor LDR y lo convierte a un valor aproximado"""
# Promedio de 3 lecturas para mayor estabilidad
readings = []
for _ in range(3):
readings.append(self.ldr_pin.read())
time.sleep(0.05)
avg_reading = sum(readings) / len(readings)
return int(avg_reading)
def calculate_lux(self, adc_value):
"""Conversión ADC a Lux con interpolación lineal para máxima precisión
Tabla de calibración medida:
ADC 3933 = 1 lux
ADC 3671 = 5 lux
ADC 3431 = 10 lux
ADC 3231 = 15 lux
ADC 3092 = 20 lux
ADC 2531 = 50 lux
ADC 2045 = 100 lux
ADC 999 = 500 lux
Relación: más ADC = menos luz (LDR inverso)
"""
# Puntos de calibración (ADC, Lux)
calibration_points = [
(999, 500),
(2045, 100),
(2531, 50),
(3092, 20),
(3231, 15),
(3431, 10),
(3671, 5),
(3933, 1)
]
# Si está fuera de rango, devolver límites
if adc_value <= calibration_points[0][0]:
return calibration_points[0][1] # >= 500 lux
if adc_value >= calibration_points[-1][0]:
return calibration_points[-1][1] # <= 1 lux
# Interpolación lineal entre puntos
for i in range(len(calibration_points) - 1):
adc1, lux1 = calibration_points[i]
adc2, lux2 = calibration_points[i + 1]
if adc1 <= adc_value <= adc2:
# Interpolación lineal: y = y1 + (x - x1) * (y2 - y1) / (x2 - x1)
lux = lux1 + (adc_value - adc1) * (lux2 - lux1) / (adc2 - adc1)
return int(lux)
# Fallback (no debería llegar aquí)
return 20
def read_temperature(self):
"""Lee la temperatura del sensor DHT22. Retorna temperatura en °C o None si falla."""
try:
self.dht_sensor.measure()
temp = self.dht_sensor.temperature()
return temp
except OSError as e:
print(f"Error leyendo DHT22: {e}")
return None
def check_phase_button(self):
"""Verifica si se presionó el botón para cambiar fase"""
current_state = self.phase_button.value()
# Debug: mostrar cada cambio de estado del botón
if current_state != self.last_button_state:
print(f"DEBUG Botón: cambió de {self.last_button_state} a {current_state}")
# Detectar flanco descendente (botón presionado)
# current_state == 0 significa botón presionado (conectado a GND)
if self.last_button_state == 1 and current_state == 0:
if self.phase == 1:
self.phase = 2
print("\n*** BOTÓN PRESIONADO: Cambiando a Fase 2 ***")
print("Fase 2: Control gradual (5-10 lux)\n")
elif self.phase == 2:
self.phase = 1
print("\n*** BOTÓN PRESIONADO: Regresando a Fase 1 ***")
print("Fase 1: Control total (20 lux mínimo)\n")
# Esperar a que se suelte el botón
while self.phase_button.value() == 0:
time.sleep(0.05)
time.sleep(0.2) # Debounce adicional
self.last_button_state = current_state
def update_phase(self):
"""Actualiza la fase según los días transcurridos (modo automático)"""
elapsed_time = time.time() - self.start_time
self.day_count = int(elapsed_time / 86400) + 1 # 86400 seg = 1 día
# Para simulación rápida: 1 minuto = 1 día
# self.day_count = int(elapsed_time / 60) + 1
if self.day_count <= 7:
if self.phase != 1:
self.phase = 1
print(f"Cambiando automáticamente a Fase 1 - Día {self.day_count}")
elif self.day_count <= 56:
if self.phase != 2:
self.phase = 2
print(f"Cambiando automáticamente a Fase 2 - Día {self.day_count}")
else:
if self.phase != 3:
self.phase = 3
print(f"Finalizando ciclo automático - Día {self.day_count}")
def control_lights_phase1(self, light_level):
"""Control de luces para Fase 1 (0-7 días): 20 lux mínimo"""
current_lux = self.calculate_lux(light_level)
if current_lux < 20: # Si hay menos de 20 lux (ADC > 3160)
if not all(self.lights_on):
print(f"Fase 1: Luz insuficiente ({current_lux} lux < 20) - ENCENDIENDO todas las luces")
self.turn_on_all_lights()
else: # Hay suficiente luz natural (>= 20 lux)
if any(self.lights_on):
print(f"Fase 1: Luz suficiente ({current_lux} lux >= 20) - APAGANDO luces")
self.turn_off_all_lights()
def control_lights_phase2(self, light_level):
"""Control de luces para Fase 2 (8-56 días): mantener entre 5-10 lux
Estrategia:
- Si luz > 10 lux: apagar todas (hay suficiente luz natural)
- Si luz está entre 5-10 lux: mantener luces actuales (rango objetivo)
- Si luz < 10 lux pero > 5 lux: encender luces gradualmente para complementar
- Si luz < 5 lux: encender todas las luces (muy oscuro)
"""
current_lux = self.calculate_lux(light_level)
current_lights = sum(self.lights_on)
lights_needed = 0
if current_lux > 10:
# Demasiada luz natural - apagar todas
lights_needed = 0
elif current_lux >= 9:
# 9-10 lux: casi en rango, encender 1 luz si es necesario
lights_needed = 1
elif current_lux >= 7:
# 7-9 lux: en rango medio, encender 2 luces
lights_needed = 2
elif current_lux >= 5:
# 5-7 lux: en límite inferior, encender 3 luces
lights_needed = 3
else:
# < 5 lux: muy oscuro, todas las luces
lights_needed = 3
if lights_needed != current_lights:
print(f"Fase 2: Lux actual {current_lux} - Ajustando de {current_lights} a {lights_needed} luces")
self.adjust_lights_gradually(lights_needed, current_lux)
else:
# Opcional: mostrar que está en rango correcto
if 5 <= current_lux <= 10:
pass # En rango objetivo, sin cambios
def adjust_lights_gradually(self, needed_lights, current_lux):
"""Ajusta las luces gradualmente según necesidad"""
current_lights = sum(self.lights_on)
if needed_lights > current_lights:
# Encender más luces (una por una)
for i in range(3):
if not self.lights_on[i] and sum(self.lights_on) < needed_lights:
self.turn_on_light(i + 1)
print(f" → Encendiendo luz {i+1}")
time.sleep(0.5) # Pausa entre encendidos
elif needed_lights < current_lights:
# Apagar luces (empezando por la última)
for i in range(2, -1, -1):
if self.lights_on[i] and sum(self.lights_on) > needed_lights:
self.turn_off_light(i + 1)
print(f" → Apagando luz {i+1}")
time.sleep(0.5)
def turn_on_light(self, light_num):
"""Enciende una luz específica"""
if light_num == 1:
self.relay1.value(1) # HIGH activa el relé (lógica NORMAL)
self.lights_on[0] = True
elif light_num == 2:
self.relay2.value(1)
self.lights_on[1] = True
elif light_num == 3:
self.relay3.value(1)
self.lights_on[2] = True
def turn_off_light(self, light_num):
"""Apaga una luz específica"""
if light_num == 1:
self.relay1.value(0) # LOW desactiva el relé (lógica NORMAL)
self.lights_on[0] = False
elif light_num == 2:
self.relay2.value(0)
self.lights_on[1] = False
elif light_num == 3:
self.relay3.value(0)
self.lights_on[2] = False
def turn_on_all_lights(self):
"""Enciende todas las luces"""
self.relay1.value(1) # HIGH = ON
self.relay2.value(1)
self.relay3.value(1)
self.lights_on = [True, True, True]
def turn_off_all_lights(self):
"""Apaga todas las luces"""
self.relay1.value(0) # LOW = OFF
self.relay2.value(0)
self.relay3.value(0)
self.lights_on = [False, False, False]
def control_climatizacion(self, temperature):
"""Control seguro de climatización con dos relés: frío (pin12) y calor (pin33).
Rango objetivo: 13°C ≤ T ≤ 22°C.
Histéresis:
- Enfriar si T > 22.5°C, apagar frío si T ≤ 22.0°C
- Calentar si T < 12.5°C, apagar calor si T ≥ 13.0°C
"""
if temperature is None:
return
# --- Control de ENFRIAMIENTO ---
if temperature > 22.5:
if not self.cooling_on:
print(f" Temperatura alta ({temperature:.1f}°C > 22.5°C) - ENCENDIENDO MODO FRÍO")
self.cooling_relay.value(1)
self.cooling_on = True
# Asegurar que el calor esté apagado
if self.heating_on:
self.heating_relay.value(0)
self.heating_on = False
print(" Modo calor desactivado (seguridad)")
elif self.cooling_on and temperature <= 22.0:
print(f" Temperatura normalizada ({temperature:.1f}°C ≤ 22.0°C) - APAGANDO MODO FRÍO")
self.cooling_relay.value(0)
self.cooling_on = False
# --- Control de CALEFACCIÓN ---
elif temperature < 12.5:
if not self.heating_on:
print(f" Temperatura baja ({temperature:.1f}°C < 12.5°C) - ENCENDIENDO MODO CALOR")
self.heating_relay.value(1)
self.heating_on = True
# Asegurar que el frío esté apagado
if self.cooling_on:
self.cooling_relay.value(0)
self.cooling_on = False
print(" Modo frío desactivado (seguridad)")
elif self.heating_on and temperature >= 13.0:
print(f" Temperperatura normalizada ({temperature:.1f}°C ≥ 13.0°C) - APAGANDO MODO CALOR")
self.heating_relay.value(0)
self.heating_on = False
def control_pasillo_pir(self):
"""Control independiente de luces del pasillo con PIR.
- PIR1 (pin15) → enciende relay13, apaga relay32
- PIR2 (pin16) → enciende relay32, apaga relay13
- Sin movimiento → apaga ambas
"""
pir1_active = self.pir1.value() == 1
pir2_active = self.pir2.value() == 1
if pir1_active:
if not self.pasillo_luz1_on:
self.pasillo_relay1.value(1)
self.pasillo_luz1_on = True
print(" PIR1 detectado - Encendiendo luz PASILLO 1 (entrada)")
if self.pasillo_luz2_on:
self.pasillo_relay2.value(0)
self.pasillo_luz2_on = False
elif pir2_active:
if not self.pasillo_luz2_on:
self.pasillo_relay2.value(1)
self.pasillo_luz2_on = True
print(" PIR2 detectado - Encendiendo luz PASILLO 2 (salida)")
if self.pasillo_luz1_on:
self.pasillo_relay1.value(0)
self.pasillo_luz1_on = False
else:
# Ningún movimiento: apagar ambas si están encendidas
if self.pasillo_luz1_on or self.pasillo_luz2_on:
if self.pasillo_luz1_on:
self.pasillo_relay1.value(0)
self.pasillo_luz1_on = False
if self.pasillo_luz2_on:
self.pasillo_relay2.value(0)
self.pasillo_luz2_on = False
print(" Pasillo vacío - Apagando luces del pasillo")
def control_alerta_exterior(self):
"""Control de alerta por movimiento exterior con LED parpadeante."""
pir_ext_active = self.pir_exterior.value() == 1
if pir_ext_active:
if not self.alert_active:
print(" INTRUSIÓN DETECTADA EN EXTERIOR!")
self.alert_active = True
# Parpadeo rápido: alterna el estado del LED cada 0.3s
self.alert_light.value(1)
time.sleep(0.3)
self.alert_light.value(0)
time.sleep(0.3)
return # Salir para no apagar la alerta
else:
if self.alert_active:
print(" Alerta desactivada - Movimiento detenido")
self.alert_active = False
self.alert_light.value(0)
def control_puerta_abierta(self):
"""Detecta si la puerta/ventana está abierta (pulsador presionado = abierta)."""
door_state = self.door_sensor.value() # 0 = presionado (abierta), 1 = no presionado (cerrada)
if door_state == 0 and not self.door_open: # Pulsador presionado → abierta
print(" PUERTA/VENTANA ABIERTA - ALERTA ACTIVADA")
self.door_open = True
elif door_state == 1 and self.door_open: # Pulsador no presionado → cerrada
print(" PUERTA/VENTANA CERRADA - Alerta desactivada")
self.door_open = False
def update_display(self):
"""Actualiza el LCD con información clara."""
self.display.clear()
# Línea 1: Estado de ventana
if self.door_open:
line1 = "VENTANA ABIERTA"
else:
line1 = "VENTANA CERRADA"
# Línea 2: Alerta de intrusión
if self.alert_active:
line2 = "ALERTA EXTERIOR"
else:
line2 = "SIN ALERTAS"
self.display.move_to(0, 0)
self.display.putstr(line1[:16])
self.display.move_to(0, 1)
self.display.putstr(line2[:16])
def display_status(self, light_level):
"""Muestra el estado actual del sistema"""
lux_approx = self.calculate_lux(light_level)
lights_count = sum(self.lights_on)
temp = self.read_temperature()
temp_str = f"{temp:.1f}°C" if temp is not None else "N/A"
clima_status = "OFF"
if self.cooling_on:
clima_status = "FRÍO"
elif self.heating_on:
clima_status = "CALOR"
print(f"STATUS: Día {self.day_count} | Fase {self.phase} | ADC: {light_level} | ~{lux_approx} lux | Luces: {lights_count}/3 | Temp: {temp_str} | Clima: {clima_status}")
def run(self):
"""Bucle principal del sistema"""
print("Iniciando sistema de control de iluminación...")
print("=" * 60)
print()
# Forzar estado inicial correcto de los relés
print("Verificando estado inicial de relés...")
# Conectar WiFi y MQTT
if self.connect_wifi():
self.connect_mqtt()
else:
print("WiFi no disponible - el sistema funcionará sin conectividad")
print()
self.turn_off_all_lights()
time.sleep(0.2)
print("Relés inicializados en estado APAGADO")
print()
status_counter = 0
while True:
try:
# Verificar botón para cambio manual de fase
self.check_phase_button()
# Actualizar fase automática (comentado para control manual)
# self.update_phase()
# Leer intensidad de luz
light_reading = self.read_light_intensity()
# Control según la fase actual
if self.phase == 1:
self.control_lights_phase1(light_reading)
elif self.phase == 2:
self.control_lights_phase2(light_reading)
else:
# Fase 3: Ciclo completado
print("Ciclo de 56 días completado - Modo manual")
# Leer y controlar temperatura
temp = self.read_temperature()
if temp is not None:
self.control_climatizacion(temp)
# Control independiente del pasillo
self.control_pasillo_pir()
self.control_alerta_exterior()
# Control de puerta/ventana abierta
self.control_puerta_abierta()
self.update_display()
# Actualizar LCD cada 30 ciclos (~60 segundos) para evitar parpadeo
status_counter += 1
if status_counter >= 30:
self.update_display()
status_counter = 0
# Mostrar estado en consola cada 10 ciclos
if status_counter % 10 == 0:
self.display_status(light_reading)
# Enviar datos por MQTT cada 5 segundos
current_time = time.time()
if self.mqtt_connected and (current_time - self.last_mqtt_send) >= self.mqtt_interval:
self.send_sensor_data()
self.send_lighting_status()
self.send_climate_status()
self.send_security_status()
self.last_mqtt_send = current_time
time.sleep(2) # Verificar cada 2 segundos
except KeyboardInterrupt:
print("\n" + "=" * 60)
print("Deteniendo sistema...")
self.turn_off_all_lights()
print("Todas las luces apagadas")
print("=" * 60)
break
except Exception as e:
print(f"Error: {e}")
time.sleep(2)
# Programa principal
if __name__ == "__main__":
lighting_system = ChickenCoopLighting()
lighting_system.run()LDR
VCC 5V
GND
Relees IN
A0 to GPIO36
VCC 5V
5V to COM
Relee NO
SECCIÓN LUCES CRIADERO
GND
GND
SECCIÓN TEMPERATURA GALPON
SECCIÓN LUCES PASILLO
FRIO
CALOR
1 LUZ Pasillo
2 LUZ Pasillo
SECCIÓN ALERTA EXTERNA
SECCIÓN MENSAJE PUERTAS/VENTANAS ABIERTAS