0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

PiPicoWでAndroidとBluetooth接続

Last updated at Posted at 2025-04-26

RaspberryPiPicoWの内蔵温度センサの値を、BLE(Bluetooth Low Energy)で接続してスマホに表示

目的:RaspberryPiPicoWの温度センサとBLE機能を確認する
用意するもの:RaspberryPiPicoW、書き込み用PC、スマホ

1)BLE機能が使える最新ファームウェア.uf2をDL

《 microPythonのサイト 》
  ファイル名の例:v1.25.0 (2025-04-15) .uf2 / [Release notes] (latest)
  ☞ 今回はこのファイルを使用

《 ラズパイ公式サイト 》
  ファイル名の例:RPI_PICO_W-20250415-v1.25.0.uf2

2)Bootボタンを押しながらPiPicoWを起動。

3)PiPicoWのフォルダウィンドウに.uf2をドラッグ&ドロップ

ファイルのドロップが完了したら、PicoWのフォルダウィンドウは自動的に閉じる

4)以下の3ファイルを、ThonnyでPicoW内に保存

image.png
それぞれのファイルの用途
main.py … 実行ファイル
ble_advertising.py … アドバタイズ用(BLE情報を定期的に発信)
ble_temp_sensor.py … 温度を取得して送信

# ファイル名:main.py
import time
from machine import ADC
from ble_temp_sensor import BLETemperature
import bluetooth

# 温度センサー初期化
sensor_temp = ADC(4)
conversion_factor = 3.3 / 65535

def read_temp():
    reading = sensor_temp.read_u16() * conversion_factor
    temp_c = 27 - (reading - 0.706)/0.001721
    return round(temp_c, 2)

# BLE初期化
ble = bluetooth.BLE()
temp_service = BLETemperature(ble)
print("BLE initialized and advertising...")  # ← 追加

while True:
    temperature = read_temp()
    print("Temp:", temperature)
    temp_service.send_temperature(temperature)
    time.sleep(2)
# ファイル名:ble_temp_sensor.py
import struct
import bluetooth
from micropython import const
from ble_advertising import advertising_payload

# 短いUUIDに変更(標準定義)
_TEMP_SERVICE_UUID = bluetooth.UUID(0x1809)   # Health Thermometer (BLE公式規格)
_TEMP_CHAR_UUID = bluetooth.UUID(0x2A1C)      # Temperature Measurement (公式)

# flags
_FLAG_READ = const(0x0002)
_FLAG_NOTIFY = const(0x0010)

_IRQ_CENTRAL_CONNECT = const(1) #bluetoothライブラリ使わなくてよいように追加
_IRQ_CENTRAL_DISCONNECT = const(2) #同上


class BLETemperature:
    def __init__(self, ble, name="PicoTemp"):
        self._ble = ble
        self._ble.active(True)
        self._ble.irq(self._irq)
        self._connections = set()

        # サービス登録
        ((self._temp_handle,),) = self._ble.gatts_register_services((
            (_TEMP_SERVICE_UUID, (
                (_TEMP_CHAR_UUID, _FLAG_READ | _FLAG_NOTIFY),
            )),
        ))

        # アドバタイズ用データ
        self._payload = advertising_payload(name=name, services=[_TEMP_SERVICE_UUID])
        self._advertise()

    def _irq(self, event, data):
        if event == _IRQ_CENTRAL_CONNECT: #変更
            conn_handle, _, _ = data
            print("Connected:", conn_handle)
            self._connections.add(conn_handle)
        elif event == _IRQ_CENTRAL_DISCONNECT: #変更
            conn_handle, _, _ = data
            print("Disconnected:", conn_handle)
            self._connections.discard(conn_handle)
            self._advertise()

    def _advertise(self):
        # アドバタイズ間隔を100msに(安定する値)
        self._ble.gap_advertise(100_000, adv_data=self._payload)

    def send_temperature(self, temp_c):
        temp_str = "{:.1f}℃".format(temp_c)
        # 元は、temp_bytes = struct.pack("<f", temp_c)  # floatをバイト列に変換だった
        temp_bytes = temp_str.encode('utf-8')
        for conn_handle in self._connections:
            self._ble.gatts_notify(conn_handle, self._temp_handle, temp_bytes)
# ファイル名:ble_advertising.py
import struct
import bluetooth

_ADV_TYPE_FLAGS = const(0x01)
_ADV_TYPE_NAME = const(0x09)
_ADV_TYPE_UUID16_COMPLETE = const(0x03)
_ADV_TYPE_UUID32_COMPLETE = const(0x05)
_ADV_TYPE_UUID128_COMPLETE = const(0x07)

def advertising_payload(limited_disc=False, br_edr=False, name=None, services=None):
    payload = bytearray()

    flags = 0x02 if limited_disc else 0x06
    if br_edr:
        flags |= 0x18
    payload += struct.pack("BB", 2, _ADV_TYPE_FLAGS) + bytes([flags])

    if name:
        payload += struct.pack("BB", len(name) + 1, _ADV_TYPE_NAME) + name.encode()

    if services:
        for uuid in services:
            b = bytes(uuid)
            if len(b) == 2:
                payload += struct.pack("BB", len(b) + 1, _ADV_TYPE_UUID16_COMPLETE) + b
            elif len(b) == 4:
                payload += struct.pack("BB", len(b) + 1, _ADV_TYPE_UUID32_COMPLETE) + b
            elif len(b) == 16:
                payload += struct.pack("BB", len(b) + 1, _ADV_TYPE_UUID128_COMPLETE) + b

    return payload

image.png
MicroPython公式のBLE温度サンプル

5)main.pyを実行

  Thonnyのシェルに print("Temp:", temperature) の実行結果として温度が表示される

6)スマホにLightBlueをインストール

nRFconnectでもValueの確認は可能
ただ、アプリ側でUTF-8にエンコード表示する設定が見当たらない。

7)PicoWのAdvertisingをLightBlueで確認する

順に赤〇の部分をタップ
[Peripherals] > PicoTemp の [Connect]
image.png

PicoTemp が [connected] であるのを確認して、Health Thermometerの項目の[Temperature Measurement]をタップ
image.png

Characteristic 内の [Subscribe] をタップ
image.png

すると、Read/Notified Values の下に、取得値が更新表示される
値がHEX表示のままの場合、赤〇部分が[HEX]となっていると思うので、タップして[UTF-8 String]に変更する

image.png

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?