Создание веб-сервера ESP8266 - код и схемы

Этот проект представляет собой пошаговое руководство, в котором показано, как создать автономный веб-сервер ESP8266, который управляет двумя выходами (два светодиода). Веб-сервер ESP8266 контролируется мобильными устройствами, и к нему можно получить доступ с любого устройства с браузером в локальной сети.

Если вы хотите узнать больше о модуле ESP8266, сначала прочтите мое Руководство по началу работы с модулем WiFi ESP8266.

В данном руководстве рассматриваются два разных метода построения веб-сервера:

  • Часть 1. Создание веб-сервера с использованием Arduino IDE
  • Часть 2. Создание веб-сервера с помощью NodeMCU

ЧАСТЬ 1: СОЗДАЙТЕ ВЕБ-СЕРВЕР, ИСПОЛЬЗУЯ ARDUINO IDE

В этой части показано, как создать веб-сервер для управления двумя выходами с помощью Arduino IDE. Вы можете использовать этот метод для создания другого веб-сервера для удовлетворения ваших потребностей.

Подготовьте IDE Arduino

1. Загрузите и установите Arduino IDE в вашей операционной системе (некоторые старые версии не будут работать).

2. Затем вам необходимо установить дополнение ESP8266 для Arduino IDE. Для этого перейдите в File> Preferences.

3. Введите http://arduino.esp8266.com/stable/package_esp8266com_index.json в поле «Additional boards manager urls», как показано на рисунке ниже. Затем нажмите кнопку «ОК».

4. Перейдите в Инструменты > Платы > Менеджер плат…

5. Прокрутите вниз, выберите пункт меню платы ESP8266 и установите «плату esp8266», как показано на рисунке ниже.

6. Перейдите в Инструменты > Плата и выберите свою плату ESP8266. Затем снова откройте вашу Arduino IDE.

Код

Скопируйте приведенный ниже код в вашу Arduino IDE, но пока не загружайте его. Вам нужно внести некоторые изменения, чтобы он работал у вас.

/*********
  Rui Santos
  Complete project details at https://randomnerdtutorials.com  
*********/

// Load Wi-Fi library
#include <ESP8266WiFi.h>

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

// Set web server port number to 80
WiFiServer server(80);

// Variable to store the HTTP request
String header;

// Auxiliar variables to store the current output state
String output5State = "off";
String output4State = "off";

// Assign output variables to GPIO pins
const int output5 = 5;
const int output4 = 4;

void setup() {
  Serial.begin(115200);
  // Initialize the output variables as outputs
  pinMode(output5, OUTPUT);
  pinMode(output4, OUTPUT);
  // Set outputs to LOW
  digitalWrite(output5, LOW);
  digitalWrite(output4, LOW);

  // Connect to Wi-Fi network with SSID and password
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  // Print local IP address and start web server
  Serial.println("");
  Serial.println("WiFi connected.");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
  server.begin();
}

