ESP8266 NodeMCU OTA(无线)更新——使用 Arduino IDE 的 AsyncElegantOTA

在本指南中,您将学习如何使用 AsyncElegantOTA 库对 ESP8266 NodeMCU 板进行无线 (OTA) 更新。该库创建了一个网络服务器,允许您将新固件(新草图)更新到您的电路板,而无需在 ESP8266 和您的计算机之间建立串行连接。

此外,您还可以将新文件上传到 ESP8266 文件系统 (LittleFS)。该库非常易于使用,并且与我们经常用于构建 Web 服务器项目的 ESPAsyncWebServer 库兼容。

使用 Arduino IDE 的 ESP8266 NodeMCU OTA 无线更新 AsyncElegantOTA

在本教程结束时,您将能够使用 ESP8266 轻松地将 OTA 功能添加到您的网络服务器项目中,以便将来以无线方式将新固件和文件上传到文件系统。

我们为 ESP32 开发板提供了类似的教程:


 

概述

本教程涵盖:

我们建议您按照本教程中的所有步骤来了解 ElegantOTA 的工作原理以及如何在您的项目中使用它。为了演示如何执行此操作,我们将上传文件以构建不同的 Web 服务器项目。

OTA(空中下载)编程

OTA(空中下载)更新是使用 Wi-Fi 连接而不是串行通信将新固件加载到 ESP8266 NodeMCU 板的过程。在无法物理访问 ESP8266 开发板的情况下,此功能非常有用。

有多种方法可以执行 OTA 更新。在本教程中,我们将介绍如何使用AsyncElegantOTA 库来做到这一点。在我们看来,这是执行 OTA 更新的最佳和最简单的方法之一。

AsyncElegantOTA 库创建了一个 Web 服务器,您可以在本地网络上访问该服务器以将新固件或文件上传到文件系统 (LittleFS)。您上传的文件应为.bin格式。我们稍后将在本教程中向您展示如何将您的文件转换为.bin格式。

异步 ElegantOTA 网络服务器 ESP8266 工作原理

OTA 编程的唯一缺点是您需要在您上传的每个草图中添加 OTA 代码,以便您将来可以使用 OTA。对于 AsyncElegantOTA 库,它仅包含三行代码。

AsyncElegantOTA 库

如前所述,使用 ESP8266 板进行 OTA 编程有很多替代方案。例如,在 Arduino IDE 中,Examples文件夹下有BasicOTA示例(对我们来说从来都不是很好);以及来自不同库的许多其他示例。

我们使用ESP8266 的大多数 Web 服务器项目都使用ESPAsyncWebServer 库。因此,我们想要一个与该库兼容的解决方案。该AsyncElegantOTA库仅仅是完美的,我们想要的东西:

AsyncElegantOTA 库

  • 它与 ESPAsyncWebServer 库兼容;
  • 您只需要添加三行代码即可将 OTA 功能添加到您的“常规”异步 Web 服务器;
  • 它不仅允许您将新固件更新到板上,还允许您将文件更新到 ESP8266 文件系统 (LittleFS);
  • 它提供了一个漂亮而现代的 Web 服务器界面;
  • 它工作得非常好。

如果您喜欢这个库并且将在您的项目中使用它,请考虑支持开发人员的工作

使用 AsyncElegantOTA 库进行 OTA 更新 – 快速总结

要使用 AsyncElegantOTA 库向您的项目添加 OTA 功能,请执行以下步骤:

  1. 安装AsyncElegantOTAESPAsyncTCPESPAsyncWebServer库;
  2. 在 Arduino 草图的顶部包含 AsyncElegantOTA 库: #include <AsyncElegantOTA.h>;
  3. 添加这一行 AsyncElegantOTA.begin(&server); 前 server.begin();
  4. 打开浏览器并转到 http://<IP 地址>/update, 在哪里 <IP地址> 是您的 ESP8266 IP 地址。

继续阅读教程以获取更详细的步骤。

