【翻译系列】ESP8266 NodeMcu断网后重连网络方式

时间:2022-10-15 21:55:39

  • ❤️ 博客主页 单片机菜鸟哥,一个野生非专业硬件IOT爱好者 ❤️
  • ❤️ 本篇创建记录 2022-10-14 ❤️
  • ❤️ 本篇更新记录 2022-10-14 ❤️
  • ???? 欢迎关注 ????点赞 ????收藏 ⭐️留言 ????
  • ???? 此博客均由博主单独编写,不存在任何商业团队运营,如发现错误,请留言轰炸哦!及时修正!感谢支持!
  • ???? Arduino ESP8266教程累计帮助过超过1W+同学入门学习硬件网络编程,入选过选修课程,刊登过无线电杂志????

1.前言

在网上看到一些比较好的案例代码,可惜是纯英文文献,这里博哥主要是翻译为中文以及加上自己的一些思考。

参考文献:

【翻译系列】ESP8266 NodeMcu断网后重连网络方式
主要就是介绍检测网络断开(路由器断电)或者网络无法连接外网(运营商网络问题),如何科学重连的几种方式。

2.重连网络方式

2.1 方式1 —— 利用station提供的重连api

使用station里面的 setAutoReconnect 和 persistent 两个api。

// 设置当断开连接的时候自动重连
WiFi.setAutoReconnect(true);
// 该方法设置将WiFi参数保存于Flash
WiFi.persistent(true);

比如给个初始化案例代码:

void initWiFi() {
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  Serial.print("Connecting to WiFi ..");
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print('.');
    delay(1000);
  }
  Serial.println(WiFi.localIP());
  WiFi.setAutoReconnect(true);
  WiFi.persistent(true);
}

连接上网络之后设置一下重连的标签。

完整demo:

#include <ESP8266WiFi.h>

// 替换信息
const char* ssid = "REPLACE_WITH_YOUR_SSID"; // wifi账号
const char* password = "REPLACE_WITH_YOUR_PASSWORD"; // wifi密码

unsigned long previousMillis = 0;
unsigned long interval = 30000;

void initWiFi() {
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  Serial.print("Connecting to WiFi ..");
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print('.');
    delay(1000);
  }
  Serial.println(WiFi.localIP());
  // 设置当网络断开连接的时候自动重连
  WiFi.setAutoReconnect(true);
  WiFi.persistent(true);
}

void setup() {
  Serial.begin(115200);
  initWiFi();
  Serial.print("RSSI: ");
  Serial.println(WiFi.RSSI());
}

void loop() {
  //每间隔30s打印一下网络状态
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >=interval){
    switch (WiFi.status()){
      case WL_NO_SSID_AVAIL:
        Serial.println("Configured SSID cannot be reached");
        break;
      case WL_CONNECTED:
        Serial.println("Connection successfully established");
        break;
      case WL_CONNECT_FAILED:
        Serial.println("Connection failed");
        break;
    }
    Serial.printf("Connection status: %d\n", WiFi.status());
    Serial.print("RRSI: ");
    Serial.println(WiFi.RSSI());
    previousMillis = currentMillis;
  }
}

2.2 方式2 —— 利用 disconnect 方法

当我们检测到 WiFi.status() != WL_CONNECTED,我们可以使用:

// 断开原本的网络连接
WiFi.disconnect();
// 重新连接网络
WiFi.begin(ssid, password);

完整demo:

#include <ESP8266WiFi.h>

// 替换为个人wifi账号密码
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";

unsigned long previousMillis = 0;
unsigned long interval = 30000;

void initWiFi() {
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  Serial.print("Connecting to WiFi ..");
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print('.');
    delay(1000);
  }
  Serial.println(WiFi.localIP());
}

void setup() {
  Serial.begin(115200);
  initWiFi();
  Serial.print("RRSI: ");
  Serial.println(WiFi.RSSI());
}

