14
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

ESP32 WiFiにつながらないとき

Last updated at Posted at 2022-10-06

1. WiFiルータにつなぐ

ESP32をWiFiルータに接続する時、マニュアルに倣い下記のようなコードを書きますが、なぜか全然つながらないことがあります。開発ボードのリセットスイッチを押して起動し直すと すんなりつながったりして、なんなんだろう?と思った経験がありませんか?

Serial.print("WiFi connecting");
WiFi.begin(ssid, pass);
while (WiFi.status() != WL_CONNECTED) {
  delay(500);
  Serial.print('.');
}
Serial.println("\nWiFi connected.");

今回は結論を先に書きます。今後は下記のようなコードに変えましょう。つながらないイライラが解消します。

5秒待ってつながらない時は、reconnect()で再接続
bool done = true;
WiFi.begin(ssid, pass);
while (done) {
    Serial.print("WiFi connecting");
    auto last = millis();
    while (WiFi.status() != WL_CONNECTED && last + 5000 > millis()) {
        delay(500);
        Serial.print(".");
    }
    if (WiFi.status() == WL_CONNECTED) {
        done = false;
    } else {
        Serial.println("retry");
        WiFi.disconnect();
        WiFi.reconnect();
    }
}
Serial.println("\nWiFi connected.");

2. つながらない時は何が起こっているのだろう?

冒頭のコードの実行ログをシリアルモニタで確認してみました。
STA_CONNECTEDイベントが発生していながらも、statusWL_CONNECTEDにならないため、ずーっと.が続きます。

20:55:54.382 -> [     3][D][esp32-hal-cpu.c:244] setCpuFrequencyMhz(): PLL: 480 / 2 = 240 Mhz, APB: 80000000 Hz
20:55:54.825 -> [   450][I][esp32-hal-psram.c:96] psramInit(): PSRAM enabled
20:55:54.892 -> [   483][D][WiFiGeneric.cpp:929] _eventCallback(): Arduino Event: 0 - WIFI_READY
20:55:54.960 -> WiFi connecting[   574][D][WiFiGeneric.cpp:929] _eventCallback(): Arduino Event: 2 - STA_START
20:55:54.994 -> [   616][D][WiFiGeneric.cpp:929] _eventCallback(): Arduino Event: 4 - STA_CONNECTED
20:55:55.476 -> ..........................................................................................

下記は数秒でつながった時のログ。比較すると、上は、IPアドレスの払い出しを待っているように見えます。(固定IPならこんなことにならないのかも?)

20:58:32.511 -> [     3][D][esp32-hal-cpu.c:244] setCpuFrequencyMhz(): PLL: 480 / 2 = 240 Mhz, APB: 80000000 Hz
20:58:32.955 -> [   450][I][esp32-hal-psram.c:96] psramInit(): PSRAM enabled
20:58:32.955 -> [   483][D][WiFiGeneric.cpp:929] _eventCallback(): Arduino Event: 0 - WIFI_READY
20:58:33.056 -> WiFi connecting[   572][D][WiFiGeneric.cpp:929] _eventCallback(): Arduino Event: 2 - STA_START
20:58:33.089 -> [   615][D][WiFiGeneric.cpp:929] _eventCallback(): Arduino Event: 4 - STA_CONNECTED
20:58:33.572 -> ......[  3989][D][WiFiGeneric.cpp:929] _eventCallback(): Arduino Event: 7 - STA_GOT_IP
20:58:36.509 -> [  3989][D][WiFiGeneric.cpp:991] _eventCallback(): STA IP: 192.168.21.114, MASK: 255.255.255.0, GW: 192.168.21.1
20:58:36.577 -> .
20:58:36.577 -> WiFi connected.

つながらない時は、DHCPプロトコルのシーケンスのどこか途中で止まっているのでしょうか? TCP/IPレベルのパケットトレースを確認すればより詳しくわかると思いますが、今回はそこまでしていません。

今回、この記事にまとめるにあたり、ESP32のハードリセットによりWiFi接続までの所要時間を測ってみました。(WiFi connectingからWiFi connectedまでのシリアルモニタのタイムスタンプ時間[])

