Wio LTEを省電力に使おう

Wio LTEのユーザーさんが、タワーマンションの郵便受けの監視を作ってみたという記事(タワマンとWio LTE)を書いてくださいました。実際にWio LTEを使って何かを作ってみたという記事を読むのは、興味深く、とても嬉しいです。

MAX氏も著者の方にアドバイスしてくださったみたいですが、LTEモジュールを使って通信をすると、とても大きな電力を消費してしまいます。できるだけイベントのハンドリングはWio LTEのマイコンで処理して、LTE通信は必要なときにのみ行う様にしたほうがパワーコンサンプション的にも、通信量(料?)的にも優しいです。

実際のスケッチを見てみると、ああそういうことかと理解してもらえると思いますので、サンプルスケッチを書いてGistに置いてみました。

#include <WioLTEforArduino.h>
#include <stdio.h>
#define APN "soracom.io"
#define USERNAME "sora"
#define PASSWORD "sora"
#define WEBHOOK_EVENTNAME "ENTER_YOUR_WEBHOOK_EVENTNAME_HERE"
#define WEBHOOK_KEY "ENTER_YOUR_WEBHOOK_KEY_HERE"
#define WEBHOOK_URL "https://maker.ifttt.com/trigger/"WEBHOOK_EVENTNAME"/with/key/"WEBHOOK_KEY
#define INTERVAL (60000)
// You can use WIOLTE_(D20|A4|A6) with `Wio.PowerSupplyGrove(true);`
#define BUTTON_PIN (WIOLTE_D38)
WioLTE Wio;
volatile bool State = false;
void post_to_ifttt()
{
char data[100];
int status;
State = false;
SerialUSB.println("### Power supply ON.");
Wio.PowerSupplyLTE(true);
delay(500);
SerialUSB.println("### Turn on or reset.");
if (!Wio.TurnOnOrReset()) {
SerialUSB.println("### ERROR! ###");
return;
}
SerialUSB.println("### Connecting to \""APN"\".");
if (!Wio.Activate(APN, USERNAME, PASSWORD)) {
SerialUSB.println("### ERROR! ###");
return;
}
SerialUSB.println("### Post.");
sprintf(data, "{\"value1\":\"uptime %lu\"}", millis() / 1000);
SerialUSB.print("Post:");
SerialUSB.println(data);
if (!Wio.HttpPost(WEBHOOK_URL, data, &status)) {
SerialUSB.println("### ERROR! ###");
delay(INTERVAL);
}
SerialUSB.print("Status:");
SerialUSB.println(status);
SerialUSB.println("### Power supply OFF.");
Wio.Deactivate(); // Deactivate a PDP context. Added at v1.1.9
Wio.TurnOff(); // Shutdown the LTE module. Added at v1.1.6
Wio.PowerSupplyLTE(false); // Turn the power supply to LTE module off
attachInterrupt(BUTTON_PIN, change_state, RISING);
}
void change_state()
{
detachInterrupt(BUTTON_PIN);
// SerialUSB.println("Interrupt happen");
State = true;
}
void setup()
{
delay(200);
SerialUSB.println("");
SerialUSB.println("--- START ---");
SerialUSB.println("### I/O Initialize.");
Wio.Init();
pinMode(BUTTON_PIN, INPUT);
attachInterrupt(BUTTON_PIN, change_state, RISING);
}
void loop()
{
if (State) {
post_to_ifttt();
}
else {
delay(1000);
}
}

スケッチを見ていただけると、attachInterrupt()を使って割り込みが発生したときに、change_state()を呼び出し、detachInterrupt()してStateをtrueにしているのが見て取れると思います。

そして、loop()の中でStateを見て、trueのときpost_to_ifttt()を呼び、LTEモジュールの電源を入れて通信、通信を終えたらモジュールの電源を切った上で再びattachInterrupt()しています。

こういう構造にしているのは、最初、割り込みの処理に全てを書いたところ、print()など正常に処理が行われなくなったからです。(推測ですが、長い間割り込みの処理をしていると、ポーリング応答ができなくなってUSBシリアル接続処理などに問題が生じるのでしょう。)

さて、スケッチの中でボタンを接続するポートをD38と指定していますので、写真のポートにボタンを接続します。

スケッチを書き込んでリセットし、シリアルモニタを起動してボタンを押すと、シリアルモニタでこのように動作する状況が確認できると思います。LTEモジュールの電源を入れて通信をしたあと、電源を切っていることが確認できますね。(なお、LTEモジュールの電源を切るためのより良い関数を追加したライブラリを現在準備中です。年が明けてしばらくすれば公開すると思います。公開したら、この記事とサンプルスケッチもその関数を使って電源を切るように更新したいと思います。)

(2018年1月22日追記)ライブラリをアップデートし、上記のスケッチで、より良い方法で電源を切っています。コメントを参照してください。

また、このスケッチではWio LTEのマイコンは動かしっぱなしです。より省電力を目指すのであれば、マイコンもスリープさせるべきなのですが、それは次のステップに取っておきます。

最後に、テストはスイッチを使ってみましたが、Grove IoT スターターキット for SORACOMにも入っているGrove – 磁気スイッチでも、このスケッチのまま実行できます。

磁気スイッチに、この青いレターオープナーの端に付いている磁石を近づけると、ボタンを押したのと同じことになります。これを郵便受けのフタに工夫して付けておくとフタを開けたことを検出してIFTTTなどのウェブサービスに通知を飛ばすことができます。ぜひ、工夫して使ってみて、作例を教えてみていただけると嬉しいです。

最後に、早いものでもう年末です。今年はSeeed株式会社ができた年で、バタバタとしていたらあっという間に2017年が終わりそうでビックリしています。
それでは皆さま、良いお年を!来年もよろしくお願い致します。