PlatformIO编译通过的库版本

  • Blynk:0.6.1
  • ArduinoJson:5.13.4
  • WifiManager:0.14
  • ESP8266:2.0.4、2.1.1、2.2.0

ArduinoIDE编译通过的库版本

  • Blynk:0.6.1
  • ArduinoJson:5.13.5
  • WifiManager:0.14.0
  • ESP8266:2.5.1

文中实测的开发板

  • WeMos D1 mini
  • NodeMCU V2/V3

实现功能

  • 可选SSID和输入TOKEN
  • 支持OTA
  • 不需要每次做一个设备就在代码里输入一次key

需要的材料

  • ESP8266
  • 按钮开关

APP端先要设置的插件

  • V0-文本框插件
  • V1-文本框插件
  • V2-文本框插件
  • V3-虚拟LED插件

附注

  1. 操作流程
    • 重置(刚上传完代码的设备最好先重置一遍):按住按钮 > 按一下RST(第一次操作最好留意串口信息我都写了的) > 设备会重启 > 出现设备热点
    • 配置:进入设备WIFI热点 > 输入SSID/密码/KEY > 点击SAVE > 等待连接成功(留意串口是否已经连接到BLYNK)

示例代码(点击代码框内左上角三个点显示全屏模式)

#define BLYNK_PRINT Serial              //必须放到第一行
#define BLYNK_DEBUG

#include <Arduino.h>              //在PlatformIO需要
#include <FS.h>                     //如果不正常就放到第二位
#include <BlynkSimpleEsp8266.h>
#include <ESP8266WiFi.h>           //https://github.com/esp8266/Arduino
#include <ESP8266mDNS.h>
#include <ESP8266WebServer.h>

#include <DNSServer.h>
#include <WiFiManager.h>          //https://github.com/tzapu/WiFiManager
#include <WiFiUdp.h>
#include <ArduinoOTA.h>
#include <ArduinoJson.h>          //https://github.com/bblanchon/ArduinoJson

const int ResetButton = D1;             //用于重置的按钮引脚,因应高低电平自行修好下面的代码
const int LEDButton = D2;               //用于点亮虚拟LED的按钮引脚,因应高低电平自行修好下面的代码

WidgetLED led3(V3);  //虚拟LED插件

int ResetButtonState = digitalRead(ResetButton);

//这里声明"参数"的预设值, 如果和值不同,则会将他们覆盖,这里可以预先把KEY填好,每次重置后都会预先输入KEY,按需要改
char blynk_token[34] = "";

//用于保存数据的标志
bool shouldSaveConfig = false;
boolean LEDbtnState = false;
BlynkTimer timer;

void buttonLedWidget()
{
  // 读取按钮引脚
  boolean isPressed = (digitalRead(LEDButton) == HIGH);
  // 如果值有变化
  if (isPressed != LEDbtnState) {
    if (isPressed) {
      led3.on();
    } else {
      led3.off();
    }
    LEDbtnState = isPressed;
  }
}
//回调通知我们需要保存配置
void saveConfigCallback () 
{
  Serial.println("Should save config");
  shouldSaveConfig = true;
}

