from machine import Pin, PWM, ADC
import time
import json
# Configuración de pines
class HardwareConfig:
# Teclado
ROW_PINS = [13, 12, 14, 27]
COL_PINS = [26, 25, 33, 32]
# Servo
SERVO_PIN = 5
# Sensores y actuadores
DOOR_SWITCH_PIN = 4
BUZZER_PIN = 23
LED_RED = 18
LED_GREEN = 19
LED_BLUE = 21
EMERGENCY_BTN = 2
# Configuración del teclado
KEYPAD_MAP = [
['1', '2', '3', 'A'],
['4', '5', '6', 'B'],
['7', '8', '9', 'C'],
['*', '0', '#', 'D']
]
class CerraduraInteligente:
def __init__(self):
# Configurar hardware
self.setup_pins()
# Estado del sistema
self.input_code = ""
self.master_code = "1234"
self.door_locked = True
self.door_closed = True
self.last_door_state = True
self.last_emergency_state = True
# Posiciones del servo
self.SERVO_LOCKED = 30
self.SERVO_UNLOCKED = 140
# Inicializar sistema
self.lock_door()
self.set_led(0, 0, 255) # Azul - Esperando código
print("=== SISTEMA CERRADURA INTELIGENTE ===")
print("MicroPython ESP32 - Iniciado")
print("Ingrese código de 4 dígitos:")
print("* = Bloquear, # = Cancelar, A = Estado")
print("--------------------------------------")
def setup_pins(self):
# Configurar pines del teclado
self.rows = [Pin(pin, Pin.OUT) for pin in HardwareConfig.ROW_PINS]
self.cols = [Pin(pin, Pin.IN, Pin.PULL_DOWN) for pin in HardwareConfig.COL_PINS]
# Configurar servo
self.servo = PWM(Pin(HardwareConfig.SERVO_PIN))
self.servo.freq(50) # 50Hz para servo (20ms periodo)
self.servo.duty(0) # Inicializar en 0
# Configurar LED RGB
self.led_red = PWM(Pin(HardwareConfig.LED_RED))
self.led_green = PWM(Pin(HardwareConfig.LED_GREEN))
self.led_blue = PWM(Pin(HardwareConfig.LED_BLUE))
self.led_red.freq(1000)
self.led_green.freq(1000)
self.led_blue.freq(1000)
# Configurar otros componentes
self.door_switch = Pin(HardwareConfig.DOOR_SWITCH_PIN, Pin.IN, Pin.PULL_UP)
# 🔧 CORREGIDO: Configurar buzzer como PWM
self.buzzer = PWM(Pin(HardwareConfig.BUZZER_PIN))
self.buzzer.duty(0) # Inicialmente silenciado
self.emergency_btn = Pin(HardwareConfig.EMERGENCY_BTN, Pin.IN, Pin.PULL_UP)
def read_keypad(self):
"""Leer teclado matricial"""
for i, row in enumerate(self.rows):
row.value(1)
time.sleep_ms(2)
for j, col in enumerate(self.cols):
if col.value() == 1:
row.value(0)
time.sleep_ms(50)
return KEYPAD_MAP[i][j]
row.value(0)
return None
def set_servo_angle(self, angle):
"""Mover servo a ángulo específico (0-180)"""
min_duty = 25
max_duty = 128
duty = int(min_duty + (angle / 180) * (max_duty - min_duty))
self.servo.duty(duty)
time.sleep(0.5)
def set_led(self, red, green, blue):
"""Controlar LED RGB (0-255)"""
self.led_red.duty(int(red * 4))
self.led_green.duty(int(green * 4))
self.led_blue.duty(int(blue * 4))
def beep(self, frequency=1000, duration_ms=100, volume=512):
"""🔧 CORREGIDO: Generar tono con frecuencia específica"""
if frequency > 0:
self.buzzer.freq(frequency)
self.buzzer.duty(volume) # Volumen (0-1023)
time.sleep_ms(duration_ms)
self.buzzer.duty(0) # Silenciar
def play_success_tone(self):
"""🔧 CORREGIDO: Tono de éxito - escala ascendente"""
tones = [523, 659, 784] # Do, Mi, Sol
for tone_freq in tones:
self.beep(tone_freq, 150, 300)
time.sleep_ms(50)
def play_error_tone(self):
"""🔧 CORREGIDO: Tono de error - escala descendente"""
tones = [784, 659, 523] # Sol, Mi, Do
for tone_freq in tones:
self.beep(tone_freq, 200, 400)
time.sleep_ms(30)
def play_emergency_tone(self):
"""🔧 CORREGIDO: Tono de emergencia - alternancia rápida"""
for _ in range(8):
self.beep(880, 100, 600) # La agudo
time.sleep_ms(50)
def play_keypress_tone(self):
"""🔧 NUEVO: Tono corto para pulsación de tecla"""
self.beep(800, 50, 200)
def play_door_tone(self):
"""🔧 NUEVO: Tono para cambio de estado de puerta"""
self.beep(600, 100, 350)
def lock_door(self):
"""Bloquear puerta"""
self.set_servo_angle(self.SERVO_LOCKED)
self.door_locked = True
print("🔒 Cerradura BLOQUEADA")
def unlock_door(self):
"""Desbloquear puerta"""
self.set_servo_angle(self.SERVO_UNLOCKED)
self.door_locked = False
print("🔓 Cerradura DESBLOQUEADA")
def handle_key_press(self, key):
"""Manejar presión de tecla"""
self.play_keypress_tone() # 🔧 CAMBIADO: Usar nuevo tono
if key in '0123456789':
self.input_code += key
print("*", end="")
if len(self.input_code) == 4:
self.verify_code()
elif key == '#':
self.input_code = ""
print("\n❌ Entrada cancelada")
self.set_led(0, 0, 255)
elif key == '*':
self.lock_door()
print("🔒 Puerta bloqueada manualmente")
elif key == 'A':
self.show_system_status()
def verify_code(self):
"""Verificar código ingresado"""
print(f"\n🔐 Verificando código: {self.input_code}")
if self.input_code == self.master_code:
print("✅ Código CORRECTO - Acceso permitido")
self.unlock_door()
self.set_led(0, 255, 0)
self.play_success_tone()
else:
print("❌ Código INCORRECTO - Acceso denegado")
self.set_led(255, 0, 0)
self.play_error_tone()
self.input_code = ""
time.sleep(2)
if self.door_locked:
self.set_led(0, 0, 255)
def emergency_lock(self):
"""Bloqueo de emergencia"""
print("🚨 BLOQUEO DE EMERGENCIA ACTIVADO")
self.lock_door()
self.set_led(255, 255, 0)
self.play_emergency_tone()
time.sleep(3)
self.set_led(0, 0, 255)
def handle_serial_command(self, command):
"""Manejar comandos por serial"""
command = command.strip()
print(f"📱 Comando recibido: {command}")
if command == "UNLOCK" or command == "ABRIR":
self.unlock_door()
self.set_led(0, 255, 0)
self.play_success_tone()
elif command == "LOCK" or command == "CERRAR":
self.lock_door()
self.set_led(0, 0, 255)
self.beep(600, 200, 300) # 🔧 CORREGIDO
elif command == "STATUS" or command == "ESTADO":
self.show_system_status()
elif len(command) == 4 and command.isdigit():
self.input_code = command
self.verify_code()
def show_system_status(self):
"""Mostrar estado completo del sistema"""
print("\n=== ESTADO DEL SISTEMA ===")
print(f"🔒 Cerradura: {'BLOQUEADA' if self.door_locked else 'DESBLOQUEADA'}")
print(f"🚪 Puerta: {'CERRADA' if self.door_closed else 'ABIERTA'}")
print(f"🔑 Código ingresado: {self.input_code}")
print("==========================\n")
def update_status_led(self):
"""Actualizar LED según estado del sistema"""
if not self.door_locked and self.door_closed:
self.set_led(0, 255, 0) # Verde - Desbloqueada y cerrada
elif not self.door_locked and not self.door_closed:
self.set_led(255, 255, 0) # Amarillo - Desbloqueada y abierta
elif self.door_locked and not self.door_closed:
self.set_led(255, 100, 0) # Naranja - Bloqueada pero abierta (alerta)
else:
self.set_led(0, 0, 255) # Azul - Normal, esperando código
def run(self):
while True:
# Leer estado del slide switch (puerta)
self.door_closed = self.door_switch.value()
# Detectar cambio de estado de la puerta
if self.door_closed != self.last_door_state:
if self.door_closed:
print("🚪 Puerta CERRADA")
self.play_door_tone() # 🔧 CAMBIADO
else:
print("🚪 Puerta ABIERTA")
self.play_door_tone() # 🔧 CAMBIADO
time.sleep_ms(100)
self.play_door_tone() # Doble tono para abierta
self.last_door_state = self.door_closed
# Leer teclado
key = self.read_keypad()
if key:
self.handle_key_press(key)
# Verificación del botón de emergencia
current_emergency_state = self.emergency_btn.value()
if not current_emergency_state and self.last_emergency_state:
print("🔄 Botón de emergencia detectado...")
self.emergency_lock()
self.last_emergency_state = current_emergency_state
# Actualizar LED según estado
self.update_status_led()
time.sleep(0.1)
# Inicializar y ejecutar sistema
if __name__ == "__main__":
cerradura = CerraduraInteligente()
cerradura.run()