OTA Web 更新程序如何工作?

  • 第一个草图应该通过串口上传。此草图应包含用于创建 OTA Web 更新程序的代码,以便您稍后可以使用浏览器上传代码。
  • OTA 网络更新程序草图创建了一个网络服务器,您可以访问它以通过网络浏览器上传新的草图。
  • 然后,您需要在您上传的每个草图中实施 OTA 例程,以便您能够通过无线方式进行下一次更新/上传。
  • 如果您上传没有 OTA 例程的代码,您将无法再访问网络服务器并通过无线方式上传新的草图。

安装 AsyncElegantOTA 库

在本教程中,ESP8266 将使用 Arduino IDE 进行编程。如果你想学习如何使用 VS Code + PlatformIO 来做同样的事情,请按照下一个教程:  ESP8266 NodeMCU OTA(空中)更新 – AsyncElegantOTA(VS Code + PlatformIO)

您可以使用 Arduino 库管理器安装 AsyncElegantOTA 库。在您的 Arduino IDE 中,转到Sketch > Include Library > Manage Libraries...搜索“ AsyncElegantOTA ”并安装它。

安装 Async Elegant OTA 库 Arduino IDE

安装 ESPAsyncWebServer 和 ESPAsyncTCP 库

您还需要安装 ESPAsyncTCP 和 ESPAsyncWebServer 库。单击下面的链接下载库。

这些库无法通过 Arduino 库管理器安装,因此您需要将库文件复制到 Arduino 安装库文件夹。或者,在您的 Arduino IDE 中,您可以转到 Sketch  >  Include Library  >  Add .zip Library 并选择您刚刚下载的库。

AsyncElegantOTA ESP8266 基本示例

让我们从库提供的基本示例开始。此示例使用 ESP8266 创建一个简单的 Web 服务器。根 URL 显示一些文本,并且/更新 URL 显示更新固件和文件系统的界面。

将以下代码复制到您的 Arduino IDE。

/*
  Rui Santos
  Complete project details
   - Arduino IDE: https://RandomNerdTutorials.com/esp8266-nodemcu-ota-over-the-air-arduino/
   - VS Code: https://RandomNerdTutorials.com/esp8266-nodemcu-ota-over-the-air-vs-code/
     
  This sketch shows a Basic example from the AsyncElegantOTA library: ESP8266_Async_Demo
  https://github.com/ayushsharma82/AsyncElegantOTA
*/

#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <ESPAsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include <AsyncElegantOTA.h>

const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";

AsyncWebServer server(80);

void setup(void) {
  Serial.begin(115200);
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  Serial.println("");

  // Wait for connection
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.print("Connected to ");
  Serial.println(ssid);
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());

  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) {
    request->send(200, "text/plain", "Hi! I am ESP8266.");
  });

  AsyncElegantOTA.begin(&server);    // Start ElegantOTA
  server.begin();
  Serial.println("HTTP server started");
}

void loop(void) {
  AsyncElegantOTA.loop();
}

插入您的网络凭据,代码应立即生效:

const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";

代码的工作原理

首先,包括必要的库:

#include <ESP8266WiFi.h>
#include <ESPAsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include <AsyncElegantOTA.h>

在以下变量中插入您的网络凭据,以便 ESP8266 可以连接到您的本地网络。

const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";

创建一个 异步网络服务器 端口 80 上的对象:

AsyncWebServer server(80);

在里面 设置(),初始化串口监视器:

Serial.begin(115200);

初始化无线网络:

WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
Serial.println("");

// Wait for connection
while (WiFi.status() != WL_CONNECTED) {
  delay(500);
  Serial.print(".");
}
Serial.println("");
Serial.print("Connected to ");
Serial.println(ssid);
Serial.print("IP address: ");
Serial.println(WiFi.localIP());

然后,处理客户端请求。以下几行,发送一些文本你好!我是ESP8266。 当您访问根 (/) 网址:

server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) {
  request->send(200, "text/plain", "Hi! I am ESP8266.");
});

如果您的 Web 服务器需要处理更多请求,您可以添加它们(我们将在下一个示例中向您展示)。

然后,添加下一行以启动 ElegantOTA:

AsyncElegantOTA.begin(&server);    // Start ElegantOTA

最后,初始化服务器:

server.begin();

最后在里面添加以下内容 loop()

void loop(void) {
  AsyncElegantOTA.loop();
}

访问网络服务器

上传代码到板子后,以115200的波特率打开串口监视器,按下ESP8266板载RST按钮。它应该显示 ESP IP 地址如下(你的可能不同):

Async ElegantOTA 获取 ESP IP 地址串行监视器

在本地网络中,打开浏览器并输入 ESP8266 IP 地址。您应该可以访问根目录(/) 显示一些文本的网页。

ESP8266 Async ElegantOTA 演示示例 Web 服务器根 URL

现在,假设您要修改 Web 服务器代码。要通过 OTA 执行此操作,请转到 ESP IP 地址,然后是/更新. 应加载以下网页。

ESP8266 Async ElegantOTA 更新页面

按照下一节了解如何使用 AsyncElegantOTA 上传新固件。

上传新固件 OTA(无线)更新 – ESP8266

您通过 OTA 上传的每个文件都应为.bin格式。您可以使用 Arduino IDE 从您的草图中生成一个.bin文件。

打开草图后,您需要转到Sketch > Export Compiled Binary。一个名为.bin文件将从您的草图生成。生成的文件将保存在您的项目文件夹下。

如果您想上传新固件,您应该使用 AsyncElegantOTA 网页上传那个.bin文件。

上传新的 Web 服务器草图 – 示例

让我们看一个实际的例子。想象一下,在上传之前的草图后,您想上传一个新的草图,该草图允许您通过网络界面控制 LED,例如这个项目。以下是您需要遵循的步骤:

1. 将以下代码复制到您的 Arduino IDE。不要忘记插入您的网络凭据。

/*
  Rui Santos
  Complete project details
   - Arduino IDE: https://RandomNerdTutorials.com/esp8266-nodemcu-ota-over-the-air-arduino/
   - VS Code: https://RandomNerdTutorials.com/esp8266-nodemcu-ota-over-the-air-vs-code/
     
  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files.
  
  The above copyright notice and this permission notice shall be included in all
  copies or substantial portions of the Software.
*/

// Import required libraries
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <ESPAsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include <AsyncElegantOTA.h>

// Replace with your network credentials
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";

bool ledState = 0;
const int ledPin = 2;

// Create AsyncWebServer object on port 80
AsyncWebServer server(80);
AsyncWebSocket ws("/ws");

const char index_html[] PROGMEM = R"rawliteral(
<!DOCTYPE HTML><html>
<head>
  <title>ESP Web Server</title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" href="data:,">
  <style>
  html {
    font-family: Arial, Helvetica, sans-serif;
    text-align: center;
  }
  h1 {
    font-size: 1.8rem;
    color: white;
  }
  h2{
    font-size: 1.5rem;
    font-weight: bold;
    color: #143642;
  }
  .topnav {
    overflow: hidden;
    background-color: #143642;
  }
  body {
    margin: 0;
  }
  .content {
    padding: 30px;
    max-width: 600px;
    margin: 0 auto;
  }
  .card {
    background-color: #F8F7F9;;
    box-shadow: 2px 2px 12px 1px rgba(140,140,140,.5);
    padding-top:10px;
    padding-bottom:20px;
  }
  .button {
    padding: 15px 50px;
    font-size: 24px;
    text-align: center;
    outline: none;
    color: #fff;
    background-color: #0f8b8d;
    border: none;
    border-radius: 5px;
    -webkit-touch-callout: none;
    -webkit-user-select: none;
    -khtml-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
    -webkit-tap-highlight-color: rgba(0,0,0,0);
   }
   /*.button:hover {background-color: #0f8b8d}*/
   .button:active {
     background-color: #0f8b8d;
     box-shadow: 2 2px #CDCDCD;
     transform: translateY(2px);
   }
   .state {
     font-size: 1.5rem;
     color:#8c8c8c;
     font-weight: bold;
   }
  </style>
