M5StickCで、再コンパイルせずに別のWifiにつなぎたい場合WiFiManagerが便利


# 概要

M5StickCでWiFiを利用している場合に、自宅でテストして、ほかの場所で動かそうと思って、接続先のWiFiが違って焦ったりすることがあるかと思います。すぐに再コンパイルできれば良いですが、開発環境を持ち歩いていない場合は困ることになります。

[WiFiManager](https://github.com/tzapu/WiFiManager) を使うと、WiFiの接続先をその場でスマホを使って変更でき、とても便利です。

また、起動後すぐにパワーボタンを押すと強制的にWiFi設定画面に移行する工夫を行うことで、ほとんどのケースで便利に利用することができるので、そのようなコードサンプルを紹介します。

M5Atom等でも利用できそうですが、状態の表示手段が限られるのが悩ましいところですね。

# WiFiManagerのWiFi設定モードについて

M5StickC自体がAP（アクセスポイント）になり、スマホから接続することができます。接続すると自動的にWiFi設定画面が表示されます。

以下のように、WiFiの接続先に ESP32_ ではじまるアクセスポイントが出てくるのでこちらにつなぎます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/71421/be5fbedc-b707-a2e6-7499-6b98aa6f80ea.png)

接続するとこちらのような画面が自動で出てきます。自動で出てこない場合は ブラウザで 192.168.4.1 につなぐと良いようです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/71421/df08aeca-9220-b331-4802-3b46b3dfe01b.png)

Configure Wifiボタンを押すとこのような画面が出て、SSIDとパスワードを入力できます。サーチもしてくれるので、その中からSSIDを選択できて便利。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/71421/8c8678cf-a66a-94fb-bc28-175c2424f8ab.png)

これでSaveと押すと、M5StickC側で接続処理が行われます。
問題なく接続できれば、設定モード終了します。パスワードが間違っているなどで接続できない場合などはそのまま設定モードが継続します。

# WiFiManagerの使い方

## WiFiManagerのインストール
（ArduinoのライブラリマネージャにもWiFiManagerがありますが、現時点ではESP32対応版はalpha版しか取れないので、ここでは手動でインストールする方法を紹介します）

[こちら](https://github.com/tzapu/WiFiManager/archive/development.zip) から、WifiManagerのdevelopmentブランチの内容をzipファイルで取得し、
Arduinoのライブラリフォルダに展開します。

Arduinoのライブラリフォルダは、Windowsではドキュメントフォルダ内の Arduino/libraries になります。

展開すると WiFiManager-development フォルダができるので、これをWiFiManagerにリネームして Arduino/libraries 以下に移動させると良いでしょう。

## WiFiManagerの利用

WiFiManagerを利用するため、以下のように.ino 内でインクルードする必要があります。
※ WiFiのFが大文字なので注意！
また、WiFiManagerインスタンスをグローバルで定義しておきます。

```cpp
#include <WiFiManager.h>

WiFiManager wifiManager;
```

次節で、M5StickCでの具体的な利用方法を紹介しますが、ここでWiFiManagerの主な関数を紹介しておきます。いったん飛ばしてもらっても良いと思います。

### autoConnect()

setup()内で以下のように wifiManager.autoConnect() を呼び出すと、保存されているSSID/パスワードを利用して接続を試みます。そして、接続失敗した場合は、WiFi設定モードに自動的に切り替わります。
注意点としては、上記の処理中、autoConnect()は戻ってきません。接続が成功したか、設定を終了するなどして失敗が確定したときにはじめて処理が返ってきます。

```cpp
    if (wifiManager.autoConnect()) {
      Serial.println("autoConnect() success!");
    } else {
      Serial.println("autoConnect() failed!");
    }
```

### startConfigPortal()

また、接続をせずにWiFi設定モードを直接起動する方法もあります。
wifiManager.startConfigPortal() を呼び出すと、WiFi設定モードに移行します。こちらの関数も、最終的に成功・失敗が確定するまで処理を戻しません。

```cpp
    if (wifiManager.startConfigPortal()) {
      Serial.println("startConfigPortal() success!");
    } else {
      Serial.println("startConfigPortal() failed!");
    }
```

# M5StickCで便利に使うためのサンプルコード

強制的にWiFi変更したいこともあるので、PCのBIOS画面の方法をまねて、以下のようにしたいと思いました。

* 通常は、起動後記憶しているSSIDに自動接続する。接続できなければWiFi設定モードに移行する
* 起動後２秒程度の間にパワーボタンを押すとWiFi設定モードに強制移行する

起動後２秒程度表示される画面
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/71421/2c976225-fc1a-a29f-1c1f-1221884432d3.png)
放置すると自動接続
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/71421/aefdde85-c227-d115-da1f-6a0dfe1e7ad5.png)

