LoginSignup
20
20

More than 5 years have passed since last update.

GoでBLEセンサーデータをBeamする

Last updated at Posted at 2015-12-14

はじめに

SORACOM Advent Calendar 2015 の 15 日目の記事です。

やりたいこと

BLE センサーデータを AWS IoT に Publish します。
これを Go 言語でやってみます。
Publish するときは、SORACOM Beam を使って、暗号化処理をオフロードします。
Go で実装するのは最近 Go を触り始めて、勉強がてら何か書いてみようと思ったからです。
Mac で動作確認をしています。
最近は、IoT 関連の技術情報はネットに溢れているので、調べてすぐ分かるところは本記事では適宜省略します。
いろいろごった煮にしてしまったので、重要な前提が欠けていたりしたらすみません。

AWS IoT のセットアップ

(手順だけ整理します!)

  1. Thing を作成します。
  2. 証明書の作成・ダウンロードします。(忘れずに!)
  3. Policy を作成します。
  4. 証明書に Thing と Polich をアタッチします。

SORACOM Beam のセットアップ

(Beam の設定は User Console だけでできます!)

  1. AWS IoT のエンドポイントを取得します。
  2. CA 証明書 をダウンロードします。
  3. SORACOM User Console でグループを追加し、そのグループに対して SORACOM Beam 設定を追加します。
  4. 使用する 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 になります。

というわけで、センサーからデータを取得する部分のコードはこんな感じになりました。

app.go
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 する部分を書いてみます。

publisher.go
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 を使う/使わないで比較
  • 多言語で実装してみて比較

などやってみたいなと思います。

20
20
1

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
20
20