ESP32でwifi接続情報をブラウザから編集・保存して使うサンプル 接続できない時は自己AP化

Arduino/ESP32ESP32,nvs,WebServer,wifi,保存

今回はwifiの設定値を内蔵フラッシュメモリのnvs領域に書き込んで保持しておき、外部からこれを書き換えられる様にするテストをしてみようと思います。

また、接続出来なかった時は自己AP化して設定を促す感じに。

レシピはこんな感じ。

・nvs領域にwifi接続情報があればこれを使って接続する
・wifi接続情報が無い、または接続できなければ無線APモードで立ち上がる
・APモード、STAモードにかかわらず、ブラウザから設定情報を編集できる様にする

まずはブートから。

nvsに設定がある場合、nvsから読みだしてwifi接続し、nvsに設定が無い、または設定があっても接続出来なかった場合にはAPモードで起動するっと

#include <Arduino.h>
/*
	・nvs領域にwifi接続情報があればこれを使って接続する
	・wifi接続情報が無い、または接続できなければ無線APモードで立ち上がる
	・APモード、STAモードにかかわらず、ブラウザから設定情報を編集できる様にする
*/
// WiFiライブラリ
#include <WiFi.h>
WiFiClass wifi;

// nvsライブラリ
#include <Preferences.h>
Preferences prefs;

// ----------------------------------------------------------------
// 無線APモード時のデフォルトSSID、パスワード
String ap_ssid = "ESP32AP";
String ap_pass = "12345678";
IPAddress ap_ip = IPAddress(192, 168, 4, 1);
IPAddress ap_gw = IPAddress(192, 168, 4, 1);
IPAddress ap_mask = IPAddress(255, 255, 255, 0);
uint8_t ap_ch = 5;
uint8_t ap_hidden = 0;		  // SSIDを隠し属性にするか
uint8_t ap_maxconnection = 4; // 最大コネクション数(MAX=4)

// wifi接続用
uint8_t charrenge_retry_count = 3; // 何回接続試行するか
String wifi_ssid;
String wifi_pass;

// basic認証用
String auth_user = "basic";
String auth_pass = "basic";
// ----------------------------------------------------------------

