.. note::

    ¡Hola! Bienvenido a la Comunidad de Entusiastas de SunFounder para Raspberry Pi, Arduino y ESP32 en Facebook. Sumérgete en el mundo de Raspberry Pi, Arduino y ESP32 con otros entusiastas.

    **¿Por qué unirse?**

    - **Soporte experto**: Resuelve problemas post-venta y desafíos técnicos con la ayuda de nuestra comunidad y equipo.
    - **Aprender y compartir**: Intercambia consejos y tutoriales para mejorar tus habilidades.
    - **Avances exclusivos**: Accede anticipadamente a nuevos anuncios de productos y avances.
    - **Descuentos especiales**: Disfruta de descuentos exclusivos en nuestros productos más recientes.
    - **Promociones y sorteos festivos**: Participa en sorteos y promociones de temporada.

    👉 ¿Listo para explorar y crear con nosotros? Haz clic en [|link_sf_facebook|] y únete hoy mismo.

.. _4.1.14_py:

4.1.14 Cerradura de Contraseña
===================================

Introducción
-----------------

En este proyecto, utilizaremos un teclado y una pantalla LCD para 
crear una cerradura de combinación. La pantalla LCD mostrará un mensaje 
correspondiente para que ingreses tu contraseña en el teclado. Si la 
contraseña es correcta, se mostrará “Correcto”.

Basándonos en este proyecto, podemos agregar componentes electrónicos 
adicionales, como un buzzer, un LED, etc., para añadir diferentes fenómenos 
experimentales para la entrada de la contraseña.

Componentes Requeridos
------------------------------

En este proyecto, necesitamos los siguientes componentes.

.. image:: ../img/list_Password_Lock.png
    :align: center

Es definitivamente conveniente comprar un kit completo, aquí está el enlace:

.. list-table::
    :widths: 20 20 20
    :header-rows: 1

    *   - Nombre	
        - ELEMENTOS EN ESTE KIT
        - ENLACE
    *   - Kit Raphael
        - 337
        - |link_Raphael_kit|

También puedes comprarlos por separado en los siguientes enlaces.

.. list-table::
    :widths: 30 20
    :header-rows: 1

    *   - INTRODUCCIÓN DE COMPONENTES
        - ENLACE DE COMPRA

    *   - :ref:`cpn_gpio_extension_board`
        - |link_gpio_board_buy|
    *   - :ref:`cpn_breadboard`
        - |link_breadboard_buy|
    *   - :ref:`cpn_wires`
        - |link_wires_buy|
    *   - :ref:`cpn_resistor`
        - |link_resistor_buy|
    *   - :ref:`cpn_i2c_lcd`
        - |link_i2clcd1602_buy|
    *   - :ref:`cpn_keypad`
        - \-

Diagrama Esquemático
------------------------

================= =============== ======== ===
Nombre de T-Board Conexión física wiringPi BCM
GPIO18            Pin 12          1        18
GPIO23            Pin 16          4        23
GPIO24            Pin 18          5        24
GPIO25            Pin 22          6        25
GPIO17            Pin 11          0        17
GPIO27            Pin 13          2        27
GPIO22            Pin 15          3        22
SPIMOSI           Pin 19          12       10
SDA1              Pin 3             
SCL1              Pin 5             
================= =============== ======== ===

.. image:: ../img/Schematic_three_one9.png
   :align: center

Procedimientos Experimentales
-----------------------------------

**Paso 1:** Construir el circuito.

.. image:: ../img/image262.png

**Paso 2:** Cambiar directorio.

.. raw:: html

   <run></run>

.. code-block:: 

    cd ~/raphael-kit/python/

**Paso 3:** Ejecutar.

.. raw:: html

   <run></run>

.. code-block:: 

    sudo python3 4.1.14_PasswordLock.py

Después de ejecutar el código, se utiliza el teclado para ingresar la 
contraseña: 1984. Si aparece "CORRECT" en el LCD1602, la contraseña es 
correcta; de lo contrario, aparecerá "WRONG KEY".

.. note::

    * Si aparece el error ``FileNotFoundError: [Errno 2] No such file or directory: '/dev/i2c-1'``, necesitas consultar :ref:`i2c_config` para habilitar el I2C.
    * Si aparece el error ``ModuleNotFoundError: No module named 'smbus2'``, por favor ejecuta ``sudo pip3 install smbus2``.
    * Si aparece el error ``OSError: [Errno 121] Remote I/O error``, significa que el módulo está mal cableado o está roto.
    * Si el código y el cableado están bien, pero el LCD aún no muestra contenido, puedes girar el potenciómetro en la parte posterior para aumentar el contraste.


**Código**

.. note::
    Puedes **Modificar/Restablecer/Copiar/Ejecutar/Detener** el código a continuación. Pero antes de eso, necesitas ir a la ruta del código fuente como ``raphael-kit/python``. Después de modificar el código, puedes ejecutarlo directamente para ver el efecto.

.. raw:: html

    <run></run>