void loop(){
  WiFiClient client = server.available();   // Listen for incoming clients

  if (client) {                             // If a new client connects,
    Serial.println("New Client.");          // print a message out in the serial port
    String currentLine = "";                // make a String to hold incoming data from the client
    while (client.connected()) {            // loop while the client's connected
      if (client.available()) {             // if there's bytes to read from the client,
        char c = client.read();             // read a byte, then
        Serial.write(c);                    // print it out the serial monitor
        header += c;
        if (c == '\n') {                    // if the byte is a newline character
          // if the current line is blank, you got two newline characters in a row.
          // that's the end of the client HTTP request, so send a response:
          if (currentLine.length() == 0) {
            // HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK)
            // and a content-type so the client knows what's coming, then a blank line:
            client.println("HTTP/1.1 200 OK");
            client.println("Content-type:text/html");
            client.println("Connection: close");
            client.println();
            
            // turns the GPIOs on and off
            if (header.indexOf("GET /5/on") >= 0) {
              Serial.println("GPIO 5 on");
              output5State = "on";
              digitalWrite(output5, HIGH);
            } else if (header.indexOf("GET /5/off") >= 0) {
              Serial.println("GPIO 5 off");
              output5State = "off";
              digitalWrite(output5, LOW);
            } else if (header.indexOf("GET /4/on") >= 0) {
              Serial.println("GPIO 4 on");
              output4State = "on";
              digitalWrite(output4, HIGH);
            } else if (header.indexOf("GET /4/off") >= 0) {
              Serial.println("GPIO 4 off");
              output4State = "off";
              digitalWrite(output4, LOW);
            }
            
            // Display the HTML web page
            client.println("<!DOCTYPE html><html>");
            client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");
            client.println("<link rel=\"icon\" href=\"data:,\">");
            // CSS to style the on/off buttons 
            // Feel free to change the background-color and font-size attributes to fit your preferences
            client.println("<style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}");
            client.println(".button { background-color: #195B6A; border: none; color: white; padding: 16px 40px;");
            client.println("text-decoration: none; font-size: 30px; margin: 2px; cursor: pointer;}");
            client.println(".button2 {background-color: #77878A;}</style></head>");
            
            // Web Page Heading
            client.println("<body><h1>ESP8266 Web Server</h1>");
            
            // Display current state, and ON/OFF buttons for GPIO 5  
            client.println("<p>GPIO 5 - State " + output5State + "</p>");
            // If the output5State is off, it displays the ON button       
            if (output5State=="off") {
              client.println("<p><a href=\"/5/on\"><button class=\"button\">ON</button></a></p>");
            } else {
              client.println("<p><a href=\"/5/off\"><button class=\"button button2\">OFF</button></a></p>");
            } 
               
            // Display current state, and ON/OFF buttons for GPIO 4  
            client.println("<p>GPIO 4 - State " + output4State + "</p>");
            // If the output4State is off, it displays the ON button       
            if (output4State=="off") {
              client.println("<p><a href=\"/4/on\"><button class=\"button\">ON</button></a></p>");
            } else {
              client.println("<p><a href=\"/4/off\"><button class=\"button button2\">OFF</button></a></p>");
            }
            client.println("</body></html>");
            
            // The HTTP response ends with another blank line
            client.println();
            // Break out of the while loop
            break;
          } else { // if you got a newline, then clear currentLine
            currentLine = "";
          }
        } else if (c != '\r') {  // if you got anything else but a carriage return character,
          currentLine += c;      // add it to the end of the currentLine
        }
      }
    }
    // Clear the header variable
    header = "";
    // Close the connection
    client.stop();
    Serial.println("Client disconnected.");
    Serial.println("");
  }
}

Вам необходимо изменить следующие две переменные с сетевыми учетными данными, чтобы ваш ESP8266 мог установить соединение с маршрутизатором.

 

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

Загрузка скетча

Загрузка скетча в ESP-12E

Если вы используете ESP-12E NodeMCU Kit, загрузка скетча очень проста, поскольку в нем есть встроенный программатор. Подключите вашу плату к компьютеру. Убедитесь, что вы выбрали правильную плату и COM-порт.

Затем нажмите кнопку «Загрузить» в IDE Arduino и подождите несколько секунд, пока не увидите сообщение «Закончена загрузка» в левом нижнем углу.

Загрузка скетча в ESP-01

Загрузка кода в ESP-01 требует установления последовательного соединения между вашим ESP8266 и программатором FTDI, как показано на схематической диаграмме ниже.

В следующей таблице показаны соединения, которые необходимо установить между ESP8266 и программатором FTDI.

ESP8266 FTDI programmer
RX TX
TX RX
CH_PD 3.3V
GPIO 0 GND
VCC 3.3V
GND GND

Если у вас новый программатор FTDI, и вам нужно установить драйверы FTDI на ПК с Windows, посетите официальный веб-сайт для получения официальных драйверов. Кроме того, вы можете связаться с продавцом, который продал вам программатор FTDI.

