import time
from machine import Pin, I2C
from time import sleep
import dht
from i2c_lcd import I2cLcd
# --- Configuración LCD ---
I2C_ADDR = 0x27
i2c = I2C(0, sda=Pin(0), scl=Pin(1), freq=400000)
lcd = I2cLcd(i2c, I2C_ADDR, 4, 20)
# --- Pines de botones ---
btn_anterior = Pin(2, Pin.IN, Pin.PULL_UP)
btn_siguiente = Pin(3, Pin.IN, Pin.PULL_UP)
btn_aceptar = Pin(4, Pin.IN, Pin.PULL_UP)
btn_regresar = Pin(5, Pin.IN, Pin.PULL_UP)
# --- Pines de sensores de nivel ---
N1_T1 = Pin(11, Pin.IN, Pin.PULL_UP)
N2_T1 = Pin(12, Pin.IN, Pin.PULL_UP)
N1_T2 = Pin(13, Pin.IN, Pin.PULL_UP)
N2_T2 = Pin(14, Pin.IN, Pin.PULL_UP)
# --- Bombas ---
Bomba_T1 = Pin(16, Pin.OUT)
Bomba_T2 = Pin(17, Pin.OUT)
# --- Sensores DHT22 ---
sensor_dht1 = dht.DHT22(Pin(6))
sensor_dht2 = dht.DHT22(Pin(10))
# --- Variables de configuración ---
modo_operacion = "temporizado" # o "control"
hora_inicio = "15:35:10"
hora_final = "15:32:00"
duracion_minutos = 30
ref_humedad_low1 = 30
ref_humedad_low2 = 35
ref_humedad = 50
ref_temp_high = 30
ref_temp = 23
area = 10 # m2
profundidad = 0.2 # m
caudal_bomba = 5 # litros/seg
tanque_actual = 1
# Simulación de hora del sistema
segundos_simulados = 15 * 3600 + 30 * 60
# --- Variables pantalla modo control ---
pos_control = 0
parametros_control = [
lambda: f"Ref_H_Low1: {ref_humedad_low1}%",
lambda: f"Ref_H_Low2: {ref_humedad_low2}%",
lambda: f"Ref_Temp_High: {ref_temp_high}C",
lambda: f"Area: {area} m2",
lambda: f"Prof: {profundidad} m"
]
def obtener_hora_simulada():
global segundos_simulados
segundos_simulados += 1
h = segundos_simulados // 3600
m = (segundos_simulados % 3600) // 60
s = segundos_simulados % 60
return "{:02d}:{:02d}:{:02d}".format(h, m, s)
def tiempo_actual():
return obtener_hora_simulada()
def leer_sensores():
try:
sensor_dht1.measure()
h1 = sensor_dht1.humidity()
t1 = sensor_dht1.temperature()
sensor_dht2.measure()
h2 = sensor_dht2.humidity()
t2 = sensor_dht2.temperature()
return h1, t1, h2, t2
except:
return 0, 0, 0, 0
def mostrar_lcd(l1="", l2="", l3="", l4=""):
lcd.clear()
lcd.move_to(0, 0)
lcd.putstr(l1)
lcd.move_to(0, 1)
lcd.putstr(l2)
lcd.move_to(0, 2)
lcd.putstr(l3)
lcd.move_to(0, 3)
lcd.putstr(l4)
def convertir_a_minutos(hora_str):
h, m = map(int, hora_str.split(":")[:2])
return h * 60 + m
modo_edicion = False
cursor_hora = 0
def espera_boton_suelto(pin_btn, timeout=2):
start = time.ticks_ms()
while not pin_btn.value():
sleep(0.05)
# Timeout para evitar bloqueo infinito
if time.ticks_diff(time.ticks_ms(), start) > timeout*1000:
break
def verificar_modo_temporizado():
global tanque_actual, modo_edicion, cursor_hora, hora_inicio, hora_final
riego_activado = False
vol_total = 0
tiempo_riego = 0
tiempo_inicio = 0
editando = None # 'inicio' o 'final'
while True:
hora_actual = obtener_hora_simulada()
if not riego_activado:
if modo_edicion:
lcd.show_cursor()
hora_editada = hora_inicio if editando == "inicio" else hora_final
lcd.clear()
lcd.putstr(f"Editar {editando}:")
lcd.move_to(0, 1)
lcd.putstr(hora_editada)
pos_cursor = cursor_hora
if hora_editada[pos_cursor] == ':':
while pos_cursor < len(hora_editada) and hora_editada[pos_cursor] == ':':
pos_cursor += 1
if pos_cursor >= len(hora_editada):
pos_cursor = 0
while hora_editada[pos_cursor] == ':':
pos_cursor += 1
lcd.move_to(pos_cursor, 1)
else:
lcd.hide_cursor()
mostrar_lcd(
f"Hora: {hora_actual} TEMP",
"Riego OFF",
f"Inicio: {hora_inicio}",
f"Final: {hora_final}"
)
# Manejo de botones si NO está en edición
if not modo_edicion:
if not btn_aceptar.value():
espera_boton_suelto(btn_aceptar)
modo_edicion = True
editando = "inicio"
# Coloca cursor en posición editable
cursor_hora = 0
while cursor_hora < len(hora_inicio):
if hora_inicio[cursor_hora] != ':':
break
cursor_hora += 1
if cursor_hora >= len(hora_inicio):
cursor_hora = 0
elif not btn_siguiente.value():
espera_boton_suelto(btn_siguiente)
modo_edicion = True
editando = "final"
cursor_hora = 0
while cursor_hora < len(hora_final):
if hora_final[cursor_hora] != ':':
break
cursor_hora += 1
if cursor_hora >= len(hora_final):
cursor_hora = 0
elif not btn_regresar.value():
espera_boton_suelto(btn_regresar)
Bomba_T1.off()
Bomba_T2.off()
lcd.hide_cursor()
return
else:
# En modo edición
if not btn_aceptar.value():
espera_boton_suelto(btn_aceptar)
hora_editada = list(hora_inicio if editando == "inicio" else hora_final)
if hora_editada[cursor_hora].isdigit():
val = int(hora_editada[cursor_hora])
pos = cursor_hora
if pos == 0:
val = (val + 1) % 3
if val == 2 and int(hora_editada[1]) > 3:
hora_editada[1] = '3'
elif pos == 1:
max_val = 9 if int(hora_editada[0]) < 2 else 3
val = (val + 1) % (max_val + 1)
elif pos == 3:
val = (val + 1) % 6
elif pos == 4:
val = (val + 1) % 10
elif pos == 6:
val = (val + 1) % 6
elif pos == 7:
val = (val + 1) % 10
hora_editada[pos] = str(val)
if editando == "inicio":
hora_inicio = ''.join(hora_editada)
else:
hora_final = ''.join(hora_editada)
elif not btn_siguiente.value():
espera_boton_suelto(btn_siguiente)
cursor_hora += 1
hora_editada = hora_inicio if editando == "inicio" else hora_final
if cursor_hora >= len(hora_editada):
cursor_hora = 0
while hora_editada[cursor_hora] == ':':
cursor_hora += 1
if cursor_hora >= len(hora_editada):
cursor_hora = 0
elif not btn_anterior.value():
espera_boton_suelto(btn_anterior)
cursor_hora -= 1
hora_editada = hora_inicio if editando == "inicio" else hora_final
if cursor_hora < 0:
cursor_hora = len(hora_editada) - 1
while hora_editada[cursor_hora] == ':':
cursor_hora -= 1
if cursor_hora < 0:
cursor_hora = len(hora_editada) - 1
elif not btn_regresar.value():
espera_boton_suelto(btn_regresar)
modo_edicion = False
editando = None
lcd.hide_cursor()
# Lógica de riego
minutos_ahora = convertir_a_minutos(hora_actual)
minutos_inicio = convertir_a_minutos(hora_inicio)
minutos_fin = convertir_a_minutos(hora_final)
if minutos_inicio <= minutos_ahora < minutos_fin:
if not riego_activado:
h1, t1, _, _ = leer_sensores()
vol_agua = area * profundidad * 1000 * ((ref_humedad - h1) / 100)
factor_ajuste = 1 + ((t1 - ref_temp) / 100)
vol_total = vol_agua * factor_ajuste
tiempo_riego = vol_total / caudal_bomba
tiempo_inicio = segundos_simulados
riego_activado = True
sensores_tanque = {
1: {'N2': N2_T1.value()},
2: {'N2': N2_T2.value()}
}
if sensores_tanque[tanque_actual]['N2']:
if tanque_actual == 1:
Bomba_T1.on()
Bomba_T2.off()
else:
Bomba_T2.on()
Bomba_T1.off()
else:
tanque_actual = 2 if tanque_actual == 1 else 1
if sensores_tanque[tanque_actual]['N2']:
if tanque_actual == 1:
Bomba_T1.on()
Bomba_T2.off()
else:
Bomba_T2.on()
Bomba_T1.off()
else:
mostrar_lcd("ERROR", "Tanques sin agua")
Bomba_T1.off()
Bomba_T2.off()
riego_activado = False
return
tiempo_transcurrido = segundos_simulados - tiempo_inicio
tiempo_restante = max(0, tiempo_riego - tiempo_transcurrido)
if tiempo_transcurrido >= tiempo_riego:
Bomba_T1.off()
Bomba_T2.off()
riego_activado
mostrar_lcd(f"Hora: {hora_actual} TEMP", "Riego ON", f"Vol= {vol_total:.1f} lt", f"Rest= {tiempo_restante:.0f} seg")
else:
if riego_activado:
Bomba_T1.off()
Bomba_T2.off()
riego_activado = False
if not modo_edicion:
mostrar_lcd(f"Hora: {hora_actual} TEMP", "Riego OFF", f"Inicio: {hora_inicio}", f"Final: {hora_final}")
sleep(0.2)
def verificar_modo_control():
global pos_control, tanque_actual, ref_humedad_low1
mostrar_estado = 0
editar = False
humedad_edit = ref_humedad_low1
bomba_encendida = False
tiempo_inicio = 0
vol_total = 0
tiempo_riego = 0
bomba_prev = 2 if tanque_actual == 1 else 1
while True:
hora_actual = obtener_hora_simulada()
# Botón regresar detiene el modo control
if not btn_regresar.value():
Bomba_T1.off()
Bomba_T2.off()
return
# Lectura de sensores
h1, t1, h2, t2 = leer_sensores()
# --- MODO EDICIÓN de ref_humedad_low1 ---
if editar:
mostrar_lcd(
"Editar Hum Low1:",
f"Valor: {humedad_edit:.1f}%",
"",
"Aceptar=A Cancelar=R"
)
if not btn_siguiente.value(): # Aumentar valor
humedad_edit = min(humedad_edit + 0.5, 100.0) # límite superior 100%
sleep(0.2)
elif not btn_anterior.value(): # Disminuir valor
humedad_edit = max(humedad_edit - 0.5, 0.0) # límite inferior 0%
sleep(0.2)
elif not btn_aceptar.value(): # Confirmar edición
ref_humedad_low1 = humedad_edit
editar = False
sleep(0.3)
elif not btn_regresar.value(): # Cancelar edición sin guardar
editar = False
sleep(0.3)
continue # Salta el resto del ciclo mientras editas
# --- LÓGICA DE RIEGO AUTOMÁTICO ---
activar_riego_1 = h1 < ref_humedad_low1
activar_riego_2 = t1 >= 35 and h2 < ref_humedad_low2
if activar_riego_1 or activar_riego_2:
if not bomba_encendida:
humedad_usada = h2 if activar_riego_2 else h1
temp_usada = t2 if activar_riego_2 else t1
vol_agua = area * profundidad * 1000 * ((ref_humedad - humedad_usada) / 100)
factor_ajuste = 1 + ((temp_usada - ref_temp) / 100)
vol_total = vol_agua * factor_ajuste
tiempo_riego = vol_total / caudal_bomba
tiempo_inicio = segundos_simulados
if activar_riego_2:
tanque_actual = 1 if bomba_prev == 2 else 2
bomba_prev = tanque_actual
sensores_tanque = {
1: {'N2': N2_T1.value()},
2: {'N2': N2_T2.value()}
}
if sensores_tanque[tanque_actual]['N2']:
if tanque_actual == 1:
Bomba_T1.on()
Bomba_T2.off()
else:
Bomba_T2.on()
Bomba_T1.off()
bomba_encendida = True
else:
tanque_actual = 2 if tanque_actual == 1 else 1
if sensores_tanque[tanque_actual]['N2']:
if tanque_actual == 1:
Bomba_T1.on()
Bomba_T2.off()
else:
Bomba_T2.on()
Bomba_T1.off()
bomba_encendida = True
else:
mostrar_lcd("ERROR", "Tanques sin agua")
Bomba_T1.off()
Bomba_T2.off()
bomba_encendida = False
else:
Bomba_T1.off()
Bomba_T2.off()
bomba_encendida = False
# Control del tiempo de riego
if bomba_encendida:
tiempo_transcurrido = segundos_simulados - tiempo_inicio
tiempo_restante = max(0, tiempo_riego - tiempo_transcurrido)
if tiempo_transcurrido >= tiempo_riego:
Bomba_T1.off()
Bomba_T2.off()
bomba_encendida = False
else:
tiempo_restante = 0
# --- PANTALLAS DE VISUALIZACIÓN ---
if mostrar_estado == 0:
estado_riego = "ON" if bomba_encendida else "OFF"
mostrar_lcd(
f"Hora: {hora_actual} Cont",
f"Riego {estado_riego}",
f"Vol={vol_total:.1f} lt",
f"Rest= {tiempo_restante:.0f} seg"
)
elif mostrar_estado == 1:
mostrar_lcd(
f"Hora: {hora_actual} Cont",
f"Humedad1: {h1:.1f}%",
f"Temp1: {t1:.1f} C",
""
)
elif mostrar_estado == 2:
mostrar_lcd(
f"Hora: {hora_actual} Cont",
f"Humedad2: {h2:.1f}%",
f"Temp2: {t2:.1f} C",
""
)
elif mostrar_estado == 3:
# Pantalla dedicada a editar ref_humedad_low1
mostrar_lcd(
f"Editar Hum Low1:",
f"Valor: {ref_humedad_low1:.1f}%",
"",
"Presiona A para editar"
)
else:
# Otras pantallas según parámetros_control (si tienes)
idx = mostrar_estado - 4
linea1 = parametros_control[idx]() if idx < len(parametros_control) else ""
linea2 = parametros_control[idx + 1]() if idx + 1 < len(parametros_control) else ""
mostrar_lcd(f"Hora: {hora_actual} Cont", linea1, linea2, "")
# --- NAVEGACIÓN DE PANTALLAS ---
if not btn_siguiente.value():
mostrar_estado = (mostrar_estado + 1) % (len(parametros_control) + 4)
sleep(0.3)
elif not btn_anterior.value():
mostrar_estado = (mostrar_estado - 1) % (len(parametros_control) + 4)
sleep(0.3)
# Entrar a edición si está en pantalla 3 y se presiona aceptar
if mostrar_estado == 3 and not btn_aceptar.value():
editar = True
humedad_edit = ref_humedad_low1
sleep(0.3)
sleep(0.5)
# Menú básico
opciones = ["Temporizado", "control"]
posicion_menu = 0
def mostrar_menu():
lcd.clear()
lcd.putstr("Menu: ")
lcd.move_to(0, 1)
lcd.putstr(opciones[posicion_menu])
def ciclo_menu():
global posicion_menu, modo_operacion
mostrar_menu()
while True:
if not btn_siguiente.value():
posicion_menu = (posicion_menu + 1) % len(opciones)
mostrar_menu()
sleep(0.3)
elif not btn_anterior.value():
posicion_menu = (posicion_menu - 1) % len(opciones)
mostrar_menu()
sleep(0.3)
elif not btn_aceptar.value():
modo_operacion = opciones[posicion_menu].lower()
lcd.clear()
lcd.putstr("Modo seleccionado:")
lcd.move_to(0,1)
lcd.putstr(modo_operacion.upper())
sleep(2)
break
def ciclo_principal():
while True:
ciclo_menu()
if modo_operacion == "temporizado":
verificar_modo_temporizado()
elif modo_operacion == "control":
verificar_modo_control()
def inicio():
mostrar_lcd("Iniciando sistema", "Hora inicial: 15:30", "Modo: Temporizado", "")
sleep(2)
ciclo_principal()
inicio()
Anterior
Siguiente
Aceptar
OK y Regresar
(click to edit)
(click to edit)
N2_T2
N2_T1
N1_T2
N1_T1
sensor_dht1
sensor_dht2