文章程式碼顯示

2018年3月3日 星期六

NodeMCU 教學 - 14:NodeMCU 讀取 Flash 資料與 SmartConfig 結合

前文提到我們不太喜歡將 Wifi 的帳號密碼寫死在程式裡面,所以我們藉由 SmartConfig 的方式,可以用手機來讓 NodeMCU 連上網路

但也有一個很麻煩的地方在於,只要 NodeMCU 斷電之後,又要重新開起手機的 APP 再連線一次

故我們希望,如果可以將 Wifi 的帳號密碼儲存於 Flash 之中,並且調用出來呢?

註 : 

沒錯,將帳號密碼從 Flash 中讀取出來再讓 NodeMCU 連上網路

跟 "把 WIFi 帳密寫死在程式內 " 可以說是一模一樣的行為

但這個只是一個練習而已,只要結合前一篇文章中的 Flash 資料寫入

我們就可以串接起來,讓 NodeMCU 可以在初次連接 WiFi 的時候使用手機 APP 設定,並且將 WiFi 帳號密碼寫入 Flash 中。

當 NodeMCU 斷電重啟後,可以自動從 Flash 中抓出 WiFi 帳號密碼 

#include "ESP8266WiFi.h"

bool connectWiFi(const char* ssid, const char* pass, int tryNumber);
bool combine();
void smartConfig();

const uint32_t Base_address = 0x3FA000;
char Name_buff[64];
char pass_buff[64];
uint32_t Count;
static int n = 0;
static int RemJ = 0;
int _SSID = 404;

void setup() {
  
  Serial.begin(115200);
  pinMode(D4, OUTPUT);
  if ( combine() ) Serial.println("Success");
  else Serial.println("False");  
  
  if ( !ESP.flashRead( Base_address + 2*RemJ*64, (uint32_t*)pass_buff, 64 ) ) {
    } else Serial.printf( "%2d: addr: %p value [%s] \n", 1, Base_address + 2*64, pass_buff );
  
  connectWiFi(Name_buff,pass_buff,20);
  
  if ( WiFi.status() != WL_CONNECTED ) smartConfig();

}

void loop() {
  // put your main code here, to run repeatedly:
}

bool connectWiFi(const char* ssid, const char* pass, int tryNumber){
    
    int _try = 0;
    WiFi.mode(WIFI_STA);
    delay(500);
    WiFi.begin(ssid,pass);
    Serial.print("Connecting to ");
    Serial.println(ssid);
    
    while( WiFi.status() != WL_CONNECTED ){
      if( _try <= tryNumber){
        delay(500);
        _try++;
        Serial.print(_try);
      }
      else {Serial.println("\nConnected Failed");  return false; }
    }

    Serial.println("\nConnected success");
    
    return true;
}

void smartConfig(){
  
  Serial.println("\r\nWait for Smartconfig");
  WiFi.beginSmartConfig();
  pinMode(D4,OUTPUT);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500); //勿刪
    digitalWrite(D4, !digitalRead(D4) ); // ESP8266 上的藍色指示燈閃爍
    Serial.print(".");

      if ( WiFi.smartConfigDone() )
      {
        Serial.println("\nSmartConfig Success");
        Serial.printf("SSID : %s\r\n", WiFi.SSID().c_str() );
        Serial.printf("PassWord : %s\r\n", WiFi.psk().c_str() );
        break;
      }      
  }  
  Serial.println("WiFi connected");  
  digitalWrite(D4, LOW);
  
}

bool combine(){  
  
// 搜尋週邊 wifi ,可由 WiFi.SSID(i) 讀取出,回傳搜尋到的 wifi 數量
  WiFi.mode(WIFI_STA);
  WiFi.disconnect();
  
  n = WiFi.scanNetworks(); //回傳找到的 wifi 數量

  if (n == 0){
    Serial.println("No networks found !");
  }
  else
  {
    Serial.print(n);
    Serial.println(" networks found\n");
    for (int i = 0; i < n; ++i)
    {
      Serial.printf("%d. ", i);
      Serial.println(WiFi.SSID(i));
      delay(10);
    }
  }
  Serial.println("");

  if ( !ESP.flashRead( Base_address, (uint32_t*)&Count, 32 ) ) {;}
        else Serial.printf( "addr: %p Count : %d \n\n", Base_address, Count ); // 讀取 Flash 中被記憶過的 Wifi 名稱

  Serial.printf("n = %d\n", n);
  
  for ( int i = 0; i < n ; i++){
    for ( int j = 1; j <= (Count*2) -1 ; j = j + 2){
        if ( !ESP.flashRead( Base_address + j*64, (uint32_t*)Name_buff, 64 )){
        }//else Serial.printf( "addr: %p SSID : %s \n", Base_address + j*64, Name_buff ); // 列印 Flash 中被記憶過的 Wifi 名稱              
        if ( !(strcmp(WiFi.SSID(i).c_str(),Name_buff)) ) {  _SSID = i; RemJ = j; Serial.printf("SSID Match, RemJ = %d\n",RemJ); break;}
          else Serial.printf("%s is NOT in the FLASH \n",WiFi.SSID(i).c_str());        
    }
    if ( _SSID != 404 ) { break; }
  }

  if ( _SSID == 404 ) { Serial.println("\nNot found"); return false; }
    else {  
      Serial.printf("\nFind SSID : %s\r\n", WiFi.SSID(_SSID).c_str() );    
      return true;
    }
}





註:已事先在 0x3fa040 及 0x3fa080 寫入 WIFI 帳號以及密碼(見前一章的補充),並且故意將 WiFi 來源關閉

開啟 WiFi 分享的話會是以下結果


↓↓↓ 連結到部落格方針與索引 ↓↓↓

Blog 使用方針與索引