Затем вам просто нужно подключить программатор FTDI к вашему компьютеру и загрузить код в ESP8266.

Schematics

Для построения схемы вам понадобятся следующие детали:

Требуются запчасти:

  • ESP8266 12-E
  • Платы для разработки Wi-Fi
  • 2 светодиода
  • 2 резистора (220 или 330 Ом подойдут)
  • макетная плата
  • Перемычки

Если вы используете ESP-01, вам также нужен программатор FTDI.

Подключите два светодиода к ESP8266, как показано на следующей принципиальной схеме - один светодиод подключен к GPIO 4 (D2), а другой к GPIO 5 (D1).

Если вы используете ESP-01 ...

Если вы используете ESP8266-01, используйте следующую схему в качестве справки, но вам нужно изменить назначение GPIO в коде (на GPIO 2 и GPIO 0).

Тестирование веб-сервера

Теперь вы можете загрузить код, и он сразу заработает. Не забудьте проверить, правильно ли выбрана плата и COM-порт, в противном случае вы получите ошибку при попытке загрузки. Откройте последовательный монитор со скоростью 115200 бод.

Нахождение IP-адреса ESP

Нажмите кнопку сброса ESP8266, и он выведет IP-адрес ESP на последовательный монитор

Скопируйте этот IP-адрес, потому что он нужен вам для доступа к веб-серверу.

Доступ к веб-серверу

Откройте браузер, введите IP-адрес ESP, и вы увидите следующую страницу. Эта страница отправляетсяESP8266, когда вы посылаете запрос на IP-адрес ESP.

Если вы посмотрите на последовательный монитор, вы можете увидеть, что происходит в фоне. ESP получает HTTP-запрос от нового клиента - в данном случае, вашего браузера.

Вы также можете увидеть другую информацию о HTTP-запросе - эти поля называются полями HTTP-заголовка и определяют рабочие параметры HTTP-запроса.

Тестирование веб-сервера

Давайте проверим веб-сервер. Нажмите кнопку, чтобы включить GPIO 5. ESP получает запрос по URL-адресу / 5 / и включает светодиод 5.

Состояние светодиода также обновляется на веб-странице.

Проверьте кнопку GPIO 4 и убедитесь, что она работает аналогичным образом.

Как работает код

Теперь давайте подробнее рассмотрим код, чтобы увидеть, как он работает, чтобы вы могли изменить его в соответствии со своими потребностями.

Первое, что вам нужно сделать, это включить библиотеку ESP8266WiFi.

// Load Wi-Fi library
#include <ESP8266WiFi.h>

Как упоминалось ранее, вам нужно вставить свой ssid и пароль в следующие строки внутри двойных кавычек.

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

Затем вы устанавливаете свой веб-сервер на порт 80.

// Set web server port number to 80
WiFiServer server(80);

Следующая строка создает переменную для хранения заголовка HTTP-запроса:

String header;

Затем вы создаете вспомогательные переменные для хранения текущего состояния ваших выходных данных. Если вы хотите добавить больше выходных данных и сохранить их состояние, вам нужно создать больше переменных.

// Auxiliar variables to store the current output state
String output5State = "off";
String output4State = "off";

Вам также необходимо назначить GPIO каждому из ваших выходов. Здесь мы используем GPIO 4 и GPIO 5. Вы можете использовать любые другие подходящие GPIO.

// Assign output variables to GPIO pins
const int output5 = 5;
const int output4 = 4;

Настройка

Теперь перейдем к настройке. Функция setup () запускается только один раз при первой загрузке ESP. Сначала мы запускаем последовательную связь со скоростью 115200 бод для целей отладки.

Serial.begin(115200);

Вы также определяете свои GPIO как ВЫХОДЫ и устанавливаете их в LOW.

// Initialize the output variables as outputs
pinMode(output5, OUTPUT);
pinMode(output4, OUTPUT);
// Set outputs to LOW
digitalWrite(output5, LOW);
digitalWrite(output4, LOW);

