ESP8266 評価ボードに「二度寝」を実装してみた

投稿者: | 2016/09/20

Implemented "snooze mode" to reduce wake-up frequency.  In other words, it goes to sleep again (N - 1) times an N wake-ups.

先日、ESP8266 を CR2032 コイン電池ひとつで動かす試作ボードを作りましたが、実際のところ、植木の水分測定のようなアプリケーションでは一日に 24回も「起き出す」必要はありません。一日に数回程度でも良いのではないでしょうか。

しかし ESP8266 の SDK で実装されている deep-sleep API では、与えられる時間が 32ビット符号無し整数(単位はマイクロ秒)で、おおむね 1.2時間に制約されます。おそらく、これは内部の低消費電流タイマハードウェアで実装しているでしょうから、ソフト的に変更するのは困難と思われます。一つの代替案として、deep-sleep API に 0 を与えて、外部からトリガを与えられるまでは起きないようにするという方法もありますが、ESP8266 単体で実現できる簡単な方法はないものでしょうか。

諦めかけていたところ、知り合いの K さんという技術者がヒントをくださいました。すなわち「二度寝すれば如何?」

面白いアイデアなので実装してみました。deep-sleep から起き上がったとき、カウンタ値(変数)を確認して、例えば 3回に 1回だけ測定および HTTP 通信を実施し、それ以外はすぐに寝てしまう、という方法です。問題は、deep-sleep から起きると変数値は全てクリアされてしまう(Python の実行系がリセットされてしまう)ということです。そこで、変数値をローカルストレージに保管して、再度読み出すようにしてみます。

MicroPython のコードでは、次のような感じです。

global global_ct
storage = "storage.txt"

def read_global_vars():
    global global_ct
    try:
        f = open(storage, "r")
        global_ct = int(f.readline())
        f.close()
    except (OSError, ValueError):
        global_ct = 0
    print("global_ct = %d" % (global_ct))

def write_global_vars():
    f = open(storage, "w")
    f.write("%d\n" % (global_ct))
    f.close()

read_global_vars()

if global_ct % 3 == 0:
    # start_network()
    # wait_network_up()
    # test_http()

global_ct += 1
write_global_vars()

import esp
esp.deepsleep(1000000 * 60)

あまり綺麗なコードではありませんが、アイデアを示しているだけ、ということで御容赦ください。Python の構文をうまく使えば、複数の変数値を保存できるエレガントなコードが書けるかも知れません。(ちなみに MicroPython には pickle ライブラリが入っていないようなので、pickle はできません。)

実際に試したところ、このコードの実行には 0.6〜0.7秒程度の時間がかかることが分かりました。つまり、0.1C(クーロン)程度の電流量を消費してしまうのです。結果として、仮に 3回のうち 2回を「二度寝」したとしても、消費電力量を 1/3 に抑えることはできません。それでも若干の電池節約にはなりそうです。

もっと消費電流を抑えられないか?

ESP8266 のデータシートを読むと、sleep モードというものがあって、Wi-Fi を使わなければ 10mA(ミリアンペア)程度まで消費電流を落とすことができると書かれており、MircoPython 1.8.4 辺りでも実装されているようなのですが、ESP8266 SDK API の使い勝手があまり良くないようで、MicroPython との親和性が悪いようです。議論は、この辺にあります。将来、うまい方法が実装されるのを待ちたいと思います。(もしかすると、SDK API 側の改良も盛り込まれてくるかも知れません。)