• 加筆
  • 2018.01.26
  • 修正
十二月
29
金曜日

ドアの動き検知システムの構築1

TWELITE 2525Aというコイン電池で動く500円玉相当の小型加速度センサーなるものを見つけた。
MONOSTICKというUSBスティックを併用することでTWELITE 2525Aのセンサーデータをリアルタイムに受信することができる。
これがあれば電子工作能力ゼロの自分にもIoTっぽい何かが出来そうな気が沸々と沸いてきたので早速これを使ってドアが動いた事を検知する鳴子のようなシステムを構築してみる。


完成イメージ

  1. TWELITE 2525Aを対象のドアに貼り付け。
  2. Raspberry Pi3にMONOSTICKを差しアプリケーションからドアの動きを常時モニタリング。
  3. 検知したドアの動きをリアルタイムにAWS IoT上のMQTTトピックへパブリッシュ。
  4. パブリッシュされたドアの動きを Amazon Kinesis Data Firehose経由でS3に蓄積。
  5. S3に蓄積したドアの動きデータをAmazon Athenaからクエリで参照できるように。
  6. ドアの動きを検知したらSlackの任意のチャネルへ投稿するようにする。

この記事のゴールと作業の流れ

まずは完成イメージの 3. 検知したドアの動きをリアルタイムにAWS IoT上のMQTTトピックへパブリッシュ までを実装する。

作業の流れは以下の通り。

  • TWELITE 2525Aの設定変更とMONOSTICKのファーム更新
  • AWS IoTのセットアップ
  • IAMの設定
  • アプリケーションの作成
  • Raspberry Pi3上にアプリケーション実行環境を用意

TWELITE 2525Aの設定変更とMONOSTICKのファーム更新

子機であるTWELITE 2525Aはデフォルトで 無線タグアプリ がインストール済みであるが、親機であるMONOSTICKには無線タグアプリではなく 超簡単!TWELITE標準アプリがインストールされている。超簡単!TWELITE標準アプリは試作やデモ用途に用意されており応答性や省電力は追求されていないとのことなので無線タグアプリに変更する。
また子機側の設定もデフォルトでは接続先の親機を超簡単!TWELITE標準アプリとするなっているためこちらも併せて修正する。

これらの作業は以下の手順で行う。

  1. アプリ更新用ユーティリティのセットアップ
  2. 無線タグアプリの取得
  3. 子機の設定変更
  4. 親機のアプリ更新

アプリ更新用ユーティリティのセットアップ

アプリの更新は TWELITE NET SDK に付属するtweterm.py を利用する。
今回はmacOS上で作業を行うためmacOS用2017/8月号 SDKを利用した。

ダウンロードしたzipを解凍し ~/opt/TWELITE/MWSDK へ配置。

次にtweterm.pyの実行に必要なものを揃える。

まずはHomebrewでpython3とlibusbをインストール。

$ brew install python3

$ python3 -V
Python 3.6.3

$ brew install libusb

python3.3から標準モジュールとして導入されvenvを使用して今回専用のPython仮想環境を作成する。

$ python3 -m venv ~/.venv/TWELITE

作成したPython仮想環境を有効化する。
自環境ではfish shellを利用しているのでactivate用のシェルもfish用を使用。

$ . ~/.venv/TWELITE/bin/activate.fish
(TWELITE)  ~

pip経由で pyserialと pyftdi をインストール。

$ pip install pyserial
$ pip install pyftdi

一旦Python仮想環境を終了する。

$ deactivate 

無線タグアプリの取得

今回使うTWELITE 2525Aは少し古く搭載されている無線タグアプリはV1.6.1であるためこれと互換性のあるバージョンを入手する。
無線タグアプリのダウンロードページからv1.6.2 親機・子機用をダウンロード。

zipを解凍し、 ~/opt/TWELITE/Samp_Monitor_bin_1_6_2 へ配置。

子機の設定変更

TWELITE 2525Aのデフォルト設定では「親機を超簡単!TWELITE標準アプリにする」が有効になっているが今回親機は無線タグアプリを利用するためこの設定をオフにする。
設定の変更はOTA(Over The Air)と呼ばれる無線経由の設定変更が可能であるためこれを利用する。

OTAには親機と専用のアプリが必要であるため一旦MONOSTICKをOTA用アプリに更新しTWELITE 2525Aを無線経由で設定する。

まずは事前にFTDI関連のドライバをアンロードしておく。

