WebエンジニアにとってのIoT ~Physical Webが拓く未来~

第2回Physical Web技術解剖(1)-Inside UriBeacon

前回はPhysical Webの概要を説明させていただきました。早速この技術の上でどんな応用が可能なのか考えていきたいところではありますが、そのためにはまずその基盤となる技術を把握し、制約を知らなければなりません。

今回と次回に分け、一つ一つのパートを技術的に掘り下げていきたいと思います。

さて、まずは何と言ってもUriBeaconです。UriBeaconではBluetooth Low Energyを利用していますので、まずはそちらについて解説していきます。

Bluetooth Low Energy

Bluetoothの現状

UriBeaconではBluetooth Low Energyという無線通信技術を使って近接検知を行います。Bluetooth Low Energyは、⁠Bluetooth LE⁠⁠BTLE⁠⁠BLE⁠というように略されます。本稿では以降BLEと略すことにします。

Bluetoothを知らないという人は現在ではさすがにいないでしょう。ヘッドホンやキーボードなど、日常でBluetooth機器の恩恵に預かっている方もたくさんいるかと思います。

ですが、Bluetoothの登場から現在までの変遷についてまでは、あまり知られていないのではないでしょうか。

Bluetoothは1999年にバージョン1.0の仕様が発表され、2000年代前半から普及期に入りました。ユビキタスネットワークという言葉が流行っていたのを思いだす人もいるかもしれません。

Bluetoothは登場以降、バージョンを重ねながら通信の高速化などの進化を続けていましたが、Wi-Fiなどの他の無線通信技術とうまく差別化を計れずに伸び悩んでいた所がありました。

こういった中、それまでの高速化追求とは方針を別にした、省エネの方向にターゲットを向けた規格であるBLEを発表しBluetooth 4.0において統合されました[1]⁠。

また、4.0の後にも進化は続いていて、2014年12月には4.2の規格が発表されIPv6との連携なども考えられています。

UriBeaconで利用されているのは、この省エネバージョンであるBLEの規格になります。

BLEの手続きの流れ

主題があまり逸れてしまわないように、ここではBLEの仕組みのうち、UriBeaconの動作の理解に必要な部分だけ簡単に解説していきます。

それ以上のBluetooth及びBLEの情報について、より詳しくは専門の文献を当たっていただければと思います。

アドバタイズ

BLEのフローはまずはアドバタイズという動作から始まります。BLEのサービスを提供するデバイスが、⁠自分はこんなサービスを提供していますよ」と言う情報を周囲に発信します。この情報を載せたパケットをアドバタイジングパケットと言います。サービスの識別にはUUIDを利用します。一般的にはアドバタイジングパケットService UUIDが載せられます。

図1 ビーコンはアドバタイジングパケットを放出し、それぞれのパケットにはServiceを識別するためのUUIDが載っている
図1 ビーコンはアドバタイジングパケットを放出し、それぞれのパケットにはServiceを識別するためのUUIDが載っている

1秒おき、あるいは0.5秒おきなど、設定されたインターバルに従い、このブロードキャスト処理を行います。もちろんインターバルが短いほど、相手に到達しやすくなるのですが、電力は消費しやすくなります。なので、トレードオフを考慮してインターバルを設定することになります。

ちなみに到達可能距離は10m程度と言われています。電力を弱めれば到達距離を短くすることも可能です。

スキャン

BLEのスキャナが起動しているデバイス(スマートフォン等)が、このように発信されているアドバタイジングパケットの到達範囲内に入ることでこのパケットを読み込み、解析します[2]⁠。

図2 スキャンすることでパケットを取得し、その中のService UUIDなどをチェックする
図2 スキャンすることでパケットを取得し、その中のService UUIDなどをチェックする

Service UUIDなどを見て識別を行い、このパケットの発信元が自分の求めるサービスを提供していると判断すると、接続処理を行います。

図3 UUIDを見て、目的のサービスだと判断したら接続
図3 UUIDを見て、目的のサービスだと判断したら接続

接続を行うことで、デバイスが提供するサービスを利用することが出来るようになります。このとき必要であればペアリングなどを行いますが、BLEではペアリングを必要としない用途で使われることも多いようです。

サービスとは何か

ではここで言う「サービス」とは何でしょうか[3]⁠。

サービスにはcharacteristic(特性)と呼ばれる値がぶら下がっています。この値に対して読み書きしたり、値の変更をすることができます。

例えば、エアコンのコントローラであれば次のような例が考えられます。