void setup() {
  Serial.begin(115200);
  pinMode(ResetButton,INPUT);
  pinMode(LEDButton,INPUT);

  //读取FS json的配置
  Serial.println("mounting FS...");
  if (SPIFFS.begin()) {
    Serial.println("mounted file system");
    if (SPIFFS.exists("/config.json")) {
      //文件存在,读取和加载
      Serial.println("reading config file");
      File configFile = SPIFFS.open("/config.json", "r");
      if (configFile) {
        Serial.println("opened config file");
        size_t size = configFile.size();
        // 分配缓冲区以存储文件的内容。
        std::unique_ptr<char[]> buf(new char[size]);
        configFile.readBytes(buf.get(), size);
        DynamicJsonBuffer jsonBuffer;
        JsonObject& json = jsonBuffer.parseObject(buf.get());
        json.printTo(Serial);
        if (json.success()) {
          Serial.println("\nparsed json");
          strcpy(blynk_token, json["blynk_token"]);
        } else {
          Serial.println("failed to load json config");
        }
        configFile.close();
      }
    }
  } else {
    Serial.println("failed to mount FS");
  }

  // 要配置的额外参数(可以是全局的,也可以只是在设置中)
  // 连接后,parameter.getValue()将获得配置的值//After connecting, parameter.getValue() will get you the configured value
  // id/name placeholder/prompt 的默认长度
  WiFiManagerParameter custom_blynk_token("blynk", "blynk token", blynk_token, 32);

  //WiFiManager
  //本地初始化。一旦业务完成,就没有必要保留它
  WiFiManager wifiManager;

  //设置配置保存通知回调
  wifiManager.setSaveConfigCallback(saveConfigCallback);

  //在这里添加所有参数
  wifiManager.addParameter(&custom_blynk_token);

  //设置重置按钮的功能
  if (ResetButtonState == HIGH)
  {
    Serial.println("Getting Reset ESP Wifi-Setting.......");
    delay(1000);
    wifiManager.resetSettings();
    delay(5000);
    Serial.println("Formatting FS......");
    delay(1000);
    SPIFFS.format();
    delay(5000);
    Serial.println("Done Reboot In 5 seconds");
    delay(5000);
    ESP.restart();
  }

  //获取ssid并传递并尝试连接
  //如果它没有连接,它将启动具有指定名称的访问点,"AutoConnectAP",并进入等待配置的阻塞循环
  //若写成wifiManager.autoConnect("abc", "12345678"),则设备的AP热点名称为"abc",密码为"12345678",留空则热点名字为ESP_#后四位MAC,无密码.热点名可以输入中文,视乎手机而定,有的手机会显示乱码
  if (!wifiManager.autoConnect("AutoConnectAP", "")) {
    Serial.println("failed to connect and hit timeout");
    delay(3000);
    //重置并重试,或者让它深入睡眠
    ESP.reset();
    delay(5000);
  }
  //如果已经连接
  Serial.println("connected...yeey :)");
  //读取更新的参数
   strcpy(blynk_token, custom_blynk_token.getValue());
  //将自定义参数保存到FS
  if (shouldSaveConfig) {
    Serial.println("saving config");
    DynamicJsonBuffer jsonBuffer;
    JsonObject& json = jsonBuffer.createObject();
      json["blynk_token"] = blynk_token;
    File configFile = SPIFFS.open("/config.json", "w");
    if (!configFile) {
      Serial.println("failed to open config file for writing");
    }
    json.printTo(Serial);
    json.printTo(configFile);
    configFile.close();
    //end save
  }
  Serial.println("local ip");
  Serial.println(WiFi.localIP());

  //OTA部分
  // 默认主机名为:esp8266-[ChipID]可以改中文
   ArduinoOTA.setHostname("");

  ArduinoOTA.onStart([]() {
    String type;
    if (ArduinoOTA.getCommand() == U_FLASH) {
      type = "sketch";
    } else { // U_SPIFFS
      type = "filesystem";
    }
    //注意:如果更新SPIFFS,这将是使用SPIFFS.end()卸载SPIFFS的地方
    Serial.println("Start updating " + type);
  });
  ArduinoOTA.onEnd([]() {
    Serial.println("\nEnd");
  });
  ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
    Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
  });
  ArduinoOTA.onError([](ota_error_t error) {
    Serial.printf("Error[%u]: ", error);
    if (error == OTA_AUTH_ERROR) {
      Serial.println("Auth Failed");
    } else if (error == OTA_BEGIN_ERROR) {
      Serial.println("Begin Failed");
    } else if (error == OTA_CONNECT_ERROR) {
      Serial.println("Connect Failed");
    } else if (error == OTA_RECEIVE_ERROR) {
      Serial.println("Receive Failed");
    } else if (error == OTA_END_ERROR) {
      Serial.println("End Failed");
    }
  });
  ArduinoOTA.begin();
  Serial.println("Ready");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
  Blynk.config(blynk_token,"yourdomainname",8080);
  timer.setInterval(500L, buttonLedWidget);
}
void loop() {
  ArduinoOTA.handle();
  Blynk.run();
  timer.run();
  //用于显示网络信息的模块插件,不需要可省略
  Blynk.virtualWrite(V0,WiFi.localIP().toString());
  Blynk.virtualWrite(V1,WiFi.macAddress());
  Blynk.virtualWrite(V2,"RSSI:",WiFi.RSSI()," ","SSID: ",WiFi.SSID());
}

一沙一世界,一花一天堂。君掌盛无边,刹那成永恒。