.. note::

    Ciao, benvenuto nella Community di appassionati di SunFounder Raspberry Pi, Arduino e ESP32 su Facebook! Approfondisci le tue conoscenze su Raspberry Pi, Arduino e ESP32 insieme ad altri appassionati.

    **Perché unirti?**

    - **Supporto esperto**: Risolvi i problemi post-vendita e le sfide tecniche con l'aiuto della nostra community e del nostro team.
    - **Impara e condividi**: Scambia consigli e tutorial per migliorare le tue competenze.
    - **Anteprime esclusive**: Ottieni accesso anticipato agli annunci di nuovi prodotti e alle anteprime.
    - **Sconti speciali**: Approfitta di sconti esclusivi sui nostri prodotti più recenti.
    - **Promozioni festive e giveaway**: Partecipa a promozioni festive e concorsi a premi.

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

.. _nt_mqtt_Subscribe:

6. Lettore cloud con @MQTT
=========================================

Si consiglia di eseguire prima il progetto :ref:`nt_mqtt_publish` per completare l'installazione di alcuni moduli e la configurazione della piattaforma HiveMQ.

In questo progetto, Pico W agirà come sottoscrittore e riceverà il nome della canzone sotto l'argomento specificato.
Se il nome della canzone è già presente nel codice, Pico W farà suonare il brano al buzzer.

**1. Componenti necessari**

In questo progetto, abbiamo bisogno dei seguenti componenti. 

È 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 Kepler	
        - 450+
        - |link_kepler_kit|

Puoi anche acquistarli separatamente dai link qui sotto.

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

    *   - SN
        - COMPONENTE	
        - QUANTITÀ
        - LINK

    *   - 1
        - :ref:`cpn_pico_w`
        - 1
        - |link_picow_buy|
    *   - 2
        - Cavo Micro USB
        - 1
        - 
    *   - 3
        - :ref:`cpn_breadboard`
        - 1
        - |link_breadboard_buy|
    *   - 4
        - :ref:`cpn_wire`
        - Diverse
        - |link_wires_buy|
    *   - 5
        - :ref:`cpn_transistor`
        - 1(S8050)
        - |link_transistor_buy|
    *   - 6
        - :ref:`cpn_resistor`
        - 1(1KΩ)
        - |link_resistor_buy|
    *   - 7
        - Buzzer passivo :ref:`cpn_buzzer`
        - 1
        - |link_passive_buzzer_buy|
    *   - 8
        - :ref:`cpn_lipo_charger`
        - 1
        -  
    *   - 9
        - Batteria 18650
        - 1
        -  
    *   - 10
        - Supporto batteria
        - 1
        -  

**2. Costruisci il circuito**

Nel kit sono inclusi due buzzers, utilizziamo un buzzer passivo (quello con PCB esposto sul retro). Il buzzer necessita di un transistor per funzionare, qui usiamo S8050.

    .. warning:: 
        
        Assicurati che il modulo caricabatterie Li-po sia collegato come mostrato nello schema. Altrimenti, un cortocircuito potrebbe danneggiare la batteria e il circuito.

.. image:: img/wiring/6.mqtt_sub_bb.png



**3. Esegui il codice**

#. Carica il file ``play_music.py`` nel percorso ``kepler-kit-main/iot`` nel Raspberry Pi Pico W.

    .. image:: img/mqtt-A-1.png

#. Apri il file ``6_mqtt_subscribe_music.py`` nel percorso ``kepler-kit-main/iot`` e clicca sul pulsante **Esegui script corrente** o premi F5 per eseguirlo.

    .. image:: img/6_cloud_player.png

    .. note::
        Prima di eseguire il codice, assicurati di avere gli script ``do_connect.py`` e ``secrets.py`` nel tuo Pico W, in caso contrario fai riferimento a :ref:`iot_access` per crearli.

#. Apri |link_hivemq| nel tuo browser, inserisci il Topic come ``SunFounder MQTT Music``, inserisci il nome della canzone come **Messaggio**. Dopo aver cliccato sul pulsante **Publish**, il buzzer collegato al Pico W riprodurrà la canzone corrispondente.

    .. note::
        Incluse in play_music.py sono le canzoni ``nokia``, ``starwars``, ``nevergonnagiveyouup``, ``gameofthrone``, ``songofstorms``, ``zeldatheme``, ``harrypotter``.

    .. image:: img/mqtt-5.png
        :width: 500

#. Se desideri che questo script si avvii automaticamente, puoi salvarlo nel Raspberry Pi Pico W come ``main.py``.

**Come funziona?**

Per facilitare la comprensione, abbiamo separato il codice MQTT dal resto.
Di conseguenza, ottieni il seguente codice, che implementa le funzionalità di base delle sottoscrizioni MQTT in tre punti.

.. code-block:: python
    :emphasize-lines: 13,14,15,16,20,28,29,30

    import time
    from umqtt.simple import MQTTClient

    from do_connect import *
    do_connect()

    mqtt_server = 'broker.hivemq.com'
    client_id = 'Jimmy'

    # sottoscrivi il messaggio
    topic = b'SunFounder MQTT Music'

    def callback(topic, message):
        print("New message on topic {}".format(topic.decode('utf-8')))
        message = message.decode('utf-8')
        print(message)

    try:
        client = MQTTClient(client_id, mqtt_server, keepalive=60)
        client.set_callback(callback)
        client.connect()
        print('Connected to %s MQTT Broker'%(mqtt_server))
    except OSError as e:
        print('Failed to connect to MQTT Broker. Reconnecting...')
        time.sleep(5)
        machine.reset()
        
    while True:
        client.subscribe(topic)
        time.sleep(1)


