スキップしてメイン コンテンツに移動

Google Home miniを喋らせる

 


以前、ESP32を使ってGoogle Home Miniに音声を出力させましたので、今回は同じことがRaspberry Pi Pico Wでもできないかと試行錯誤を重ねた結果、無事に音声を出力させることができました。その過程を備忘録としてまとめておきます。

1.接続図


2.Google Home miniにMP3を再生させるコード

import ssl
import json
import socket
import struct
import network
import time
import machine
from machine import Pin

def calc_variant(value):
    byte_list = []
    while value > 0x7F:
        byte_list += [value & 0x7F | 0x80]
        value >>= 7
    return bytes(byte_list + [value])

def play_url(url, host):
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    sock.setsockopt(socket.SOL_SOCKET, 15, 1)
    sock.settimeout(30)
    sock.connect((host, 8009))
    sock = ssl.wrap_socket(sock)
    sock.write(b'\x00\x00\x017\x08\x00\x12\x08sender-0\x1a\nreceiver-0"(urn:x-cast:com.google.cast.tp.connection(\x002\xf0\x01{"type": "CONNECT", "origin": {}, "userAgent": "PyChromecast", "senderInfo": {"sdkType": 2, "version": "15.605.1.3", "browserVersion": "44.0.2403.30", "platform": 4, "systemVersion": "Macintosh; Intel Mac OS X10_10_3", "connectionType": 1}}')
    sock.write(b'\x00\x00\x00g\x08\x00\x12\x08sender-0\x1a\nreceiver-0"#urn:x-cast:com.google.cast.receiver(\x002&{"type": "GET_STATUS", "requestId": 1}')
    sock.write(b'\x00\x00\x00e\x08\x00\x12\x08sender-0\x1a\nreceiver-0"\'urn:x-cast:com.google.cast.tp.heartbeat(\x002 {"type": "PING", "requestId": 2}')
    sock.read(struct.unpack(">I", sock.read(4))[0])
    sock.read(struct.unpack(">I", sock.read(4))[0])
    sock.write(b'\x00\x00\x00x\x08\x00\x12\x08sender-0\x1a\nreceiver-0"#urn:x-cast:com.google.cast.receiver(\x0027{"type": "LAUNCH", "appId": "CC1AD845", "requestId": 3}')
    transport_id = sock.read(struct.unpack(">I", sock.read(4))[0]).split(b'"transportId"')[1].split(b'"')[1]
    sock.write(b'\x00\x00\x01Q\x08\x00\x12\x08sender-0\x1a$%s"(urn:x-cast:com.google.cast.tp.connection(\x002\xf0\x01{"type": "CONNECT", "origin": {}, "userAgent": "PyChromecast", "senderInfo": {"sdkType": 2, "version": "15.605.1.3", "browserVersion": "44.0.2403.30", "platform": 4, "systemVersion": "Macintosh; Intel Mac OS X10_10_3", "connectionType": 1}}' % transport_id)
    sock.write(b'\x00\x00\x00~\x08\x00\x12\x08sender-0\x1a$%s" urn:x-cast:com.google.cast.media(\x002&{"type": "GET_STATUS", "requestId": 4}' % transport_id)
    payload = json.dumps({
        "media": {
            "contentId": url,
            "streamType": "BUFFERED",
            "contentType": "audio/mp3",
            "metadata": {}
        },
        "type": "LOAD",
        "autoplay": True,
        "customData": {},
        "requestId": 5,
        "sessionId": transport_id.decode()
    })
    msg = (b'\x08\x00\x12\x08sender-0\x1a$%s" urn:x-cast:com.google.cast.media(\x002' % transport_id) + calc_variant(len(payload)) + payload.encode()
    sock.write(struct.pack(">I", len(msg)) + msg)
    sock.read(struct.unpack(">I", sock.read(4))[0])
    sock.read(struct.unpack(">I", sock.read(4))[0])
    sock.read(struct.unpack(">I", sock.read(4))[0])
    sock.close()

# Wi-Fi 接続
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect("あなたのSSID", "あなたのパスワード")

while not wlan.isconnected() and wlan.status() >= 0:
    time.sleep(1)

# ボタンとLED設定
button16 = Pin(16, Pin.IN, Pin.PULL_UP)
button17 = Pin(17, Pin.IN, Pin.PULL_UP)
button18 = Pin(18, Pin.IN, Pin.PULL_UP)
button19 = Pin(19, Pin.IN, Pin.PULL_UP)
led = Pin('LED', Pin.OUT)

playing = False

while True:
    if button16.value() == 0 and not playing:
        playing = True
        led.on()
        play_url('https://nyanpass.com/nyanpass.mp3', 'Google Home miniのIPアドレス')
        led.off()
        playing = False
    elif button17.value() == 0 and not playing:
        playing = True
        led.on()
        play_url('再生したいMP3のアドレス', 'Google Home miniのIPアドレス')
        led.off()
        playing = False
    elif button18.value() == 0 and not playing:
        playing = True
        led.on()
        play_url('再生したいMP3のアドレス', 'Google Home miniのIPアドレス')
        led.off()
        playing = False
    elif button19.value() == 0 and not playing:
        playing = True
        led.on()
        play_url('再生したいMP3のアドレス', 'Google Home miniのIPアドレス')
        led.off()
        playing = False
    time.sleep(0.1)


3.Google Home miniにTextを喋らせるコード


