ラズパイPICOWでbloetooth(スマホと接続)

はじめに

今回はラズパイPICOWでBlurtooth通信をして、スマホからラズパイを動かしていきます!

この記事を読めば「Raspberry Pi Pico W」でBluetoothを使ったものを作れるようになります!

無線通信では、コントローラーを作ったりスマホからデバイスを操作したりすることができるようになります。

有線接続して動作させることが困難な時や、無線で動作させたいときに必須になってくる機能です。

わからないことがありましたら、問い合わせページまたは公式ラインに連絡をください!
Youtubeもありますので、ぜひ見てみてください!

つかうもの

この記事で使っているものを紹介します。
*このリンクは、アフィリエイトリンクです。
こちらのリンクから購入されると、投稿主にインセンティブが発生します。
より良い記事のために、ぜひ購入する際は以下のリンクよりお願いします。。

実際に投稿主が購入したキットを紹介します。
こちらのキットは、マイコンと電子工作に必要な部品がセットになったものです。
こちら購入すればすぐに電子工作始められます!
また、公式HPでモジュール、プログラムの解説もされているので、非常におススメです。

購入はこちらをクリック!
*画像はリンク先より引用

個別で購入したい方は、以下のリンクより購入ください!

購入はこちらをクリック!
*画像はリンク先より引用

プログラム

今回は3つのファイルを使います
それぞれコピペをして、指定した名前で保存してください!

ble_advertising.py

以下のコードを「ble_advertising.py」という名前でpicoのほうに保存します。

# 必要なライブラリのインポート
import bluetooth  # Bluetooth機能を提供するためのライブラリ
import struct  # バイナリデータとPythonのデータ型の変換を行うためのライブラリ
import time  # 時間の管理を行うためのライブラリ
import machine  # マイクロコントローラーのハードウェア機能を制御するためのライブラリ
import ubinascii  # バイト列とASCII文字列を相互変換するためのライブラリ
from ble_advertising import advertising_payload  # BLEのアドバタイズメントペイロードを作成するための関数
from micropython import const  # マイクロPythonの定数を定義するためのライブラリ
from machine import Pin  # ピンを制御するためのクラス
import dht  # DHTセンサーを制御するためのライブラリ

# 割り込み処理の定義
IRQ_CENTRAL_CONNECT = const(1)  # セントラルが接続したときの割り込み番号
IRQ_CENTRAL_DISCONNECT = const(2)  # セントラルが切断したときの割り込み番号
IRQ_GATTS_INDICATE_DONE = const(20)  # GATTのインジケーションが完了したときの割り込み番号

# UUIDの定義
ENV_SENSE_UUID = bluetooth.UUID(0x151A)  # 環境センサーのUUID

# 温度キャラクタリスティックの定義(読み込み可能、通知可能、指示可能)
_TEMP_CHAR = (
    bluetooth.UUID(0x2A6E),  # 温度のUUID
    bluetooth.FLAG_READ | bluetooth.FLAG_NOTIFY | bluetooth.FLAG_INDICATE,  # 読み込み、通知、指示可能な特性フラグ
)

# ペリフェラルの定義(例:時計、ヘッドホンなど)
APPEARANCE_GENERIC_THERMOMETER = const(768)  # 一般的な温度計の外観値

