xor

二兎を得るか、一兎をも得ざるか

スマホからBluetooth経由でESP32のWi-Fi接続設定を書き換えられるようにする

ESP32において、BLEを使って特定のキャラクタリスティックにSSIDとパスワードを書き込むことで、Wi-Fi設定が簡単にできました。

Bluetooth Classic(Bluetoothシリアル)とWi-Fiを同時に使うと、どちらを先に begin() しても同時に有効になった時点でBluetoothがしにます。
(2020年7月末・Arduino core for the ESP32 development v1.0.4時点)

と書いておきながら、よっぽど自力で実装してみたいというわけでなければ "ESP32 Smart Config" の利用をおすすめします。

www.kerislab.jp

前提条件

  • Arduino IDEでESP32が開発できる環境

  • 同上に加え "ESP32 Sketch Data Upload" が利用できること
    f:id:ukkz:20200727173934p:plain
    www.mgo-tec.com

  • BLEの基礎知識(サービス・キャラクタリスティックなどの理解)
    わかりやすくて以下おすすめです。
    jellyware.jp

  • Arduino core for the ESP32 を GitHubからインストールする

    (訂)Bluetooth Classicを使う場合の話なので以下は必要ないです(いちおう残しておく)

    通常、Arduino IDE のボードマネージャからESP32開発用の環境を用意することが多いですが、現時点(2020年7月)ではボードマネージャ経由のビルドでは onData などのコールバック関数を利用することができません。
    そのためgitから直接Developmentビルドを持ってきて利用します。
    以下の "Using Arduino IDE with the development repository" 項目から自分の環境(OS)に合った方法で「Arduino core for the ESP32」をインストールしてください。

    github.com

サンプルコード

github.com

自作の Store クラスを使い、SPIFFS上で設定を読み書きできるようにしているところが基本です。
BLEのキャラクタリスティックにアクセスされたときのコールバックを使い、設定値の読み取りや書き込みを行っています。

スケッチ書き込みをする前に

  • ツール → "Partition Scheme" を "Huge APP (3MB No OTA/1MB SPIFFS)" に設定してください。

  • "ESP32 Sketch Data Upload" を実行して、SPIFFSを初期化してください。
    ダイアログが出ますがそのままOKをクリックします。

使い方

BLEのセントラル側となる端末が必要です。
最も手軽に使う具体例としては、スマホに「BLE Scanner」アプリをインストールして使うのがよいです。

BLE Scanner 4.0

BLE Scanner 4.0

  • Bluepixel Technologies LLP
  • 仕事効率化
  • 無料
apps.apple.com

play.google.com

f:id:ukkz:20200727174012p:plain

アプリを起動したら、それっぽい端末が表示されるので接続します。

f:id:ukkz:20200727174054p:plain

カスタムサービスを開くと、Wi-Fi接続状態確認(READ, NOTIFY)、SSID読み書き(READ)、パスワード書き込み(WRITE)の各キャラクタリスティックが表示されるので、画像手順通りに設定します。最終的に、状態確認のキャラクタリスティックを呼んだときにIPアドレスが表示されるようになっていれば接続成功です。

各キャラクタリスティックにはUUIDが割り振られていますが、これは独自の設定UIを持つBLEアプリを作ったときに「このUUIDを持つキャラクタリスティックはSSIDを書き込むところ」などのように認識して操作することができる「キー」となりうるものです。ここでは簡易的に使えればよいのでまだセントラルアプリ側は作りませんが、Web Bluetooth APIとかでそのうちさくっと作れればいいなと思っています。

なお、この上記のスクリーンショットを撮ったときにはM5Cameraを使っていたのですが、 "flash read err, 1000" というSPIFFSが利用できなくなるエラーで書き込みができなかったため、接続表示まで至っていません。(もちろん別のESP32でちゃんと使えることは確認しています)

esp32.com


ここから技術メモ

基本的にはWi-FiBluetoothの同時使用はシビア

どうやら電波周りの回路が同じものを使っているため、プログラム的に重複するっぽいです。

www.facebook.com

最初はBluetooth Classicによるシリアル通信で対話的にSSIDやパスワードを設定しようとしたんですが、試行錯誤ののちに冒頭の結論となり諦めました。

Bluetooth Classic では同時使用オプション SW_COEXIST_ENABLE はあまり意味ないかも

SW_COEXIST_ENABLE というコンパイルオプションを変更したらなんかよさそうかも? な情報がありました。

qiita.com

このオプションが設定できる実体は、Macの場合 ~/Documents/Arduino/hardware/espressif/esp32/tools/sdk/sdkconfig であるようです。

demo-dijiudu.readthedocs.io

見てみると、値はすでに y となっており、有効フラグとなっています。WiFiBluetoothを同時使用するときのマネジメントをソフトウェア制御優先で行う? ようですが、 n にしても挙動はあまり変わらず、詳細不明でした。

Bluetoothライブラリだけで1MB近くプログラムメモリを消費するため、Partition Scheme(メモリマップ)を変更する必要がある

通常状態だとプログラムに1.2MB、SPIFFSに1.5MB、残りはOTA(ネットワーク経由でプログラム書き込み)、のようなメモリ割り当てになっています。
Bluetooth関係のヘッダファイルをインクルードするとコンパイル後に間違いなく1MB超えるので、OTAを無効にした以下のようなメモリ割り当てに変更しないと書き込みできません。

f:id:ukkz:20200723120112p:plain

WiFi.status()WL_CONNECTED かどうかだけ見ればよい

garretlab.web.fc2.com

WiFi.status() が返す値は8種類定義されています。
ただし、存在しないSSIDを指定しても WL_DISCONNECTED になるなど、返却値に基づいたデバッグメッセージを表示してもあまり意味がありませんでした。
ユーザプログラム内でハンドリングしないが細かい状況が知りたい場合は、Core Debug Level: "Warn" 以上でコンパイル&書き込みしてシリアルモニタで確認すると良いと思います。

あまり関係ないハマりポイント:ボード選択でESP32が2つあった件

f:id:ukkz:20200720155711p:plain

最初、BluetoothSerialの onData が、ちゃんとライブラリのコード内に存在しているのに、何回コンパイルしても 'class BluetoothSerial' has no member named 'onData' というエラーが出て困り果ててました。
試行錯誤したところ、最近のIDEのアップデートでいつのまにか新しくなっていたボード選択部分にESP32ファミリーを示す大分類が2種類あることに気付き、これを「(in sketchbook)」という表記のある中のESP32モジュールを選択してコンパイルを行ったらすんなりと成功しました。
ボードマネージャ経由のライブラリとGitHub直のライブラリで重複してるような気もしましたがそうでもなく……
この重複表記、ご存知の方いらっしゃったらぜひ教えてください。