Raspberry PiからSORACOM Beamに温度データを送る
はじめに
先日の記事でSORACOMとAWS間のプライベートネットワーク接続をまとめました。
今回はRaspberry Piでセンサからデータを取得し、ソラコムへ送信する部分をまとめます。
デバイス側の実装を極力シンプルに保つため、SORACOMのメタデータサービスに必要な情報を格納するようにします。
また、デバイスごとに固有の識別子を振るのは管理が煩雑になるのでSORACOM Beamにデータを送信し、そこでIMSIやIMEIといったユニークになるキーをヘッダに付与してもらいます。
使うもの
植物観察ハンズオンで利用したものを流用します。
デバイスはSORACOMのWebコンソールの「購入」からセットで買うことができます。
また、ハンズオン資料ではシェルスクリプトでHarvestへのデータ登録を行なっていますが、今回はGo言語を利用します。
実装
それでは実装に入っていきます。
配線
ハンズオンと同等の配線を行います。
モジュールの読み込み
GPIO4の設定を行います。/boot/config.txt
の末尾に以下を追記します。
dtoverlay=w1-gpio-pullup,gpiopin=4
1-Wireデバイスのモジュールを読み込ませます。/etc/modules
の末尾に以下を追記します。
w1-gpio w1-therm
設定を反映させるために再起動します。
# reboot
すると /sys/bus/w1/devices/
に '28-' から始まるディレクトリが見えるようになります。
配下の w1_slave
というファイルに現在の温度が書かれています。(値の1000分の1 が温度となります。)
$ cat /sys/bus/w1/devices/28-*/w1_slave 5a 01 4b 46 7f ff 06 10 a3 : crc=a3 YES 5a 01 4b 46 7f ff 06 10 a3 t=21625
Goから値を読み込む
今回は以下のパッケージを利用しました。
github.com
実態はioutil.ReadFile("/sys/bus/w1/devices/w1_bus_master1/w1_master_slaves")
で接続されているセンサーを走査しioutil.ReadFile("/sys/bus/w1/devices/" + sensor + "/w1_slave")
でファイルの中身を読み取っている実直な作りになっているようです。
エラーハンドリング等省略しますが以下のように温度が取得できそうです。
package main import ( "fmt" "github.com/yryz/ds18b20" ) func main() { // 接続されているセンサーを取得 sensors, _ := ds18b20.Sensors() // 温度を取得(今回はセンサーを1つしか接続していないので `sensors[0]` として利用) t, _ := ds18b20.Temperature(sensors[0]) // 温度を表示 fmt.Printf(temperature: %.2f°C\n", t) }
SORACOM メタデータから可変なデータを取得する
接続先のURL情報など変わる可能性のあるものをデバイスに埋め込んでしまうと、URLが変わるたびに全デバイスへのファイル更新が必要となってしまいます。
今回はその練習としてSORACOM BeamのURLをSORACOM メタデータから取得してみます。
まずはソラコムのWebコンソールのSIMグループ設定からメタデータをONにし、ユーザーデータを設定し保存します。
{"beamURL": "http://beam.soracom.io:8888/"}
SIM経由で以下のURLへアクセスすると設定したデータが取得できます。
$ curl http://metadata.soracom.io/v1/userdata
これを以下のようにGoで書き直してみます。
type URL struct { BeamURL string `json:"beamURL"` } func getMetadata() (url *URL, err error) { res, _ := http.Get("http://metadata.soracom.io/v1/userdata") defer res.Body.Close() body, _ := ioutil.ReadAll(res.Body) url = &URL{} err = json.Unmarshal(body, &url) if err != nil { return nil, err } return url, nil }
SORACOM Beamへデータを送信する
送りたいデータと送信先が取得できたので、SORACOM Beamへデータを送信します。
ソラコムのWebコンソールのSIMグループ設定からBeamを設定します。
前回設定したプライベート接続したAWS EC2への転送設定とIMSI/IMEIのヘッダを追加しています。
こうすることでデバイス側にIMSI/IMEIを取得する実装を省けますし、転送先を変更したくなった場合でもデバイスに手を入ることなく瞬時に変更することができそうです。
Goで簡単なHTTP Clientを書いてみます。
取得時間と温度を5秒間隔で送信します。
type Postdata struct { Time time.Time `json:"time"` Temp float64 `json:"temp"` } func main() { // 接続されたセンサーを走査 sensors, _ := ds18b20.Sensors() // メタデータを取得 metadata, _ := getMetadata() // 5秒間隔を設定 t := time.NewTicker(5 * time.Second) for { // 温度を取得 temp, _ := ds18b20.Temperature(sensors[0]) // POSTするデータを作成 postdata, _ := json.Marshal(Postdata{Time: time.Now(), Temp: temp}) // データを送信 resp, _ := http.Post(metadata.BeamURL, "application/json", bytes.NewBuffer(postdata)) // 5秒ブロック <-t.C } }
まとめ
コードはこちらにのせておきます。
メタデータ、Beam等を活用することでデバイス実装をシンプルかつ変更に強いものにできそうです。
次回はBeamで付与したIMSI等の固有識別子を活用してサーバー側でデータをハンドリングしてみようと思います。
以上