from machine import Pin, ADC, I2C
import time
# =========================
# Pines
# =========================
PIN_DIR = 2
PIN_STEP = 3
PIN_ENABLE = 4
PIN_BOMBA = 15
LED_SECO = 6
LED_MEDIO = 7
LED_MOJADO = 8
ADC_PIN = 26
# =========================
# LCD I2C
# =========================
I2C_SDA = 0
I2C_SCL = 1
LCD_ADDR = 0x27
# =========================
# Hardware
# =========================
dir_pin = Pin(PIN_DIR, Pin.OUT)
step_pin = Pin(PIN_STEP, Pin.OUT)
enable_pin = Pin(PIN_ENABLE, Pin.OUT)
bomba_pin = Pin(PIN_BOMBA, Pin.OUT)
led_seco = Pin(LED_SECO, Pin.OUT)
led_medio = Pin(LED_MEDIO, Pin.OUT)
led_mojado= Pin(LED_MOJADO, Pin.OUT)
adc = ADC(ADC_PIN)
# =========================
# Umbrales
# =========================
UMBRAL_BAJO = 30
UMBRAL_ALTO = 60
STEP_DELAY_US = 1600
STEP_BURST_MS = 400
# =============================
# FILTRO DE HUMEDAD (20 muestras)
# =============================
BUFFER = [0] * 20
index = 0
def leer_humedad_filtrada():
global index
raw = adc.read_u16()
BUFFER[index] = raw
index = (index + 1) % 20
promedio = sum(BUFFER) / len(BUFFER)
pct = (promedio / 65535) * 100
# limitar
return max(0, min(100, pct))
# =============================
# LCD DRIVER 100% SEGURO
# =============================
i2c = I2C(0, sda=Pin(I2C_SDA), scl=Pin(I2C_SCL), freq=400000)
def lcd_send(nibble, rs):
data = nibble | (0x01 if rs else 0x00)
i2c.writeto(LCD_ADDR, bytes([data | 0x04])) # EN = 1
i2c.writeto(LCD_ADDR, bytes([data])) # EN = 0
def lcd_cmd(cmd):
lcd_send(cmd & 0xF0, 0)
lcd_send((cmd << 4) & 0xF0, 0)
def lcd_char(ch):
hi = ch & 0xF0
lo = (ch << 4) & 0xF0
lcd_send(hi, 1)
lcd_send(lo, 1)
def lcd_print(text, line=1):
text = str(text)
# rellenar manual, sin usar .ljust()
if len(text) < 16:
text = text + (" " * (16 - len(text)))
else:
text = text[:16]
lcd_cmd(0x80 if line == 1 else 0xC0)
for c in text:
lcd_char(ord(c))
def lcd_init():
time.sleep_ms(50)
lcd_cmd(0x33)
lcd_cmd(0x32)
lcd_cmd(0x28)
lcd_cmd(0x0C)
lcd_cmd(0x06)
lcd_cmd(0x01)
time.sleep_ms(5)
# =============================
# Control motor
# =============================
def motor_on():
enable_pin.value(0) # habilita A4988
bomba_pin.value(1) # informa al chip
def motor_off():
enable_pin.value(1) # deshabilita A4988
bomba_pin.value(0)
def mover_motor(ms, delay_us):
end_t = time.ticks_add(time.ticks_ms(), ms)
while time.ticks_diff(end_t, time.ticks_ms()) > 0:
step_pin.value(1)
time.sleep_us(delay_us//2)
step_pin.value(0)
time.sleep_us(delay_us//2)
# =============================
# MAIN LOOP
# =============================
lcd_init()
bomba_activa = False
while True:
humedad = leer_humedad_filtrada()
# LEDs
led_seco.value(1 if humedad < UMBRAL_BAJO else 0)
led_medio.value(1 if UMBRAL_BAJO <= humedad <= UMBRAL_ALTO else 0)
led_mojado.value(1 if humedad > UMBRAL_ALTO else 0)
# Histeresis
if humedad < UMBRAL_BAJO and not bomba_activa:
bomba_activa = True
motor_on()
elif humedad > UMBRAL_ALTO and bomba_activa:
bomba_activa = False
motor_off()
# Estado del suelo
if humedad < UMBRAL_BAJO:
estado_suelo = "SECO"
elif humedad <= UMBRAL_ALTO:
estado_suelo = "PERFECTO"
else:
estado_suelo = "MOJADO"
estado_motor = "ENCENDIDO" if bomba_activa else "APAGADO"
# LCD
lcd_print("Humedad: " + str(int(humedad)) + "%", 1)
lcd_print(estado_suelo + " " + estado_motor, 2)
if bomba_activa:
mover_motor(STEP_BURST_MS, STEP_DELAY_US)
else:
time.sleep(0.3)