// setup
void setup()
{

	// シリアル開始
	Serial.begin(115200);
	Serial.println();
	Serial.println("beginning AP..");

	// Wifi ------------------------------------------------------------
	// 既に接続中なら一旦切る
	wifi.setAutoConnect(false);
	if (wifi.isConnected())
	{
		wifi.disconnect();
		delay(3000);
	}

	//	・nvs領域にwifi接続情報があればこれを使って接続する
	//	nvsシリアル開始 ReadOnly
	if (prefs.begin("config-wifi", true))
	{
		// コンフィグリセット
		if (prefs.getBool("reset_config"))
		{
			// Writeで開き直してリセット
			prefs.end();
			prefs.begin("config-wifi");
			prefs.clear();
			prefs.end();
			delay(5000);
		}
		else
		{
			// コンフィグロード
			if (prefs.getString("wifi_ssid").length() > 0)
				wifi_ssid = prefs.getString("wifi_ssid");
			if (prefs.getString("wifi_pass").length() > 0)
				wifi_pass = prefs.getString("wifi_pass");

			if (prefs.getString("ap_ssid").length() > 0)
				ap_ssid = prefs.getString("ap_ssid");
			if (prefs.getString("ap_pass").length() > 0)
				ap_pass = prefs.getString("ap_pass");

			if (prefs.getUInt("ap_ip") > 0)
				ap_ip = IPAddress(prefs.getUInt("ap_ip"));
			if (prefs.getUInt("ap_gw") > 0)
				ap_ip = IPAddress(prefs.getUInt("ap_gw"));
			if (prefs.getUInt("ap_mask") > 0)
				ap_ip = IPAddress(prefs.getUInt("ap_mask"));

			if (prefs.getUChar("ap_ch") > 0)
				ap_ch = prefs.getUChar("ap_ch");
			if (prefs.getUChar("ap_hidden") > 0)
				ap_hidden = prefs.getUChar("ap_hidden");
			if (prefs.getUChar("ap_maxconnection") > 0)
				ap_maxconnection = prefs.getUChar("ap_maxconnection");

			if (prefs.getUChar("charrenge_retry_count") > 0)
				charrenge_retry_count = prefs.getUChar("charrenge_retry_count");

			if (prefs.getString("auth_user").length() > 0)
				auth_user = prefs.getString("auth_user");
			if (prefs.getString("auth_pass").length() > 0)
				auth_pass = prefs.getString("auth_pass");
			// 閉じておく
			prefs.end();
		}

		Serial.println("configure wifi mode.");

		// STA-mode ssid, pass
		if (wifi_ssid.length() > 0 && wifi_pass.length() > 0)
		{
			// wifi通信開始
			wifi.mode(WIFI_STA);
			wifi.begin(wifi_ssid.c_str(), wifi_pass.c_str());
			Serial.println("start wifi.");
			delay(6000);

			// 接続待ち
			int _count = 0;
			while (wifi.status() != WL_CONNECTED)
			{
				// 指定回数で抜ける
				if (_count >= charrenge_retry_count)
				{
					Serial.println("wifi connection failed. booting AP mode.");
					break;
				}
				Serial.println("wifi connecting...");
				Serial.println();
				delay(3000);
				if (wifi.status() == WL_CONNECT_FAILED)
				{
					Serial.println("wifi connection failed. please check settings again.");
					Serial.print("\n\n");
					break;
				}
				_count++;
			}
		}
	}

	// リザルトメッセージ
	if (wifi.status() == WL_CONNECTED)
	{
		Serial.println("wifi connected.");
		Serial.println("IP address: ");
		Serial.println(wifi.localIP());
		Serial.println("GW address: ");
		Serial.println(wifi.gatewayIP());
		Serial.println("DNS address: ");
		Serial.println(wifi.dnsIP());
		Serial.println();
	}
	else
	{
		// nvs読み込み失敗 | コネクション確立不可
		// softAPモードで設定
		Serial.println("booting AP-mode.");
		wifi.mode(WIFI_AP);
		wifi.softAP(ap_ssid.c_str(), ap_pass.c_str(), ap_ch, ap_hidden, ap_maxconnection);
		delay(200);
		wifi.softAPConfig(ap_ip, ap_gw, ap_mask);

		Serial.print("AP-mode IP address: ");
		Serial.print(wifi.softAPIP());
		Serial.println();
	}
	// Wifi ------------------------------------------------------------

	delay(100);
}

void loop()
{
	delay(15000);
}

なんかゴチャゴチャーっとしてきました。

更にWebServerを追加します、、、

// WebServerライブラリ
#include <WebServer.h>
#include <uri/UriRegex.h>
WebServer server;
TaskHandle_t *pWebServerPolling;


// wifiスキャン文字列を返すだけ
bool getWifiScanStr(String &_str, WiFiScanClass &_wifi)
{
	// wifiスキャン
	//	int16_t scan_res = wifi.scanNetworks();
	int16_t scan_res = _wifi.scanNetworks();
	if (scan_res > 0)
	{
		// 発見したwifiAPを表示
		_str += "- SCAN SSID RESULT -<br /><br />\n";
		_str += String(scan_res) + " of SSID found.<br /><br />\n";
		for (int i = 0; i < scan_res; ++i)
		{
			// SSIDとRSSIをprint
			_str += String(i) + ": " + _wifi.SSID(i) + " (RSSI:" + _wifi.RSSI(i) + " dBm)<br />\n";
		}
		return true;
	}
	else
	{
		//
		_str += "-- Wifi Not Found --<br />\n";
		return false;
	}
}