$ sudo kextunload -b com.apple.driver.AppleUSBFTDI

TWELITE252Aにボタン電池が装填済みである場合は、一旦外しておく。

今回用に作成したPython仮想環境を有効化する。

$ . ~/.venv/TWELITE/bin/activate.fish
(TWELITE)  ~

MONOSTICKをUSBに差し込み、以下コマンドでデバイスが認識されるか確認する。

$ ~/opt/TWELITE/MWSDK/Tools/tweprog_py/tweterm.py -p "ftdi:///?"
Available interfaces:
  ftdi://ftdi:232:MWM9S1D/1   (MONOSTICK)

tweterm.py で無線タグのOTA用アプリを書き込む。

$ ~/opt/TWELITE/MWSDK/Tools/tweprog_py/tweterm.py \
    -p ftdi://ftdi:232:MWM9S1D/1 \
    -b 115200 \
    -F ~/opt/TWELITE/Samp_Monitor_bin_1_6_2/App_Tag_EndDevice_Input_JN5164_OTA_1_6_2.bin

OTA用アプリの書き込みが完了すると子機用の設定変更モードが立ち上がる。

--- CONFIG/App_Tag V2-00-3/SID=0x810e149b/LID=0x00/RC=10000 ---
 a: set Application ID (0x67726305)
 i: set Device ID (--)
 c: set Channels (15)
 x: set Tx Power (13)
 b: set UART baud (38400)
 B: set UART option (8N1)
 k: set Enc Key (0xA5A5A5A5)
 o: set Option Bits (0x00000011)
 d: set Sleep Dur (5000)
 w: set Sensor Wait Dur (0)
 m: set Sensor Mode (0x35)
 p: set Sensor Parameter (15)
 P: set Sensor Parameter2 ( )
---
 S: save Configuration
 R: reset to Defaults
 *** POWER ON END DEVICE NEAR THIS CONFIGURATOR ***

設定項目の詳細については無線タグアプリの設定変更(インタラクティブ)モード 『子機の設定』を参照。

今回はオプションビットに設定されている「親機を”超簡単!TWELITE標準アプリ”にする」(0x00000010)を無効にする。

o を選択し新しいオプションビットに1を指定。

Input option bits (HEX): 1
-> 0x00000001

動作モード1/2(Tap/Double Tap)の感度を上げるためパラメータをカスタマイズする。
動作モードとパラメータの詳細についてはTWELITE 2525A設定の詳細 『動作モードとパラメータ変更』を参照。

P を選択し

THT=300を指定。

Input Sensor Parameter : THT=300
-> THT=300

S で保存。

この状態でMONOSTICKとなるべく近い位置でTWELITE 2525Aに電池を装填する。

電池を装填するとMONOSTICKの黄色と赤のLEDが点灯し、ターミナルに以下のメッセージが表示される。

SUCCESS <SID>

以上でOTA設定が成功。設定は子機に反映されている。

CTRL-C を二回押してOTAを終了する。

親機のアプリ更新

事前にFTDI関連のドライバをアンロードしておく。

$ sudo kextunload -b com.apple.driver.AppleUSBFTDI

今回用に作成したPython仮想環境を有効化する。

$ . ~/.venv/TWELITE/bin/activate.fish
(TWELITE)  ~

MONOSTICKをUSBに差し込み、以下コマンドでデバイスが認識されるか確認する。

$ ~/opt/TWELITE/MWSDK/Tools/tweprog_py/tweterm.py -p "ftdi:///?"
Available interfaces:
  ftdi://ftdi:232:MWM9S1D/1   (MONOSTICK)

tweterm.py で無線タグの親機用アプリを書き込む。
今回利用しているMONOSTICKは標準出力タイプ(BLUE)であるため、BLUE用の親機アプリを利用する。

$ ~/opt/TWELITE/MWSDK/Tools/tweprog_py/tweterm.py \
    -p ftdi://ftdi:232:MWM9S1D/1 \
    -b 115200 \
    -F ~/opt/TWELITE/Samp_Monitor_bin_1_6_2/App_Tag_Parent_JN5164_MONOSTICK_1_6_2.bin

以下メッセージが表示されたら更新完了。

0%..10%..20%..30%..40%..50%..60%..70%..80%..90%..done - 10.51 kb/s
Entering minicom mode

続いて子機で得られたセンサ情報についての親機側の出力形式をセミコロン区切りに設定する。
設定項目の詳細については無線タグアプリの設定変更(インタラクティブ)モード 『親機の設定』を参照。
また出力形式の詳細についてはTWELITE 2525A設定の詳細 『親機のUART出力』を参照。