<title>ESP Web Server</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" href="data:,">
</head>
<body>
  <div class="topnav">
    <h1>ESP WebSocket Server</h1>
  </div>
  <div class="content">
    <div class="card">
      <h2>Output - GPIO 2</h2>
      <p class="state">state: <span id="state">%STATE%</span></p>
      <p><button id="button" class="button">Toggle</button></p>
    </div>
  </div>
<script>
  var gateway = `ws://${window.location.hostname}/ws`;
  var websocket;
  window.addEventListener('load', onLoad);
  function initWebSocket() {
    console.log('Trying to open a WebSocket connection...');
    websocket = new WebSocket(gateway);
    websocket.onopen    = onOpen;
    websocket.onclose   = onClose;
    websocket.onmessage = onMessage; // <-- add this line
  }
  function onOpen(event) {
    console.log('Connection opened');
  }
  function onClose(event) {
    console.log('Connection closed');
    setTimeout(initWebSocket, 2000);
  }
  function onMessage(event) {
    var state;
    if (event.data == "1"){
      state = "ON";
    }
    else{
      state = "OFF";
    }
    document.getElementById('state').innerHTML = state;
  }
  function onLoad(event) {
    initWebSocket();
    initButton();
  }
  function initButton() {
    document.getElementById('button').addEventListener('click', toggle);
  }
  function toggle(){
    websocket.send('toggle');
  }
</script>
</body>
</html>)rawliteral";

void notifyClients() {
  ws.textAll(String(ledState));
}

void handleWebSocketMessage(void *arg, uint8_t *data, size_t len) {
  AwsFrameInfo *info = (AwsFrameInfo*)arg;
  if (info->final && info->index == 0 && info->len == len && info->opcode == WS_TEXT) {
    data[len] = 0;
    if (strcmp((char*)data, "toggle") == 0) {
      ledState = !ledState;
      notifyClients();
    }
  }
}

void onEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type,
             void *arg, uint8_t *data, size_t len) {
  switch (type) {
    case WS_EVT_CONNECT:
      Serial.printf("WebSocket client #%u connected from %s\n", client->id(), client->remoteIP().toString().c_str());
      break;
    case WS_EVT_DISCONNECT:
      Serial.printf("WebSocket client #%u disconnected\n", client->id());
      break;
    case WS_EVT_DATA:
      handleWebSocketMessage(arg, data, len);
      break;
    case WS_EVT_PONG:
    case WS_EVT_ERROR:
      break;
  }
}

void initWebSocket() {
  ws.onEvent(onEvent);
  server.addHandler(&ws);
}

String processor(const String& var){
  Serial.println(var);
  if(var == "STATE"){
    if (ledState){
      return "ON";
    }
    else{
      return "OFF";
    }
  }
  return String();
}

void setup(){
  // Serial port for debugging purposes
  Serial.begin(115200);

  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, LOW);
  
  // Connect to Wi-Fi
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Connecting to WiFi..");
  }

  // Print ESP Local IP Address
  Serial.println(WiFi.localIP());

  initWebSocket();

  // Route for root / web page
  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send_P(200, "text/html", index_html, processor);
  });

  // Start ElegantOTA
  AsyncElegantOTA.begin(&server);
  // Start server
  server.begin();
}

void loop() {
  AsyncElegantOTA.loop();
  ws.cleanupClients();
  digitalWrite(ledPin, ledState);
}

查看原始代码

这与此项目中使用的代码相同,但它包含处理 ElegantOTA 所需的代码行:

