2025年1月4日土曜日

ESP32でSTAとAPを同時に起動してWiFi設定。

 ESP32でWiFiを設定するのにWiFiマネージャーのライブラリとか色々試してみたけど、STAとAPを同時に起動してスキャンできないか試してみた。
毎回いろんなスケッチにバラバラで実装して入れるのも面倒なのでメモ的な…

STAとAPを同時に起動して、STAに繋がったらAPを無効にする感じにしてみた。一旦STAに繋がったら自動再接続を動かすようにして、再起動しない限りはAPに繋がらない。たまに長時間動かしたりするとWiFiが切断されていてそれ以降繋がらない事があるので対策をしてみた感じ。

停電とかでWiFiルーターよりもESP32が先に立ち上がってしまった場合もこれならAPモードを起動しながらSTAでWiFiを探し続けてくれるので、勝手にAPモードに切り替わってずっと待ってるってことがなくなる。

#include <WiFi.h>
#include <WebServer.h>
#include "esp_mac.h"

bool apStopped = false;
WebServer server(80);

String generateWiFiPage() {
  Serial.println("Scanning networks...");
  if (!apStopped) {
    WiFi.mode(WIFI_AP_STA);
    WiFi.disconnect(true);
    delay(100);
  }
  int n = WiFi.scanNetworks(false, false);
  Serial.printf("Found %d networks\n", n);
  String list = "";
  if (n == 0) {
    list = "<option>No networks found</option>";
  } else {
    for (int i = 0; i < n; i++) {
      list += "<option value='" + WiFi.SSID(i) + "'>";
      list += WiFi.SSID(i) + " (" + String(WiFi.RSSI(i)) + "dBm)";
      list += "</option>";
    }
  }
  WiFi.scanDelete();
  String html = "<!DOCTYPE html><html><head><meta charset='utf-8'></head><body>"
                "<h3>WiFi Setup</h3>"
                "<form action='/save'>"
                "SSID: <select name='ssid'>"
                + list + "</select><br><br>"
                         "Password: <input name='pass' type='password'><br><br>"
                         "<input type='submit' value='Save'>"
                         "</form>"
                         "<br><button onclick='location.reload()'>Rescan</button>"
                         "</body></html>";
  return html;
}
void handleSave() {
  String ssid = server.arg("ssid");
  String pass = server.arg("pass");
  WiFi.begin(ssid, pass);
  server.send(200, "text/html", "<h3>Saved</h3>");
}

void WiFiEvent(WiFiEvent_t event, WiFiEventInfo_t info) {
  switch (event) {
    case ARDUINO_EVENT_WIFI_STA_CONNECTED:
      Serial.println("STA connected to AP!");
      if (!apStopped) {
        WiFi.softAPdisconnect(true);
        WiFi.mode(WIFI_STA);
        apStopped = true;
        Serial.println("AP stopped after STA connection");
      }
      break;
    case ARDUINO_EVENT_WIFI_STA_DISCONNECTED:
      if (apStopped) {
        Serial.println("STA disconnected, attempting reconnect...");
        WiFi.disconnect(true);
        WiFi.mode(WIFI_STA);
        WiFi.begin();
      }
      break;
    default:
      break;
  }
}

void setup() {
  Serial.begin(115200);
  uint8_t mac[6];
  esp_read_mac(mac, ESP_MAC_WIFI_STA);
  char apName[20];
  sprintf(apName, "ESP32-%02X%02X", mac[4], mac[5]);
  Serial.print("AP SSID: ");
  Serial.println(apName);
  WiFi.mode(WIFI_AP_STA);
  WiFi.softAP(apName);
  Serial.println("AP started");
  WiFi.begin();
  WiFi.onEvent(WiFiEvent);
  server.on("/", []() {
    server.send(200, "text/html", generateWiFiPage());
  });
  server.on("/save", handleSave);
  server.begin();
  Serial.println("HTTP server started");
}

void loop() {
  server.handleClient();
  if (WiFi.status() == WL_CONNECTED) {
    Serial.print("STA IP: ");
    Serial.println(WiFi.localIP());
  }
  delay(5000);
}

とりあえずモバイルルーターとかで試してみたんだけどちゃんと動いてそう。

ESP32の電源を入れてから3分後にモバイルルーターを入れてもちゃんと勝手に繋がってくれてそう。途中でモバイルルーターを再起動してもちゃんと再接続されるし。

SSIDを決め打ちでスケッチの中に入れておきたくないときとか、いろんな環境で使いたい場合はこっちのほうが便利ね。


0 件のコメント:

コメントを投稿