BLE通信 〜nRF52480編〜
前回、micripythonのubluetoothを使って、ラズパイpicoWやESP32でBLE通信をする方法を書きました。
電子工作界隈ではこれらのマイコンがメジャーですが、消費電力が大きいという弱点があります。
一方でnRF52480は消費電力がかなり小さく、ボタン電池一つで1年くらい稼働するそうです。
電子工作で使うなら、Seeed StudioのDevelopment Boardsがおすすめ
(昔は一千円ちょいだったのですが、円安で相当値上がりしてますね。ファック日銀)ただ、一個致命的な弱点がありまして、2023年6月時点ではnRF52480(以下nRF)はファームウェアの仕様上microPythonのubluetoothやujsonなどいくつかのmicropythonライブラリは使えません。
そこでcircuitPythonを使って実装していくことになります。
(エディタはMu editorを使っています)
なお、circuitPythonのライブラリですが、pip等を使ってインストールできないので、手動で追加していきます。
ライブラリを追加
以下よりライブラリのzipファイルをダウンロードし、解凍します。
このうち8.x系を選びます。
解凍すると、たくさんのフォルダとファイルができますが、これら全てをnRFに入れることは容量の都合でできないので、必要なものだけを入れます。
どのファイルを入れるかについては後述します。
コードを書く
こちらにドキュメントやサンプルコードが載っています。
今回は①キャラクタリスティックにデータをJSON形式で格納したかったので、ble_jsonのコードを参考にしました。
以下が今回作成したコードです。
ble_json_service.py
from adafruit_ble.uuid import VendorUUID
from adafruit_ble.services import Service
from adafruit_ble.characteristics import Characteristic
from adafruit_ble.characteristics.json import JSONCharacteristic
# A custom service with two JSON characteristics for this device. The "sensors" characteristic
# provides updated sensor values for any connected device to read. The "settings" characteristic
# can be changed by any connected device to update the peripheral's settings. The UUID of your
# service can be any valid random uuid (some BLE UUID's are reserved).
# NOTE: JSON data is limited by characteristic max_length of 512 byes.
class SensorService(Service):
# pylint: disable=too-few-public-methods
uuid = VendorUUID("a72c3f53-ac6f-4367-8d65-c855ee89acee")
tx = JSONCharacteristic(
uuid=VendorUUID("93222d1f-2837-4f1d-88d0-e30b6d1935e1"),
properties=Characteristic.READ,
initial_value={"humid": 50, "temp": 20},
)
rx = JSONCharacteristic(
uuid=VendorUUID("4836c2f5-001a-4d2b-a67f-a2701b1354e5"),
properties=Characteristic.WRITE,
)
def __init__(self, service=None):
super().__init__(service=service)
self.connectable = True
code.py
# SPDX-FileCopyrightText: 2020 Mark Raleson
#
# SPDX-License-Identifier: MIT
# Provide readable sensor values and writable settings to connected devices via JSON characteristic.
import alarm
import board
import time
import random
from ble_json_service import SensorService
from adafruit_ble import BLERadio
from adafruit_ble.advertising.standard import ProvideServicesAdvertisement
# Create BLE radio, custom service, and advertisement.
ble = BLERadio()
service = SensorService()
advertisement = ProvideServicesAdvertisement(service)
# Function to get some fake weather sensor readings for this example in the desired unit.
def measure(unit):
temperature = random.uniform(0.0, 10.0)
humidity = random.uniform(0.0, 100.0)
if unit == "fahrenheit":
temperature = (temperature * 9.0 / 5.0) + 32.0
return {"temp": temperature, "humid": humidity}
# Advertise until another device connects, when a device connects, provide sensor data.
while True:
print("Advertise services")
ble.stop_advertising() # you need to do this to stop any persistent old advertisement
ble.start_advertising(advertisement)
print("Waiting for connection...")
while not ble.connected:
pass
print("Connected")
while ble.connected:
rx = service.rx
if rx is None:
continue
else:
instruction, val = rx # ('sleep',1000)のようなタプル型
if instruction == "sleep":
print("good night!")
time_alarm = alarm.time.TimeAlarm(monotonic_time=time.monotonic() + val)
pin_alarm = alarm.pin.PinAlarm(board.D7,value=False)
alarm.exit_and_deep_sleep_until_alarms(time_alarm, pin_alarm)
elif instruction == "measure":
service.tx = measure({"unit": "celsius"})
print(service.tx)
else:
pass
time.sleep(1)
print("Disconnected")
ubluetoothで存在したイベント発生時の割り込み関数(BLE.irq)はAdaftuitのcircuitPythonライブラリにはありませんので、whileループを使ってセントラル側からの指示を受け取ったり、指示に対して測定などのアクションをしています。
ディープスリープがmachineライブラリではなくalarmライブラリにあるなど、かなり書き方が違うので慣れるまで大変かもしれません。
ライブラリの追加
ble_json_service.pyのimport部分より、必要なライブラリは「adafruit_ble」だとわかります。
先ほどダウンロードしたライブラリファイル一覧から、adafruit_bleをフォルダごとnRFのlibフォルダに放り込みましょう
これでcircuitPythonを実行すれば、セントラル側とデータをやり取りできるはずです。
Discussion