void response()
{
	// 処理内容モニタ
	Serial.println("Incomming Request.");
	Serial.print("request:");
	Serial.println(server.uri());

	// BASIC認証
	if (!server.authenticate(auth_user.c_str(), auth_pass.c_str()))
	{
		return server.requestAuthentication();
	}

	// リザルト文字列
	String str;

	// サーバーリセット
	if (server.uri() == "/factory_reset")
	{
		server.send(200, "text/plain", "Factory RESET at ESP32. after restart server at 10 sec..");
		prefs.begin("config-wifi");
		prefs.clear();
		prefs.end();
		delay(10000);
		ESP.restart();
	}
	else if (server.uri() == "/set_ssid")
	{
		// html作成
		str += "<html><head></head><body>\n";
		// 現在のSSIDを表示
		str += "Wifi Setting<br /><br />\n";

		// 設定受信した場合
		if (server.hasArg("_ssid") && server.hasArg("_pass") &&
			String(server.arg("_ssid")).length() > 0 && String(server.arg("_pass")).length() > 0)
		{
			// パスワード登録モード
			prefs.begin("config-wifi");
			// nvsに保存
			if (prefs.putString("wifi_ssid", (server.arg("_ssid")).c_str()) &&
				prefs.putString("wifi_pass", (server.arg("_pass")).c_str()))
			{
				delay(5000);
				prefs.end();
				str += "Success : SSID and Password saved.<br />\n";
				str += "SSID = " + String(server.arg("_ssid")) + "<br />Pass = " + String(server.arg("_pass")) + "<br /><br />\n";
				str += "server going reset after 10 sec.<br />\n";
				str += "</body></html>";
				server.send(200, "text/html", str);
				delay(10000);
				ESP.restart();
			}
			else
			{
				prefs.remove("wifi_ssid");
				prefs.remove("wifi_pass");
				prefs.end();
				delay(10000);
				str += "Error: not saved SSID and Password. plz retry.";
			}
		}
		else
		{
			// wifi scan print
			getWifiScanStr(str, wifi);

			// SSID,Pass設定用フォーム
			str += "<br /><form action='' method='post'>\n";
			str += "SSID : <input type='text' name='_ssid'><br />\n";
			str += "PASS : <input type='text' name='_pass'><br />\n";
			str += "<input type='submit' value='send'>\n";
			str += "</form>";
		}
	}
	else if (server.uri() == "/set_auth")
	{
		// html作成
		str += "<html><head></head><body>\n";
		// 現在のSSIDを表示
		str += "Auth Setting<br /><br />\n";

		// 設定受信した場合
		if (server.hasArg("_auth_user") && server.hasArg("_auth_pass") &&
			String(server.arg("_auth_user")).length() > 0 && String(server.arg("_auth_pass")).length() > 0)
		{
			// パスワード登録モード
			prefs.begin("config-wifi");
			// nvsに保存
			if (prefs.putString("auth_user", server.arg("_auth_user")) &&
				prefs.putString("auth_pass", server.arg("_auth_pass")))
			{
				delay(5000);
				prefs.end();
				str += "Success : User and Password saved.<br />\n";
				str += "User = " + String(server.arg("_auth_user")) + "<br />Pass = " + String(server.arg("_auth_pass")) + "<br /><br />\n";
				str += "server going reset after 10 sec.<br />\n";
				str += "</body></html>";
				server.send(200, "text/html", str);
				delay(10000);
				ESP.restart();
			}
			else
			{
				prefs.remove("auth_user");
				prefs.remove("auth_pass");
				prefs.end();
				delay(10000);
				str += "Error: not saved User and Password. plz retry.";
			}
		}
		else
		{
			// SSID,Pass設定用フォーム
			str += "<br /><form action='' method='post'>\n";
			str += "User : <input type='text' name='_auth_user'><br />\n";
			str += "Pass : <input type='text' name='_auth_pass'><br />\n";
			str += "<input type='submit' value='send'>\n";
			str += "</form>";
		}
	}
	else
	{
		// html作成
		str += "<html><head></head><body>\n";
		// 現在のSSIDを表示
		str += "Welcome ESP32 Server<br /><br />\n";
		// wifi scan print
		getWifiScanStr(str, wifi);
		str += "<br /><br />\n";
		str += "<a href='/set_ssid'>Wifi Setting</a> ";
		str += "<a href='/set_auth'>Auth Setting</a> ";
		str += "<a href='/factory_reset'>factory_reset</a><br />\n";
	}

	if (str.length() > 0)
	{
		str += "</body></html>";
		server.send(200, "text/html", str);
	}
	else
	{
		server.send(200, "text/plain", "Invalid Request");
	}
	delay(2);
}

