ESP-WROOM-32のwebserverでLED点灯

前回の続きになるが、ESP32開発ボードを使ってWiFiアクセスポイントとwebサーバーを動作させ、クライアント(スマホ)からの操作でLEDを点けたり消したりするようなスケッチを書いてみた。ついでにベースとなる簡易Webサーバーのクラスも用意した。

以前、ESP-WROOM-02でも似たようなことをやっていたので、すぐに出来上がったのだけど、何も新しいことをやっていないとも言える。まだ梅雨も明けていないはず(梅雨はなかった?)なのに、外に出る気がしないほど暑くあまり難しいことは考えられない。

回路

回路はGPIO13に10KΩの抵抗を介して赤色LEDを接続しただけ。電源はPCから接続するUSBケーブルからもらう。
ESP32のデータシートによれば、各ピンの出力電流の絶対最大定格(Imax)は当初12mAだったものが40mAに変更されている(ESP32 Datasheet V1.4での変更。リリースノートの記述には80mAに変更とあるが、V1.6の本文では40mAになっている)。また、各IOピンの駆動能力は設定可能であり、初期値は20mAと書いてある。10mAまでと思っておけば、壊すことはないだろう。LEDに10mA流すとすれば330Ωの直列抵抗を使うことになる。今回は、点灯することが目で確認できればいいので10KΩの抵抗を使った。

ESP32-HTTPD-LED1
ESP32-HTTPD-LED1, カメラ内深度合成

スケッチ

ESP-WROOM-02(ESP8266)のときには、ESP8266WebServerクラスという便利なスケッチが一緒に付いてきたのだけど、今回導入したArduino Core for ESP32 には見当たらなかったので、簡易的なWebサーバー機能をもつ SimpleWebServer クラスというのをまずこしらえた。このクラスを使う実装側では、自分が処理したいリクエスト文字列と、そのリクエスト文字列に対応したハンドラ(関数ポインタ)を登録しておけばよいので、実装側のスケッチがちょっとすっきりする。もしかしたら、Arduino IDEにESP8266の開発環境も追加してやればESP8266用のサンプルが使えるのかもしれないが、混乱のもとになるのでまだやっていない。

SimpleWebServer.h

以下の内容を SimpleWebServer.h という名前で保存し、実装するスケッチと同じディレクトリに置いてincludeすれば、Arduino IDEにソースタブが増えるから参照や手直しも容易になる。

概要

WiFiのアクセスポイントおよびtcpサーバーとして機能させるため、ライブラリにあるWiFiServerクラスを派生している。インクルードしているライブラリファイルは、前回の導入時にArduino のソース格納用ディレクトリ内に置いた、”…\hardware\espressif\esp32\libraries\WiFi\src\” あたりに入っている。

コンストラクタとbegin()

softAPを構成するために必要なssidやパスワード、tcpサーバーのサーバーアドレスやListenするポートをもらっておく。基本クラスのWiFiServer()にはListenポートを渡しておく。

WiFi.softAP() によってESP32をsoftAPモードとし、WiFi.softAPConfig()の呼び出しにより、サーバーアドレスやネットワーク・アドレスを設定するとともに、dhcpの動作も開始させる。リスタート時にステーションモード(WIFI_STA)になっている場合、このメソッドを呼ばないとdhcpが開始しないので、dhcpを頼りにしているスマホから接続できない。

ハンドラ追加メソッド

実装側のスケッチでは、

といった記述で、URIのスキームとホスト名以降の部分(ここでは、リクエスト文字列と表記)と、そのリクエスト文字列を受け取ったときに処理する関数ポインタを渡す。ハンドラ追加メソッドは、リクエスト文字列をキーとしたmap内に格納する。mapおよび関数ポインタの宣言は以下のとおり。

Handler_tは実装内で特別に処理する仕組みのための関数用で、今回の例ではLEDのオンとオフに使う。DefaultHandler_t は、リクエスト文字列がmapに格納されていなかったときに使うハンドラ用で、例えばSPIフラッシュやSDカードからファイルを読み出して返すようなときに使う予定にしており、引数としてリクエスト文字列をとる。

リクエストを処理するメソッド

void handle_request(); では、WiFiServerがクライアントからのtcp接続を受け入れたかどうかを判定し、接続済ならばGETリクエストのリクエスト文字列を取り出し、request_handlers に登録があれば対応する関数を呼び出し、なければdefault_handler として登録されている関数を呼ぶ。GETリクエスト以外への対応や、リクエストヘッダの格納、リクエスト文字列からのクエリの切り出しなどは、必要に応じて追加していくことになる。

WiFiClient clientオブジェクトに対して、if (client) {… } とかwhile (client) {…} とか書いてあるのはちょっと気になるところだが、WiFiClientクラス内に、接続中ならばtrueを返す boolのオペレータが定義されているから、接続中かどうかを判断していることがわかる。

リクエスト元への応答は、各ハンドラ内で行う必要がある。