Quando ci si connette al broker MQTT, chiamiamo la funzione ``client.set_callback(callback)``, che serve come callback per i messaggi di sottoscrizione ricevuti.

.. code-block:: python
    :emphasize-lines: 3

    try:
        client = MQTTClient(client_id, mqtt_server, keepalive=60)
        client.set_callback(callback)
        client.connect()
        print('Connected to %s MQTT Broker'%(mqtt_server))
    except OSError as e:
        print('Failed to connect to MQTT Broker. Reconnecting...')
        time.sleep(5)
        machine.reset()

Successivamente viene eseguita la funzione callback, che stampa il messaggio ricevuto dall'argomento sottoscritto.
MQTT è un protocollo basato su byte binari e non su stringhe di testo, quindi questi messaggi devono essere decodificati utilizzando ``message.decode('utf-8')``.

.. code-block:: python

    def callback(topic, message):
        print("New message on topic {}".format(topic.decode('utf-8')))
        message = message.decode('utf-8')
        print(message)

Use a ``While True`` loop to get messages under this topic at regular intervals.

.. code-block:: python

    while True:
        client.subscribe(topic)
        time.sleep(1)

        
Successivamente, verrà riprodotta la musica. Questa funzione è inserita nello script ``play_music.py``, che consiste in tre parti principali.

   * ``Tone``: Simula un tono specifico basato sulla |link_piano_frequency| fondamentale, utilizzato per riprodurlo.

        .. code-block:: python

            NOTE_B0 =  31
            NOTE_C1 =  33
            ...
            NOTE_DS8 = 4978
            REST =      0

   * ``Score``: Modifica la musica in un formato che il programma possa utilizzare. Questi spartiti provengono dalla `condivisione gratuita di Robson Couto <https://github.com/robsoncouto/arduino-songs>`_, puoi anche aggiungere la tua musica preferita nel seguente formato.

    .. code-block:: python

        # notes of the moledy followed by the duration.
        # a 4 means a quarter note, 8 an eighteenth , 16 sixteenth, so on
        # !!negative numbers are used to represent dotted notes,
        # so -4 means a dotted quarter note, that is, a quarter plus an eighteenth!!
        song = {
            "nokia":[NOTE_E5, 8, NOTE_D5, 8, NOTE_FS4, 4, NOTE_GS4, 4, NOTE_CS5, 8, NOTE_B4, 8, NOTE_D4, 4, 
                        NOTE_E4, 4,NOTE_B4, 8, NOTE_A4, 8, NOTE_CS4, 4, NOTE_E4, 4, NOTE_A4, 2],
            "starwars":[,,,],
            "nevergonnagiveyouup":[,,,],
            "gameofthrone":[,,,],
            "songofstorms":[,,,],
            "zeldatheme":[,,,],
            "harrypotter":[,,,],
        }

    * ``Play``: Questa parte è sostanzialmente la stessa di :ref:`py_pa_buz`, ma leggermente ottimizzata per adattarsi allo spartito sopra.

   .. code-block:: python

       import time
       import machine

       # cambia questo per rendere la canzone più lenta o più veloce
       tempo = 220

       # questo calcola la durata di una nota intera in ms
       wholenote = (60000 * 4) / tempo

       def tone(pin,frequency,duration):
           if frequency is 0:
               pass
           else:
               pin.freq(frequency)
               pin.duty_u16(30000)
           time.sleep_ms(duration)
           pin.duty_u16(0)

       def noTone(pin):
           tone(pin,0,100)

       def play(pin,melody):

           # iterare sulle note della melodia.
           # Ricorda, l'array è il doppio del numero di note (note + durate)
           for thisNote in range(0,len(melody),2):
               # calcola la durata di ciascuna nota
               divider = melody[thisNote+1]
               if divider > 0:
                   noteDuration = wholenote/divider
               elif divider < 0:
                   noteDuration = wholenote/-(divider)
                   noteDuration *= 1.5

               # suoniamo la nota solo per il 90% della durata, lasciando il 10% come pausa
               tone(pin,melody[thisNote],int(noteDuration*0.9))

               # Attendi la durata specificata prima di suonare la nota successiva.
               time.sleep_ms(int(noteDuration))

               # ferma la generazione d'onda prima della nota successiva.
               noTone(pin)


Torna alla funzione principale e lascia che MQTT attivi la riproduzione della musica.
Nella funzione callback, determina se il messaggio inviato è il nome di una canzone inclusa.
Se lo è, assegna il nome della canzone alla variabile ``melody`` e imposta ``play_flag`` su ``True``.

.. code-block:: python
    :emphasize-lines: 5,6,7,8

    def callback(topic, message):
        print("New message on topic {}".format(topic.decode('utf-8')))
        message = message.decode('utf-8')
        print(message)
        if message in song.keys():
            global melody,play_flag
            melody = song[message]
            play_flag = True

Nel ciclo principale, se ``play_flag`` è ``True``, suona ``melody``.

.. code-block:: python
    :emphasize-lines: 4,5,6

    while True:
        client.subscribe(topic)
        time.sleep(1)
        if play_flag is True:
            play(buzzer,melody)
            play_flag = False