ESP8266/ESP32+OLED12864简单WiFi扫描器 支持OTA

功能描述

OLED显示SSID
全中文界面
支持中文SSID
Arduino OTA支持

硬件准备

ESP8266:NodeMCU WiFi
ESP32:WIFI+BLE+OLED开发板(OLED控制芯片:SSD1315兼容SSD1306)
OLED:1.3’ 控制芯片:SH1106

软件准备

Arduino IDE
U8g2lib

连线

按键:GPIO 0
板载LED:GPIO 16
GND -
VCC - 3.3v
OLED SCK - GPIO 14 (NodeMCU D5)
OLED MOSI - GPIO 13(NodeMCU D7)
OLED CS - GPIO 15 (NodeMCU D8)
OLED DC - GPIO 2 (NodeMCU D4)
ESP8266/ESP32+OLED12864简单WiFi扫描器 支持OTA_第1张图片

程序

/*
   WiFiScannerOLED.ino -- 一个简易ESP8266/ESP32网络扫描器.
   扫描结果将会被显示在OLED12864上.
   可以通过OTA进行升级
   Written by CNflysky 20.3.10
   last edited by CNflysky at 20.3.21*/

#define BOARD 32
/* 板卡选择,ESP32=32,ESP8266=8266 */
#if (BOARD == 32)
#include 
#elif (BOARD == 8266)
#include 
#endif

#include 
#include 
#include 
#include 
#define LED 16      /* 板载LED选择 */
#define BUTTON 0    /* 板载按键选择,这里选择的是板上的Flash(Boot)按键作为扫描键 */
int ssids = 0;
bool networkfound = false;
const char *ssid = "TP-LINK_18A4";   /* 你的SSID */
const char *password = "jse105724482";   /* 你的密码 */
int state = 0; /* 0:正常运行 1:OTA升级模式 */

/* OLED构造函数,按需修改即可 */
U8G2_SSD1306_128X64_NONAME_F_SW_I2C u8g2( U8G2_R0, /* clock=*/ 4, /* data=*/ 5, /* reset=*/ U8X8_PIN_NONE );

typedef enum {
  BUTTON_CLICK,
  BUTTON_LONG_PRESS,
  BUTTON_NOT_PRESSED
} buttonState;

struct wifis_t {
  String  ssid;
  String  encryption;
  int rssi;
};

void setup() {
  /* 初始化开发板 */
  pinMode( LED, OUTPUT );
  digitalWrite( LED, HIGH );      /* 本人开发板上的LED是低电平触发,所以将LED脚拉高,请按需选择 */
  u8g2.setFont( u8g2_font_wqy12_t_gb2312 );
  u8g2.begin();
  u8g2.enableUTF8Print();
  displayWelcome();               /* 显示欢迎语,可去除 */
  WiFi.mode( WIFI_STA );
  //配置OTA函数
  ArduinoOTA.onStart( handleOTAStart );
  ArduinoOTA.onEnd( handleOTAEnd );
  ArduinoOTA.onProgress( handleOTAProgress );
  ArduinoOTA.onError( handleOTAError );
  delay( 100 );
}

void handleOTA() {
  char * str = "升级模式";
  char * str2 = "连接中...";
  char * str3 = "未搜索到预保存SSID";
  u8g2.clearBuffer();
  u8g2.drawUTF8( u8g2.getDisplayWidth() / 2 - u8g2.getUTF8Width( str ) / 2, u8g2.getMaxCharHeight(), str );
  if (networkfound == false) {
    u8g2.sendBuffer();
    int count = WiFi.scanNetworks();
    for (int i = 0; i < count; ++i) {
      if (!strcmp(ssid, WiFi.SSID(i).c_str())) {
        networkfound = true;
      }
    }
  }
  if (networkfound == false) {
    u8g2.drawUTF8( 0, u8g2.getMaxCharHeight() * 2, str3 );
    u8g2.sendBuffer();
    delay(3000);
  } else {
    if (WiFi.status() != WL_CONNECTED) {
      u8g2.drawUTF8( u8g2.getDisplayWidth() / 2 - u8g2.getUTF8Width( str ) / 2, u8g2.getMaxCharHeight() * 2, str2 );
      WiFi.begin(ssid, password);
      delay(1000);
      if (WiFi.status() != WL_CONNECTED)
        WiFi.reconnect();
    } else {
      u8g2.setCursor( 0, u8g2.getMaxCharHeight() * 2 );
      u8g2.print( WiFi.localIP() );
      ArduinoOTA.begin();
      ArduinoOTA.handle();
    }
    u8g2.sendBuffer();
  }
}
void handleOTAStart() {
  digitalWrite( LED, LOW );
}

