はじめに
SORACOM Advent Calendar 2015 の 15 日目の記事です。
やりたいこと
BLE センサーデータを AWS IoT に Publish します。
これを Go 言語でやってみます。
Publish するときは、SORACOM Beam を使って、暗号化処理をオフロードします。
Go で実装するのは最近 Go を触り始めて、勉強がてら何か書いてみようと思ったからです。
Mac で動作確認をしています。
最近は、IoT 関連の技術情報はネットに溢れているので、調べてすぐ分かるところは本記事では適宜省略します。
いろいろごった煮にしてしまったので、重要な前提が欠けていたりしたらすみません。
AWS IoT のセットアップ
(手順だけ整理します!)
- Thing を作成します。
- 証明書の作成・ダウンロードします。(忘れずに!)
- Policy を作成します。
- 証明書に Thing と Polich をアタッチします。
SORACOM Beam のセットアップ
(Beam の設定は User Console だけでできます!)
- AWS IoT のエンドポイントを取得します。
- CA 証明書 をダウンロードします。
- SORACOM User Console でグループを追加し、そのグループに対して SORACOM Beam 設定を追加します。
- 使用する SIM を 2. で設定したグループに所属させます。
Go で BLE センサーデータを取得する
今回はセンサーに SensorTag CC2650STK を使用します。
ちょっと時間が足りなかったので、今回はボタンを押したらその都度通知させる、というところまでしかできませんでした。
Go でセンサーデータを取得するために、paypal/gatt を使用します。
% go get github.com/paypal/gatt
examples/explorer.go 参考に、SensorTag からデータを取得する処理を書いてみます。
BLEセンサーからデータを取得するには、以下の情報が必要になります。
- Peripheral ID
- Service の UUID
- Charactaristic の UUID
Peripheral ID は examples/discover.go を実行することで、確認することができます。
Service の UUID と Charactaristic の UUID は examples/explorer.go を実行したりドキュメントを確認すれば分かるはずなんですが、少し楽をするために、sandeepmistry/node-sensortag を参考にしました。
node-sensortag の lib/common.js に SIMPLE_KEY_UUID と、SIMPLE_KEY_DATA_UUID という定数が定義されていて、この値が Sensortag のボタンを押した時に通知してもらうために必要な、UUID になります。
というわけで、センサーからデータを取得する部分のコードはこんな感じになりました。
package main
import (
"fmt"
"strings"
"github.com/paypal/gatt"
)
var message = make(chan string)
var done = make(chan struct{})
func main() {
d, err := gatt.NewDevice()
if err != nil {
fmt.Println(err)
return
}
go publish(message)
d.Handle(
gatt.PeripheralDiscovered(onPeriphDiscovered),
gatt.PeripheralConnected(onPeriphConnected),
gatt.PeripheralDisconnected(onPeriphDisconnected),
)
d.Init(onStateChanged)
<-done
fmt.Println("Exit")
}
func onStateChanged(d gatt.Device, s gatt.State) {
switch s {
case gatt.StatePoweredOn:
fmt.Println("Scanning...")
d.Scan([]gatt.UUID{}, false)
return
default:
d.StopScanning()
}
}
func onPeriphDiscovered(p gatt.Peripheral, a *gatt.Advertisement, rssi int) {
id := strings.ToUpper(<Peripheral ID>)
if strings.ToUpper(p.ID()) != id {
return
}
p.Device().StopScanning()
p.Device().Connect(p)
}
func onPeriphConnected(p gatt.Peripheral, err error) {
fmt.Println("connected")
sUUID := gatt.MustParseUUID("ffe0")
ss, err := p.DiscoverServices([]gatt.UUID{sUUID})
if err != nil {
return
}
cUUID := gatt.MustParseUUID("ffe1")
cc, err := p.DiscoverCharacteristics([]gatt.UUID{cUUID}, ss[0])
if err != nil {
return
}
p.SetNotifyValue(cc[0], func(c *gatt.Characteristic, b []byte, err error) {
switch b[0] {
case 0x1:
message<-"left"
case 0x2:
message<-"right"
case 0x3:
message<-"gobeam"
}
})
}
func onPeriphDisconnected(p gatt.Peripheral, err error) {
fmt.Println("Disconnected")
close(done)
}
Scan を開始するといろんな Peripheral が見つかりますので、onPeriphDiscovered 関数では、見つかった Peripheral の中から Sensortag に一致するものだけに接続しています。
この辺、コマンドライン引数で渡せるようにしたり、アドレスや名前で検索できるようにした方が便利ですね。
Peripheral に繋がったら、onPeriphConnected 関数で Service と Characteristic を取得し、Peripheral に対して SetNotifyValue しています。
ボタンが押されると、右のボタンか、左のボタンか、あるいは両方かで取得できる値が変わります。
次に、AWS IoT に Publish する部分を書いてみます。
package main
import (
"fmt"
MQTT "git.eclipse.org/gitroot/paho/org.eclipse.paho.mqtt.golang.git"
)
const uri = "tcp://beam.soracom.io:1883"
func publish(message chan string) {
opts := MQTT.NewClientOptions().AddBroker(uri)
opts.SetClientID("clientid2")
c := MQTT.NewClient(opts)
if token := c.Connect(); token.Wait() && token.Error() != nil {
panic(token.Error())
}
defer c.Disconnect(250)
for ;; {
select {
case text := <-message:
token := c.Publish("gobeam", 0, false, text)
token.Wait()
fmt.Printf("published: %s\n", text)
}
}
}
Paho MQTT client library 使用しました。
肝は、ホストに SORACOM Beam を指定することと、メインの処理からチャネルを経由してメッセージを受け取るところです。
実行してみる
私は gobeam というパッケージを作ったので、ビルドすると gobeam というコマンドができあがりました。
ちゃんと Mac が SORACOM Air を使ってインターネットに接続できていることを確認してから
% ./gobeam
とやって実行すると、"Scanning..." と表示されて Sensortag を探し始めます。
見つかると、"connected" と表示されるので、ボタンを押しまくります。
がその前にちゃんと Publish されているか確認するために、mosuquitto_sub コマンドを実行しておきます。
% mosquitto_sub -h beam.soracom.io -p 1883 -q 1 -d -t gobeam -i clientid1
そうすると、ボタンの右か左か両方かで Subscribe される内容が変わるかと思います。
このあとやりたいこと
時間切れになってしまったので今回はできませんでしたが、
- SensorTag 以外のセンサーからデータを取得する。
- IoT ゲートウェイに配置してみて、Beam を使う/使わないで比較
- 多言語で実装してみて比較
などやってみたいなと思います。