注釈

こんにちは、SunFounder Raspberry Pi & Arduino & ESP32 Enthusiasts Communityへようこそ!仲間たちと一緒にRaspberry Pi、Arduino、ESP32についてさらに深く学びましょう。

参加する理由は?

  • 専門家のサポート: コミュニティやチームの助けを借りて、購入後の問題や技術的な課題を解決できます。

  • 学びと共有: ヒントやチュートリアルを交換して、スキルを向上させましょう。

  • 限定プレビュー: 新製品の発表や先行情報をいち早く手に入れましょう。

  • 特別割引: 最新製品の特別割引をお楽しみください。

  • イベント・プレゼント: プレゼント企画や祝日セールに参加しましょう。

👉 一緒に探求し、創造を楽しみませんか?[ここ]をクリックして、今すぐ参加しましょう!

8.6 @MQTTを使ったクラウドプレイヤー

まず、 8.5 @MQTTを使ったクラウド呼び出しシステム プロジェクトを先に実施して、いくつかのモジュールをインストールし、HiveMQプラットフォームの設定を完了することをお勧めします。

このプロジェクトでは、Pico 2 Wはサブスクライバーとして機能し、トピックの下で曲名を受信します。 もし曲名がすでにコード内に含まれていれば、Pico 2 Wはブザーでその曲を再生します。

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

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

キット一式を購入するのが便利です。こちらのリンクから購入できます:

名前

このキットに含まれるアイテム

リンク

Pico 2 W スターターキット

450以上

Pico 2 W Kit

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

SN

コンポーネント

数量

リンク

1

Pico 2 Wの概要

1

2

Micro USBケーブル

1

3

ブレッドボード

1

買う

4

ジャンパーワイヤー

複数

買う

5

トランジスタ

1(S8050)

買う

6

抵抗器

1(1KΩ)

買う

7

パッシブ ブザー

1

買う

8

Li-Po充電モジュール

1

9

18650バッテリー

1

2. 回路を組み立てる

キットには2つのブザーが含まれていますが、ここではパッシブブザー(背面にPCBが露出しているタイプ)を使用します。ブザーは動作させるためにトランジスタが必要で、ここではS8050を使用します。

警告

Li-po充電モジュールが図のように接続されていることを確認してください。そうしないと、短絡が原因でバッテリーや回路が損傷する可能性があります。

../../_images/6.mqtt_sub_bb.png

3. コードを実行する

  1. pico-2w-kit-main/micropython/iot のパスにある play_music.py ファイルをRaspberry Pi Pico 2 Wにアップロードします。

    ../../_images/mqtt-A-1.png
  2. pico-2w-kit-main/micropython/iot のパスにある 8.6_mqtt_subscribe_music.py ファイルを開き、 現在のスクリプトを実行 ボタンをクリックするか、F5を押して実行します。

    ../../_images/6_cloud_player.png

    注釈

    コードを実行する前に、Pico 2 Wに do_connect.py および secrets.py スクリプトを作成する必要があります。作成方法については 8.1 ネットワークへの接続 を参照してください。

  3. ブラウザで|link_hivemq|を開き、トピックを SunFounder MQTT Music として、曲名を Message として入力します。 Publish ボタンをクリックすると、Pico 2 Wに接続されたブザーが対応する曲を再生します。

    注釈

    play_music.py には、 nokiastarwarsnevergonnagiveyouupgameofthronesongofstormszeldathemeharrypotter が含まれています。

    ../../_images/mqtt-5.png
  4. このスクリプトを起動時に実行できるようにしたい場合は、Raspberry Pi Pico 2 Wに main.py として保存できます。

仕組みは?

理解を容易にするため、MQTTのコードを他の部分から分けました。 その結果、以下のコードが得られ、MQTTサブスクリプションの最も基本的な機能が3つの場所で実装されています。

import time
from umqtt.simple import MQTTClient

# `do_connect()`関数をインポートします。この関数には、`network`モジュールを使ってWi-Fiに接続するロジックが含まれています。`do_connect()`関数が呼び出されると、`secrets.py`で指定されたWi-Fiネットワークに接続します。接続に失敗した場合は例外が発生し、成功すれば次のステップに進みます。
from do_connect import *
do_connect()

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

# メッセージをサブスクライブする
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) 関数を呼び出し、これが受信したサブスクリプションメッセージのコールバックとして機能します。

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') を使ってデコードする必要があります。

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

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

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

次に、音楽が再生されます。この関数は play_music.py スクリプトに配置されており、3つの主要な部分から構成されています。

  • Tone: 基本的な ピアノの鍵盤の周波数 を基にした特定の音色をシミュレートし、それを再生します。

    NOTE_B0 =  31
    NOTE_C1 =  33
    ...
    NOTE_DS8 = 4978
    REST =      0
    
  • Score : 音楽をプログラムが使用できる形式に編集します。これらのスコアは Robson Coutoの無料共有 から取得したもので、以下の形式でお気に入りの曲を追加することもできます。

# メロディのノートとその長さ
# 4は4分音符、8は8分音符、16は16分音符などを意味します
# !!負の数は付点音符を表すため、-4は付点4分音符、すなわち4分音符+8分音符!!

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":[,,,],
}
import time
import machine

# 曲を遅くまたは速くするために調整
tempo = 220

# 4分音符の長さをミリ秒単位で計算
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):

    # メロディのノートを反復
    # 配列はノートとその長さで2倍の数になります
    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

        # ノートの90%の時間だけ再生し、残りの10%はポーズ
        tone(pin,melody[thisNote],int(noteDuration*0.9))

        # 次のノートの前に指定された時間だけ待機
        time.sleep_ms(int(noteDuration))

        # 次のノートの前に波形生成を停止
        noTone(pin)

メイン関数に戻り、MQTTで音楽の再生をトリガーします。 コールバック関数内で、送信されたメッセージがすでに含まれている曲名であるかを確認します。 そうであれば、曲名を melody 変数に割り当て、 play_flagTrue に設定します。

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_flagTrue の場合、 melody を再生します。

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