#include <AsyncElegantOTA.h>
AsyncElegantOTA.begin(&server);
AsyncElegantOTA.loop();

2. 保存您的草图:文件>保存并为其命名。例如:Web_Server_LED_OTA_ESP8266

3.从你的草图中生成一个.bin文件。转到Sketch > Export Compiled Binary。应该在项目文件夹下创建一个新的.bin文件。

为 OTA 更新 Arduino IDE 生成的 ESP8266 Bin 文件

4. 现在您只需要使用 ElegantOTA 页面上传该文件。转到您的 ESP IP 地址,然后是/更新. 确保您选择了固件选项。单击“选择文件”并选择您刚刚生成的.bin文件。

ESP8266 更新新固件 Elegant OTA

5. 完成后,单击“返回”按钮。

ESP8266 NodeMCU 上传新固件 Elegant OTA 成功

6.然后,你可以去根(/) 访问新 Web 服务器的 URL。这是访问根目录上的 ESP IP 地址时应该看到的页面 (/) 网址。

ESP8266 NodeMCU Websocket 服务器控制输出

您可以单击按钮来打开和关闭 ESP8266 板载 LED。

ESP8266 NodeMCU 板 内置 LED 高亮

因为我们还为这个新的 Web 服务器添加了 OTA 功能,所以我们可以在未来根据需要上传新的草图。您只需要转到 ESP8266 IP 地址,然后/更新.

恭喜,您已使用 ElegantOTA 通过 Wi-Fi 将新代码上传到您的 ESP8266。

如果您想了解如何使用 AsyncElegantOTA 将文件上传到 ESP8266 文件系统 (LittleFS),请继续阅读。

将文件上传到文件系统 OTA(无线)更新 – ESP8266

在本节中,您将学习使用 AsyncElegantOTA 将文件上传到 ESP8266 文件系统 (LittleFS)。

ESP8266 LittleFS 文件系统上传插件

在继续之前,您需要在 Arduino IDE 中安装 ESP8266 LittleFS Uploader Plugin。在继续之前,请按照下一个教程进行操作:

带有 LittleFS 文件的 Web 服务器

想象一下您需要将文件上传到 ESP8266 文件系统的场景,例如配置文件、HTML、CSS 和 JavaScript 文件以更新 Web 服务器页面或您可能希望通过 OTA 保存在 LittleFS 中的任何其他文件。

为了向您展示如何执行此操作,我们将创建一个新的 Web 服务器,该服务器提供来自文件系统 (LittleFS) 的文件:HTML、CSS 和 JavaScript 文件,以构建一个远程控制 ESP8266 GPIO 的网页。

在继续之前,请确保您已安装Arduino 0.1.0 版Arduino_JSON 库。您可以在 Arduino IDE 库管理器中安装此库。只需转到 Sketch  >  Include Library  >  Manage Libraries 并按如下方式搜索库名称:Arduino_JSON。

将以下代码复制到您的 Arduino IDE。

/*
  Rui Santos
  Complete project details
   - Arduino IDE: https://RandomNerdTutorials.com/esp8266-nodemcu-ota-over-the-air-arduino/
   - VS Code: https://RandomNerdTutorials.com/esp8266-nodemcu-ota-over-the-air-vs-code/
     
  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files.
  
  The above copyright notice and this permission notice shall be included in all
  copies or substantial portions of the Software.
*/

// Import required libraries
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <ESPAsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include "LittleFS.h"
#include <Arduino_JSON.h>
#include <AsyncElegantOTA.h>

// Replace with your network credentials
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";

// Create AsyncWebServer object on port 80
AsyncWebServer server(80);

// Create a WebSocket object
AsyncWebSocket ws("/ws");

// Set number of outputs
#define NUM_OUTPUTS  4

// Assign each GPIO to an output
int outputGPIOs[NUM_OUTPUTS] = {2, 4, 12, 14};

