クラウド事業部エンジニアの川勝です。
わけあって人感センサで在室確認したいという要望がありまして、やってみることになりました。
ちょっとIoTブームが個人的にきているのもあってAWS IoT Coreをつかってやってみたいと思います。
※その2はこちら
目次
使うのサービスとモノ
今回はAWS IoTに送信までやってみます。
使うのサービスとモノは以下。
AWS IoT
https://aws.amazon.com/jp/iot-core/
AWS IoT Core は、インターネットに接続されたデバイスから、クラウドアプリケーションやその他のデバイスに簡単かつ安全に通信するためのマネージド型クラウドサービスです。
簡単とうたうだけあってチュートリアルのnode.jsとかpythonのデバイス用sdkを使ったものでmacでも簡単に接続まで試すことができました。
Raspberry Pi
会社に眠っていたもの。多分Raspberry Pi Type B
赤外線モーションセンサ
ググってでてきたRsbeeの3個セットのもの。安い。
Raspberry Piと接続するのにジャンパーワイヤーもいります。
言語
チュートリアルはnode.jsでやったのですがgoで実装していきます。
Raspberry Piのセットアップ
microSD
Raspberry Piを触るのは初めてだったのですが、microSDにosをインストールして使用します。眠っていた機器にもともと8GBのmicroSDは刺さっていたのですが、ちょっと怪しそうだったので家にあった東芝の16GBのものを使いました。
最低8GBは必要みたいです。
OS
CLIでしか操作しなにのでこちらからRaspbian Buster LiteをDLして使用しました。Ubuntu CoreっていうのもIoT向けで良さそうだったのですが今回使うRaspberry Piだと型が古くて対応外みたいでした…残念。
インストール
公式サイトにインストール方法あります。
今回はmac上でフォーマット、OSインストールした後にSSHできるようにします。(Raspberry Piにつなぐようのディスプレイが手元になかったので…)
microSDを接続したら以下コマンドで確認。
1$ diskutil list
/dev/disk0 とか /dev/disk1 とかでてくるので要確認。間違うとmac本体がやられます。自分の環境では /dev/disk2 でした。
1/dev/disk2 (external, physical):
2#: TYPE NAME SIZE IDENTIFIER
30: FDisk_partition_scheme *7.9 GB disk2
41: Windows_FAT_32 boot 58.7 MB disk2s1
52: Linux 7.9 GB disk2s2
確認できたらフォーマット。
1$ diskutil eraseDisk MS-DOS RPI disk2
フォーマットが完了したら一旦アンマウントして…
1$ diskutil unmountDisk /dev/disk2DLしたOSのイメージを書き込みます。sudo dd bs=1m if=path_of_your_image.img of=/dev/rdisk2 conv=sync
終わったら、sshできるようにもうひと手間かけます。
もしbootディレクトリがでてこなかったら一度SDカードを取り出して入れるとでてきました。
1$ touch /Volumes/boot/ssh
ちなみに Raspberry PiがWifiモデルだったらwifiの設定ファイルを用意しておくと有線で繋がなくても接続できるようです。
wpa_supplicant.confというファイルで以下のような内容をboot以下に保存します。
1country=JP
2ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
3update_config=1
4network={
5 ssid="hoge"
6 psk="fuga"
7}
mac上でここまでできたらSDカードを取り出してRaspberry Piにセットします。
Raspberry Pi へSSH
Raspberry PiはmicroUSB端子の電源アダプタでつなぐと起動します。
が、電源アダプタがなかったのでAmazon Echoの電源で起動しました。
とりあえず動きはするみたい。
ちなみにRaspberry Pi 4では5V 3Aが推奨のようです。
モニターもないのでLANケーブルもつないで電源ライトの赤と緑のランプが付けばOKとしてmacからsshします。
portがわからないので調べます。
1$ arp -a
1? (192.168.3.1) at 30:::::** on en0 ifscope [ethernet]
2
3? (192.168.3.3) at ac:::::** on en0 ifscope [ethernet]
4
5? (192.168.3.6) at fc:::::** on en0 ifscope [ethernet]
6
7? (192.168.3.8) at 14:::::** on en0 ifscope [ethernet]
8
9? (224.0.0.251) at 1:::::** on en0 ifscope permanent [ethernet]
10
11? (239.255.255.250) at 1:::::** on en0 ifscope permanent [ethernet]
上みたいにIPアドレスとMACアドレスがでてきます。b8:27:e1 から始まるMACアドレスがRaspberry Piらしいのででてくるまで arp -a を連打しましたw
IPアドレスがわかったらSSHします。
1$ ssh pi@192.168.xx.xx
初期ユーザはpiでパスワードはraspberryでSSHできます。
パスワードはログイン後に変更しておきましょう。
その他いろいろ設定したほうがよさそうですが、ひとまず接続できたのでAWSの設定と実行プログラムを設置していきます。
AWS IoT
AWSコンソールから作成していきます。
AWS IoTの 管理 > モノ からデバイスの作成をします。
単一のAWS IoT モノの登録を選択します。
Things Registryにデバイスを追加
とりあえず名前だけつけて次へ
証明書を作成します。
ボタンをクリックするだけで新規に証明書が作成されました。
忘れずに証明書、プライベートキー、パブリックキーをダウンロードしましょう。またAWS IoT のルートCAも必要ですのでリンク先からダウンロードします。
ダウンロードしたら証明書を有効化します。
ポリシーをアタッチは先にポリシーを作成しておく必要がありますのでここでは一旦完了します。
モノの一覧にもどるとTestDeviceが作成されていますね!
続いて 安全性 > ポリシー からポリシーの作成をします。
アクションは iot:* としておきます。リソースARNは画像はデフォルトで挿入されている値ですが、接続確認だけなら * にしておいてもよいです。
ポリシーを作成したら 安全性 > 証明書 から証明書にポリシーをアタッチします。
最後に モノ詳細画面からHTTPSエンドポイントを確認しておきます。
センサ接続
ちょっと見にくいですが以下のPINに接続しています。
接続は電源を入れる前に。
1ピン :5V電源(Power)
6ピン :0Vアース(GND)
12ピン:GPIO18 (Output)
実行プログラム
goのライブラリでgobotというのを使いました。使いやすくてよかったです。
Raspberry Pi 用のdriver
https://gobot.io/documentation/platforms/raspi/
モーションセンサ用
https://gobot.io/documentation/drivers/pir-motion-sensor/
大体そのまま使っています。
モーションセンサで使っているドライバーはRaspberry Pi用のものじゃなくて最初ちょっとハマりました…
あとモーションセンサをつないだpin番号が最初謎でした…
物理ピン番号とGPIOのBCMピン番号があるのですが、物理ピン番号を設定するようです。
Raspberry Piの設定は以下の様になりました。
1func newRobot(c MQTT.Client) *gobot.Robot {
2// raspiと接続するアダプター
3r := raspi.NewAdptor()
4// モーションセンサ。pin番号はgpioのpin番号ではない
5sensor := gpio.NewPIRMotionDriver(r, pirMotionDriverPin)
6
7// センサの振る舞い
8work := func() {
9// センサONになったら
10sensor.On(gpio.MotionDetected, func(data interface{}) {
11fmt.Println(gpio.MotionDetected)
12token := c.Publish(fmt.Sprintf(shadowUpdateEndpoint), 0, false, sensorOnMessage)
13if token.Wait() && token.Error() != nil {
14fmt.Printf("error: %+v", token.Error())
15}else {
16fmt.Print("Message Publish Success\n")
17}
18})
19// センサOffになったら
20sensor.On(gpio.MotionStopped, func(data interface{}) {
21fmt.Println(gpio.MotionStopped)
22token := c.Publish(shadowUpdateEndpoint, 0, false, sensorOffMessage)
23if token.Wait() && token.Error() != nil {
24fmt.Printf("error: %+v", token.Error())
25}else {
26fmt.Print("Message Publish Success\n")
27}
28})
29}
30
31return gobot.NewRobot("motionBot",
32[]gobot.Connection{r},
33[]gobot.Device{sensor},
34work,
35)
36}
センサのON/OFF時にAWS IoTにMTQQでメッセージを送信します。
あとからきづいたのですがgobotにもMTQQのクライアントがありましたが( https://gobot.io/documentation/platforms/mqtt/ )、違うパッケージを使用しています。
https://github.com/eclipse/paho.mqtt.golang
プログラムでいうと以下あたり
1func newTLSConfig() (*tls.Config, error) {
2certpool := x509.NewCertPool()
3// AWS IoTのルートCA
4pemCerts, err := ioutil.ReadFile(caCertificate)
5if err == nil {
6certpool.AppendCertsFromPEM(pemCerts)
7}
8// ダウンロードした証明書とプライベートキーのチェック
9cert, err := tls.LoadX509KeyPair(clientCertificate, privateKey)
10if err != nil {
11log.Printf("error: cert file mismatch. clientCertificate: %s, privateKey: %s\n", clientCertificate, privateKey)
12return nil, err
13}
14
15cert.Leaf, err = x509.ParseCertificate(cert.Certificate[0])
16if err != nil {
17log.Print("error: parse certificate.\n")
18return nil, err
19}
20
21return &tls.Config{
22RootCAs: certpool,
23ClientAuth: tls.NoClientCert,
24ClientCAs: nil,
25InsecureSkipVerify: true,
26Certificates: []tls.Certificate{cert},
27}, nil
28}
29
30var f MQTT.MessageHandler = func(client MQTT.Client, msg MQTT.Message) {
31fmt.Printf("TOPIC: %s\n", msg.Topic())
32fmt.Printf("MSG: %s\n", msg.Payload())
33}
34
35func mqttClient() (MQTT.Client, error) {
36// 証明書の読み込み
37tlsconfig, err := newTLSConfig()
38if err != nil {
39log.Print("error: newTLSConfig error.\n")
40return nil, err
41}
42// AddBrokerでAWS IoTのエンドポイント設定
43opts := MQTT.NewClientOptions().
44AddBroker(fmt.Sprintf(awsIotHostName, hostName)).
45SetClientID(clientID).
46SetTLSConfig(tlsconfig).
47SetDefaultPublishHandler(f)
48
49return MQTT.NewClient(opts), nil
50}
プログラムのbuildはmac上でしてscpでRaspberry Piに転送して動かしました。
実行時のコマンド
1./build/deploy/cmd/${PROJECT_NAME} \
2-host-name xxxxxxxx.iot.ap-northeast-1.amazonaws.com \
3-client-id testDevice-1 \
4-client-certificate certificate.pem.crt \
5-ca-certificate root-CA.crt \
6-private-key private.pem.key \
7-thing-name testDevice
引数で証明書のパスとかを指定します。センサのPIN番号も引数にしてもいいかもですね。
このあたりのコマンドはMakefile用意しておいて実行できるようにしています。(引数わすれるので。)
https://github.com/kawakattsun/iot-motion-sensor-go/blob/master/Makefile_go
動かしてみた
左がRaspberry Piにsshしてターミナルからコマンド実行した画面。
右はAWS IoTの 管理 > モノ からシャドウという項目をみています。
ちょっと見にくいですが連動して更新されていますね!
ターミナルの表示は
●センサが検知
motion-detected
Message Publish Success
●検知後
motion-stopped
Message Publish Success
どうも検知したあと一定時間で必ずstoppedになるようですね…
この後
次はシャドウの更新をさらにAWS上のサービスに流せるので最終的にLambdaで状態判定して在室検知判定しようと思います。
当初AWS IoTからLambda直で流す予定でしたが、On Offが必ずセットでくるのでkinesis にデータを流して一定期間のレコードからLambdaで判定にしようかな、と思案中。
続きは次回ブログで公開したいと思います。
乞うご期待!
※その2公開しました
「AWS IoT Core にRaspberry Piから赤外線モーションセンサのログを送る その2 ~ブラウザで会議室の使用状況を確認できるようにする」