void handleOTAEnd() {
  digitalWrite( LED, HIGH );
  char * str  = "升级完成";
  char * str2 = "三秒后自动重启";
  u8g2.clearBuffer();
  u8g2.drawUTF8( u8g2.getDisplayWidth() / 2 - u8g2.getUTF8Width( str ) / 2, u8g2.getMaxCharHeight(), str );
  u8g2.drawUTF8( u8g2.getDisplayWidth() / 2 - u8g2.getUTF8Width( str2 ) / 2, u8g2.getMaxCharHeight() * 2, str2 );
  u8g2.sendBuffer();
  delay( 3000 );
  ESP.restart();
}

void handleOTAError( ota_error_t error ) {
  char * str = "升级失败";
  u8g2.clearBuffer();
  u8g2.drawUTF8( u8g2.getDisplayWidth() / 2 - u8g2.getUTF8Width( str ) / 2, u8g2.getDisplayHeight() / 2 + u8g2.getMaxCharHeight() / 2, str );
  u8g2.sendBuffer();
}

void handleOTAProgress( unsigned int progress, unsigned int total ) {
  u8g2.clearBuffer();
  u8g2.setCursor( 0, u8g2.getMaxCharHeight() );
  u8g2.print( "升级中:" );
  u8g2.print( (progress / (total / 100) ) );
  u8g2.print( "%" );
  u8g2.sendBuffer();
}

struct wifis_t *getWiFisInfo( int count ) {
  wifis_t *wifis = new wifis_t[count];
  wifis_t switcher;
  for ( int i = 0; i < count; ++i ) {
    wifis[i].ssid = WiFi.SSID( i );
    wifis[i].rssi = WiFi.RSSI( i );
    /* 由于ESP8266和ESP32在加密方式的常量定义上有所不同,这里分为两部分 */
#if (BOARD == 32)
    switch ( WiFi.encryptionType( i ) ) {
      case WIFI_AUTH_OPEN:
        wifis[i].encryption = "Open";
        break;
      case WIFI_AUTH_WEP:
        wifis[i].encryption = "WEP";
        break;
      case WIFI_AUTH_WPA_PSK:
        wifis[i].encryption = "WPA";
        break;
      case WIFI_AUTH_WPA2_PSK:
        wifis[i].encryption = "WPA2";
        break;
      case WIFI_AUTH_WPA_WPA2_PSK:
        wifis[i].encryption = "WPA/WPA2";
        break;
      case WIFI_AUTH_WPA2_ENTERPRISE:
        wifis[i].encryption = "WPA2 EP";
        break;
    }
#elif (BOARD == 8266)
    switch ( WiFi.encryptionType( i ) ) {
      case ENC_TYPE_NONE:
        wifis[i].encryption = "Open";
        break;
      case ENC_TYPE_WEP:
        wifis[i].encryption = "WEP";
        break;
      case ENC_TYPE_TKIP:
        wifis[i].encryption = "WPA";
        break;
      case ENC_TYPE_CCMP:
        wifis[i].encryption = "WPA2";
        break;
      case ENC_TYPE_AUTO:
        wifis[i].encryption = "WPA/WPA2";
        break;
    }
#endif
    /* wifis[i].encryption=WiFi.encryptionType(i); */
  }
  /* 排序 */
  for ( int i = 0; i < count; i++ ) {
    for ( int j = 0; j < count; j++ ) {
      if ( wifis[i].rssi * -1 < wifis[j].rssi * -1 ) {
        switcher = wifis[i];
        wifis[i] = wifis[j];
        wifis[j] = switcher;
      }
    }
  }
  return (wifis);
}

void displayWelcome() {
  char *str = "正在启动...";
  u8g2.clearBuffer();
  /* 将字符串显示在屏幕中央 */
  u8g2.drawUTF8( u8g2.getDisplayWidth() / 2 - u8g2.getUTF8Width( str ) / 2, u8g2.getDisplayHeight() / 2 + u8g2.getMaxCharHeight() / 2, str );
  u8g2.sendBuffer();
  /* while(1); */
}