// Initialize LittleFS
void initLittleFS() {
  if (!LittleFS.begin()) {
    Serial.println("An error has occurred while mounting LittleFS");
  }
  Serial.println("LittleFS mounted successfully");
}

// Initialize WiFi
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());
}

String getOutputStates(){
  JSONVar myArray;
  for (int i =0; i<NUM_OUTPUTS; i++){
    myArray["gpios"][i]["output"] = String(outputGPIOs[i]);
    myArray["gpios"][i]["state"] = String(digitalRead(outputGPIOs[i]));
  }
  String jsonString = JSON.stringify(myArray);
  return jsonString;
}

void notifyClients(String state) {
  ws.textAll(state);
}

void handleWebSocketMessage(void *arg, uint8_t *data, size_t len) {
    AwsFrameInfo *info = (AwsFrameInfo*)arg;
  if (info->final && info->index == 0 && info->len == len && info->opcode == WS_TEXT) {
    data[len] = 0;
    if (strcmp((char*)data, "states") == 0) {
      notifyClients(getOutputStates());
    }
    else{
      int gpio = atoi((char*)data);
      digitalWrite(gpio, !digitalRead(gpio));
      notifyClients(getOutputStates());
    }
  }
}

void onEvent(AsyncWebSocket *server, AsyncWebSocketClient *client,AwsEventType type,
             void *arg, uint8_t *data, size_t len) {
  switch (type) {
    case WS_EVT_CONNECT:
      Serial.printf("WebSocket client #%u connected from %s\n", client->id(), client->remoteIP().toString().c_str());
      break;
    case WS_EVT_DISCONNECT:
      Serial.printf("WebSocket client #%u disconnected\n", client->id());
      break;
    case WS_EVT_DATA:
      handleWebSocketMessage(arg, data, len);
      break;
    case WS_EVT_PONG:
    case WS_EVT_ERROR:
      break;
  }
}

void initWebSocket() {
  ws.onEvent(onEvent);
  server.addHandler(&ws);
}

void setup(){
  // Serial port for debugging purposes
  Serial.begin(115200);

  // Set GPIOs as outputs
  for (int i =0; i<NUM_OUTPUTS; i++){
    pinMode(outputGPIOs[i], OUTPUT);
  }
  initLittleFS();
  initWiFi();
  initWebSocket();

  // Route for root / web page
  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send(LittleFS, "/index.html", "text/html",false);
  });

  server.serveStatic("/", LittleFS, "/");

  // Start ElegantOTA
  AsyncElegantOTA.begin(&server);
  
  // Start server
  server.begin();
}

void loop() {
  AsyncElegantOTA.loop();
  ws.cleanupClients();
}

查看原始代码

在以下变量中插入您的网络凭据并保存代码。

const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";

更新固件

从此草图创建一个.bin文件,如前所示(此草图包括提供 OTA 功能所需的代码行)。

转到 ESP8266 IP 地址,然后是 /更新 并上传新固件。

接下来,我们将看到如何上传文件。

更新文件系统

在项目文件夹下创建一个名为data的文件夹并粘贴以下 HTML、CSS 和 JavaScript 文件(单击链接下载文件):

<!DOCTYPE HTML><html>
<head>
  <title>ESP IOT DASHBOARD</title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="stylesheet" type="text/css" href="style.css">
  <link rel="icon"  type="image/png" href="favicon.png">
  <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.2/css/all.css" integrity="sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr" crossorigin="anonymous">