起動後すぐにパワーボタンを押すか、自動接続失敗すると以下の画面になってスマホからの設定を促す
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/71421/329e5f2e-6d4e-185b-e686-b4e999bf06d2.png)

接続成功時
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/71421/ca1b1089-650a-75fa-4af2-dbecc270850c.png)

google.comからデータ取得（参考）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/71421/2c48ef81-7af0-54e5-a284-bfe4fab3226f.png)



以下のコードを.inoにコピペして、setup()からsetupWiFi()を呼ぶようにしてもらえれば、上記の機能が利用できます。

```cpp
#include <M5StickC.h>
#include <WiFiManager.h>

WiFiManager wifiManager;

// WiFi設定が成功したかどうかのフラグ
bool isWifiConfigSucceeded = false;

// LCD画面にメッセージを表示する
void showMessage(String msg)
{
  M5.Lcd.setRotation(1);
  M5.Lcd.setCursor(0, 10, 2);
  M5.Lcd.fillScreen(BLACK);
  M5.Lcd.println(msg);
}

// WiFi接続モードに移行した時に呼ばれるコールバック
void configModeCallback (WiFiManager *myWiFiManager) {
  Serial.println("Entered config mode");
  Serial.println(WiFi.softAPIP());
  Serial.println(myWiFiManager->getConfigPortalSSID());
  showMessage("Please connect to this AP\nto config WiFi\nSSID: " + myWiFiManager->getConfigPortalSSID());
}

// 起動後すぐにパワーボタンが押されたらWiFi設定モードに移行し、そうでなければ自動接続を行う
void setupWiFi()
{
  wifiManager.setAPCallback(configModeCallback);

  // clicking power button at boot time to enter wifi config mode
  bool doManualConfig = false;
  showMessage("Push POWER button to enter Wifi config.");
  for(int i=0 ; i<200 ; i++) {
    M5.update();
    if (M5.Axp.GetBtnPress()) {
      doManualConfig = true;
      break;
    }
    delay(10);
  }

  if (doManualConfig) {
    Serial.println("wifiManager.startConfigPortal()");
    if (wifiManager.startConfigPortal()) {
      isWifiConfigSucceeded = true;
      Serial.println("startConfigPortal() connect success!");
    }
    else {
      Serial.println("startConfigPortal() connect failed!");
    }
  } else {
    showMessage("Wi-Fi connecting...");

    Serial.println("wifiManager.autoConnect()");
    if (wifiManager.autoConnect()) {
      isWifiConfigSucceeded = true;
      Serial.println("autoConnect() connect success!");
    }
    else {
      Serial.println("autoConnect() connect failed!");
    }
  }

  if (isWifiConfigSucceeded) {
    showMessage("Wi-Fi connected.");
  } else {
    showMessage("Wi-Fi failed.");
  }
}
```

setup()の例です。Serial.begin(115200)とM5.begin()は呼ぶようにしてください。

```cpp
void setup()
{
  Serial.begin(115200);
  Serial.println("M5StickC started.");
  M5.begin();
  setupWiFi();
}
```

# サンプルコード

こちらにサンプルの全体コードを置いておきました。こちらはそのまま動作します。接続後 google.com の情報を取得します。
https://gist.github.com/mhama/6c8c8cc1a0076e1c68ed5feec9d605a4


# 接続後について

既にWiFiに接続されているので、ウェブサーバーから情報を取得するのであれば、たとえば以下のようにしてWiFiClientを利用してアクセスすることができます。（エラーチェックなどを省略した簡易コードです）

```cpp
  WiFiClient client;
  if (client.connect("google.com", 80)) {
    client.println("GET / HTTP/1.0");
    client.println();
    String body = client.readString();
    showMessage("google.com: " + body.substring(0, 100));
    Serial.println("google.com: " + body);
  }
```