.. note::

    Ciao, benvenuto nella community SunFounder Raspberry Pi & Arduino & ESP32 Enthusiasts su Facebook! Approfondisci Raspberry Pi, Arduino e ESP32 con altri appassionati.

    **Perché unirti?**

    - **Supporto Esperto**: Risolvi i problemi post-vendita e affronta le sfide tecniche con l'aiuto della nostra community e del nostro team.
    - **Impara e Condividi**: Scambia consigli e tutorial per migliorare le tue abilità.
    - **Anteprime Esclusive**: Ottieni l'accesso anticipato ai nuovi annunci di prodotto e anteprime.
    - **Sconti Speciali**: Approfitta di sconti esclusivi sui nostri prodotti più recenti.
    - **Promozioni Festive e Omaggi**: Partecipa a omaggi e promozioni speciali durante le festività.

    👉 Pronto per esplorare e creare con noi? Clicca su [|link_sf_facebook|] e unisciti oggi!

.. _4.1.14_py:

4.1.14 Blocco a Combinazione
================================

Introduzione
-----------------

In questo progetto utilizzeremo una tastiera e un LCD per creare un blocco a 
combinazione. L'LCD visualizzerà un messaggio corrispondente per l'inserimento 
della password tramite la tastiera. Se la password viene inserita correttamente, 
verrà visualizzato "Correct".

Su questa base, possiamo aggiungere componenti elettronici aggiuntivi, come buzzer, 
LED e altro, per creare diversi fenomeni sperimentali durante l'inserimento della password.


Componenti Necessari
------------------------------

In questo progetto, abbiamo bisogno dei seguenti componenti.

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

È sicuramente conveniente acquistare un kit completo, ecco il link: 

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

    *   - Nome	
        - ELEMENTI IN QUESTO KIT
        - LINK
    *   - Kit Raphael
        - 337
        - |link_Raphael_kit|

Puoi anche acquistare i componenti separatamente dai link sottostanti.

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

    *   - INTRODUZIONE AI COMPONENTI
        - LINK PER L'ACQUISTO

    *   - :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`
        - \-

Schema Elettrico
--------------------

============ ======== ======== ===
T-Board Name physical 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

Procedure Sperimentali
-------------------------

**Passo 1:** Costruisci il circuito.

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

**Passo 2:** Cambia directory.

.. raw:: html

   <run></run>

.. code-block:: 

    cd ~/raphael-kit/python/

**Passo 3:** Esegui.

.. raw:: html

   <run></run>

.. code-block:: 

    sudo python3 4.1.14_PasswordLock.py

Dopo che il codice viene eseguito, la tastiera viene utilizzata per inserire la password: 1984. Se appare “CORRECT” su LCD1602, la password è corretta; altrimenti, apparirà “WRONG KEY”.

.. note::

    * Se ottieni l'errore ``FileNotFoundError: [Errno 2] No such file or directory: '/dev/i2c-1'``, devi fare riferimento a :ref:`i2c_config` per abilitare l'I2C.
    * Se ottieni l'errore ``ModuleNotFoundError: No module named 'smbus2'``, esegui ``sudo pip3 install smbus2``.
    * Se compare l'errore ``OSError: [Errno 121] Remote I/O error``, significa che il modulo è collegato male o è guasto.
    * Se il codice e il cablaggio sono corretti, ma l'LCD non mostra ancora contenuti, puoi regolare il potenziometro sul retro per aumentare il contrasto.


**Codice**

.. note::
    Puoi **Modificare/Reimpostare/Copiare/Eseguire/Interrompere** il codice qui sotto. Ma prima devi andare al percorso del codice sorgente come ``raphael-kit/python``. Dopo aver modificato il codice, puoi eseguirlo direttamente per vedere l'effetto.

.. raw:: html

    <run></run>

.. code-block:: python

    #!/usr/bin/env python3

    import RPi.GPIO as GPIO 
    import time
    import LCD1602

    ##################### QUI È LA LIBRERIA KEYPAD TRASPORTATA DA Arduino ############
    #class Key:Definisci alcune delle proprietà del 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

    ################ IL CODICE ESEMPIO INIZIA QUI ################        
    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(indirizzo slave, retroilluminazione)
        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__':     # Il programma inizia qui
        try:
            setup()
            loop()
        except KeyboardInterrupt:  # Quando viene premuto 'Ctrl+C', il programma destroy() verrà eseguito.
            destroy()

**Spiegazione del Codice**

.. 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"]

Qui, definiamo la lunghezza della password (LENS), l'array keys che contiene 
i tasti della tastiera a matrice, e l'array password che memorizza la 
password corretta.

.. 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)
    ...

Questa classe è il codice che legge i valori dei tasti premuti. Per ulteriori dettagli, fai riferimento a :ref:`2.1.8_py` di questo documento.

.. 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
    ...

Leggi il valore del tasto e memorizzalo nell'array testword. Se il numero di 
valori di tasti memorizzati è maggiore di 4, la correttezza della password viene 
automaticamente verificata e i risultati della verifica vengono visualizzati 
ull'interfaccia LCD.

.. code-block:: python

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

Verifica la correttezza della password. Restituisce 1 se la password è corretta, 
e 0 se non lo è.

Foto del Fenomeno
--------------------------

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