</head>
<body>
  <div class="topnav">
    <h1>ESP WEB SERVER - Control Multiple Outputs WebSocket</h1>
  </div>
  <div class="content">
    <div class="card-grid">
        <div class="card">             
            <p class="card-title"><i class="fas fa-lightbulb"></i> GPIO 2</p>
            <label class="switch">
                <input type="checkbox" onchange="toggleCheckbox(this)" id="2">
                <span class="slider"></span>
            </label>
            <p class ="state">State: <span id="2s"></span></p>
        </div>
        <div class="card">
            <p class="card-title"><i class="fas fa-lightbulb"></i> GPIO 4</p>
            <label class="switch">
                <input type="checkbox" onchange="toggleCheckbox(this)" id="4">
                <span class="slider"></span>
            </label>
            <p class ="state">State: <span id="4s"></span></p>
        </div>
        <div class="card">
            <p class="card-title"><i class="fas fa-lightbulb"></i> GPIO 14</p>
            <label class="switch">
                <input type="checkbox" onchange="toggleCheckbox(this)" id="14">
                <span class="slider"></span>
            </label>
            <p class ="state">State: <span id="14s"></span></p>
        </div>
        <div class="card">
            <p class="card-title"><i class="fas fa-lightbulb"></i> GPIO 12</p>
            <label class="switch">
                <input type="checkbox" onchange="toggleCheckbox(this)" id="12">
                <span class="slider"></span>
            </label>
            <p class="state">State: <span id="12s"></span></p>
        </div>
    </div>
</div>
<script src="/script.js"></script>
</body>
</html>
html {
    font-family: Arial, Helvetica, sans-serif; 
    text-align: center;
}
h1 {
    font-size: 1.8rem; 
    color: white;
}
.topnav { 
    overflow: hidden; 
    background-color: #0A1128;
}
body {  
    margin: 0;
}
.content { 
    padding: 50px;
}
.card-grid { 
    max-width: 600px; 
    margin: 0 auto; 
    display: grid; 
    gap: 2rem; 
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
}
.card { 
    background-color: white; 
    box-shadow: 2px 2px 12px 1px rgba(140,140,140,.5);
}
.card-title { 
    font-size: 1.2rem;
    font-weight: bold;
    color: #034078
}
.state {
    font-size: 1.2rem;
    color:#1282A2;
}
.switch {
    position: relative; 
    display: inline-block; 
    width: 120px; 
    height: 68px
} 
.switch input {
    display: none
}
.slider {
    position: absolute; 
    top: 0; left: 0; right: 0; bottom: 0; 
    background-color: #ccc; 
    border-radius: 50px
}
.slider:before {
    position: absolute; 
    content: ""; 
    height: 52px; 
    width: 52px; 
    left: 8px; 
    bottom: 8px; 
    background-color: #fff; 
    -webkit-transition: .4s; 
    transition: .4s;
    border-radius: 50px;
}
input:checked+.slider {
    background-color: #b30000;
}
input:checked+.slider:before {
    -webkit-transform: translateX(52px);
    -ms-transform: translateX(52px); 
    transform: translateX(52px);
}
var gateway = `ws://${window.location.hostname}/ws`;
var websocket;
window.addEventListener('load', onLoad);

function onLoad(event) {
    initWebSocket();
}

function initWebSocket() {
    console.log('Trying to open a WebSocket connection...');
    websocket = new WebSocket(gateway);
    websocket.onopen    = onOpen;
    websocket.onclose   = onClose;
    websocket.onmessage = onMessage;
}

function onOpen(event) {
    console.log('Connection opened');
    websocket.send("states");
}
  
function onClose(event) {
    console.log('Connection closed');
    setTimeout(initWebSocket, 2000);
} 

function onMessage(event) {
    var myObj = JSON.parse(event.data);
            console.log(myObj);
            for (i in myObj.gpios){
                var output = myObj.gpios[i].output;
                var state = myObj.gpios[i].state;
                console.log(output);
                console.log(state);
                if (state == "1"){
                    document.getElementById(output).checked = true;
                    document.getElementById(output+"s").innerHTML = "ON";
                }
                else{
                    document.getElementById(output).checked = false;
                    document.getElementById(output+"s").innerHTML = "OFF";
                }
            }
    console.log(event.data);
}

// Send Requests to Control GPIOs
function toggleCheckbox (element) {
    console.log(element.id);
    websocket.send(element.id);
    if (element.checked){
        document.getElementById(element.id+"s").innerHTML = "ON";
    }
    else {
        document.getElementById(element.id+"s").innerHTML = "OFF"; 
    }
}

