話題の Wio Node を買うも、MicroPython 化するの巻

(更新

Firmlogics no longer recommend IFTTT, which was introduced below, to our customers.  Purchased a Wio Node but rewritten with MicroPython firmware which has OTA capability.

(前置き: ファームロジックスでは、現在お客様に IFTTT を推奨しておりません御参考

いつもの前ふりです。

最近、ソフト設計専門の知人が Raspberry Pi と Google Home を使って、家庭内機器の音声コントロールに挑戦しているそうです。私も負けじと AIY Voice Kit を購入して Google Assisntnt SDK の勉強中です。

私は Node.js や Firebase という単語にたじろいでいますが、いっぽうで彼のほうは Raspberry Pi の GPIO の電気的扱いで苦心されているようです。こんど、彼に Node.js を教えてもらおうと思っています。専門分野の異なる友人というのは大切なものですね。

Wio Node を買ってみた

さて前ふり終了。彼のように電気のことはあまり詳しくないけどソフトなら任せろ、という技術者にとって、最近はおもしろいボードが売られています。Seeed 社の Wio Link あるいは Wio Node というものです。こんなものです、じゃん!

売り文句を覗いてみましょう。

  • An  ESP8266 based open-source Wi-Fi development board
  • Supports Plug-n-Play Groves
  • Visual Configuration
  • OTA (Over-The-Air) Firmware Updates
  • RESTful APIs
  • IFTTT Application
  • Android & iOS APPs

簡単に言うと、

  • 流行りの ESP8266(Wi-Fi マイコン)を搭載し、
  • Grove と呼ばれる I/O(LED やセンサ、サーボモータなど)をプラグ & プレイで接続し、
  • スマホ画面で I/O の構成を決め、
  • RESTful API で制御でき、
  • さらに話題の IFTTT で世の中のあらゆる仕組とリンクできる

という素晴らしいツールです。はっきり言って、こんなのを出されたらワタシは失業だと思いました。

ライバル会社(?)のツールは(あまり高くない限り)購入して研究するのが私のポリシーなので、早速ポチりました。ちょうど良い題材があって、スマート電気コンセント(スマートプラグ, smart plug)を買って、部屋の湿度に応じて加湿器を制御してやろうと思っていたのです。(ちょうど、インフルエンザが流行っている時期です。)

必要なブツ

スマート電気コンセントは、こんなものです。

実はいろんな名称で売られていて、ここが本家(OEM 元)かと思うのですが、実はよく分かりません。とりあえず、Tuya という会社の Smart Life というアプリで制御できるもののようです。なにぶん、日本国内に限定すると電気用品安全法(PSE)的に怪しいものですし、御利用は皆さんの責任でお願いします。私も、とりあえずは仕事の実験室の中でのみ評価しようと思っています。くれぐれも、スマートプラグにコタツを繋いだまま外出したりしないように!

加湿器ですが、最近の高級すぎるものは中途半端でダメです。(いっそのこと、ネットワーク制御できるように初めから作られていればいいのですが。) 私が選んだのはこれです。

なぜか値上がりしてますが、私が以前購入したときは 3,000円くらいだったのです。

最後に必要なブツは温湿度センサーです。いままで、いろんなメーカーのセンサーを使っていますが、DHT22 も HTU21D も、使っているうちの湿度計の出力がおかしくなってしまいました。以前に使ったことのある Sensirion 社のセンサーは高価で購入がためらわれるものでしたが、最近は SHT31 とういうものが安価に売られているので、上記 Grove と呼ばれるセンサーの中から選んでみました。

というわけで、こんなガジェットを揃えました。

しかしここで問題が。

なんと、Wio Node は SHT31 センサーに対応してなかったのです!

Grove シリーズなのに…。(対応機器リストはここにありました。)

まず、ここを読み、続いてアドバンスト・ユーザー・ガイドを読んでみましたが、「スマホで 5分でセットアップ!」は、自分でサーバーを立てないと難しい感じでした。(サーバーの立て方は、ここにありますが試していません。)

そこで方針転換。やっぱり今回も、MicroPython 化したいと思います!

MicroPython のインストール

実は、MicroPython のインストールは難しくありません。なにしろ Wio Node で使われているモジュールは有名な ESP-WROOM-02 だからです。MicroPython は Espressif Systems 社の正規ファームウェアで実装されているので、技適の上でも問題ないはずです。

はっきり言って、MicroPython のウェブサイト通りに作業すればインストールできてしまうのですが、初めての方はハマることもあると思うので、備忘録的にまとめておきます。

UART をどう繋ぐ?

まず最初に、UART を接続します。なにしろ Wio Node はコンパクトに作られているので、UART の接続が大変です。FTDI のようなチップも搭載されていないので、Raspberry Pi 用などに売られている UART ケーブルなどが必要です。こんなのです。もっと安いものは eBay で見つかります。電圧は 3.3V である必要があります。また、ケーブルの先は一本ずつ分かれているものが応用が利いて便利です。

さて問題は、この UART 変換ケーブルをどうやって繋ぐか、です。幸い、Grove のセンサを買ってましたので、付属のケーブルを「うまく」使うことにしました。

まず、ケーブルの片側のコネクタからワイヤを外します。そのとき、ピンの配置を覚えておいてください。なお、赤のワイヤは 3.3V なので外さなくて良いです。(UART の接続は、Tx、Rx、GND だけで良いです。)

ワイヤには金具が付いていて、プラスチックの爪で固定されています。爪を折らない程度に持ち上げながらワイヤをそうっと引くと抜けます。

次に、このままでは Raspberry Pi 用のコネクタが刺さらないので(どちらもメスなので)、ジャンパワイヤを探してきます。こんなのを買っておくと便利です。ちなみに、どうせ SparkFun から購入するのなら、こういう発明家キット(?)を買っておくと、子供のベンキョウにも役立ちます。

閑話休題。うまくワイヤが外れたら、Wio Node の回路図(PDF)を参考にし、Wio Node の UART/I2C0/D0 と書かれたコネクタのうち黄色のワイヤを USB 変換ケーブルの Tx(送信)に、白いワイヤを Rx(受信)に、黒いワイヤを GND に繋ぐようにします。つまり、Wio Node の UART Tx は Rx に、Rx は Tx に、という具合に反対に結線することになります。なお、繰り返しになりますが赤線(3.3V)は繋がないでください。

なお、Grove のコネクタのピンは若干細く、普通のジャンパピンは刺さりません。そこで虫眼鏡などで見ながら、ピンのバネの反対側からジャンパピンを差すようにするとうまくいきます。(いわゆる TIPS です。 🙂 ) 以下の写真が参考になれば幸いです。

ファームウェアを書き込もう

そうしたらファームウェアの書き込みです。ここに説明がありますが、Windows の方は以下のサイトが参考になります。書き込みアドレスは 0 で良いはずです。

まず最初に、ESP8266 を ROM フラッシュモードにします。そのためには、Wio Node の FUNC ボタンを押したまま RST ボタンを押します。RST ボタンは 1秒くらいは押し続けたほうが良さそうです。

私は esptool.py を使いました。こんな具合です。

linux$ sudo esptool.py --port /dev/ttyUSB0 erase_flash
esptool.py v2.2
Connecting....
Detecting chip type... ESP8266
Chip is ESP8266EX
Uploading stub...
Running stub...
Stub running...
Erasing flash (this may take a while)...
Chip erase completed successfully in 17.5s
Hard resetting...

うまく行かない場合は、やり直してみてください。

つづいで、フラッシュに書き込みます。私は OTA 版を使いました。後で、OTA(Wi-Fi 経由でファームウェアを更新できる)の実験もします。

linux$ sudo esptool.py --port /dev/ttyUSB0 --baud 460800 write_flash --flash_size=detect \
       0 esp8266-ota-20171229-v1.9.3-238-g42c4dd09.bin
esptool.py v2.2
Connecting....
Detecting chip type... ESP8266
Chip is ESP8266EX
Uploading stub...
Running stub...
Stub running...
Changing baud rate to 460800
Changed.
Configuring flash size...
Auto-detected Flash size: 4MB
Flash params set to 0x0040
Compressed 821920 bytes to 546528...
Wrote 821920 bytes (546528 compressed) at 0x00000000 in 12.7 seconds (effective 517.7 kbit/s)...
Hash of data verified.

Leaving...
Hard resetting...

そうしたらリセットしてみましょう。

加筆(2018/03/04)

うまく行かない場合、

esptool.py --port /dev/ttyUSB0 write_flash --flash_size 32m 0 esp8266-ota-20171229-v1.9.3-238-g42c4dd09.bin

も試してみてください。

UART から MicroPython

まずは、ターミナルソフトを繋ぎます。私は Linux なので screen コマンドを使いましたが、Windows ならば  Tera Term などが良いでしょう。スピードは 115.2kbps です。

(バケバケの文字)
boot8266
HW RTC Reset reason: 2
System reset reason: 1
Initial GPIO state: c0030001, OE: 0
Running app
Writing init data
#0 ets_task(40245c10, 31, 3ffe9110, 4)
(またバケバケ)
Performing initial setup
bcn 0
del if1
usl
add if1
#5 ets_task(4024adc0, 29, 3fff9160, 10)
dhcp server start:(ip:192.168.4.1,mask:255.255.255.0,gw:192.168.4.1)
bcn 100
OSError: [Errno 2] ENOENT

MicroPython v1.9.3-238-g42c4dd09 on 2017-12-29; ESP module with ESP8266
Type "help()" for more information.
>>>

こんな風になれば OK です。

Wi-Fi の設定

最初に、Wi-Fi の設定をします。help() コマンドを実行すると説明が出ます。

>>> help()
Welcome to MicroPython!

For online docs please visit http://docs.micropython.org/en/latest/esp8266/ .
For diagnostic information to include in bug reports execute 'import port_diag'.

Basic WiFi configuration:

import network
sta_if = network.WLAN(network.STA_IF); sta_if.active(True)
sta_if.scan()                             # Scan for available access points
sta_if.connect("<AP_name>", "<password>") # Connect to an AP
sta_if.isconnected()                      # Check for successful connection
# Change name/password of ESP8266's AP:
ap_if = network.WLAN(network.AP_IF)
ap_if.config(essid="<AP_NAME>", authmode=network.AUTH_WPA_WPA2_PSK, password="<password>")

Control commands:
  CTRL-A        -- on a blank line, enter raw REPL mode
  CTRL-B        -- on a blank line, enter normal REPL mode
  CTRL-C        -- interrupt a running program
  CTRL-D        -- on a blank line, do a soft reset of the board
  CTRL-E        -- on a blank line, enter paste mode

For further help on a specific object, type help(obj)

なお、私のバージョンは OTA の daily ビルドのせいか、ときどきクラッシュします。OTA に興味のない方は安定版のほうが良いかも知れません。(私はいずれ、OTA の安定版が出たらアップデートするつもりです。なにぶん、Wio Node の UART 接続は面倒なので OTA に期待しています。)

後記(2018/01/02): OTA の安定版があるのを見つけました。esp8266-ota-20171101-v1.9.3 の OTA 版にアップデートしました。

話を戻して、次のように Wi-Fi を設定します。

import network
sta_if = network.WLAN(network.STA_IF); sta_if.active(True)
sta_if.scan()
sta_if.connect("アクセスポイントの ESSID", "パスフレーズ")
sta_if.isconnected()

これは help の説明にあるとおりですね。うまくいくと、

connected with なんとかかんとか, channel N
dhcp client start...
ip:192.168.x.x,mask:255.255.255.0,gw:192.168.x.y
>>> sta_if.isconnected()
True

のようになると思います。うまくいかずにスクロールが続く場合は、目をつむったまま 🙂 、

sta_if.active(False)

とタイプしリターンキーを押します。そして、

sta_if = network.WLAN(network.STA_IF); sta_if.active(True)

からやり直してみてください。なお、Wi-Fi の設定は不揮発メモリに記録されますので、リセットしても自動的にネットに繋がるようになります。

ネットからログインできるようにする

次に、WebREPL を設定しましょう。これがあると、USB シリアル変換ケーブルを繋がずともネットワークから操作できるので便利です。説明はここにありますが、やってみます。

>>> import webrepl_setup
WebREPL daemon auto-start status: disabled

Would you like to (E)nable or (D)isable it running on boot?
(Empty line to quit)
> e
To enable WebREPL, you must set password for it
New password (4-9 chars): ほげほげら
Confirm password: ほげほげら
Changes will be activated after reboot
Would you like to reboot now? (y/n) y

これで WebREPL が有効になるので、ウェブブラウザから http://micropython.org/webrepl にアクセスしましょう。現れる画面の左上に

ws://192.168.x.x:8266/

のように Wio Node に割り当てられて IP アドレスを入力し、Connect ボタンを押します。すると、次のようにログインができます。パスワードは、上記で設定したパスワードです。

あとはほぼ Python ですので、好きに遊べます。

ネットからファームウェアをアップデートできるようにする

最後に OTA(On-the-Air)ファームウェアアップデートをしてみましょう。これはまだベータっぽい機能のようで、正式リリースには入っていません。OTA 版の daily release にだけ入っている機能です。

まず、ここの説明にあるように yaota8266 というツールをインストールします。(サイトはここです。) Python で書かれているので、Windows の人は Python のインストールが必要です。Linux のほうが楽でしょう。

インストールができたら、まず OTA のコマンドをタイプし、リターンキーを押さずに待機します。ここで、192.168.x.x は Wio Node の IP アドレスです。

linux$ ./ota_client.py -a 192.168.x.x ota esp8266-ota-20171230-v1.9.3-238-g42c4dd09.ota

なお、必ず OTA 版のファイル(拡張子が .ota)を使います。OTA ファイルには署名があるらしく、署名が合っていないファイルはアップロードできないようになっているそうです。

それでは OTA アップデートしましょう。Wio Node のリセット(RST)ボタンを押して指を離したのち、すぐに FUNC ボタンを押します。(押してすぐに離して大丈夫です。) そうしたら、先ほどの ota_client.py コマンドを、リターンキーを押して実行します。最初は、UARTの画面を見ながらほうが良いでしょう。(これだけは、WebREPL では無理です。)

boot8266
HW RTC Reset reason: 2
System reset reason: 1
Initial GPIO state: e0030001, OE: 0
GPIO changed: 0
Running OTA

のように、Running OTA と表示されていれば OTA が走っているので、その間に ota_client.py コマンドを実行するという訳です。

このような表示が ota_client.py の実行画面で次のような表示が出れば OK です。

Sending #1
resp: (1, 0, 256, 0)
Sending #2
resp: (2, 0, 256, 256)
Sending #3
resp: (3, 0, 256, 512)
(続く)

無事にファームウェアをアップデートできましたね。

温湿度センサー SHT31 を繋ぐ

それでは、温湿度センサー SHT31 を繋いでみましょう。ここで、I2C0 のほうは UART として利用したいので、I2C1 ポート(コネクタ)のほうに SHT31 Grove モジュールを繋ぎます。

ここで一つ注意です。上述の OTA ファームウェアを使っている場合、Wio Node の電源投入時にセンサーが繋がっていると OTA モードに遷移してしまうようなので(未確認)、SHT31 センサーモジュールを外した状態で電源を投入します。数秒待ってからセンサーモジュールを繋ぎましょう。

さて。ググってみると、既に MicroPython 用の SHT31 ライブラリを提供されている先達がいらっしゃいますので、その成果を使わせて頂きましょう。こちらで公開されています。

さてどうやって使ったら良いのでしょうか。まず最初に注意しないといけないのは(私はここでハマりました)、Wio Node では Grove のコネクタにデフォルトでは 3.3V 電源が供給されていないことです。GPIO と MOSFET を使って電源を制御しているのです。これを MicroPython でオンにするには、以下のようにします。

import machine
p15 = machine.Pin(15, machine.Pin.OUT)
p15.value(1)    # Enable power 3V3B

つまり、GPIO15 に high を出力すると Grove モジュールに電源が供給されるわけです。

ここまでできたら、あとは簡単です。上述のライブラリを利用して、

import sht31
i2c = machine.I2C(scl=machine.Pin(5), sda=machine.Pin(4))
sensor = sht31.SHT31(i2c)
temp, humid = sensor.get_temp_humi()
print(temp, humid)

これで無事に、

21.8009 47.4174

のような表示が出ました。

Wio Node から IFTTT に webhook する

次は、湿度に応じての加湿器オン/オフです。スマートコンセントのセットアップはできましたでしょうか?  私のは Amazon で購入した、こんなタイプです。

スマートコンセントをセットアップしたら、IFTTT で

  • もし、webhook を叩かれたら、Smart Life 経由でスマートコンセントを on/off にする

というロジックを書けば良い訳です。IFTTT で次のようなロジックをアプレットとして定義します。

これは on 側ですが、同様に off 側も定義します。

このように定義すると、webhook として、それぞれ次のような URL が使えるようになります。

https://maker.ifttt.com/trigger/smartplug_on/with/key/なんとかかんとか
https://maker.ifttt.com/trigger/smartplug_off/with/key/なんとかかんとか

前者が加湿器オン用で、後者がオフ用ですね。

まずは、MicroPython から HTTP を簡単に叩けるように、ここでも先達のライブラリを利用させて頂くことにしましょう。ここからダウンロードできます。

そうしたら、Wio Node の MicroPython で次のようなコードが書けます。

URL = 'https://maker.ifttt.com/trigger/%s/with/key/%s'
KEY = 'なんとかかんとか'
SCL_PIN = 5
SDA_PIN = 4
MIN_HUMID = 30
MAX_HUMID = 50
SEC_SLEEP = 60

def humidifier(s):
    import urequests

    if s:
        print("Turning on humidifier")
        urequests.get(URL % ('smartplug_on', KEY))
    else:
        print("Turning off humidifier")
        urequests.get(URL % ('smartplug_off', KEY))

def run():
    import machine
    import sht31
    import time

    p15 = machine.Pin(15, machine.Pin.OUT)
    p15.value(1)    # Enable power 3V3B

    i2c = machine.I2C(scl=machine.Pin(SCL_PIN), sda=machine.Pin(SDA_PIN))
    sensor = sht31.SHT31(i2c)

    while True:
        temp, humid = sensor.get_temp_humi()
        print(temp, humid)

        if humid < MIN_HUMID:
            humidifier(True)
        elif humid > MAX_HUMID:
            humidifier(False)

        time.sleep(SEC_SLEEP)

MIN_HUMID は最低湿度(これ以下になったら加湿器をオン)、MAX_HUMID は最高湿度(これ以上になったたら加湿器をオフ)、SEC_SLEEP は制御感覚(秒)ですね。このファイルを humidcont.py として保存しましょう。

import humidcont
humidcont.run()

これで無事に加湿器を自動制御できるようになりました!

今日はここまで。