CTRL-C i で設定変更モードに入る。

--- CONFIG/App_Tag V2-00-3/SID=0x810e149b/LID=0x00 ---
 a: set Application ID (0x67726305)
 c: set Channels (15)
 x: set Tx Power (3)
 b: set UART baud (38400)
 B: set UART option (8N1)
 k: set Enc Key (0xA5A5A5A5)
 o: set Option Bits (0x00000001)
---
 S: save Configuration
 R: reset to Defaults

o を選択し新しいオプションビットに0x20(UART出力をセミコロン区切り形式で出力)を指定。

Input option bits (HEX): 20
-> 0x00000020

S で保存。CTRL-C を二回押して設定変更モードを終了する。

以上で親機側も無線タグアプリとなり子機からのセンサーデータをセミコロン区切り形式で出力するようになった。

AWS IoTのセットアップ

AWS IoTに計測対象となるドアを表す「モノ」を作成する。
ドアの動きによって発生する加速度情報はMQTT経由でこのモノの状態を更新していくという形となる。

AWSマネージメントコンソールから AWS IoT を開く。

タイプの作成

管理 タイプ モノのタイプを作成する から 新規にモノのタイプを作成する。

名前
door

モノのタイプの作成 ボタンを押下して作成。

グループの作成

管理 グループ モノのグループを作成する から 新規にモノのグループを作成する。

名前
door

モノのグループの作成 ボタンを押下して作成。

モノの登録

管理 モノ モノの登録 単一のモノを作成する から 新規にモノを登録する。

名前
door1
モノのタイプ
door
モノのグループ
door

次へ 証明書なしでモノを作成

IAMの設定

MQTTで接続しドアを表す「モノ」のトピックを更新する際に利用するユーザ、グループ、ポリシーを作成する。
ここで作成したユーザのアクセスキーIDとシークレットアクセスキーはMQTT接続する際の署名付きリクエストを作成するために利用する。

AWSマネージメントコンソールから IAM を開く。

ポリシーの作成

ポリシー ポリシーの作成 から JSON で以下ポリシーを作成。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "sid1",
            "Effect": "Allow",
            "Action": "iot:Connect",
            "Resource": "arn:aws:iot:ap-northeast-1:<アカウントID>:client/naruko"
        },
        {
            "Sid": "sid2",
            "Effect": "Allow",
            "Action": "iot:Publish",
            "Resource": "arn:aws:iot:ap-northeast-1:<アカウントID>:topic/$aws/things/door1/shadow/update"
        }
    ]
}

内容としては、まず sid1 でクライアントID naruko でMQTTブローカーへ接続できるよう Connect権限を付与した。 このクライアントIDはMONOSTICKを読み取りドアの動作情報をMQTTトピックへパブリッシュするアプリケーションが利用する。

次にsid2にてAWS IoT側で作成したドアを表すモノ door1 のシャドウ更新トピックへのPublish権限を付与した。

Review policy 押下。

名前
NarukoMQTTPublisher

Create policy 押下でポリシーを作成。

グループの作成

グループ から 新しいグループの作成

グループ名
DoorMonitor

次のステップ

作成したポリシー NarukoMQTTPublishewr をアタッチ。

次のステップ グループの作成

ユーザの作成

ユーザ から ユーザを追加

ユーザ名
naruko
アクセスにお種類
プログラムによるアクセス

次のステップ:アクセス権限

ユーザをグループ DoorMonitor へ追加。

次のステップ:確認 ユーザーの追加 でユーザを作成。

アクセスキーIDとシークレットアクセスキーをメモしておく。

アプリケーションの作成

MONOSTICKからTWELITE 2525Aの加速度情報を読み取りAWS IoT上のMQTTトピックへパブリッシュするアプリケーションnaruko-mqtt-publisherを作成した。

Golang

本当はClojureScript(on Node.js)で書きたかったのだがRaspberry Pi3上(32ビットOSなのでARMv7)でのUSBシリアルポートへのアクセスが難航しそうな予感がしたので日和ってGolangを選択。

  • USBシリアルポートのアクセスにはtarm/serial
  • MQTTクライアントにはpaho.mqtt.golang
  • コンフィグレーションフィアル、環境変数の参照にviper
  • go-bindataでコンフィグレーションを含んだシングルバイナリ
  • seelogでロギング

