低電力にポスト投函検出してLINE通知
概要
ESP32 MCUリーフと4-Sensorsリーフの加速度センサを利用して、ポストの開け閉めを検出します。
バッテリーを長持ちさせるためにESP32は主にDeep Sleep
状態で、ポストが開いたときに加速度センサから割り込み信号を生成します。
ESP32が立ち上がってからGoogle Apps Script
にデータを送信して、そこからLINEに通知を送信します。
実際にこのシステムは東京大学の桜井研究室で利用されています。
その時の開発のポイントや、どのように役立っているのかを動画にまとめました。
LINE通知サービスの設定
LINE通知にはLINE Notifyを利用します。
-
LINE Notifyのトップページから自分のLINE IDを使ってログインしましょう。
-
メールアドレスとパスワードを入力します。
-
ログイン後にトップ画面からマイページを開きます。
-
トークンの新規作成ボタンをクリック。
-
トークンの名前を入力し、通知を送信するグループを選択する。
-
トークンが発行されたら、しっかりとコピーして下さい。
この画面を閉じたらこのトークンの記号列は二度と表示されなくなります。
-
トークンの生成が完了しました。設定したLINEにもメッセージが届いているはずです。
Googleクラウドサービスの設定
Google Apps Script
の設定はGoogle Sheetsを使ったIoTサービスの内容を参照します。
コードはGithubのgoogle_scripts_code.js
にアップされています。
-
Google Sheetsの準備の1-3の手順に沿ってスプレッドシートの用意をします。
-
Google Sheetsの準備の4の部分で以下のコードを貼り付けます。
その際,以下の箇所を適宜修正してください。- 3行目: LINE通知サービスの設定の6の画面で発行されたトークンの記号列に置き換える
var token = "line_notify_token"
- 16-17行目: GoogleスプレッドシートのID
let id = 'google_sheets_id'; let sheetName = 'sheet_name';
- 44行目: LINEに送るテキストメッセージ
例のように+
でテキストと変数を連結できます。var lineMessage = "ポストに投函ました\n現在のバッテリーの電圧:" + e.parameter.battery + "[V]";
1// LINEへの送信処理 2function sendToLine(text){ 3var token = "line_notify_token"; 4 5 var options = 6 { 7 "method" : "post", 8 "payload" : "message=" + text, 9 "headers" : {"Authorization" : "Bearer "+ token} 10 }; 11UrlFetchApp.fetch("https://notify-api.line.me/api/notify", options); 12} 13 14function doGet(e) { 15 16 let id = 'google_sheets_id'; 17 let sheetName = 'sheet_name'; 18 var result; 19 20 // e.parameter has received GET parameters, i.e. temperature, humidity, illumination 21 if (e.parameter == undefined) { 22 result = 'Parameter undefined'; 23 } else { 24 var sheet = SpreadsheetApp.openById(id).getSheetByName(sheetName); 25 var newRow = sheet.getLastRow() + 1; // get row number to be inserted 26 var rowData = []; 27 28 // get current time 29 rowData[0] = new Date(); 30 rowData[1] = e.parameter.UniqueID; 31 rowData[2] = e.parameter.temperature; 32 rowData[3] = e.parameter.humidity; 33 rowData[4] = e.parameter.illumination; 34 rowData[5] = e.parameter.battery; 35 36 // 1 x rowData.length cells from (newRow, 1) cell are specified 37 var newRange = sheet.getRange(newRow, 1, 1, rowData.length); 38 39 // insert data to the target cells 40 newRange.setValues([rowData]); 41 result = 'Ok'; 42 } 43 44 var lineMessage = "ポストに投函されました\n現在のバッテリーの電圧:" + e.parameter.battery + "[V]"; 45 sendToLine(lineMessage); 46 47 return ContentService.createTextOutput(result); 48}
- 3行目: LINE通知サービスの設定の6の画面で発行されたトークンの記号列に置き換える
-
Google Sheetsの準備の6-12の手順に沿ってデプロイします。
Google Sheetsの動作確認と修正
Google Sheetsを使ったIoTサービスの以下の項目を参照してください。
Leafonyの準備
使用するリーフ
ESP32 MCUリーフと4-sensorリーフを重ねます。
書き込みプログラム
ESP32にGithubに上がっている以下のファイルをESP32 MCUリーフに書き込みます。
- ESP32_Post_Notify.ino
- MyLIS3DH.cpp
- MyLIS3DH.h
システム全体の制御フローは以下の図ように設計します。
Wi-Fiの設定
ESP32_Post_Notify.ino
にWi-FiのSSIDやパスワードなどの設定項目があります。
重要な項目を箇条書きにしたので、適当に設定してください。
-
Wi-Fiを使ってネットに接続する場合は
USE_WiFi
を定義します。#define USE_WiFi
-
接続先のWi-FiがWPA2 Personal(自宅のルーターなどで利用される認証方式。通常これ)を利用しているときは以下の変数にSSIDとパスワードを格納します。
const char* SSID = "wifi-ssid"; // WiFi SSID const char* PASSWORD = "wifi-pass"; // WiFi Password
-
特に、接続先のWi-Fiが大学や企業などにあり、EduroamなどのWPA2 Enterpriseを使用しているときのみ、以下を定義します。
#define USE_WiFi_ENTERPRISE
Wi-Fi Enterprise用のIDやパスワードは以下に入力してください。
///////////////////////////////////////////////////////////////////////////////////////////////////// // parameters for connecting eduroam enterprise ///////////////////////////////////////////////////////////////////////////////////////////////////// #define EAP_IDENTITY "eap_id" //if connecting from another corporation, use identity@organisation.domain in Eduroam #define EAP_PASSWORD "eap_pass" //your Eduroam password const char* SSID_ENT = "eduroam"; // Eduroam SSID /////////////////////////////////////////////////////////////////////////////////////////////////////
接続先Googleクラウドの設定
ESP32_Post_Notify.ino
で接続先Googleスクリプトの設定を行っています。
Googleクラウドサービスの設定の3で設定したGoogle Apps Scriptの固有IDを以下の変数に格納します。
const char* KEY = "google_scripts_key";
スリープ動作
Wi-Fiに接続してデータを送った後は,EP32 MCUがDeep Sleep
モードに入ることで待機電力を極力減らします。
Deep Sleep
モードに入る前にESP32 MCU内のWi-Fiモジュールの電源を切ることを忘れないでください。
WiFi.disconnect(true) // Wi-Fiをオフにするために,trueを明示してください
加速度センサ(LIS3DH)の設定
加速度センサ用の設定パラメータはレポジトリに上がっているMyLIS3DH.cpp
で修正できます。
実際に身の回りのポストに実装する場合にはパラメータを環境に合わせて設定する必要があります。
今回は例として、以下のように蓋が開閉するポストを考えます。
加速度センサが生成できる割り込み信号は独立に2つ(INT1
, INT2
)あり、そのうちのINT1
を使います。
データシートによると割り込み信号の指定にはCTRL_REG3
というレジスタに書き込みます。
CTRL_REG3
の説明をデータシートから読んでみます。
データシートから、I1_AOI1
ビットを1
に設定するとINT1
の割り込みが有効になります。
よって、以下のようにプログラムします。
writeRegister8(LIS3DH_REG_CTRL3, 0x40);
割り込み信号を生成するための条件(どのような振動の場合に割り込み信号を生成するのか、等)を設定できるのですが、今回主に設定するパラメータは以下の4つです。
閾値 (Threshold)
ポストの蓋の裏面にリーフが張り付けると、蓋が傾いた時に、加速度センサからみた重力加速度の向きが変化します。
この加速度の向きを検出することが出来れば、郵便物が投函されたかどうかセンシング出来ます。
いま、実験により、郵便物が投函されるとき蓋が少なくとも10度は傾くことが分かったとします。
そのとき、加速度センサのz軸方向の加速度(図中の緑色の矢印)が0g
から0.17g
まで増加することが分かるので、この0.17g
を閾値に設定してあげれば良さそうです。
一方、加速度センサのLIS3DHはデフォルトでフルスケールが±2gの検出を行います。
(これはESP32_PostNotify.ino
で設定されています。)
lis.setRange(LIS3DH_RANGE_2_G); // 2, 4, 8 or 16 G!
データシートによると、使用している加速度センサは軸の正(負)方向に対してそれぞれ128段階の分解能(フルスケールで8-bitの分解能)を持っています。
0.17gが2gに対して、どのレベルなのかを128段階のレベルで表すと、
128 / 2g * 0.17g = 10.88
なので、閾値レベル11
(16進数では0x0B
)を設定します。
この閾値の情報はINT1THS
というレジスタに書き込みます。
一応、レジスタの情報をデータシートから確認してみると、書き込める数値は0~127までだということが分かります。
プログラムでは以下のように記述します。
writeRegister8(LIS3DH_REG_INT1THS, 0x0B);
検出軸 (Detection Axes)
閾値の項目で考えた通り,今回は加速度の3軸のうち1つの軸のみを使って郵便物の投函を検出します。
軸の選択には、以下の2つのレジスタに書き込みます。
-
CTRL_REG1
センシングする3軸方向の加速度の有効・無効の設定を行います。
使用する軸以外は無効にすることで電力を抑えられ、バッテリーが長持ちします。
また、低電力モード(Low Power Mode)とサンプル周波数の設定もこのレジスタで行います。 -
INT1_CFG
割り込み用に設定する軸方向の決定を行います。
また、軸の選択以外に割り込み信号の発生方法も設定出来ます。
CTRL_REG1に関して、今回の用途では、以下のように設定しようと思います。
- Z軸方向のみで検出を行う
- 理由は後述するが、10Hzで加速度をサンプリングを行う
- 低電力モードも使う
よってデータシートから、レジスタはODR3からXenまで順に00101100
と設定すればいいので以下のようにプログラムします。
writeRegister8(LIS3DH_REG_CTRL1, 0x2C);
INT1_CFGに関して、上のデータシートに、AOI
と6D
というよく分からない項目があります。
データシートのTable 48.を見てみると、どうやらAOI
と6D
を使って割り込み信号を生成する方法を設定できるようです。
ORとANDの条件は各軸それぞれに対して割り込みを発生させるときの条件として考えれば良さそうです。
一方、6 direction movement
と6 direction position recognition
はここからだとよく分かりません。
それらの説明はアプリケーションノートに以下のように記述されていました。
少し難しいですが簡単にまとめると、こんな感じになります。
- 6D movement: 指定した閾値を超えたときと、そこから戻るときに一瞬だけ割り込み信号を生成
- 6D position: 指定した閾値以上になっている間、常に割り込み信号を生成
また、このアプリケーションノートのFigure 12から、X・Y・Z軸の中でも、上方向と下方向で別々に割り込み処理を設定できるということも分かりました。
これらの設定がINT1_CFGのZHIE/ZUPE``ZLIE/ZDOWNE
・・・XLIE/XDOWNE
の箇所で設定できるようです。
以上のことから、割り込み信号の生成条件としては、
- Z方向の割り込み信号のみを有効
- Z方向の指定した閾値を超えたときに一瞬だけ割り込み信号を生成する
以下のようにプログラムすれば良いと分かりました。
writeRegister8(LIS3DH_REG_INT1CFG, 0x70);
サンプリング周波数 (Sampling Rate) & 時間幅 (Duration)
サンプリング周波数と時間幅は関連しているので、一緒に説明します。はじめにそれぞれを簡単に説明します。
- サンプリング周波数:センサが加速度を取得する時間間隔を設定できます。周波数が上がるほど,時間分解能は上がりますが,その分センサの消費電力も増加してしまいます。
- 時間幅:割り込み信号が発生するまでに閾値を何秒間越えなければいけないか、という条件を設定できます。
ポストの蓋に何かがぶつかってしまったりなど、たまたま環境ノイズを拾ってしまったりしたときに、誤って検知してしまうことを防げます。
郵便物が投函されたときに加速度センサの応答が図のように0.3秒以上閾値を超えるとし、それ以下の場合は環境ノイズとして処理します。
この場合、サンプリング周波数は10Hzで設定すれば問題なさそうです。
検出軸の項で説明した通り、設定レジスタはCTRL_REG1
です。
ODR0
-ODR3
でサンプリング周波数を決定できます。
再掲ですが、以下のようにプログラムします。
writeRegister8(LIS3DH_REG_CTRL1, 0x2C);
時間幅の設定レジスタはINT1_DURATION
です。実際にセンサは連続時間を測っているわけではなく、サンプリング回数で時間間隔を計算しています。
0.3秒以上閾値を超えるようであれば、割り込み信号を生成します。
今回はサンプル周波数を10Hz
で設定しており、設定値は以下のように計算します。
0.3 / 0.1 = 3
これは以下のようにプログラムします。
writeRegister8(LIS3DH_REG_INT1DUR, 0x03);
実行結果
ESP32を傾けたときにスリープから立ち上がり、Wi-Fiに接続してからLINE Notifyに通知を送信します。
LINE Notifyで受け取った画面は以下のようになります。