使うもの
- 太陽誘電 BLEモジュール EYSGJNAWY-WX (https://akizukidenshi.com/catalog/g/gK-12339/)
- Microchip BLEモジュール RN4020 (https://akizukidenshi.com/catalog/g/gK-11102/)
参考文書
- RN4020 Bluetooth Low Energy モジュール ユーザガイド
(https://ww1.microchip.com/downloads/jp/DeviceDoc/70005191A_JP.pdf)
太陽誘電のEYSGJNはファームウエアのソースまで開示されるようなのですが、個人用途だからか入手までたどり着けませんでした。資料は入手できましたが、Confidentialなので、詳しいことは書けません。
MicrochipのRN4020は資料が公開されていますが、ソースは入手できません。ファームのアップデート機能はありますが、ファームを自分でつくることはできません。
資料をざっと見た限りでは、Microchipの方が親切というか、色々できそうな気がします。
Microchip RN4020
RN4020(正確にはRN4020使用モジュール)は5Vを直接つなげられるので、USBで電源供給します。
USBシリアル変換モジュール (https://akizukidenshi.com/catalog/g/gM-08461/) を使っています。この手の変換ケーブルは結構高くて、何本も買うと思わぬ出費になりますが、これはコスパもよくて非常によいです。ただし、ちょっとだけハンダ付けが必要です。
USBケーブルをPCに挿すと起動します。
Dコマンド(RN4020設定出力コマンド)を実行してみると、
意味 | 値 | 対応コマンド | |
---|---|---|---|
BTA | MACアドレス | 68271921D57D | |
Name | デバイス名 | RND57D | |
Connected | 接続済みデバイス | no (なし) | |
Bonded | ボンディング済みデバイス | no (なし) | |
Server Services | サーバーロールで サポートするサービス |
80000000 (Device Information) |
SS |
Features | サポート機能(Feature) | 00060000 (I/O Capability = No Input, no output) |
SR |
TxPower | 送信出力 | 4 (-2.5dBm) | SP |
Connected,Bondedは現在の状態ですが、設定は対応するコマンドで変更することができます。
I/O Capability = No Input, no output は、私はキーボード(操作パネル)もディスプレイも持たないデバイスだという宣言になります。今回は、PCがキーボードとディスプレイになるので、I/O Capability = Keyboard Display にするのが適切です。
起動が確認できたので、RN4020をペリフェラルとしてスマホから接続してみます。
参考文書[1]
Chapter 3. アプリケーション例
3.1 スマートデバイスとの接続によるデモ
コマンド | 応答 | 備考 |
---|---|---|
Echo On | +コマンドの応答 | |
SF,1 | AOK | 工場出荷設定にリセット |
SS,C0000000 | AOK | Device InformationとBatteryサービスの有効化 |
SR,00000000 | AOK | ペリフェラルに設定 |
R,1 | Reboot | 再起動 |
CMD | 起動メッセージ | |
Echo On | +コマンドの応答 | |
LS | 180A~END | サービス一覧取得 |
A | AOK | アドバタイズ開始 |
LSコマンドは、SSコマンドで設定したサービスの確認です。
180AはDevice Informationサービス、180FはBatteryサービスのUUIDです。
これをスマホで見てみると、
このBLEモジュールのデバイス名である、RND57Dが表示されています。
スマホアプリはnRF Connect for Mobileを使いました。
LSコマンドで表示される2A25,2A27,...は各サービスのキャラクタリスティックのUUIDですが、それぞれの意味はこの画面を見れば一目瞭然です。例えば、2A25はシリアル番号を意味し、その値は68271921D57Dです。
この値はMACアドレスなのですが、それはこのモジュールにおいて、シリアル番号のデフォルト値がMACアドレスであるためです。
太陽誘電 EYSGJN
EYSGJNの電源は1.8~3.6Vです。ラズパイの3.3Vから取ってもいいのですが、USBの5Vからレギュレータ (https://akizukidenshi.com/catalog/g/gI-11318/) を使って3Vにしました。
スマホで見てみると、
TYSA-B 3.0.0が、このモジュールのデバイス名です。
全体
EYSGJNをペリフェラル、RN4020をセントラルとして、RN4020から接続します。
F // Start scan
AOK
DCBDD693FA10,1,TYSA-B 3.0.0,1804|180F,-1E
X // Stop scan
E,1,DCBDD693FA10 // Establish connection
AOK
Connected
ConnParam:00A0,0000,01F4
EYSGJNのサービスを取得します。
LC
180F
2A19,0012,02
2A19,0013,10
END
180FはBattery serviceのUUIDです。2A19はBattery levelのcharacteristicで、0012,0013はUUIDの代わりに使用できるハンドルです。このハンドルは、UUIDの桁が大きいときに入力の手間を省くためのもので、RN4020のコマンドでのみ使用できます。
Battery levelの値を取得すると、
CHR,0012
R,64.
USB給電だからか、0x64 = 100%でした。この値を任意に変更できると面白いのですが、EYSGJNのマニュアルを見てもよくわかりませんでした。
なお、EYSGJNのコマンドはConfidentialなので、書くことができません。
Battery levelの値を一定周期で何点か取ってグラフにするGUIを、Djangoでつくりました。
import re
from serial import Serial
class BleSerialPort:
def __init__(self) -> None:
try:
self.port = Serial("COM6", 115200)
except:
self.port = None
self.scan_list = []
def __del__(self):
if self.port != None:
self.port.close()
def start_scan(self):
if self.port != None:
self.scan_list = []
self.send("F", callback=self.scan_callback)
def send(self, command, timeout=1, callback=None):
self.port.timeout = timeout
print(f"> {command}")
self.port.write(f"{command}\r\n".encode("utf-8"))
while True:
line = self.port.readline()
if line == b"":
# timeout
break
if callback != None:
callback(line)
print(line)
def scan_callback(self, line):
# <BTADDR>,<PRIVATE>,<BTName>,<UUID>,<RSSI>
pattern = re.compile("([^,]*),([^,]*),([^,]*),([^,]*),([^,]*)")
m = pattern.match(line.decode("utf-8"))
if m != None:
device = {
"BTADDR": m.group(1),
"PRIVATE": m.group(2),
"BTName": m.group(3),
"UUID": m.group(4),
"RSSI": int(m.group(5), 16)
}
self.scan_list.append(device)
from django.shortcuts import render
from .ble_serial import BleSerialPort
def index(request):
port = BleSerialPort()
port.start_scan()
port.stop_scan()
context = {
"scan_list": port.scan_list,
}
print(context)
return render(request, 'monitor/index.html', context)
<table class="table">
<thead>
<tr>
<th>BTADDR</th>
<th>PRIVATE</th>
<th>BTName</th>
<th>UUID</th>
<th>RSSI</th>
</tr>
</thead>
<tbody>
{% for device in scan_list %}
<tr>
<td>{{ device.BTADDR }}</td>
<td>{{ device.PRIVATE }}</td>
<td>{{ device.BTName }}</td>
<td>{{ device.UUID }}</td>
<td>{{ device.RSSI }}</td>
</tr>
{% endfor %}
</tbody>
</table>