int getButtonState( int pin ) {
  pinMode( pin, INPUT );
  if ( digitalRead( pin ) == LOW ) { /* 本人开发板上的按键按下为低电平,请根据你自己的情况修改 */
    int pressTime = millis();
    while ( digitalRead( pin ) == LOW );
    int releaseTime = millis();
    if ( releaseTime - pressTime <= 500 && releaseTime - pressTime >= 20 )
      return (BUTTON_CLICK);
    else if ( releaseTime - pressTime > 2000 ) {
      return (BUTTON_LONG_PRESS);
    }
  } else return (BUTTON_NOT_PRESSED);
}

void displaySSIDs( int count, wifis_t *wifis ) {
  int y = u8g2.getMaxCharHeight();
  int offset  = 11;
  u8g2.drawUTF8( 0, y - 3, "网络名称" );
  u8g2.drawUTF8( (u8g2.getDisplayWidth() - u8g2.getMaxCharWidth() * 3) - 10, y - 3, "强度" );
  u8g2.drawUTF8( u8g2.getDisplayWidth() - u8g2.getMaxCharWidth() * 2 + 3, y - 3, "安全" );
  for ( int i = 0; i < count; i++ ) {
    if ( y < u8g2.getDisplayHeight() ) {
      u8g2.setCursor( 0, y + offset );
      u8g2.print( wifis[i].ssid );
      /* Serial.println(wifis[i].ssid.isAlpha()); */
      u8g2.print( " " );
      u8g2.setCursor( (u8g2.getDisplayWidth() - u8g2.getMaxCharWidth() * 3) - 1, y + offset );
      u8g2.print( wifis[i].rssi * -1 );
      u8g2.print( " " );
      u8g2.setCursor( u8g2.getDisplayWidth() - u8g2.getMaxCharWidth() * 2 + 3, y + offset );
      /* 由于屏幕大小限制,没有显示全加密方式 */
      if ( wifis[i].encryption != "Open" )
        u8g2.print( "加密" );
      else
        u8g2.print( "开放" );
      /* u8g2.println(wifis[i].encryption); */
      y += u8g2.getMaxCharHeight();
    }
  }
}

void messageWhileNoSSID() {
  char * str  = "没有发现WiFi";
  char * str2 = "按下按键开始扫描";
  u8g2.clearBuffer();
  u8g2.drawUTF8( u8g2.getDisplayWidth() / 2 - u8g2.getUTF8Width( str ) / 2, u8g2.getMaxCharHeight(), str );
  u8g2.drawUTF8( u8g2.getDisplayWidth() / 2 - u8g2.getUTF8Width( str2 ) / 2, u8g2.getMaxCharHeight() * 2, str2 );
  u8g2.sendBuffer();
}

void scanNetwork() {
  digitalWrite( LED, LOW );
  u8g2.clearBuffer();
  char * str = "扫描中...";
  u8g2.drawUTF8( u8g2.getDisplayWidth() / 2 - u8g2.getUTF8Width( str ) / 2, u8g2.getMaxCharHeight(), str );
  u8g2.sendBuffer();
  ssids = WiFi.scanNetworks();
  digitalWrite( LED, HIGH );
}

void loop() {
  int bstate = getButtonState( BUTTON );
  if ( bstate == BUTTON_CLICK && state != 1 ) {
    scanNetwork();
  } else if ( bstate == BUTTON_LONG_PRESS && state != 1 ) {
    state = 1;
  } else {
    if ( ssids > 0 && state == 0 ) {
      wifis_t *wifis = getWiFisInfo( ssids );
      u8g2.clearBuffer();
      displaySSIDs( ssids, wifis );
      u8g2.sendBuffer();
      delete[] wifis;
    } else if ( state == 1 ) {
      handleOTA();
    } else {
      messageWhileNoSSID();
    }
  }
}

成果图

ESP8266/ESP32+OLED12864简单WiFi扫描器 支持OTA_第2张图片

如何使用OTA升级功能

在代码中修改SSID和密码为你自己的WiFi名称和密码
在开机状态下,长按按钮三到五秒,松开后进入如下界面:ESP8266/ESP32+OLED12864简单WiFi扫描器 支持OTA_第3张图片
其中显示的IP地址 xxx.xxx.xxx.xxx就是ESP连接WiFi后得到的的IP地址。
打开Arduino IDE,检查工具/端口菜单,你应该会看到一个网络端口:
ESPxx-xxxxxxxxxxxx at xxx.xxx.xxx.xxx:
ESP8266/ESP32+OLED12864简单WiFi扫描器 支持OTA_第4张图片
选择这个端口之后点击上传即可。

你可能感兴趣的:(嵌入式)