# 温度センサのクラス
class BLETemp:
    # 初期設定
    def __init__(self, ble):
        # 温度センサ使用ピン
        self.dht_sensor = dht.DHT11(Pin(28))  # ピン28をDHT11センサーとして使用
        
        # BLEの初期化, 起動
        self.ble = ble  # BLEオブジェクトの取得
        self.ble.active(True)  # BLEを有効化
        
        # BLEにサービス登録、BLEに自分の特徴や外見を読み込ませる
        ((self.handle,),) = self.ble.gatts_register_services((_TEMP_CHAR,))  # 温度キャラクタリスティックを登録
        
        # 接続中のセントラルを保持するためのセット
        self.connections = set()
        
        # ペイロードの設定(通信に使うデータの設定)
        mac_address = ubinascii.hexlify(self.ble.config('mac')[1], ':').decode().upper()  # MACアドレスの取得
        payload_name = 'Pinco {}'.format(mac_address)  # ペイロードの名前をMACアドレスから生成
        self.payload = advertising_payload(name=payload_name, services=[ENV_SENSE_UUID])  # アドバタイズメントペイロードの生成
        
        # BLEのIRQ(割り込み処理)の設定
        self.ble.irq(self.irq)  # IRQを設定
        
        # 通信開始
        self.advertise()  # アドバタイズメントを開始
    
    # 温度センサの情報を更新、通知
    def update_temp(self, notify=False, indicate=False):
        # 温度センサから温度を取得
        self.dht_sensor.measure()  # 温度と湿度を測定
        temperature = self.dht_sensor.temperature()  # 温度の取得
        humidity = self.dht_sensor.humidity()  # 湿度の取

ble_simple_peripheral.py

以下のコードをpicoに「ble_simple_peripheral.py」という名前で保存します。

# 必要なライブラリのインポート
import bluetooth  # Bluetooth機能を提供するライブラリ
import random  # 乱数を生成するライブラリ
import struct  # バイナリデータとPythonのデータ型の変換を行うライブラリ
import time  # 時間の管理を行うライブラリ
from ble_advertising import advertising_payload  # BLEのアドバタイズメントペイロードを作成する関数
from micropython import const  # マイクロPythonの定数を定義するためのライブラリ

# BLEイベントの定義
_IRQ_CENTRAL_CONNECT = const(1)  # セントラルが接続したときのイベント
_IRQ_CENTRAL_DISCONNECT = const(2)  # セントラルが切断したときのイベント
_IRQ_GATTS_WRITE = const(3)  # GATTの書き込みが発生したときのイベント

# GATT特性フラグの定義
_FLAG_READ = const(0x0002)  # 読み込み可能な特性フラグ
_FLAG_WRITE_NO_RESPONSE = const(0x0004)  # 書き込み(レスポンスなし)可能な特性フラグ
_FLAG_WRITE = const(0x0008)  # 書き込み可能な特性フラグ
_FLAG_NOTIFY = const(0x0010)  # 通知可能な特性フラグ

# UARTのUUIDと特性の定義
_UART_UUID = bluetooth.UUID("6E400001-B5A3-F393-E0A9-E50E24DCCA9E")  # UARTサービスのUUID
_UART_TX = (
    bluetooth.UUID("6E400003-B5A3-F393-E0A9-E50E24DCCA9E"),  # TX特性のUUID
    _FLAG_READ | _FLAG_NOTIFY,  # 読み込み可能で通知可能な特性フラグ
)
_UART_RX = (
    bluetooth.UUID("6E400002-B5A3-F393-E0A9-E50E24DCCA9E"),  # RX特性のUUID
    _FLAG_WRITE | _FLAG_WRITE_NO_RESPONSE,  # 書き込み可能(レスポンスなし)な特性フラグ
)
_UART_SERVICE = (
    _UART_UUID,
    (_UART_TX, _UART_RX),  # TXとRXの2つの特性を持つUARTサービス
)