実装側 ESP32_HTTPD_LED1.ino

面倒なことは先に書いたクラス側がやってくれるので、実装側で本来やるべきことだけ書けばよくなっている。今回はLEDを点けたり消したりするだけなので、digitalWrite()を使ってオン/オフしている。

SimpleWebServer クラスのインスタンスを必要なパラメータを並べて作成し、LEDをオンにしたりオフにしたりするハンドラを書き、setup()内でそれらをリクエスト文字列とともに登録している。led_500() や default_handler() といった関数は無くても困らないのだが、SimpleWebServerクラスが意図通りに動いていることを確認するために用意した。void loop() では、server.handle_request() を繰り返し呼ぶだけ。

ビルドと実行

スケッチのコンパイルやESP32開発ボードへのダウンロード(マイコンボードへの書込み)は特に問題なく、開発ボードのボタンを操作することもなく、Arduino IDEの操作(「マイコンボードに書き込む」を選ぶ)だけですんなりとできた。シリアルモニタを開いたままでも書込みに問題はなかった。コンパイル時に表示されたメッセージは以下のとおり。

プログラムを格納できるフラッシュメモリサイズは1280Kバイトで、今回のスケッチをコンパイルしたら435,839バイトのバイナリができましたということのようだ。ライブラリをいろいろと抱えているので、これくらいのバイナリサイズになるのだろう (後述するが、この数字はちょっと矛盾している)。

WROOM-02のときは使えるRAMの最大サイズが81,920バイトだったものが、294,912バイトになったのは嬉しい。

フラッシュにはパーティションごとに書き込まれる

スケッチメニューから「マイコンボードに書き込む」を選ぶと、以下のように表示された。

esptoolによって、4つのブロックがESP-WROOM-32内のSPIフラッシュに書き込まれているようである。表示内容の、” Writing at 0x00001000… ” の 数値部分がフラッシュ内での書込み先アドレスに相当していて、以下のような内容を書き込んでいるようである。

  • 0x01000 :  2ndブートローダー (…/esp32/tools/sdk/bin/bootloader.bin) 11120バイト。1stブートローダーから呼ばれ、フラッシュ内プログラムを開始する。
  • 0x08000 :  パーティションテーブル (ESP32_HTTPD_LED1.ino.partitions.bin) 3072バイト 。フラッシュ内の領域情報。なおかつ0x09000から20Kバイトはnvs( non volatile storage ) 領域のようで、何も書き込まれないから内容が保持される。
  • 0x0e000:  (…/esp32/tools/partitions/boot_app0.bin) otaデータ領域 8192バイト。boot_app0.binの中身はほとんど0xff。この領域は、スケッチのダウンロードごとに初期化されることになる。
  • 0x10000 : 今回のスケッチ (ESP32_HTTPD_LED1.ino.bin)  505984バイト。さきほどのコンパイル結果とはサイズが大きく異なっている。コンパイル時のデバッグオプション( Core Debug Level ) を変えても、一致した数字にはならなかった。

パーティションテーブルとスケッチは、Arduino IDEでビルドすると、ビルド先ディレクトリ ( c:\Users\ユーザー名\AppData\Local\Temp\arduino_build_xxxxxx) 内に作成されている。パーティションテーブルのファイルをダンプしてみると、…/tools/partitions/default.csvと同じ内容だった。このcsvファイルを書き換えることで、パーティションテーブルも変更可能なのだろう。
なお、default.csvをみるとSPIフラッシュの後ろの方の1472Kバイトがspiffs領域のようなので、そのうちファイルシステム領域として利用したい。

実行

スケッチの転送が終了すると、USBを介してリセット指示が送られ開発ボードがリスタートしシリアルモニタには以下のような内容が表示される。なお、コンパイル時にはCore Debug Level : Debug としてビルドしているので、WiFiGeneric.cpp のDebugメッセージ (log_d() の出力) が表示されていて、[D] で開始する行がそれにあたる。

スマホのブラウザを操作することで、ブレッドボード上のLEDが点灯/消灯する様子を動画にしてYoutubeにおいた。4Kではありません。

動画は、”/”をリクエストしてメニュー( led_menu() による)を表示しているところから始まり、ONおよびOFFのリンクを触ることで、ブレッドボード手前の赤いLEDが点いたり消えたりする。
また、ハンドリングしていないURIを指定することで、実装側の default_handler() が応答している様子なども含まれている。

きょうのまとめ

ESP-WROOM-02のときと同じように動かすことができた。ただ、この程度ならWROOM-02で十分であるとも言える。まぁ、しばらく離れていたのでリヒハビリテーションのつもり。次はSPIフラッシュにファイルを置く方法を調べてみる予定。

ESP32モジュールはけっこう熱をもつ。WROOM-02がほんのり暖かという感じだったのに対し、熱いの一歩手前くらいの感じ。リスタート時はWiFi機能などをオフにしておき、必要に応じて必要な機能だけをオンにするような設定方法も考えておいた方がよさそうである。