ソースコードはNoteにて有料で公開します('ω')

コメント

このブログの人気の投稿

Raspberry Pi Pico Wを使ってみよう

   Raspberry Pi Pico W(ラズベリーパイ ピコ ダブリュー) は、英国 Raspberry Pi 財団が 2022 年に発売した Wi-Fi 搭載マイコンボードです。従来の「Raspberry Pi」と聞くと Linux が動くシングルボードコンピュータ(SBC)を思い浮かべがちですが、Pico W は マイクロコントローラ (MCU)に分類され、いわゆる “組み込み開発” を手軽に始められるデバイスです。搭載 MCU はデュアルコア Arm Cortex-M0+(133 MHz 動作)の RP2040 。ここに Infineon 製 CYW43439 チップが追加され、 2.4 GHz IEEE 802.11 b/g/n Wi-Fi(BLE 対応 FW も提供中) が使えるのが最大の特徴です。  開発言語は MicroPython や CircuitPython が真っ先に紹介されることが多いのですが、 公式 Pico SDK を使えば C/C++ でも本格的に開発 できます。SDK は CMake ベースで Windows/macOS/Linux いずれでも利用可能。さらに、Arduino Core RP2040 が整備されたことで Arduino IDE 2.x からも “スケッチ感覚” で書き込みが可能 になりました。したがって、 「まずは Python でサッと試す」 「より高速化や省メモリ化が必要になったら C/C++ へ移行」 といった二段構えの学習ルートが取れるのが魅力です。 メニュー(基礎編) 01. Raspberry Pi Pico Wの開発環境を整える。 02. スイッチで 発光ダイオード(LED) を点灯・消灯させる 03. タイマーで発光ダイオード(LED)を1秒ごとに点滅させる 04. シリアル通信(オウム返し ) 05. シリアル通信(発光ダイオードの点灯・消灯) 06. サーボモーターを動かしてみよう(SG90制御入門) 07. DCモータを動かす(PWM) 08. IRリモートでRGBLED点灯 09. アナログ電圧を測定する(ADCの基本) 10. GPIO割り込み処理 11. リレーを駆動してLEDを制御する 12. DFPlayer で MP3 再生 13. 7 セグ 4 ...

スイッチで発光ダイオード(LED)を点灯・消灯させる

 スイッチを使って発光ダイオード(LED)を制御してみましょう。今回は、スイッチをオンにすると LED が点灯し、オフにすると消灯するように動作させます。もちろん、スイッチと LED を直接接続するのではなく、適切な回路を介して制御します。 1.回路 GPIO16 はデジタル入力として使用し、内部プルアップを有効にします。GPIO15 は出力として設定します。なお、接続には 1kΩ(1キロオーム)の抵抗を使用します。 【ソースコード】 # スイッチで LED を ON / OFF する簡単な例 #   GPIO15 : LED(出力)— LOW で消灯、HIGH で点灯 #   GPIO16 : スイッチ(入力)— 内部プルアップ抵抗を使用 # # ※ 配線例 #   LED のアノード → 1 kΩ 抵抗 → GPIO15 #   LED のカソード → GND #   スイッチ片側   → GPIO16 #   スイッチ反対側 → GND # # ★ 動作 #   スイッチを押す(GPIO16 が LOW)   → LED 点灯 #   スイッチを離す(GPIO16 が HIGH) → LED 消灯 from machine import Pin    # GPIO 制御ライブラリ import utime               # 時間関連(今回は使用しないが拡張用に読み込み) led = Pin ( 15 , Pin.OUT)                 # GPIO15 を出力モードに設定(LED 用) sw   = Pin ( 16 , Pin.IN, Pin.PULL_UP)     # GPIO16 を入力モード+内部プルアップ有効 while True:     if sw. value () == 1 :      # プルアップなので押していないときは 1   ...

シリアル通信(オウム返し)

 Raspberry Pi Pico Wは単体で使うのも便利ですが、パソコンや他のマイコンなど、さまざまな機器と通信できるとさらに活用の幅が広がります。 そこで今回は「シリアル通信」について紹介します。 まずは、パソコンから送られてきたデータをPico Wが受け取り、同じデータをそのままパソコンに送り返す、いわゆる「オウム返し(エコー)」を実装してみましょう。 シリアル通信とは? シリアル通信は、マイコンとパソコンや他の機器がデータを1ビットずつ順番に送受信する通信方式です。Raspberry Pi Pico WではUART(Universal Asynchronous Receiver/Transmitter)というハードウェアを使って実現します。 接続回路  id      TX       RX        baudrate     parity    stopbit  0  GPIO0 GPIO1   9600  なし  1  1  GPIO4 GPIO5   9600  なし  1 今回はUART1(GPIO4:TX、GPIO5:RX)を使用します。 ソースコード例 from machine import UART, Pin # UART1ポートを9600bpsで初期化(ボーレートを指定) sirial = UART ( 1 , 9600 ) # UARTの詳細設定: 9600bps 、データビット8、パリティ無し、ストップビット1で初期化 sirial. init ( 9600 , bits = 8 , parity = None, stop = 1 ) # UARTで文字列を送信する(※MicroPythonではバイト列で送るのが正しいため b '' にしたほうが安全) sirial. write (b 'Hello World \n\r ' )  # 起動時に「Hello World」を送信 # メインループ while True:     # 受信バッファにデータが存在するかチェック     if sirial. any () > 0 : ...