# BLEの単純なペリフェラルクラス
class BLESimplePeripheral:
    def __init__(self, ble, name="mpy-uart"):
        self._ble = ble  # BLEオブジェクトの取得
        self._ble.active(True)  # BLEを有効化
        self._ble.irq(self._irq)  # BLEのIRQを設定
        ((self._handle_tx, self._handle_rx),) = self._ble.gatts_register_services((_UART_SERVICE,))  # UARTサービスを登録
        self._connections = set()  # 接続中のセントラルの集合
        self._write_callback = None  # RX特性への書き込みコールバック
        self._payload = advertising_payload(name=name, services=[_UART_UUID])  # アドバタイズメントペイロードの生成
        self._advertise()  # アドバタイズメント開始

    # BLEイベントハンドラ
    def _irq(self, event, data):
        # 接続を追跡し、通知を送信する
        if event == _IRQ_CENTRAL_CONNECT:
            conn_handle, _, _ = data
            print("New connection", conn_handle)
            self._connections.add(conn_handle)  # 接続中のセントラルを追加
        elif event == _IRQ_CENTRAL_DISCONNECT:
            conn_handle, _, _ = data
            print("Disconnected", conn_handle)
            self._connections.remove(conn_handle)  # 接続中のセントラルを削除
            # 新しい接続を受け入れるために再度アドバタイズメントを開始
            self._advertise()
        elif event == _IRQ_GATTS_WRITE:
            conn_handle, value_handle = data
            value = self._ble.gatts_read(value_handle)
            # RX特性への書き込みを処理するコールバックが登録されていれば呼び出す
            if value_handle == self._handle_rx and self._write_callback:
                self._write_callback(value)

    # データの送信
    def send(self, data):
        for conn_handle in self._connections:
            self._ble.gatts_notify(conn_handle, self._handle_tx, data)

    # 接続状態の確認
    def is_connected(self):
        return len(self._connections) > 0

    # アドバタイズメント開始
    def _advertise(self, interval_us=500000):
        print("Starting advertising")
        self._ble.gap_advertise(interval_us, adv_data=self._payload)

    # RX特性への書き込み時のコールバック設定
    def on_write(self, callback):
        self._write_callback = callback


# デモ関数
def demo():
    ble = bluetooth.BLE()  # BLEオブジェクトの生成
    p = BLESimplePeripheral(ble)  # BLEペリフェラルオ

main.py

以下のコードを「main.py」という名前で保存します。

# 必要なモジュールのインポート
from machine import Pin  # ピン制御を行うためのmachineモジュールからPinクラスをインポート
import bluetooth  # Bluetoothモジュールをインポート
from ble_simple_peripheral import BLESimplePeripheral  # BLEシンプルペリフェラルクラスをインポート

# Bluetooth Low Energy(BLE)オブジェクトの生成
ble = bluetooth.BLE()

# BLEオブジェクトを使用してBLESimplePeripheralクラスのインスタンスを作成
sp = BLESimplePeripheral(ble)

# ボード上のLED用のPinオブジェクトを作成し、出力として設定
led = Pin("LED", Pin.OUT)

# LEDの初期状態を0(オフ)に設定
led_state = 0

# 受信データを処理するコールバック関数の定義
def on_rx(data):
    print("Data received: ", data)  # 受信したデータを出力
    global led_state  # グローバル変数 led_state にアクセス
    if data == b'toggle\r\n':  # 受信したデータが "toggle" であるか確認
        led.value(not led_state)  # LEDの状態を切り替える(オン⇔オフ)
        led_state = 1 - led_state  # LEDの状態を更新

# 無限ループ開始
while True:
    if sp.is_connected():  # BLE接続が確立されているかを確認
        sp.on_write(on_rx)  # データ受信用のコールバック関数を設定

参考文献:https://wisteriahill.sakura.ne.jp/CMS/WordPress/2023/10/09/pi-pico-bluetooth-low-energy-ble/

実際に動かす!

コードを実行します。

その後スマホで操作します
以下の画像を参考にしてください

画像の順番でスマホとつないで、
「a」と送ってみてください!

そうすると、、

もう一度「a」と送ると、、

消えました!

どうでしょうか?

動かないとき

プログラム

プログラムを保存するときのファイル名が間違っていないか確認してください!

公式ラインに連絡!

解決しない場合は、↓から公式ラインを追加して連絡ください!
可能な範囲でサポートさせていただきます!

友だち追加

Raspberry Pi Pico Wカテゴリの最新記事