市販されている IoT 機器は、 いつサービス終了してしまう (クラウドサーバ停止で使えなくなる) かも知れず、 そのたびに API を解析するのは現実的ではないなぁと思っていたところ、 MicroPython (日本語) を使えば手軽に IoT 機器を自作できることに気付いた。
例えば部屋の明るさを Wi-Fi 経由でサーバへ通知する照度センサは、 こんな感じで書ける:
import machine import socket import network_cfg pwr = machine.Pin(15, machine.Pin.OUT) pwr.value(1) def webhook(v): addr = socket.getaddrinfo('gt.gcd.org', 12345)[0][-1] s = socket.socket() s.connect(addr) s.send('{"magic":"'+network_cfg.MAGIC+'","type":"Illuminance", "Darkness":"'+str(v)+'", "DeviceName":"wionode"}\n') s.close() adc = machine.ADC(0) def illumi(p): darkness = adc.read() try: webhook(darkness) except OSError as exc: print("exception\n") tim = machine.Timer(-1) tim.init(period=60000, callback=illumi)
webhook(v) はサーバ (この例では gt.gcd.org のポート 12345番。 LAN 内のサーバなので外部からはアクセスできない) へ通知する関数。 「adc.read()」で照度センサの値 (0 〜 1024) を読み取って、 webhook(v) でサーバへ通知するだけ。 タイマを使って 60秒ごとに illumi 関数を実行して、 その時点の照度をサーバへ通知するようにしてみた。
C などのコンパイル型言語と違って、 Python だから対話的にコード片を実行してみることができて (REPL)、 とりあえず動くプログラムを書くだけなら、 あっと言う間に書ける。 Arduino のスケッチみたいに、 いちいち 「コンパイルしてボードへ書込んで実行」 を何度も何度も繰り返すのと比べると、 REPL は圧倒的に楽。 IoT 機器だと実行速度はさほど要求されない (ことが多い) わけで、 REPL 一択だと思う。
いわゆる 「ラズパイ電子工作」 だとブレッドボードで配線するのが定番で、 ブレッドボードだから配線を手軽にできるのはいいのだけど、 IoT 機器として実地に使おうとすると電子部品が剥き出しのままでは困るし、 ケースにいれると大きすぎて設置方法に困る。
その点、 Wio Node (Seeed Studio 102110057) は、 極めてコンパクトなのに Grove コネクタが 2個ついているので、 Grove シリーズと互換なセンサ類をつなぐだけ。 電子部品の出っ張りとかが無いので、 ケースにいれなくてもそのまま使えそう (というか実際、このままで実地に使っている)。
Wio Node の 2個の Grove コネクタに、 照度センサと人感センサをつないでみた。 写真中央左寄りが M5Stack用 光センサユニット (517円) で、 写真右上が HC-SR312 (AM312) 人体検知センサ (1個 166円)。 Wio Node (写真下) は私が買ったとき (2021年11月) は 1250円だったのに、 急に値上がりして今は 1700円くらい。
値上がりしてしまったとはいえ、 合計 2400円くらいで Wi-Fi 通信する照度&人感センサが作れてしまう。 いつサービス終了してしまうか恐れながら市販の IoT 機器を使うよりずっといい。
Grove コネクタは 黄 白 赤 黒 の 4ピン。 黄と白は信号線で、 赤は電源 (5V or 3.3V)、黒は GND。 Seeed studio オリジナルの Grove ケーブルは 1番ピンが黄色 (写真左側) だけど、 M5Stack などの互換ケーブルだと 1番ピンが白色で 白 黄 赤 黒 の順番 (写真右側)。
オリジナルと互換ケーブルとでは黄と白が入れ替わっているが、 違うのは色だけで互換性は配慮されている (と思う)。 例えば、 アナログ出力の Grove センサのほとんど (全て?) は、 1番ピンがアナログ信号線となっている。
3番ピン(赤) は、 Wio Node の場合 3.3V が供給されるが、 M5Stack や Arduino だと 5V のものが多いので注意を要する。 例えば人感センサの定番 HC-SR501 (1個 136円) の電源電圧は 5V 〜 20V なので Wio Node の Grove コネクタから電源を供給することはできない。
Wio Node は PORT 1 (写真右側の Grove コネクタ) がアナログ信号を入力することができて、 前掲のプログラムのように
import machine adc = machine.ADC(0) darkness = adc.read()
などとすることで PORT 1 の 1番ピンに印加された電圧を読み取ることができる。 このプログラムの場合、 入力電圧 0V 〜 3V に対して変数 darkness は 0 〜 1024 となる。 3V 以上では常に 1024 となった。
M5Stack用 光センサユニット は照度に応じた電圧を 1番ピンに出力する。 Wio Node PORT 1 に接続した場合、 その電圧を受けて変数 darkness が 0 (照度最大) 〜 1024 (真っ暗) になる。 また、2番ピンには 0 (明) または 1 (暗) のデジタル値を出力する。 0/1 の閾値 (つまり 0 が出力される照度の最小値) は、 ユニット表面にある可変抵抗で設定できる。
Wio Node PORT 1 の 2番ピンは ESP8266 (Wio Node のマイクロコントローラ) の GPIO 4 につながっているので、
drk = machine.Pin(4, machine.Pin.IN) drk.irq(trigger=machine.Pin.IRQ_RISING | machine.Pin.IRQ_FALLING, handler=illumi)
などと GPIO 4 の 0/1 が変化したときに割り込みが起きるようにしておけば、 タイマによる一定間隔の割り込みに加えて、 照度が閾値を超えた瞬間に照度をサーバへ通知することができる。 例えば部屋の照明を (手動で) オン/オフした瞬間をサーバが検知できる。
Wio Node の PORT 0 には前掲の写真のように人感センサ HC-SR312 をつないだ。 1番ピン(黄) を HC-SR312 のセンサピン (写真左中央) につなぎ、 3番ピン(赤) を電源ピン (写真左上)、 4番ピン(黒) を GND ピン (写真左下) につなぐ。
HC-SR312 には説明書がついていない (日本の Amazon で注文したのにキルギスから届いた) し、 基板のシルク印刷にもピンの役割は書かれていなかったので、 接続方法は基板の配線パターンから推測した。 人の動きを検出すると、 センサピンから 1 のデジタル値を出力する。
人感センサ HC-SR312 は接続がピンヘッダなので、 そのまま実地に使うにはやや難があるが、 M5Stack用PIRセンサユニット UNIT-PIR なら Grove コネクタで接続できる。
でもケースに入ってる分、UNIT-PIR は割高 (←写真では 825円もする)。 他製品と比べるとフレネルレンズの口径が小さいので、 広範囲の人の動きを検知したい場合は不向きかもしれない。
HC-SR312 と UNIT-PIR、 どちらの人感センサも AS312 PIR センサを使っていて 3.3V 電源で使うことができる。 ちなみに PIR は 「Pyroelectric Infrared Radial」 つまり 「焦電赤外線放射」 の略。 PIR センサには、 赤外線放射を集めるための半球状の白いフレネルレンズがついている。
人感センサ (HC-SR312 または UNIT-PIR) のセンサピンをつないだ Wio Node PORT 0 の 1番ピン(黄) は ESP8266 の GPIO 3 につながっているので、 GPIO 3 の 0/1 が変化したときに割り込みが起きるようにして、 その時の GPIO 3 の値を webhook(v) でサーバへ通知すればよい。
led = machine.Pin(2, machine.Pin.OUT) rx = machine.Pin(3, machine.Pin.IN) def pir(p): v = p.value() try: webhook(v) except OSError as exc: print("exception\n") if v > 0: led.value(0) else: led.value(1) rx.irq(trigger=machine.Pin.IRQ_RISING | machine.Pin.IRQ_FALLING, handler=pir)
Wio Node では GPIO 2 に 0 を出力すると青LED が点灯し、 1 を出力すると消灯する。 人感センサが人の動きを検知したときに青LED が点灯するようにしてみた。
Wio Node における GPIO のまとめ:
GPIO | 役割 |
---|---|
0 | FUNC ボタンの状態 (0:押下, 1:離上) |
1 | PORT 0 の 2番ピン(白) |
2 | 青 LED (1:消灯, 0:点灯) |
3 | PORT 0 の 1番ピン(黄) |
4 | PORT 1 の 2番ピン(白) |
5 | PORT 1 の 1番ピン(黄) |
15 | PORT 0 および 1 への電源供給 (1:ON, 0:OFF) |
Wio Node には、 Wio Link のコントローラとして動作させるためのファームウェアが あらかじめ書き込まれている。 Wio Link はプログラミング不要で IoT アプリケーションを構築できるのが 「売り」らしいが、 むしろプログラミングしたい私は、 速攻でファームウェアを MicroPython に書き換えた。
見れば明らかだが Wio Node には ESP-WROOM-02 (ESP8266EX を搭載した Wi-Fi モジュール) がそのまま載っている (写真左下)。 したがって ESP8266 用の MicroPython ファームウェアを書込んで使うことができる。
まず Wio Node の PORT 0 に TTL シリアル通信ケーブルをつなぐ。 TTL レベル (3.3V) でシリアル通信ができるものであれば何でも使える (はず)。 私は M5Stack用 ESP32ダウンローダキット (写真上) を使った。 Wio Node は M5Stack ではないし ESP32 でもないが、 問題なく使える。 PORT 0 の 1番ピン(黄) が RX で、2番ピン(白) が TX (シルク印刷の矢印の向きが直感的でないので注意)。
Wio Node の Func ボタンを押しながら RST ボタンを押して離し (RST を離してから Func を離す)、 esptool.py コマンドでファームウェアを書込む:
senri:/ftp/pub/ESP8266 $ wget https://micropython.org/resources/firmware/esp8266-20230426-v1.20.0.bin Length: 634016 (619K) [application/octet-stream] Saving to: ‘esp8266-20230426-v1.20.0.bin’ esp8266-20230426-v1 100%[===================>] 619.16K 620KB/s in 1.0s 2023-06-10 09:37:47 (620 KB/s) - ‘esp8266-20230426-v1.20.0.bin’ saved [634016/634016] senri:/ftp/pub/ESP8266 $ esptool.py -p /dev/ttyACM1 -b 115200 write_flash --flash_size=detect 0 esp8266-20230426-v1.20.0.bin esptool.py v3.1 Serial port /dev/ttyACM1 Connecting.... Detecting chip type... ESP8266 Chip is ESP8266EX Features: WiFi Crystal is 26MHz MAC: 5c:cf:7f:XX:XX:XX Uploading stub... Running stub... Stub running... Configuring flash size... Auto-detected Flash size: 4MB Flash will be erased from 0x00000000 to 0x0009afff... Flash params set to 0x0040 Compressed 634016 bytes to 420365... Wrote 634016 bytes (420365 compressed) at 0x00000000 in 37.3 seconds (effective 136.0 kbit/s)... Hash of data verified. Leaving... Hard resetting via RTS pin...
この実行例では「Flash size: 4MB」と表示されているが、 ESP-WROOM-02 のフラッシュメモリは 2016年12月頃から 2MB になったらしい。 この Wio Node は 2021年11月に千石電商で買った (1250円)。 パッケージの日付は 2021年4月 (04/16/21)。
MicroPython は普通の Python と同様 REPL (Read-Eval-Print Loop) をサポートしている。 「import webrepl_setup」 を実行してパスワードを設定すると Web ブラウザで Wi-Fi 経由で REPL が使える。 Grove コネクタの両方にセンサ等をつなぐと、 シリアル通信ができなくなるので、 Web ブラウザで REPL を使えるようにしておくべき。
senri:~ $ cu -s 115200 -l /dev/ttyACM1 Connected. >>> 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>", "<key>") # 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(ssid="<AP_NAME>", security=network.AUTH_WPA_WPA2_PSK, key="<key>") 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) >>> 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): XXXXXXXX Confirm password: XXXXXXXX Changes will be activated after reboot Would you like to reboot now? (y/n) y
Web クライアントをダウンロードして Web ブラウザで webrepl.html をアクセスすることで、 ブラウザ上で MicroPython の REPL が使える。 ファイル転送機能もある。
[…] I installed MicroPython on Wio Node (ESP8266) and made a WiFi illuminance and motion sensor – GCD. […]
Pingback by ICYMI Python on Microcontrollers Newsletter: CircuitPython 8.2.0-beta.1, Focus on RISC-V and More! #CircuitPython #Python #micropython #ICYMI @Raspberry_Pi « Adafruit Industries – Makers, hackers, artists, designers and engineers! — 2023年6月14日 @ 22:56