ESP8266の動作中にWiFi基地局が無くなったりした時でも本体に触らないで何とかする為の実験

#まずは事件が
　最近WiFiの基地局を変更した時の事なのですが、基地局にログインできなくなった
GoogleHomeとNatureRemoと動作確認中のESP8266に再設定を行う事態に陥りました。
３つの対応は以下のとうり
　GoogleHome  :　　端末名.o のSSIDの局が出来て再設定を促している
　　　　　再設定=> 設定ソフトを呼び出し、端末名.o の局に繋いで再設定
　NatureRemo　：   なにやら表示灯が点滅している
　　　　　再設定=> 設定ソフトを呼び出し、端末のリセットボタンを押し
　　　　　　　　　　　端末固有名の局に繋いで再設定
　ESP8266　　  :   ぽか～～～ん（表示無し）
　　　　　再設定=> 端末の強制AP接続モードボタンを押し、
　　　　　　　　　　　端末固有名の局に繋いで再設定

　正直NatureRemoとESP8266の再設定は、本体を触る必要があり面倒でした。


#ESP8266はWiFi基地局との接続が１度切れると？
　折角なので今回ESP8266の接続した基地局が電源OFF・ONとなると接続はどうなる
　か確認してみました。　　結果は高い頻度で未接続状態に陥る様です。
　※我が家の運用実績はもっと良いので、接続復帰しても良いのですが・・・・　
　当然未接続に落ちても報告機能は無いので何も判りませんｗｗｗ


#そこで欲しい機能を考えた
　現在作っているESP8266のソフトは絶対WiFiに接続できる前提で作っているが
　WiFiがダウンしている状況でも動作して、WiFi復帰後は再接続を行えて、
　WiFi未接続時は基地局モードになり、WebServerに接続してWiFiの再設定が
　できるべきではないか？　


#今回の実験
　・ソフト起動時はWiFi_AP_STAモードで、自分が基地局として立ち上がりつつ
　　　設定にあるWiFi基地局への接続を試す。　並走のAPモードでは、後日追記
　　　予定のWebserverでWiFi接続設定の変更画面を提供する。
　・WiFi基地局への接続が確認できたら WiFi_AP_STAモードをWiFi_STAモードに
　　　変更して、WiFi基地局へ再度接続を行う。（目的：リソース利用量の削減
　・WiFi基地局の接続が累積で１時間接続できなかったらESP8266をリセット。
　　　原因不明の基地局検知不良を想定したリセットです。
　・WiFi基地局へ接続できない時は複数のESP8266がWiFiに繋がらないのを想定。
　　　APモードの基地局名の重複を防ぐ為にMacアドレス末尾６桁を使う。
　・とりあえず今回はWebServerの実装は無し。

　これで基本機能は達成できそうな気がする。


#でESP32の移植性はどうなのよ？
　include文の変更で動作すると思います。(今回はESP32で作成してESP8266に移植)
　APSTAモードも同様の挙動をしてくれるので、基本設計の方に感謝であります。
　※ESP32の方が若干挙動不安定で、頻繁に基地局の接続が出来ない症状を確認して
　　います。（この実験コードが役に立っている）


#そして出来たコード
　思ったより少ないコードで出来た感じです。
　このコードに以前作成した、WebServerソフトをセットしたら良い感じになるかな？
　後はNTPでの時刻合わせ完了も待つコードを足すと、良い感じになりそうです。


```ino:ESP8266APSTA.ino:
#include <ESP8266WiFi.h>
const char* ssid     = "guest";
const char* password = "guest";

char AP_SSID[13];                     // アクセスポイントのSSID(自動生成)
bool WiFi_AP_STA_mode;                // 現在の接続モード
bool WiFi_ConnectOnce;                // WiFi接続時の最初の初期処理
int WiFi_TickCount;                   // ESP8266起動からのカウント(10秒)
int WiFi_LostCount = 0;               // WiFi未接続のカウント

// 初期処理
//   WIFI_AP_STAモードで起動します。
void setup() {
  Serial.begin(115200);
  delay(10);
  WiFi_AP_STA_mode = true;
  WiFi.mode(WIFI_AP_STA);
  WiFi.disconnect(true);
  uint8_t mac1[6];
  WiFi.softAPmacAddress(mac1);
  sprintf( AP_SSID, "ESPAP_%02X%02X%02X", mac1[3], mac1[4], mac1[5] );
  WiFi.softAP( AP_SSID, "" );
  Serial.print( "AP SSID name :" );
  Serial.println( AP_SSID );
  IPAddress myIP = WiFi.softAPIP();
  WiFi.begin(ssid, password);
  delay(100);
  Serial.print("AP IP address: ");
  Serial.println(myIP);
}
// WiFi接続チェック
int WiFi_ConnectCheck( ){
  int WiFiStatus;
  WiFiStatus = WiFi.status();
  if( WiFiStatus==WL_CONNECTED ){
    if( WiFi_AP_STA_mode==true ){
      Serial.print("WiFi Reconnect[");
      Serial.print(ssid);
      Serial.println("]");
      WiFi.disconnect(true);
      WiFi.mode(WIFI_STA);
      WiFi_AP_STA_mode = false;
      WiFi.begin(ssid, password);
      WiFi_ConnectOnce = false;
      delay(1000);
      return WL_DISCONNECTED;
    }
    if( WiFi_ConnectOnce!=true ){
      Serial.print("WiFi Connect[");
      Serial.print(ssid);
      Serial.println("]");
      WiFi_ConnectOnce = true;
      WiFi_LostCount = 0;
    }
    return WiFiStatus;
  }
  // WiFi未接続時の処理
  //     10秒毎にメッセージを表示します。
  //     WiFi未接続が360カウント蓄積すると、ESP8266をリセットします。
  if( WiFi_TickCount==(millis()/10000) )  return WiFiStatus;
  WiFi_TickCount = millis()/10000;
  WiFi_LostCount++;
  if( WiFi_LostCount>(6*60) ){
    Serial.println("Can't connect WiFi network");
    Serial.println("ESP8266 reset");
    delay(1000);
    ESP.reset();
    delay(4000);
    return WiFiStatus;
  }
  Serial.print("WiFi Start[");
  Serial.print(WiFi_timeCount);
  Serial.print(":");
  Serial.print(ssid);
  Serial.print(":");
  switch( WiFiStatus ){
//  case WL_CONNECTED:       Serial.print("assigned when connected to a WiFi network;");    break; // ココは来ない
    case WL_NO_SHIELD:       Serial.print("assigned when no WiFi shield is present;");      break;
    case WL_IDLE_STATUS:     Serial.print("WL_IDLE_STATUS");                                break;
    case WL_NO_SSID_AVAIL:   Serial.print("assigned when no SSID are available;");          break;
    case WL_SCAN_COMPLETED:  Serial.print("assigned when the scan networks is completed;"); break;
    case WL_CONNECT_FAILED:  Serial.print("assigned when the connection fails for all the attempts;");break;
    case WL_CONNECTION_LOST: Serial.print("assigned when the connection is lost;");         break;
    case WL_DISCONNECTED:    Serial.print("assigned when disconnected from a network;");    break;
    default:                 Serial.print("unknown:"); Serial.print( WiFiStatus );          break;
  }
  Serial.println("]");
  return WiFiStatus;
}
// メインループ
void loop() {
  if( WiFi_ConnectCheck()!=WL_CONNECTED ) return;
  // WiFi接続中に行う処理を記述します
}```