図4 エアコンのコントローラというサービスがあり、4BC78330-337F-4D08-89B4-9A1028B56583というUUIDを割り当てている
図4 エアコンのコントローラというサービスがあり、4BC78330-337F-4D08-89B4-9A1028B56583というUUIDを割り当てている

エアコンのコントローラというサービスがあり、4BC78330-337F-4D08-89B4-9A1028B56583というUUIDを割り当てています。

このサービスは3つのcharacteristicを持っています。それぞれのcharacteristicUUIDをあてがわれています。

  • 現在の室温(9200B09-F42C-4408-8277-C084F31FA746)
  • 設定温度(47E26BA3-CF6E-4F2B-82F9-05A5C752287E)
  • スイッチ(A0370A52-E8DC-4478-BECF-420C3E373666)

BLEで利用するservicecharacteristicUUIDが、あまりヒューマンリーダブルではないために、パッと見たときに難しく感じるかもしれませんが、次のようにWebのサービスと比較してイメージするとわかりやすいかもしれません。

図5 REFTfulなWebサービスではドメインを指定して接続し、パスを指定してGET/POSTなどを行う
図5 REFTfulなWebサービスではドメインを指定して接続し、パスを指定してGET/POSTなどを行う
図6 BLEではService UUIDを指定して接続し、CharacteristicのUUIDを指定してread/writeなどを行う
図6 BLEではService UUIDを指定して接続し、CharacteristicのUUIDを指定してread/writeなどを行う
図注)
ただし、ステートレスな処理が基本となるHTTPと違い、BLEの場合は一度serviceに接続すると基本的にはその接続を維持したままでcharacteristic読み書きを行います。また、HTTPのパスのように階層構造は持つことができず、characteristicは必ずserviceに直接ぶら下がることになります。

基本的にはkey-valueペアのようなものだ、とわかってしまえば凄く単純な話です。

ただし、いわゆるデバイスのon/offを制御するスイッチのような役割を持つcharacteristicもよく使われます。このように、writeすることで動作を切り替えることが出来るコントロールポイントとしても振る舞えるという点は覚えておきましょう。

ちなみに上の例のエアコンのように、BLEでサービスを提供する側の役割をPeripheral(ペリフェラル)上の例のスマートフォンのようにサービスを享受する側の役割をCentral(セントラル)と呼びます。

UriBeaconでのBLEの利用

BLEについておおざっぱに理解できたところで、UriBeaconの話に戻ります。

UriBeaconは2つのモードを切り替えて使います。URI Advertising ModeConfiguration Modeです。

URI Advertising Mode

URI Advertising Modeでは、上で説明したような、⁠相手と接続してcharacteristicの値の読み書きを行う」いうようなやりとりは実は行いません。アドバタイジングパケットのブロードキャストのみをずっと続けます。

図7 ビーコンはひたすらURLを載せたパケットを放出しつづける
図7 ビーコンはひたすらURLを載せたパケットを放出しつづける

Configuration Mode

Configuration Modeは、ビーコンの管理者が、URIなどのデータを設定するためのモードです。サービスに接続して、各characteristicに対して読み書きを行い、ビーコンの設定を行います。

図8 それぞれのcharacteristicに対して読み書きを行うことで、URIや電力値などの設定、ロックやアンロックなどの操作を行う
図8 それぞれのcharacteristicに対して読み書きを行うことで、URIや電力値などの設定、ロックやアンロックなどの操作を行う

公式の仕様から抜粋しますが、次のようなcharacteristicが用意されています。名前を見れば何となくそれぞれのcharacteristicの役割が想像できるかと思います。

Characteristic
Lock State
Lock
Unlock
Uri Data
Uri Flags
Advertised Tx Power Levels
Tx Power Mode
Beacon Period
Reset

BLEのアドバタイジングパケットについて

UriBeaconの主要なモードはURI Advertising Modeのほうであり、その動作を把握するために一番重要なポイントはBLEのアドバタイジングパケットの理解です。

BLEのアドバタイジングパケットのうち、プリアンブルやヘッダ情報などの先頭部分、CRCが載っている後方部分を除いた31バイトの中央部に、サービス提供者がデータを選んで載せて行くことが出来ます。

図9 Advertisment Dataの箇所に載せられるデータのタイプ(Ad Type)「Generic Access Profile」で定義されている
図9 Advertisment Dataの箇所に載せられるデータのタイプ(Ad Type)は「Generic Access Profile」で定義されている

このAdvertisment Dataの箇所に載せられるデータのタイプ(Ad Type)は、以下に示した「Generic Access Profile」で定義されています。一度眺めてみると良いでしょう。

この中からサービス提供者が任意で載せたいタイプのデータを選び、容量が許す範囲でパケットに詰め込んで行きます。それぞれのデータは、データの長さ、データのタイプ、ペイロードという3つのパートで構成されています。