// ポーリングなどを
void WebServerPolling(void *param)
{
	while (1)
	{
		// Webサーバー待ち受け
		server.handleClient();
		// resistance watchdog
		delay(2);
	}
}


void setup()
{
		:
		:
		:

	~ wifi設定の後ろ辺りに追加 ~


	// WebServer ------------------------------------------------------------
	//	すべてのリクエストを取得
	server.on(UriRegex("^.*?$"), response);

	// WebServerスタート
	server.begin();

	// Core 0 でWebサーバーを起動
	//	xTaskCreatePinnedToCore
	//		コアを明確に指定しない場合は xTaskCreateUniversal ラッパーを使う方がいい
	xTaskCreateUniversal(
		WebServerPolling,	//	TaskFunction_t pvTaskCode,
		"WebServerPolling", //	const char * const pcName,
		20480,				//	const uint32_t usStackDepth,	// WebServerは結構メモリ使うので大き目に
		NULL,				//	void * const pvParameters,
		1,					//	UBaseType_t uxPriority,
		pWebServerPolling,	//	TaskHandle_t * const pvCreatedTask,
		0);					//	CPU Core

	Serial.print("WebServer Started. http://");
	if (wifi.getMode() == WIFI_MODE_AP)
	{
		Serial.print(wifi.softAPIP()); // AP-mode
	}
	else
	{
		Serial.print(wifi.localIP()); // STA-mode
	}
	Serial.println("/");
	// WebServer ------------------------------------------------------------

		:
		:
		:

}

void loop()
{
	// メインループは暇なので適当に何かさせておく
	Serial.print("Heap memory malloc: ");
	Serial.println(ESP.getFreeHeap());
	Serial.print("wifi connected client: ");
	Serial.println(wifi.softAPgetStationNum());
	delay(15000);
}

だいぶゴチャゴチャしてきましたね!

動けばいいんです動けば;

こんな感じで接続先のSSIDとパスワードをフォームから保存させる入口を設置。

ついでにBASIC認証のアイパスの変更、設定全クリアも追加。

うん、無駄にダラダラしたイイ感じのものに。

#include <Arduino.h>
/*
	・nvs領域にwifi接続情報があればこれを使って接続する
	・wifi接続情報が無い、または接続できなければ無線APモードで立ち上がる
	・APモード、STAモードにかかわらず、ブラウザから設定情報を編集できる様にする
*/

// WiFiライブラリ
#include <WiFi.h>
WiFiClass wifi;

// nvsライブラリ
#include <Preferences.h>
Preferences prefs;

// ----------------------------------------------------------------
// 無線APモード時のデフォルトSSID、パスワード
String ap_ssid = "ESP32AP";
String ap_pass = "12345678";
IPAddress ap_ip = IPAddress(192, 168, 4, 1);
IPAddress ap_gw = IPAddress(192, 168, 4, 1);
IPAddress ap_mask = IPAddress(255, 255, 255, 0);
uint8_t ap_ch = 5;
uint8_t ap_hidden = 0;		  // SSIDを隠し属性にするか
uint8_t ap_maxconnection = 4; // 最大コネクション数(MAX=4)

// wifi接続用
uint8_t charrenge_retry_count = 3; // 何回接続試行するか
String wifi_ssid;
String wifi_pass;
IPAddress wifi_ip;
IPAddress wifi_gw;
IPAddress wifi_mask;
IPAddress wifi_dns1;
IPAddress wifi_dns2;

// basic認証用
String auth_user = "basic";
String auth_pass = "basic";
// ----------------------------------------------------------------

#include <lwip/sockets.h>

// WebServerライブラリ
#include <WebServer.h>
#include <uri/UriRegex.h>
WebServer server;
TaskHandle_t *pWebServerPolling;