所要時間 所要時間 所要時間
1 0.519 21 3.530 41 7.521
2 0.508 22 7.509 42 135.502
3 1.529 23 0.508 43 0.489
4 0.521 24 3.521 44 3.527
5 0.515 25 0.487 45 0.515
6 0.510 26 3.509 46 0.489
7 3.000 27 0.515 47 0.517
8 0.490 28 0.485 48 0.512
9 0.511 29 3.535 49 3.488
10 0.506 30 3.521 50 0.483
11 0.513 31 30.514 51 0.513
12 0.518 32 0.514 52 0.520
13 3.512 33 7.510 53 0.517
14 3.508 34 7.516 54 0.511
15 45.520 35 60.502 55 0.487
16 0.501 36 60.489 56 0.519
17 0.517 37 120.526 57 0.510
18 0.524 38 150.539 58 7.505
19 0.511 39 0.514
20 0.495 40 0.522

ほとんどが数秒ですが、少ないながら長時間を要す時もありました。

所要時間 回数 割合 備考
1秒以下 35 60% 平均0.508秒
3秒以下 2 3% 平均2.265秒
5秒以下 9 16% 平均3.517秒
8秒以下 5 9% 7.505秒、7.509秒、7.510秒、7.516秒、7.521秒
10秒以上 7 12% 30.514秒、45.520秒、60.489秒、60.502秒、
120.526秒、135.502秒、150.539秒
全体 58 平均11.985秒 10秒以上の7回が全体平均を押し上げている

10秒以上の7回は永久につながらないのかと思うほどでしたが、内部でリトライしているのでしょうか、いつかはつながる結果となりました。でも、2分半(150秒)はかかりすぎです。
さらに要約すると『およそ8割は5秒以下でつながっている』ということで、冒頭の5秒の根拠としました。

所要時間 回数 割合 備考
5秒以下 46 79%  平均1.173秒
5秒超え 12 21% 平均53.429秒

58回とサンプル数は少ないですが、『5秒待ってつながらない時は、reconnectした方が早くつながる。』が今回の結論。

3. 先人に学ぶ

WiFiにつながらないこの現象に遭遇したとき、回避策をネットで検索したところ、次の二つの記事を見つけました。

一つ目の『ソフトウェアリセット』の記事は、何回かループしても接続できない場合は、プログラムからリセットする内容です。

ソフトウェアリセット(10回のループでつながらないならリセット)
int lpcnt=0 ;
WiFi.begin(ssid, pass);
while (WiFi.status() != WL_CONNECTED) { 
    delay(500);
    lpcnt +=1 ;
    if (lpcnt>10) { ESP.restart(); }
    Serial.print(".");
}

手動でリセットスイッチを押す手間が省けますね。

二つ目の『WiFiが切れている時に再接続する』記事は、一定時間後に再接続するという内容です。
冒頭のコードは、この記事を参考にさせていただきました。ありがとうございます。

unsigned long currentMillis = millis();
// if WiFi is down, try reconnecting
if ((WiFi.status() != WL_CONNECTED) && (currentMillis - previousMillis >=interval)) {
  Serial.print(millis());
  Serial.println("Reconnecting to WiFi...");
  WiFi.disconnect();
  WiFi.reconnect();
  previousMillis = currentMillis;
}

4. 検証

今回のコードがどれほど有効なのか検証しました。

所要時間 回数 割合 備考
1秒以下 55 59% 平均0.507秒
4秒以下 16 17% 平均2.998秒
6秒以下 22 24% 平均5.502秒
全数がリトライによるもの
全体 93 平均2.117秒

・1秒以下が全体の6割という点は、前回と同じ。
・5秒を超えた22回の全数がリトライによるものですが、6秒以下となっています。
つまりリトライ後は1秒でつながったとう結果で、効果絶大であると思います。
リトライが発生した22回のログを検証しましたが、リトライ後はすべて.が1個しか出ていませんでした。