Следующие строки начинают соединение Wi-Fi с WiFi.begin (ssid, пароль), ожидают успешного соединения и печатают IP-адрес ESP в Serial Monitor.

// Connect to Wi-Fi network with SSID and password
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
 delay(500);
 Serial.print(".");
}
// Print local IP address and start web server
Serial.println("");
Serial.println("WiFi connected.");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
server.begin();

Цикл

В loop() мы программируем то, что происходит, когда новый клиент устанавливает соединение с веб-сервером.

ESP всегда прослушивает входящих клиентов этой строкой:

WiFiClient client = server.available(); // Listen for incoming clients

Когда запрос получен от клиента, мы сохраним входящие данные. Последующий цикл while будет работать до тех пор, пока клиент остается подключенным. Мы не рекомендуем менять следующую часть кода, если вы точно не знаете, что делаете.

if (client) { // If a new client connects,
 Serial.println("New Client."); // print a message out in the serial port
 String currentLine = ""; // make a String to hold incoming data from the client
 while (client.connected()) { // loop while the client's connected
 if (client.available()) { // if there's bytes to read from the client,
  char c = client.read(); // read a byte, then
  Serial.write(c); // print it out the serial monitor
  header += c;
  if (c == '\n') { // if the byte is a newline character
   // if the current line is blank, you got two newline characters in a row.
   // that's the end of the client HTTP request, so send a response:
   if (currentLine.length() == 0) {
    // HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK)
    // and a content-type so the client knows what's coming, then a blank line:
    client.println("HTTP/1.1 200 OK");
    client.println("Content-type:text/html");
    client.println("Connection: close");
    client.println();

Следующий раздел операторов if и else проверяет, какая кнопка была нажата на вашей веб-странице, и соответственно контролирует результаты. Как мы видели ранее, мы делаем запрос на разные URL в зависимости от кнопки, которую нажимаем.

// turns the GPIOs on and off
if (header.indexOf("GET /5/on") >= 0) {
  Serial.println("GPIO 5 on");
  output5State = "on";
  digitalWrite(output5, HIGH);
} else if (header.indexOf("GET /5/off") >= 0) {
  Serial.println("GPIO 5 off");
  output5State = "off";
  digitalWrite(output5, LOW);
} else if (header.indexOf("GET /4/on") >= 0) {
  Serial.println("GPIO 4 on");
  output4State = "on";
  digitalWrite(output4, HIGH);
} else if (header.indexOf("GET /4/off") >= 0) {
  Serial.println("GPIO 4 off");
  output4State = "off";
  digitalWrite(output4, LOW);
}

Например, если вы нажали кнопку GPIO 5 ON, URL-адрес изменится на IP-адрес ESP, а затем / 5 / ON, и мы получим эту информацию в заголовке HTTP. Итак, мы можем проверить, содержит ли заголовок выражение GET / 5 / on.

Если он содержится, код печатает сообщение на последовательном мониторе, изменяет значение переменной output5State на on и включает светодиод.

Это работает аналогично для других кнопок. Поэтому, если вы хотите добавить больше выходных данных, вы должны изменить эту часть кода, чтобы включить их.

Отображение веб-страницы HTML

Следующее, что вам нужно сделать, это создать веб-страницу. ESP отправит в ваш браузер ответ с текстом HTML для отображения веб-страницы.

Веб-страница отправляется клиенту с помощью функции client.println (). Вы должны ввести то, что вы хотите отправить клиенту в качестве аргумента.

Первый текст, который вы всегда должны отправлять, - это следующая строка, которая указывает, что мы отправляем HTML.

<!DOCTYPE html><html>

Затем следующая строка делает веб-страницу отзывчивой в любом веб-браузере.

client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");

Следующий используется для предотвращения запросов, связанных со значком: вам не нужно беспокоиться об этой строке.

client.println("<link rel=\"icon\" href=\"data:,\">");

Стилизация веб-страницы

Далее у нас есть немного CSS для стилизации кнопок и внешнего вида веб-страницы. Мы выбираем шрифт Helvetica, определяем содержимое, которое будет отображаться в виде блока и выравниваться по центру.

client.println("<style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}");

Мы стилизуем наши кнопки с некоторыми свойствами, чтобы определить цвет, размер, границу и т. д.

client.println(".button { background-color: #195B6A; border: none; color: white; padding: 16px 40px;");
client.println("text-decoration: none; font-size: 30px; margin: 2px; cursor: pointer;}");

Затем мы определяем стиль для второй кнопки со всеми свойствами кнопки, которые мы определили ранее, но с другим цветом. Это будет стиль для кнопки выключения.

client.println(".button2 {background-color: #77878A;}</style></head>");

Настройка заголовка веб-страницы 

В следующей строке вы устанавливаете заголовок вашей веб-страницы, вы можете изменить этот текст на любой другой.

// Web Page Title
client.println("<h1>ESP8266 Web Server</h1>");

Отображение кнопок и соответствующего состояния

Затем вы пишете абзац для отображения текущего состояния GPIO 5. Как вы можете видеть, мы используем переменную output5State, поэтому состояние изменяется мгновенно при изменении этой переменной.

client.println("<p>GPIO 5 - State " + output5State + "</p>");

Затем мы отображаем кнопку включения или выключения, в зависимости от текущего состояния GPIO.

if (output5State=="off") {
 client.println("<p><a href=\"/5/on\"><button class=\"button\">ON</button></a></p>");
} else {
 client.println("<p><a href=\"/5/off\"><button class=\"button button2\">OFF</button></a></p>");
}

Мы используем ту же процедуру для GPIO 4.

Закрытие соединения

Наконец, когда ответ заканчивается, мы очищаем переменную заголовка и прекращаем соединение с клиентом с помощью client.stop ().

// Clear the header variable
header = "";
// Close the connection
client.stop();

Завершение

Теперь, когда вы знаете, как работает код, вы можете изменить код, чтобы добавить дополнительные выходные данные или изменить свою веб-страницу. Чтобы изменить свою веб-страницу, вам может понадобиться знание основ HTML и CSS. Вместо управления двумя светодиодами вы можете управлять реле для управления практически любыми электронными приборами.

ЧАСТЬ 2: СОЗДАНИЕ ВЕБ-СЕРВЕРА С ИСПОЛЬЗОВАНИЕМ NODEMCU

В этой части показано, как создать веб-сервер для управления двумя выходами с использованием прошивки NodeMCU и языка программирования LUA. Вы можете использовать этот метод для создания другого веб-сервера.

Зачем прошивать модуль ESP8266 с помощью NodeMCU?

NodeMCU - это прошивка, которая позволяет программировать модули ESP8266 с помощью сценария LUA. Программирование ESP8266 с помощью LUA с использованием прошивки NodeMCU очень похоже на программирование вашего Arduino. С помощью всего лишь нескольких строк кода вы можете установить соединение Wi-Fi, управлять GPO ESP8266, превратить ESP8266 в веб-сервер и многое другое.

Загрузка NodeMCU Flasher для Windows

После подключения вашей схемы вы должны загрузить флешер NodeMCU. Это файл .exe, который вы можете скачать по одной из следующих ссылок:

Вы можете нажать здесь, чтобы найти всю информацию о NodeMCU флешере.

Перепрошивка ESP8266

Если вы используете ESP8266-12, вам просто нужно подключить ESP к вашему компьютеру. Если вы используете ESP-01, вам нужен программатор FTDI, чтобы подключить его к вашему компьютеру. Установите последовательное соединение между вашим ESP8266 и программатором FTDI, как показано на принципиальной схеме ниже.

Откройте только что загруженный флэшер, и должно появиться окно (как показано на следующем рисунке).

Нажмите кнопку «Flash», и она должна немедленно начать процесс перепрошивки (возможно, вам придется изменить некоторые настройки на вкладке «Дополнительно»). После завершения этого процесса должен появиться зеленый кружок со значком галочки.

Схема

Для построения схемы вам понадобятся следующие детали:

Требуются запчасти:

  • ESP8266 12-E
  • 2x светодиода
  • 2х резисторов (220 или 330 Ом должны работать нормально)
  • Макетная плата
  • Перемычки

Если вы используете ESP-01, вам также нужен программатор FTDI.

Если вы используете ESP8266-01, используйте следующую схему в качестве справки.

Загрузка кода

Я рекомендую использовать программу ESPlorer, созданную 4refr0nt, для создания и сохранения файлов LUA в ESP8266. Следуйте этим инструкциям, чтобы загрузить и установить ESPlorer:

  1. Нажмите здесь, чтобы загрузить ESPlorer
  2. Распакуйте архив 
  3. Перейдите в папку dist (вот путь: ESPlorer-master \ ESPlorer \ dist)
  4. Запустите ESPlorer.jar. Это программа JAVA, поэтому на вашем компьютере должна быть установлена ​​JAVA.
  5. Откройте ESPlorer

 

Вы должны увидеть окно, похожее на предыдущий рисунок, следуйте этим инструкциям, чтобы загрузить файл LUA:

  1. Подключите ваш программатор FTDI к вашему компьютеру
  2. Выберите свой порт программатора FTDI
  3. Нажмите Открыть / Закрыть
  4. Выберите вкладку NodeMCU + MicroPtyhon
  5. Создайте новый файл с именем init.lua
  6. Нажмите Сохранить в ESP

Все, что нужно изменить, выделено красной рамкой.

Код

Загрузите следующий код в ESP8266, используя предыдущее программное обеспечение. Ваш файл должен называться «init.lua».

wifi.setmode(wifi.STATION)
wifi.sta.config("YOUR_NETWORK_NAME","YOUR_NETWORK_PASSWORD")
print(wifi.sta.getip())
led1 = 3
led2 = 4
gpio.mode(led1, gpio.OUTPUT)
gpio.mode(led2, gpio.OUTPUT)
srv=net.createServer(net.TCP)
srv:listen(80,function(conn)
    conn:on("receive", function(client,request)
        local buf = "";
        local _, _, method, path, vars = string.find(request, "([A-Z]+) (.+)?(.+) HTTP");
        if(method == nil)then
            _, _, method, path = string.find(request, "([A-Z]+) (.+) HTTP");
        end
        local _GET = {}
        if (vars ~= nil)then
            for k, v in string.gmatch(vars, "(%w+)=(%w+)&*") do
                _GET[k] = v
            end
        end
        buf = buf.."<h1> ESP8266 Web Server</h1>";
        buf = buf.."<p>GPIO0 <a href=\"?pin=ON1\"><button>ON</button></a>&nbsp;<a href=\"?pin=OFF1\"><button>OFF</button></a></p>";
        buf = buf.."<p>GPIO2 <a href=\"?pin=ON2\"><button>ON</button></a>&nbsp;<a href=\"?pin=OFF2\"><button>OFF</button></a></p>";
        local _on,_off = "",""
        if(_GET.pin == "ON1")then
              gpio.write(led1, gpio.HIGH);
        elseif(_GET.pin == "OFF1")then
              gpio.write(led1, gpio.LOW);
        elseif(_GET.pin == "ON2")then
              gpio.write(led2, gpio.HIGH);
        elseif(_GET.pin == "OFF2")then
              gpio.write(led2, gpio.LOW);
        end
        client:send(buf);
        client:close();
        collectgarbage();
    end)
end)

Не забудьте заменить данные вашего WiFi Station (Имя сети и Пароль).

Доступ к веб-серверу

Когда ESP8266 перезапускается, он печатает на вашем последовательном мониторе IP-адрес вашего ESP8266. Если вы введете свой IP-адрес ESP8266 в веб-браузере, вы сможете получить доступ к веб-серверу.