要找到您的项目文件夹,您可以转到Sketch > Show Sketch Folder

这是您的数据文件夹应位于的位置及其外观:

数据文件夹结构 ESP8266 Async ElegantOTA 示例

在此之后,将 ESP8266 与您的计算机断开连接(这就是 OTA 的全部目的),点击ESP8266 LittleFS Data Upload

ESP8266 LittleFS 数据上传 Arduino IDE

您会收到错误消息,因为没有任何 ESP8266 板连接到您的计算机 - 别担心。

在调试窗口上向上滚动,直到找到.mklittlefs.bin文件位置。那就是您应该上传的文件(在我们的例子中,该文件名为Web_Server_OTA_ESP8266_Example_2.mklittlefs.bin。

获取 LittleFS Bin 文件路径 ESP8266

这是我们文件所在的路径:

C:\Users\sarin\AppData\Local\Temp\arduino_build_375940\Web_server_OTA_ESP8266_Example_2.mklittlefs.bin

要在我的计算机上访问该文件,我需要使隐藏文件可见(AppData文件夹不可见)。检查这是否也是你的情况。

Arduino IDE ESP32 ESP8266 NodeMCU 板附加修复安装

到达文件夹路径后,您希望获取扩展名为.mklittlefs.bin的文件。

LittleFS Bin 文件 ESP8266

为方便起见,您可以将该文件复制到您的项目文件夹中。

现在我们有来自数据文件夹的.bin文件,我们可以上传该文件。转到您的 ESP8266 IP 地址,然后是/更新. 确保您选择了文件系统选项。

上传文件文件系统 ElegantOTA ESP8266

然后,选择扩展名为.mklittlefs.bin的文件。

上传成功后,点击返回按钮。并转到根 (/) 网址。您应该可以访问以下使用Web Socket 协议控制 ESP8266 输出的网页

控制多个 ESP32 ESP8266 输出 Websocket Web 服务器

要查看网络服务器的工作情况,您可以将 4 个 LED 连接到 GPIOS 上的 ESP8266:2、4、12 和 14。您应该能够控制来自网络服务器的这些输出。

如果您需要更新项目中的某些内容,只需转到您的 ESP8266 IP 地址,然后输入 /更新.

恭喜!您已使用 ElegantOTA 成功将文件上传到 ESP8266 文件系统。

  • 5
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用Arduino IDE进行ESP32的OTA升级时,您需要按照以下步骤进行操作: 1. 首先,在Arduino IDE中安装ESP32 Uploader Plugin。您可以按照教程\[1\]中的指引进行操作。 2. 确保您的ESP32开发板已正确连接到计算机,并且已选择正确的开发板和端口。 3. 在Arduino IDE中打开您的ESP32项目。 4. 在代码中添加OTA库的引用。您可以使用ESP32的内置OTA库或第三方库,如ArduinoOTA库。根据您的需求选择适合的库。 5. 在代码中设置OTA的参数,如WiFi网络的名称和密码,OTA端口等。 6. 在代码中添加OTA的回调函数,用于处理OTA过程中的事件,如开始、进度和结束。 7. 编译并上传代码到ESP32开发板。 8. 在ESP32的串口监视器中查看设备的IP地址。 9. 打开Web浏览器,输入ESP32的IP地址,进入OTA页面。 10. 在OTA页面中选择要上传的固件文件,并点击上传按钮。 11. 等待上传完成,ESP32将自动进行固件更新。 请注意,以上步骤仅为一般指导,具体操作可能因您的项目和需求而有所不同。您可以参考\[2\]和\[3\]中的引用内容获取更详细的指导和示例代码。 #### 引用[.reference_title] - *1* *2* *3* [ESP32 使用 Arduino 实现 OTA 更新](https://blog.csdn.net/jiyotin/article/details/120689434)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值