.. code-block:: python

    #!/usr/bin/env python3

    import RPi.GPIO as GPIO 
    import time
    import LCD1602

    ##################### HERE IS THE KEYPAD LIBRARY TRANSPLANTED FROM Arduino ############
    #class Key:Define some of the properties of Key
    class Keypad():

        def __init__(self, rowsPins, colsPins, keys):
            self.rowsPins = rowsPins
            self.colsPins = colsPins
            self.keys = keys
            GPIO.setwarnings(False)
            GPIO.setmode(GPIO.BCM)
            GPIO.setup(self.rowsPins, GPIO.OUT, initial=GPIO.LOW)
            GPIO.setup(self.colsPins, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)

        def read(self):
            pressed_keys = []
            for i, row in enumerate(self.rowsPins):
                GPIO.output(row, GPIO.HIGH)
                for j, col in enumerate(self.colsPins):
                    index = i * len(self.colsPins) + j
                    if (GPIO.input(col) == 1):
                        pressed_keys.append(self.keys[index])
                GPIO.output(row, GPIO.LOW)
            return pressed_keys

    ################ EXAMPLE CODE START HERE ################        
    LENS = 4
    password=['1','9','8','4']
    testword=['0','0','0','0']
    keyIndex=0
    
    def check():
        for i in range(0,LENS):
            if(password[i]!=testword[i]):
                return 0
        return 1

    def setup():
        global keypad, last_key_pressed
        rowsPins = [18,23,24,25]
        colsPins = [10,22,27,17]
        keys = ["1","2","3","A",
                "4","5","6","B",
                "7","8","9","C",
                "*","0","#","D"]
        keypad = Keypad(rowsPins, colsPins, keys)
        last_key_pressed = []
        LCD1602.init(0x27, 1)    # init(slave address, background light)
        LCD1602.clear()
        LCD1602.write(0, 0, 'WELCOME!')
        LCD1602.write(2, 1, 'Enter password')
        time.sleep(2)

    def destroy():
        LCD1602.clear()
        GPIO.cleanup()

    def loop():
        global keyIndex
        global LENS
        global keypad, last_key_pressed
        while(True):
            pressed_keys = keypad.read()
            if len(pressed_keys) != 0 and last_key_pressed != pressed_keys:
                LCD1602.clear()
                LCD1602.write(0, 0, "Enter password:")
                LCD1602.write(15-keyIndex,1, pressed_keys)
                testword[keyIndex]=pressed_keys
                keyIndex+=1
                if (keyIndex is LENS):
                    if (check() is 0):
                        LCD1602.clear()
                        LCD1602.write(3, 0, "WRONG KEY!")
                        LCD1602.write(0, 1, "please try again")
                    else:
                        LCD1602.clear()
                        LCD1602.write(4, 0, "CORRECT!")
                        LCD1602.write(2, 1, "welcome back")
                keyIndex=keyIndex%LENS

            last_key_pressed = pressed_keys
            time.sleep(0.1)
            
    if __name__ == '__main__':     # Program start from here
        try:
            setup()
            loop()
        except KeyboardInterrupt:  # When 'Ctrl+C' is pressed, the program destroy() will be  executed.
            destroy()

**Explicación del Código**

.. code-block:: python

    LENS = 4
    password=['1','9','8','4']
    ...
    rowsPins = [18,23,24,25]
    colsPins = [10,22,27,17]
    keys = ["1","2","3","A",
            "4","5","6","B",
            "7","8","9","C",
            "*","0","#","D"]

Aquí, definimos la longitud de la contraseña con LENS, el array keys 
que almacena las teclas del teclado matricial y el array password que 
almacena la contraseña correcta.

.. code-block:: python

    class Keypad():
        def __init__(self, rowsPins, colsPins, keys):
            self.rowsPins = rowsPins
            self.colsPins = colsPins
            self.keys = keys
            GPIO.setwarnings(False)
            GPIO.setmode(GPIO.BCM)
            GPIO.setup(self.rowsPins, GPIO.OUT, initial=GPIO.LOW)
            GPIO.setup(self.colsPins, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
    ...

Esta clase contiene el código que lee los valores de las teclas presionadas. 
Consulta :ref:`2.1.8_py` de este documento para más detalles.

.. code-block:: python

    while(True):
            pressed_keys = keypad.read()
            if len(pressed_keys) != 0 and last_key_pressed != pressed_keys:
                LCD1602.clear()
                LCD1602.write(0, 0, "Enter password:")
                LCD1602.write(15-keyIndex,1, pressed_keys)
                testword[keyIndex]=pressed_keys
                keyIndex+=1
    ...

Lee el valor de la tecla y lo almacena en el array de prueba testword. 
Si el número de valores de tecla almacenados es mayor que 4, se verifica 
automáticamente la corrección de la contraseña y los resultados de la verificación 
se muestran en la interfaz del LCD.

.. code-block:: python

    def check():
        for i in range(0,LENS):
            if(password[i]!=testword[i]):
                return 0
        return 1

Verifica la corrección de la contraseña. Devuelve 1 si la contraseña es correcta y 0 si no lo es.

Imagen del Fenómeno
---------------------------

.. image:: ../img/image263.jpeg
   :align: center