LoginSignup
3
1

More than 3 years have passed since last update.

屋内環境を手軽にモニタリングする~②Bluetooth LEアドバタイズ信号をJavaでキャッチする(Bluetooth LE / bluez-dbus)~

Last updated at Posted at 2019-09-04

はじめに

プラットフォームにJava / Raspberry Pi 3Bを選択しましたので、この環境で各種センサーと通信するJavaライブラリを探します。

まず最初に、Bluetooth LEについてです。ここ数年、BLE通信でセンサーデータを取得できるデバイスが出てきています。今回、メジャーどころのテキサス・インスツルメンツ社のSensorTag CC2650を選択しました。CC2650は、温度、湿度、照度、気圧、角速度、加速度、磁気を測定できる、5cm x 4cm程度のボタン電池駆動型のBLEデバイスです。

CC2650の使い方は、以下の流れになります。
1. CC2650(ペリフェラル)の電源を入れて、アドバタイズ信号を発信
2. セントラルは、アドバタイズ信号をキャッチして、CC2650に接続(CC2650はアドバタイズ信号を停止)
3. セントラルは、BLE GATTプロファイルを用いて、CC2650からセンサーデータを取得する

なお、CC2650は、アドバタイズ信号を発信し始めて3分の間に、どこからも接続されないと自動的に電源を切ります。なので、接続に備えるには、再度、電源を入れる必要があります。今回、アドバタイズ信号をJavaでキャッチするにあたり、BLE通信に対応したJavaライブラリとして、bluez-dbusを採用しました。

以前、試験的に、CC2650からセンサーデータを取得するために、Javaでコードを書いたことがありました。その時は、bluez-dbusは未だ無く、他にJavaでBLE通信するためのライブラリとして、ちょうどIntel TinyBがリリースされた頃でした。ただ、リリース間もないTinyBは不安定で、当時、BLEのNotification機能も使えませんでした。何より、bluezが公開しているdbusのI/F定義ファイルをC/C++のコードに自動変換して(1万行を超えるコードが自動生成)、これに更に手を入れてTinyBは作成されており、メンテナンス性はとても低そうに感じました。

BLEをdbus I/Fで使用する場合、dbus自体はUNIXドメインソケットの上で定義されているので、本質的には、このUNIXドメインソケットの部分だけがJNIで書かれ、その上で定義されるbluez用のdbusプロトコルは、このJNIを呼び出す形で実装するのがシンプルなのに、と思っていました。

当時は、仕方なくbluezの各種コマンドを常駐プロセスとして連携させるJavaのコードを書いて、凌いだことがあります。複雑なアーキテクチャで、ダサイなあと思いました。当時のコードは忘れましたが、このダサイ印象だけは今も残っています。

あれから月日は流れ、今では、BLEに対応したbluez-dbusなるライブラリが公開されています。Githubに書かれた開発者の動機を読むと、わたしが思ったのと同じようです。(まあ、そう思いますよね・・・)

そこで、今回はプライベートで、bluez-dbusを採用したシンプルなアーキテクチャでコードを書きました。前置きが長くなりましたが、本文は短いです。基本的に、Githubに書いた内容そのままです。詳細はコードを参照して下さい。

OSインストール

Raspberry Pi 3BのOSには、Raspbian Buster Lite OS (2019-07-10)を使用しています。このOSには、bluez-dbusが対応しているBlueZ 5.50が最初から入っており、改めて、BlueZをビルドする必要がありません。

Javaインストール

ARM版Linux用のJavaは幾つかあると思いますが、わたしはBELLSOFTのjdk11をapt-getで入れました。

# wget -q -O - https://download.bell-sw.com/pki/GPG-KEY-bellsoft | apt-key add -
# echo "deb [arch=armhf] https://apt.bell-sw.com/ stable main" | tee /etc/apt/sources.list.d/bellsoft.list
# apt-get update
# apt-get install bellsoft-java11

bluetooth-scannerとは

BLEアドバタイズ信号をキャッチするためのモジュールです。用途は、セントラルのBLE通信の範囲にBLEデバイスが入ったことを動的に認識することです。具体的には、CC2650が接近して、セントラルがその存在を認識し、接続するためのトリガーにします。

また、接続しているCC2650がセントラルの通信範囲から外れてBLE通信が切断され(アドバタイズ信号を再開します)、その後、再度、接近して、セントラルがアドバタイズ信号をキャッチして自動的にCC2650に再接続するトリガーとしても想定しています。

bluetooth-scannerの処理の肝は、dbus-javaが提供するAbstractPropertiesChangedHandler.javaextendsしたクラスを用意して、public void handle(PropertiesChanged properties)を実装することです。詳細は、Githubのコードを参照して下さい。bluetooth-scannerの使い方のサンプルは以下の通りです。IScanHandlerinterfaceを実装してScanProcess.javaのインスタンスを作成し、start()を呼び出します。

import com.github.hypfvieh.bluetooth.DiscoveryFilter;
import com.github.hypfvieh.bluetooth.DiscoveryTransport;
import com.github.hypfvieh.bluetooth.wrapper.BluetoothDevice;

import io.github.s5uishida.iot.bluetooth.scanner.IScanHandler;
import io.github.s5uishida.iot.bluetooth.scanner.ScanData;
import io.github.s5uishida.iot.bluetooth.scanner.ScanProcess;

public class MyScan {
    public static void main(String[] args) throws IOException, InterruptedException {
        Map<DiscoveryFilter, Object> filter = new HashMap<DiscoveryFilter, Object>();
        filter.put(DiscoveryFilter.Transport, DiscoveryTransport.LE);

        ScanProcess scanProcess = new ScanProcess("hci0", new MyScanHandler(), filter);
        scanProcess.start();
    }
}

class MyScanHandler implements IScanHandler {
    private static final Logger LOG = LoggerFactory.getLogger(MyScanHandler.class);

    @Override
    public void handle(BluetoothDevice device, ScanData data) {
        LOG.info(device.toString());
        LOG.info(data.toString());
    }
}

実行ログの例は以下の通りです。なお、行の先頭を省略しています。

MyScanHandler handle - BluetoothDevice [device=org.bluez:/org/bluez/hci0/dev_24_71_89_06_9D_82:interface org.bluez.Device1, adapter=/org/bluez/hci0, getBluetoothType()=DEVICE, getDbusPath()=/org/bluez/hci0/dev_24_71_89_06_9D_82] 
MyScanHandler handle - [hci0] 24:71:89:06:9D:82 name:CC2650 SensorTag rssi:-63 txPower:0 date:2019-09-03 22:40:25.483

一連の記事

このシリーズは、以下の記事から構成されます。
1. 動機とコンセプト
2. Bluetooth LEアドバタイズ信号をJavaでキャッチする(Bluetooth LE / bluez-dbus)(今回)
 関連するGithubはこちら
3. TI SensorTag CC2650から温度/湿度/照度などをJavaで取得する(Bluetooth LE / bluez-dbus)
 関連するGithubはこちら
4. MH-Z19BからCO2濃度をJavaで取得する(シリアル通信 / jSerialComm)
 関連するGithubはこちら
5. PPD42NSからPM2.5濃度をJavaで取得する(GPIO / Pi4J)
 関連するGithubはこちら
6. 産業オートメーション機器の稼動情報をJavaで取得する(OPC-UA / Eclipse Milo)
 関連するGithubはこちら
7. 簡易ツールにまとめる
 関連するGithubはこちら
8. 後記

追記

[2019.11.16]
簡易ツールの最新情報は、こちらをご参照下さい。

3
1
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
3
1