Spacemacsでコードを書いてみた。 詳細は『SpacemacsでGolang』を参照。

MQTT

AWS IoT側との接続プロトコルには名前のMQTTではなくMQTT over WebSocketを使用。そのため認証はクライアント証明書ではなくAWS署名バージョン4を利用。

署名付きリクエストは作成したURLが有効期限を持つため paho.mqtt.golang の AutoReconnectは利用することができなかった。
変則的ではあるが接続が切れたら再接続ではなくクライアントごと作り直す方法で対応した。

ビルド

macOS上でアプリケーションがうまく動いたらRaspberry Pi3上で動かすためのクロスコンパイルしてARMv7用のバイナリを作成する。

GOOS=linux GOARCH=arm GOARM=7 go build -o bin/naruko_arm7

非力なRaspberry Pi3上ではなくmacOS上でビルドが完結するのはとても便利。

Raspberry Pi3上にアプリケーション実行環境を用意

Raspberry Pi3上に鳴子の実行環境を用意する。

ディレクトリを作成

$ sudo mkdir /opt/naruko
$ sudo chown pi:pi /opt/naruko

バイナリを配置

macOS上からscpでビルドした鳴子のARMv7バイナリを配置。

scp bin/naruko_arm7 pi@<Raspberry Pi3のIPアドレス>:/opt/naruko

envファイルを作成

EnvironmentFileを作成。

$ touch /opt/naruko/env
$ chmod 600 /opt/naruko/env

/opt/naruko/env の内容は以下

ACCESS_KEY_ID=<署名付きリクエストで使用するアクセスキーID>
SECRET_ACCESS_KEY=<署名付きリクエストで使用するシークレットアクセスキー>
AWS_IOT_ENDPOINT=wss://<エンドポイント>.iot.<リージョン>.amazonaws.com/mqtt
MONOSTICK_DEVICE=/dev/ttyUSB0

systemdユニットファイルを作成

naruko用のユニット定義を追加。


sudo chmod 664 /etc/systemd/system/naruko.service

/etc/systemd/system/naruko.service の内容は以下。

[Unit]
Description=Naruko
After=network-online.target

[Service]
WorkingDirectory=/opt/naruko
EnvironmentFile=/opt/naruko/env
ExecStartPre=/bin/sleep 20
ExecStart=/opt/naruko/naruko_arm7

[Install]
WantedBy=network-online.target

有効化して確認。

sudo systemctl enable naruko.service
sudo systemctl list-unit-files -t service

起動

sudo systemctl start naruko.service

ログを確認。

journalctl -f -u naruko.service

ちなみに以前の 『Raspberry Pi3 Model Bセットアップ』で「起動時にネットワーク接続完了まで待つようにする」設定を入れた上、After=network-online.targetとしたにも関わらずRaspberry Pi3ブート時にネットワークが利用可能になる前にnarukoサービスが起動しMQTT接続に失敗してしまう事象が発生。
苦肉の策として ExecStartPre=/bin/sleep 20 を入れサービスの起動にディレイを入れて回避した。

動作確認

以上でドアの動きによって発生する加速度情報がAWS IoT上のモノのシャドウステータスとして反映されるようになった。

AWSマネージメントコンソールから AWS IoT を開き、管理 モノ door1 から シャドウ を選択し以下のようなシャドウステータスを確認できる。

{
  "reported": {
    "publishedAt": "2017-12-28 18:31:00.200",
    "lqi": 192,
    "powerSupplyVoltage": 2715,
    "sensorMode": 10,
    "x": 1,
    "y": -6,
    "z": -100
  }
}

各プロパティの意味は以下の通り

プロパティ 説明
publishedAt ドアの動きを検知した日時(UTC)
lqi 電波強度(0〜255)
powerSupplyVoltage 電源電圧[mV]
sensorMode 動作モード
TWELITE 2525A設定の詳細
『動作モードとパラメータ変更』の項を参照


また上記シャドウステータスはドアが動く度にリアルタイムに更新される。


以上で本記事でのゴールである 検知したドアの動きをリアルタイムにAWS IoT上のMQTTトピックへパブリッシュ までが実現できた。
本来ドアの開閉をきっちり検知するのであれば磁力センサーを使用すべきだが、加速度センサーの場合はドアの開閉状態は分からないもののノック程度の振動も捉えることができるので別の面白さがありそうだ。

次回の『ドアの動き検知システムの構築2』ではドアの動き情報をS3に記録しAthenaから検索できるようにする。