// wifiスキャン文字列を返すだけ
bool getWifiScanStr(String &_str, WiFiScanClass &_wifi)
{
	// wifiスキャン
	//	int16_t scan_res = wifi.scanNetworks();
	int16_t scan_res = _wifi.scanNetworks();
	if (scan_res > 0)
	{
		// 発見したwifiAPを表示
		_str += "- SCAN SSID RESULT -<br /><br />\n";
		_str += String(scan_res) + " of SSID found.<br /><br />\n";
		for (int i = 0; i < scan_res; ++i)
		{
			// SSIDとRSSIをprint
			_str += String(i) + ": " + _wifi.SSID(i) + " (RSSI:" + _wifi.RSSI(i) + " dBm)<br />\n";
		}
		return true;
	}
	else
	{
		//
		_str += "-- Wifi Not Found --<br />\n";
		return false;
	}
}

void response()
{
	// 処理内容モニタ
	Serial.println("Incomming Request.");
	Serial.print("request:");
	Serial.println(server.uri());

	// BASIC認証
	if (!server.authenticate(auth_user.c_str(), auth_pass.c_str()))
	{
		return server.requestAuthentication();
	}

	// リザルト文字列
	String str;

	// サーバーリセット
	if (server.uri() == "/factory_reset")
	{
		server.send(200, "text/plain", "Factory RESET at ESP32. after restart server at 10 sec..");
		prefs.begin("config-wifi");
		prefs.clear();
		prefs.end();
		delay(10000);
		ESP.restart();
	}
	else if (server.uri() == "/set_ssid")
	{
		// html作成
		str += "<html><head></head><body>\n";
		// 現在のSSIDを表示
		str += "Wifi Setting<br /><br />\n";

		// 設定受信した場合
		if (server.hasArg("_ssid") && server.hasArg("_pass") &&
			String(server.arg("_ssid")).length() > 0 && String(server.arg("_pass")).length() > 0)
		{
			// パスワード登録モード
			prefs.begin("config-wifi");
			// nvsに保存
			if (prefs.putString("wifi_ssid", server.arg("_ssid")) &&
				prefs.putString("wifi_pass", server.arg("_pass")))
			{

				Serial.println("IP setting.");
				uint32_t _ipAddr = 0;

				// 無ければクリア、あれば書き込み
				if (lwip_inet_pton(AF_INET, server.arg("_ip").c_str(), &_ipAddr) && server.arg("_ip").length() > 0)
				{
					prefs.putUInt("wifi_ip", _ipAddr);
				}
				else
				{
					prefs.remove("wifi_ip");
				}
				if (lwip_inet_pton(AF_INET, server.arg("_gw").c_str(), &_ipAddr) && server.arg("_ip").length() > 0)
				{
					prefs.putUInt("wifi_gw", _ipAddr);
				}
				else
				{
					prefs.remove("wifi_gw");
				}
				if (lwip_inet_pton(AF_INET, server.arg("_mask").c_str(), &_ipAddr) && server.arg("_ip").length() > 0)
				{
					prefs.putUInt("wifi_mask", _ipAddr);
				}
				else
				{
					prefs.remove("wifi_mask");
				}
				if (lwip_inet_pton(AF_INET, server.arg("_dns1").c_str(), &_ipAddr) && server.arg("_ip").length() > 0)
				{
					prefs.putUInt("wifi_dns1", _ipAddr);
				}
				else
				{
					prefs.remove("wifi_dns1");
				}
				if (lwip_inet_pton(AF_INET, server.arg("_dns2").c_str(), &_ipAddr) && server.arg("_ip").length() > 0)
				{
					prefs.putUInt("wifi_dns2", _ipAddr);
				}
				else
				{
					prefs.remove("wifi_dns2");
				}

				Serial.println(_ipAddr);

				Serial.println("IP setting end.");

				delay(5000);
				prefs.end();
				str += "Success : SSID and Password saved.<br />\n";
				str += "SSID = " + String(server.arg("_ssid")) + "<br />Pass = " + String(server.arg("_pass")) + "<br /><br />\n";
				str += "IP = " + String(server.arg("_ip")) + "<br />GW = " + String(server.arg("_gw")) + "<br /><br />\n";
				str += "MASK = " + String(server.arg("_mask")) + "<br />\n";
				str += "DNS1 = " + String(server.arg("_dns1")) + "<br />DNS2 = " + String(server.arg("_dns2")) + "<br /><br />\n";
				str += "server going reset after 10 sec.<br />\n";
				str += "</body></html>";
				server.send(200, "text/html", str);
				delay(10000);
				ESP.restart();
			}
			else
			{
				prefs.end();
				delay(5000);
				str += "Error: not saved SSID and Password. plz retry.";
			}
		}
		else
		{
			// wifi scan print
			getWifiScanStr(str, wifi);

			Serial.println("IP setting.");

			prefs.begin("config-wifi", true);
			//			uint32_t _ipAddr = 0;
			IPAddress _ipAddr;
			// SSID,Pass設定用フォーム
			str += "<br /><form action='' method='post'>\n";
			str += "SSID : <input type='text' name='_ssid' value='" + prefs.getString("wifi_ssid") + "'><br />\n";
			str += "PASS : <input type='text' name='_pass' value='" + prefs.getString("wifi_pass") + "'><br />\n";
			_ipAddr = prefs.getUInt("wifi_ip");
			str += "IP : <input type='text' name='_ip' value='" + _ipAddr.toString() + "'><br />\n";
			_ipAddr = prefs.getUInt("wifi_gw");
			str += "GW : <input type='text' name='_gw' value='" + _ipAddr.toString() + "'><br />\n";
			_ipAddr = prefs.getUInt("wifi_mask");
			str += "MASK : <input type='text' name='_mask' value='" + _ipAddr.toString() + "'><br />\n";
			_ipAddr = prefs.getUInt("wifi_dns1");
			str += "DNS1 : <input type='text' name='_dns1' value='" + _ipAddr.toString() + "'><br />\n";
			_ipAddr = prefs.getUInt("wifi_dns2");
			str += "DNS2 : <input type='text' name='_dns2' value='" + _ipAddr.toString() + "'><br />\n";
			str += "<input type='submit' value='send'>\n";
			str += "</form>";
			prefs.end();
		}
	}
	else if (server.uri() == "/set_auth")
	{
		// html作成
		str += "<html><head></head><body>\n";
		// 現在のSSIDを表示
		str += "Auth Setting<br /><br />\n";

		// 設定受信した場合
		if (server.hasArg("_auth_user") && server.hasArg("_auth_pass") &&
			String(server.arg("_auth_user")).length() > 0 && String(server.arg("_auth_pass")).length() > 0)
		{
			// パスワード登録モード
			prefs.begin("config-wifi");
			// nvsに保存
			if (prefs.putString("auth_user", server.arg("_auth_user")) &&
				prefs.putString("auth_pass", server.arg("_auth_pass")))
			{
				delay(5000);
				prefs.end();
				str += "Success : User and Password saved.<br />\n";
				str += "User = " + String(server.arg("_auth_user")) + "<br />Pass = " + String(server.arg("_auth_pass")) + "<br /><br />\n";
				str += "server going reset after 10 sec.<br />\n";
				str += "</body></html>";
				server.send(200, "text/html", str);
				prefs.end();
				delay(10000);
				ESP.restart();
			}
			else
			{
				prefs.remove("auth_user");
				prefs.remove("auth_pass");
				prefs.end();
				delay(5000);
				str += "Error: not saved User and Password. plz retry.";
			}
		}
		else
		{
			// SSID,Pass設定用フォーム
			str += "<br /><form action='' method='post'>\n";
			str += "User : <input type='text' name='_auth_user'><br />\n";
			str += "Pass : <input type='text' name='_auth_pass'><br />\n";
			str += "<input type='submit' value='send'>\n";
			str += "</form>";
		}
	}
	else
	{
		// html作成
		str += "<html><head></head><body>\n";
		// 現在のSSIDを表示
		str += "Welcome ESP32 Server<br /><br />\n";
		// wifi scan print
		getWifiScanStr(str, wifi);
		str += "<br /><br />\n";
		str += "<a href='/set_ssid'>Wifi Setting</a><br />";
		str += "<a href='/set_auth'>Auth Setting</a><br />";
		str += "<hr />";
		str += "<a href='/factory_reset'>factory_reset</a><br />\n";
	}

	if (str.length() > 0)
	{
		str += "</body></html>";
		server.send(200, "text/html", str);
	}
	else
	{
		server.send(200, "text/plain", "Invalid Request");
	}
	delay(2);
}