図10 UriBeaconの場合はServiceUUIDsServiceDataというタイプのデータを乗せることになる
図10 UriBeaconの場合はServiceUUIDsとServiceDataというタイプのデータを乗せることになる

UriBeaconの場合は、ServiceUUIDsと、ServiceDataというタイプのデータを乗せることになります。

ServiceUUIDs

このServiceUUIDsレコードに載せる、Service UUIDは、独自のものを用意すると128bit必要ですが、よく使われるサービスに関しては、32bit、16bitのものがBluetooth SIGによって定義されています。

UriBeaconでは0xFED8という一番短い16bitのService UUIDを使うことになっています。

ServiceData-いかにしてURIを詰め込むか

次はServiceDataのレコードを用意します。ここにURIを載せるのですが、載せられるスペースは非常に限られています。

ペイロード部分のフォーマットは次のようになっています。

図11 ペイロード部分のフォーマット
図11 ペイロード部分のフォーマット

フラグ、電力、URIなどの値があるのがわかりますが、この少ないスペースにURIを載せるために工夫が必要になります。

まず1つの解決策としてgoo.glbit.lyのようなURL短縮サービスを使う事が推奨されます。

URL短縮サービスを利用することで、以下の表のようにバイトサイズをだいたい20バイト前後まで縮小できるでしょう。

サービス 長さ
goo.gl http://goo.gl/fD0dPt 20
bit.ly http://bit.ly/1bWUKmo 21

さらに、次のようにURLの先頭でよく使われるパターンは1byteで表現できるように変換ルールが決められています。

文字列 代替バイト
http://www. 0x00
https://www. 0x01
http:// 0x02
https:// 0x03
uri:urn: 0x04

そうすると、goo.glを利用した場合、http://goo.gl/fD0dPt の先頭の http:// という7バイトを 1バイトに短縮することができ、全体で14バイトまで短縮ができます。

ドメインのTLD部分も同様に短縮ルールが用意されています。

comorgedunetinfobizgovの7つについて、/が続くパターンと続かないパターンそれぞれについて代替バイトが用意されています。

文字列 代替バイト
.com/ 0x00
.org/ 0x01
.edu/ 0x02
.net/ 0x03
.info/ 0x04
.biz/ 0x05
.gov/ 0x06
.com 0x07
.org 0x08
.edu 0x09
.net 0x0a
.info 0x0b
.biz 0x0c
.gov 0x0d

このようにして圧縮処理を行い、URIを18バイトまでに収まるようにします。というわけで、使いたいURIのscheme部分とTLD部分を代替バイトに置き換え18バイトに収まるならそのままで、そうでないならgoo.glなどの短縮サービスを利用すると良いでしょう。

HTTP URL以外のURI

PhysicalWebと言う⁠Web⁠と名のつく技術の話になっていますので、HTTP URLを中心に解説してきましたが、UriBeaconの仕様では、その名の通りURLに限定されず、次のようにUUIDを利用することも出来ます。

UUIDのフォーマット
urn:uuid:B1E13D51-5FC9-4D5B-902B-AB668DD54981

PhysicalWebという枠組みではなくUriBeaconの仕様のみを利用し、このUUIDをビーコンの識別子として使うことで、⁠ビーコンへの近接検知⁠⁠、⁠複数のビーコンを利用した屋内移動検知⁠など、現在AppleのiBeaconが利用されているようなタイプのサービスにも応用出来る、と言うことなのかもしれません。

特筆すべきことが無ければ、⁠基本的にはHTTP URLを使う」と言うことでこの連載では話を進めていきますが、このようにUUIDを渡すことが出来る、と言うことは覚えておきましょう。

BLEを使わないURIの共有

BLEでのアドバタイジングパケットでのフォーマットを紹介してきましたが、実はBLEを使わない方法についての議論もあります。

たとえばプライベートスペースのみでURIを共有したいケースです。アパートの部屋や会議室などを想像すれば良いでしょうか。部屋の外までパケットが到達してしまい、外にいる人が飛ばされたURIを拾うことが可能になってしまうわけですね。

このために特定のWi-Fi環境にログインできる人を限定し、mDNS[4]を利用してURIを共有する方法も考えられています。

実装について