リトライ発生時
21:24:19.128 -> [     3][D][esp32-hal-cpu.c:244] setCpuFrequencyMhz(): PLL: 480 / 2 = 240 Mhz, APB: 80000000 Hz
21:24:19.571 -> [   450][I][esp32-hal-psram.c:96] psramInit(): PSRAM enabled
21:24:19.606 -> [   482][D][WiFiGeneric.cpp:929] _eventCallback(): Arduino Event: 0 - WIFI_READY
21:24:19.684 -> [   574][D][WiFiGeneric.cpp:929] _eventCallback(): Arduino Event: 2 - STA_START
21:24:19.718 -> WiFi connecting[   620][D][WiFiGeneric.cpp:929] _eventCallback(): Arduino Event: 4 - STA_CONNECTED
21:24:20.214 -> ..........retry
21:24:24.730 -> WiFi connecting[  5585][D][WiFiGeneric.cpp:929] _eventCallback(): Arduino Event: 5 - STA_DISCONNECTED
21:24:24.730 -> [  5585][W][WiFiGeneric.cpp:950] _eventCallback(): Reason: 8 - ASSOC_LEAVE
21:24:24.730 -> [  5616][D][WiFiGeneric.cpp:929] _eventCallback(): Arduino Event: 4 - STA_CONNECTED
21:24:24.770 -> [  5656][D][WiFiGeneric.cpp:929] _eventCallback(): Arduino Event: 7 - STA_GOT_IP
21:24:24.811 -> [  5657][D][WiFiGeneric.cpp:991] _eventCallback(): STA IP: 192.168.21.114, MASK: 255.255.255.0, GW: 192.168.21.1
21:24:25.206 -> .
21:24:25.206 -> WiFi connected.

これなら、閾値を5秒ではなく、1秒にした方が全体平均は2秒以下になるのでは?と推定し、実験してみました。コードは5秒を1秒に変えるだけです。

1秒待ってつながらない時は、reconnect()で再接続
bool done = true;
WiFi.begin(ssid, pass);
while (done) {
    Serial.print("WiFi connecting");
    auto last = millis();
- //while (WiFi.status() != WL_CONNECTED && last + 5000 > millis()) {
+   while (WiFi.status() != WL_CONNECTED && last + 1000 > millis()) {
        delay(500);
        Serial.print(".");
    }
    if (WiFi.status() == WL_CONNECTED) {
        done = false;
    } else {
        Serial.println("retry");
        WiFi.disconnect();
        WiFi.reconnect();
    }
}
Serial.println("\nWiFi connected.");
所要時間 回数 割合 平均
1秒以下 26 68% 0.504秒
1秒超え 12 32% 1.503秒
全数がリトライによるもの
全体 38 0.819秒

・1秒以下が全体の7割弱という傾向は、これまでと同じ。
・1秒を超えた12回の全数がリトライによるものですが、2秒未満となっています。
サンプル数が38回と少ないですが、全体平均が1秒以下になり、これが本当の正解か?

5. さらなる改善?

もしかしたら、ステータスWL_CONNECTEDを確認する前に、reconnectしたら、もっと改善できるのかも?と考え、コードを以下のように変更して実験しました。

最初からreconnect()
bool done = true;
WiFi.begin(ssid, pass);
while (done) {
    Serial.print("WiFi connecting");
    WiFi.disconnect();
    WiFi.reconnect();
    auto last = millis();
    while (WiFi.status() != WL_CONNECTED && last + 1000 > millis()) {
        delay(500);
        Serial.print(".");
    }
    if (WiFi.status() == WL_CONNECTED) {
        done = false;
    } else {
        Serial.println("retry");
    }
}
Serial.println("\nWiFi connected.");

実は、1度もリトライが発生しなくなるのでは?と想定していましたが、結果は違いました。

所要時間 回数 割合 平均
1秒以下 26 74% 0.499秒
2秒以下 9 26% 1.508秒
全数がリトライによるもの
全体 35 0.758秒

全35回のうち、9回リトライが発生しました。リトライの割合は減りましたが、全体平均はさほど改善が見られません。
また、いきなりdisconnectreconnectも不自然ですし、この方法は却下します。

6. 最終結論

以上の実験から、今回は『1秒待ってつながらない時は、reconnectした方が早くつながる。』を最終結論とします。(冒頭の5秒説を訂正いたします。)
通常は0.5秒でつながり、たまにリトライが発生しても、1.5秒でつながります。劇的な改善です。

1秒待ってつながらない時は、reconnect()で再接続
bool done = true;
WiFi.begin(ssid, pass);
while (done) {
    Serial.print("WiFi connecting");
    auto last = millis();
    while (WiFi.status() != WL_CONNECTED && last + 1000 > millis()) {
        delay(500);
        Serial.print(".");
    }
    if (WiFi.status() == WL_CONNECTED) {
        done = false;
    } else {
        Serial.println("retry");
        WiFi.disconnect();
        WiFi.reconnect();
    }
}
Serial.println("\nWiFi connected.");

ただし、使用しているWiFiルータにも依ると思われますので、閾値は参考とお考えください。
(今回は、Aterm WG1200HS4 PA-WG1200HS4、 IEEE802.11g(2.4GHz帯)を使用)

以上、何かの参考になれば嬉しいです。

14
11
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?