// ポーリングなどを
void WebServerPolling(void *param)
{
	while (1)
	{
		// Webサーバー待ち受け
		server.handleClient();
		// resistance watchdog
		delay(2);
	}
}

// setup
void setup()
{

	// シリアル開始
	Serial.begin(115200);
	Serial.println();
	Serial.println("beginning AP..");

	// Wifi ------------------------------------------------------------
	// 既に接続中なら一旦切る
	wifi.setAutoConnect(false);
	if (wifi.isConnected())
	{
		wifi.disconnect();
		delay(3000);
	}

	//	・nvs領域にwifi接続情報があればこれを使って接続する
	//	nvsシリアル開始 ReadOnly
	if (prefs.begin("config-wifi", true))
	{
		// コンフィグリセット
		if (prefs.getBool("reset_config"))
		{
			// Writeで開き直してリセット
			prefs.end();
			prefs.begin("config-wifi");
			prefs.clear();
			prefs.end();
			delay(8000);
		}
		else
		{
			// コンフィグロード
			if (prefs.getString("wifi_ssid").length() > 0)
				wifi_ssid = prefs.getString("wifi_ssid");
			if (prefs.getString("wifi_pass").length() > 0)
				wifi_pass = prefs.getString("wifi_pass");

			if (prefs.getUInt("wifi_ip") > 0)
				wifi_ip = IPAddress(prefs.getUInt("wifi_ip"));
			if (prefs.getUInt("wifi_gw") > 0)
				wifi_gw = IPAddress(prefs.getUInt("wifi_gw"));
			if (prefs.getUInt("wifi_mask") > 0)
				wifi_mask = IPAddress(prefs.getUInt("wifi_mask"));
			if (prefs.getUInt("wifi_dns1") > 0)
				wifi_dns1 = IPAddress(prefs.getUInt("wifi_dns1"));
			if (prefs.getUInt("wifi_dns2") > 0)
				wifi_dns2 = IPAddress(prefs.getUInt("wifi_dns2"));

			if (prefs.getString("ap_ssid").length() > 0)
				ap_ssid = prefs.getString("ap_ssid");
			if (prefs.getString("ap_pass").length() > 0)
				ap_pass = prefs.getString("ap_pass");

			if (prefs.getUInt("ap_ip") > 0)
				ap_ip = IPAddress(prefs.getUInt("ap_ip"));
			if (prefs.getUInt("ap_gw") > 0)
				ap_gw = IPAddress(prefs.getUInt("ap_gw"));
			if (prefs.getUInt("ap_mask") > 0)
				ap_mask = IPAddress(prefs.getUInt("ap_mask"));

			if (prefs.getUChar("ap_ch") > 0)
				ap_ch = prefs.getUChar("ap_ch");
			if (prefs.getUChar("ap_hidden") > 0)
				ap_hidden = prefs.getUChar("ap_hidden");
			if (prefs.getUChar("ap_maxconnection") > 0)
				ap_maxconnection = prefs.getUChar("ap_maxconnection");

			if (prefs.getUChar("charrenge_retry_count") > 0)
				charrenge_retry_count = prefs.getUChar("charrenge_retry_count");

			if (prefs.getString("auth_user").length() > 0)
				auth_user = prefs.getString("auth_user");
			if (prefs.getString("auth_pass").length() > 0)
				auth_pass = prefs.getString("auth_pass");
			// 閉じておく
			prefs.end();
		}

		Serial.println("configure wifi mode.");

		// STA-mode ssid, pass
		if (wifi_ssid.length() > 0 && wifi_pass.length() > 0)
		{
			// wifi通信開始
			wifi.mode(WIFI_STA);
			Serial.println(wifi_ip);
			Serial.println(wifi_gw);
			Serial.println(wifi_mask);
			Serial.println(wifi_dns1);
			Serial.println(wifi_dns2);
			// コンフィグがあればロード
			if (wifi_ip > 0)
			{
				// 設定値があれば固定IPを設定する
				//	0はライブラリがよしなにやってくれる・・・?
				//	bool config(IPAddress local_ip, IPAddress gateway, IPAddress subnet, IPAddress dns1 = (uint32_t)0, IPAddress dns2 = (uint32_t)0)
				// ここは未検証なので暇なときにでも
				wifi.config(
					wifi_ip,
					wifi_gw,
					wifi_mask,
					wifi_dns1,
					wifi_dns2);
			}
			wifi.begin(wifi_ssid.c_str(), wifi_pass.c_str());
			Serial.println("start wifi.");
			delay(6000);

			// 接続待ち
			int _count = 0;
			while (wifi.status() != WL_CONNECTED)
			{
				// 指定回数で抜ける
				if (_count >= charrenge_retry_count)
				{
					Serial.println("wifi connection failed. booting AP mode.");
					break;
				}
				Serial.println("wifi connecting...");
				Serial.println();
				delay(3000);
				if (wifi.status() == WL_CONNECT_FAILED)
				{
					Serial.println("wifi connection failed. please check settings again.");
					Serial.print("\n\n");
					break;
				}
				_count++;
			}
		}
	}

	// リザルトメッセージ
	if (wifi.status() == WL_CONNECTED)
	{
		Serial.println("wifi connected.");
		Serial.println("IP address: ");
		Serial.println(wifi.localIP());
		Serial.println("GW address: ");
		Serial.println(wifi.gatewayIP());
		Serial.println("DNS address: ");
		Serial.println(wifi.dnsIP());
		Serial.println();
	}
	else
	{
		// nvs読み込み失敗 | コネクション確立不可
		// softAPモードで設定
		Serial.println("booting AP-mode.");
		wifi.mode(WIFI_AP);
		wifi.softAP(ap_ssid.c_str(), ap_pass.c_str(), ap_ch, ap_hidden, ap_maxconnection);
		delay(200);
		wifi.softAPConfig(ap_ip, ap_gw, ap_mask);

		Serial.print("AP-mode IP address: ");
		Serial.print(wifi.softAPIP());
		Serial.println();
	}
	// Wifi ------------------------------------------------------------

	delay(100);

	// WebServer ------------------------------------------------------------
	//	すべてのリクエストを取得
	server.on(UriRegex("^.*?$"), response);

	// WebServerスタート
	server.begin();

	// Core 0 でWebサーバーを起動
	//	xTaskCreatePinnedToCore
	//		コアを明確に指定しない場合は xTaskCreateUniversal ラッパーを使う方がいい
	xTaskCreateUniversal(
		WebServerPolling,	//	TaskFunction_t pvTaskCode,
		"WebServerPolling", //	const char * const pcName,
		20480,				//	const uint32_t usStackDepth,	// WebServerは結構メモリ使うので大き目に
		NULL,				//	void * const pvParameters,
		1,					//	UBaseType_t uxPriority,
		pWebServerPolling,	//	TaskHandle_t * const pvCreatedTask,
		0);					//	CPU Core

	Serial.print("WebServer Started. http://");
	if (wifi.getMode() == WIFI_MODE_AP)
	{
		Serial.print(wifi.softAPIP()); // AP-mode
	}
	else
	{
		Serial.print(wifi.localIP()); // STA-mode
	}
	Serial.println("/");
	// WebServer ------------------------------------------------------------
}

void loop()
{
	Serial.print("Heap memory malloc: ");
	Serial.println(ESP.getFreeHeap());
	Serial.print("wifi connected client: ");
	Serial.println(wifi.softAPgetStationNum());
	delay(15000);
}

さて、こんな感じでnvsに保存しておける訳ですね

nvsへの出入力は型を合わせないといけないので結構面倒でした。

C言語というのは文字列を扱うのがだるくて肩が凝ります。

マルチタスクっぽくCPUを別にしたりBASIC認証入れたり、あと未実装なものも色々詰め込んだ今迄テストしてきたものをゴチャっと盛り合わせた内容になっております。

・・・・

なんか酷いコードになってしまったので、再利用する時があれば作り直します・・・