この原稿の執筆時点では、国内で利用できるPhysicalWeb対応ビーコンデバイスは一般販売などで手に入れることは出来ません(海外で販売されているものはあるのですが、国内で利用するには電波法などの問題があります⁠⁠。

ですが、UriBeaconのリポジトリには、様々な開発環境でUriBeaconの振る舞いを実現するためのライブラリコードが提供されていて、これらを利用して自前でビーコンを用意することは可能です。

Linux+node.jsやRaspberry Piなどいろいろな環境のためのデモやライブラリコードが揃えられていますので、得意な環境がこの中にあったら試してみてはいかがでしょうか。

iOSとAndroidのBLEサポート

iOS/AndroidでのBLEのサポートについても少し触れておきます。

iOSでは、かなり早くからBLEへの対応がされてきました。まずiOS 5Central側の機能が使えるようになり、次のiOS 6ではPeripheral用のAPIも搭載されました。

一方Androidでは、4.3でようやく対応が始まりました。その時点ではCentral側の対応のみで、Peripheral側には対応していませんでした。Peripheral側として振る舞えるAPIが搭載されたのはAndroid 5(Lollipop)からです。

今回の解説の通り、ビーコン側はPeripheralとして振る舞います(正確にはBroadcasterだが、iOS/AndroidなどのSDKの上では区別されません⁠⁠。

ではPeripheral用のAPIが用意されているiOS 6以降、Android 5以降であればUriBeaconとして振る舞えるのかというと、必ずしもそうではありません。

iOSではアドバタイジングパケットに載せられるデータが制限されています。

CoreBluetoothプログラミングガイドより引用

ペリフェラルマネージャオブジェクトに対して指定できるのは、 CBAdvertisementDataLocalNameKeyとCBAdvertisementDataServiceUUIDsKeyの2つだけです。

と言うわけでiOSではLocalNameServiceUUIDsの2種類のデータしか直接指定できませんiBeaconのAPIを使うことで、Manufacturer Specific Dataを、決められたフォーマットのみで利用は出来ます⁠⁠。そのため、PhysicalWebで利用するServiceDataが使えませんので、現状iOSではUriBeaconの発信側の振る舞いをさせることは出来ません。

AndroidのBLEのAPIでは比較的自由にアドバタイジングパケットにデータを載せられるようです。ただし、AndroidiOSと違って様々なメーカの機種が存在しますので、それぞれに搭載されたBLEチップの影響を受けます。

例えばNexusシリーズでは、Nexus 6Nexus 9であればAndroid 5から追加されたPeripheral関係のAPIを使うことができるようですNexus 5でもL Previewの頃はPeripheral側の機能が使えたのですが、正式版のLollipopではエラーを返すようになりました。チップに何か問題が見つかってサポートを外したのかもしれません⁠⁠。

と言うわけで、スマホやタブレットをUriBeaconとして振舞わせて実験がしたいときには比較的新しいAndroidデバイスが必要になります。

iOS/Android用ライブラリ

凄く簡単にではありますが、用意されているライブラリのうち一部をピックアップして紹介してみます。

まずはAndroidです。

例えば今回紹介したURLの圧縮処理の部分であれば、次のようにエンコード/デコード処理が用意されています。

発信側のエンコード処理

先に説明したようにAndroid 5で、チップが対応している機種を利用することが前提になります。

AdvertisingData生成時に、次にように簡単にエンコードできるようになっています。

import org.uribeacon.beacon.UriBeacon;

byte[] data = UriBeacon.encodeUri(url);

受信側のデコード処理

スキャナのコールバックにおいても同様に、簡単にURIを取得することが可能です。

import org.uribeacon.beacon.UriBeacon;

UriBeacon uriBeacon = UriBeacon.parseFromBytes(scanRecordBytes);
Log.d(TAG, uriBeacon.getUriString());

次にiOSになりますが、 既に説明したようにSDKの制限があるために発信側は実装できないのですが、受信側は実装することが出来ます。

こちらのライブラリが使えます。

実装例についてはPhysicalWebのほうのリポジトリを参照すると良いでしょう。

Scannerごと用意されているので、それを利用して比較的簡単にURIの取得まで出来るようになっています。

_scanner = [[UBUriBeaconScanner alloc] init];
_scanner startScanningWithUpdateBlock:^{
    for (UBUriBeacon* uriBeacon in [_scanner beacons]) {
        // NSURI *u = [uriBeacon URI];
    }
}];

このように、PhysicalWebUriBeaconのリポジトリにはライブラリやサンプルが充実してきていますので、それらを参考に、発信側や受信側を用意して実験してみてはいかがでしょうか。

まとめ

今回はUriBeaconで利用されているBLEがどんなものなのか、そのアドバタイズパケットに対してどのようにデータを詰め込んでいるかを中心に解説させていただきました。

次回はメタデータリゾルバを中心に解説したいと思います。

おすすめ記事

記事・ニュース一覧