.. note::

    こんにちは、SunFounderのRaspberry Pi & Arduino & ESP32愛好家コミュニティへようこそ！Facebook上でRaspberry Pi、Arduino、ESP32についてもっと深く掘り下げ、他の愛好家と交流しましょう。

    **参加する理由は？**

    - **エキスパートサポート**：コミュニティやチームの助けを借りて、販売後の問題や技術的な課題を解決します。
    - **学び＆共有**：ヒントやチュートリアルを交換してスキルを向上させましょう。
    - **独占的なプレビュー**：新製品の発表や先行プレビューに早期アクセスしましょう。
    - **特別割引**：最新製品の独占割引をお楽しみください。
    - **祭りのプロモーションとギフト**：ギフトや祝日のプロモーションに参加しましょう。

    👉 私たちと一緒に探索し、創造する準備はできていますか？[|link_sf_facebook|]をクリックして今すぐ参加しましょう！

.. _nt_mqtt_Subscribe:

6. @MQTTを使ったクラウドプレイヤー
=========================================

このプロジェクトを始める前に、 :ref:`nt_mqtt_publish` プロジェクトを先に完了させて、いくつかのモジュールのインストールとHiveMQプラットフォームの設定を完了することをお勧めします。

このプロジェクトでは、Pico Wは購読者として動作し、トピックの下で曲名を受信します。
曲名がコード内に既に存在する場合、Pico Wはブザーでその曲を演奏します。

**1. 必要なコンポーネント**

このプロジェクトでは、以下のコンポーネントが必要です。

こちらのリンクで一式を購入すると便利です：

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

    *   - 名前	
        - このキットに含まれるアイテム
        - リンク
    *   - ケプラーキット	
        - 450+
        - |link_kepler_kit|

以下のリンクから個別に購入することもできます。

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

    *   - SN
        - コンポーネント	
        - 数量
        - リンク

    *   - 1
        - :ref:`cpn_pico_w`
        - 1
        - |link_picow_buy|
    *   - 2
        - マイクロUSBケーブル
        - 1
        - 
    *   - 3
        - :ref:`cpn_breadboard`
        - 1
        - |link_breadboard_buy|
    *   - 4
        - :ref:`cpn_wire`
        - 数本
        - |link_wires_buy|
    *   - 5
        - :ref:`cpn_transistor`
        - 1(S8050)
        - |link_transistor_buy|
    *   - 6
        - :ref:`cpn_resistor`
        - 1(1KΩ)
        - |link_resistor_buy|
    *   - 7
        - 受動型 :ref:`cpn_buzzer`
        - 1
        - |link_passive_buzzer_buy|
    *   - 8
        - :ref:`cpn_lipo_charger`
        - 1
        -  
    *   - 9
        - 18650バッテリー
        - 1
        -  
    *   - 10
        - バッテリーホルダー
        - 1
        -  

**2. 回路を作成する**

キットには2つのブザーが含まれていますが、ここでは受動ブザー（裏側に露出したPCBがあるもの）を使用します。このブザーはトランジスタが必要です。ここではS8050を使用します。

    .. warning:: 
        
        ダイアグラムに示されているように、Li-poチャージャーモジュールを接続してください。そうしないと、ショートしてバッテリーや回路が損傷する可能性があります。

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

**3. コードを実行する**

#. ``kepler-kit-main/iot`` のパスで ``play_music.py`` ファイルをRaspberry Pi Pico Wにアップロードします。

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

#. ``kepler-kit-main/iot`` のパスで ``6_mqtt_subscribe_music.py`` ファイルを開き、 **現在のスクリプトを実行** ボタンをクリックするか、F5を押して実行します。

    .. image:: img/6_cloud_player.png

    .. note::
        コードを実行する前に、Pico Wに ``do_connect.py`` および ``secrets.py`` スクリプトが存在することを確認してください。ない場合は、 :ref:`iot_access` を参照して作成してください。

#. ブラウザで |link_hivemq| を開き、「トピック」欄に ``SunFounder MQTT Music`` 、 **メッセージ** 欄に曲名を入力します。 **Publish** ボタンをクリックすると、Pico Wに接続されたブザーが対応する曲を演奏します。

    .. note::
        play_music.pyには ``nokia`` , ``starwars`` , ``nevergonnagiveyouup`` , ``gameofthrone`` , ``songofstorms`` , ``zeldatheme`` , ``harrypotter`` が含まれています。

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

#. このスクリプトを起動可能にしたい場合、Raspberry Pi Pico Wに ``main.py`` として保存できます。


**どうやって動作するのか？**

理解しやすくするために、MQTTのコードは他の部分から分離されています。
その結果、MQTTの購読に関する最も基本的な機能を3か所で実装する以下のコードが得られます。

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

    # to subscribe the message
    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)


MQTTブローカーに接続する際、 ``client.set_callback(callback)`` 関数を呼び出して、受信した購読メッセージのコールバックとして機能させます。

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

次に、フェッチされたトピックからのメッセージを出力するコールバック関数です。
MQTTはバイナリベースのプロトコルであり、制御要素もバイナリバイトです。したがって、これらのメッセージは ``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)

``While True`` ループを使用して、このトピックに定期的にメッセージを取得します。

.. code-block:: python

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

次に、音楽が演奏されます。この関数は ``play_music.py`` スクリプトに配置され、主に3つの部分で構成されています。

   * ``Tone`` : 基礎となる |link_piano_frequency| に基づいて特定の音をシミュレートします。

        .. code-block:: python

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

   * ``Score`` : プログラムが使用できる形式に楽曲を編集します。これらの楽譜は `Robson Coutoの無料共有 <https://github.com/robsoncouto/arduino-songs>`_ からです。

    .. code-block:: python

        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`` : この部分は基本的に :ref:`py_pa_buz` と同じですが、上記の楽譜に適合するようにわずかに最適化されています。

   .. code-block:: python

       import time
       import machine

       tempo = 220

       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):
           for thisNote in range(0,len(melody),2):
               divider = melody[thisNote+1]
               if divider > 0:
                   noteDuration = wholenote/divider
               elif divider < 0:
                   noteDuration = wholenote/-(divider)
                   noteDuration *= 1.5

               tone(pin,melody[thisNote],int(noteDuration*0.9))

               time.sleep_ms(int(noteDuration))

               noTone(pin)

メイン関数に戻って、MQTTが音楽の再生をトリガーするようにします。
コールバック関数で、送信されたメッセージが含まれている曲の名前であるかどうかを判断します。
そうであれば、曲名を変数 ``melody`` に割り当て、 ``play_flag`` を ``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

メインループでは、 ``play_flag`` が ``True`` であれば、 ``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