void loop() {
  unsigned long currentMillis = millis();
  // 如果wifi状态不对,尝试每隔30s重连一次
  if ((WiFi.status() != WL_CONNECTED) && (currentMillis - previousMillis >=interval)) {
    Serial.print(millis());
    Serial.println("Reconnecting to WiFi...");
    WiFi.disconnect();
    WiFi.begin(ssid, password);
    Serial.println(WiFi.localIP());
    Serial.println(WiFi.RSSI());
    previousMillis = currentMillis;
  }
}

2.3 方式3 —— 利用 ESP.restart 重启模块

当我们检测到 WiFi.status() != WL_CONNECTED,我们可以使用:

// 重启整个模块
ESP.restart();

完整demo:

#include <ESP8266WiFi.h>

// 替换为个人wifi账号密码
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";

unsigned long previousMillis = 0;
unsigned long interval = 30000;

void initWiFi() {
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  Serial.print("Connecting to WiFi ..");
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print('.');
    delay(1000);
  }
  Serial.println(WiFi.localIP());
}

void setup() {
  Serial.begin(115200);
  initWiFi();
  Serial.print("RRSI: ");
  Serial.println(WiFi.RSSI());
}

void loop() {
  unsigned long currentMillis = millis();
  // 如果wifi状态不对,尝试每隔30s重启一次,走初始化流程
  if ((WiFi.status() != WL_CONNECTED) && (currentMillis - previousMillis >=interval)) {
    Serial.print(millis());
    Serial.println("Restart WiFi...");
    ESP.restart();
  }
}

2.4 方式4 —— 利用 Wi-Fi Events

ESP8266可以处理不同的wifi事件。
具体可以参考

我们可以在一些网络事件里面做处理来达到重连的效果。

这里有两个跟wifi连接有关的api。

/**
 * 注册事件处理器
 * 事件类型:STA模式下模块获取到IP地址
 * @param 事件处理回调函数(函数的入参是 WiFiEventStationModeGotIP)
 * @return WiFiEventHandler 
 */
WiFiEventHandler onStationModeGotIP(std::function<void(const WiFiEventStationModeGotIP&)>);

/**
 * 注册事件处理器
 * 事件类型:STA模式下断开网络
 * @param 事件处理回调函数(函数的入参是 WiFiEventStationModeDisconnected)
 * @return WiFiEventHandler 
 */
WiFiEventHandler onStationModeDisconnected(std::function<void(const WiFiEventStationModeDisconnected&)>);

完整demo:

#include <ESP8266WiFi.h>

// 替换个人wifi账号密码
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";

WiFiEventHandler wifiConnectHandler;
WiFiEventHandler wifiDisconnectHandler;

void initWiFi() {
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  Serial.print("Connecting to WiFi ..");
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print('.');
    delay(1000);
  }
  Serial.println(WiFi.localIP());
}

void onWifiConnect(const WiFiEventStationModeGotIP& event) {
  Serial.println("Connected to Wi-Fi sucessfully.");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
}

void onWifiDisconnect(const WiFiEventStationModeDisconnected& event) {
  Serial.println("Disconnected from Wi-Fi, trying to connect...");
  // 重连网络
  WiFi.disconnect();
  WiFi.begin(ssid, password);
}

void setup() {
  Serial.begin(115200);

  //注册事件处理
  wifiConnectHandler = WiFi.onStationModeGotIP(onWifiConnect);
  // 当检测到断开网络的情况下响应 onWifiDisconnect 方法
  wifiDisconnectHandler = WiFi.onStationModeDisconnected(onWifiDisconnect);
   
  initWiFi();
  Serial.print("RRSI: ");
  Serial.println(WiFi.RSSI());
}

void loop() {
  //delay(1000);
}

2.5 额外方式5 —— 利用应用层协议的心跳机制

如果你用到mqtt协议,可以考虑mqtt协议心跳是否正常收发,收发不了也可以考虑一下重连网络。

如果你用到http协议,也可以考虑一个心跳Ping接口,一收一发表示网络通路。