ESP8266:Прошивки/Arduino/Библиотеки/Библиотека ESP8266WiFi/Класс сервера/Сервер, обслуживающий веб-страницу

Материал из Онлайн справочника
Перейти к навигацииПерейти к поиску

Перевод: Максим Кузьмин
Проверка/Оформление/Редактирование: Мякишев Е.А.



Сервер, обслуживающий веб-страницу[1]

Настройка веб-сервера на ESP8266 на удивление проста, т.к. требует очень небольшого скетча. Это простота обеспечивается за счет универсальности библиотеки ESP8266WiFi.

Цель этого скетча-примера – подготовить веб-страницу, чтобы ее можно было открыть веб-браузером. Страница будет показывать текущее значение аналогового входного контакта ESP8266.

Объект

Начнем с создания экземпляра класса WiFiServer:

WiFiServer server(80);

Сервер отвечает клиентам (в данном случае – браузерам) на порте 80, который является стандартным портом, через который браузеры «общаются» с веб-серверами.

Страница

Теперь давайте напишем короткую функцию prepareHtmlPage(), которая будет возвращать переменную типа String, содержащую содержимое веб-страницы. Мы передадим эту переменную серверу, чтобы тот передал ее клиенту.

String prepareHtmlPage()
{
  String htmlPage =
     String("HTTP/1.1 200 OK\r\n") +
            "Content-Type: text/html\r\n" +
            "Connection: close\r\n" +  // после отправки ответа
                                       // соединение будет закрыто
            "Refresh: 5\r\n" +         // автоматически обновляем 
                                       // страницу каждые 5 секунд 
            "\r\n" +
            "<!DOCTYPE HTML>" +
            "<html>" +
            "Analog input:  " + String(analogRead(A0)) +
            "</html>" +
            "\r\n";
  return htmlPage;
}

Эта функция не делает ничего выдающегося. Просто собирает вместе текстовый заголовок и HTML-содержимое страницы.

Сначала заголовок

Заголовок информирует клиента, какой тип контента последует и как его будут выдавать:

Content-Type: text/html
Connection: close
Refresh: 5

В нашем примере типом контента является text/html, после ответа соединение будет закрыто, а контент будет запрашиваться клиентом каждые 5 секунд. В конце заголовка будут стоять символы пустой строки («\r\n»). Они нужны для того, чтобы отделить заголовок от контента, который последует дальше.

<!DOCTYPE HTML>
<html>
Analog input:  [Value]
</html>

Этот контент содержит два базовых HTML-тега. Один – для описания типа HTML-документа (<!DOCTYPE HTML>), а второй – чтобы отметить начало (''') и конец (''') документа. Внутри – необработанное значение входного аналогового контакта ESP8266, считанное функцией analogRead(A0) и преобразованное в тип данных String.

String(analogRead(A0))

Выдача страницы

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

void loop()
{
  WiFiClient client = server.available();
  if (client)
  {
    // у нас новый клиент, отправивший запрос
  }
}

Когда подключится новый клиент, сервер прочтет его запрос, а затем напечатает его в мониторе порта.

while (client.connected())
{
  if (client.available())
  {
    String line = client.readStringUntil('\r');
    Serial.print(line);
  }
}

Запрос от клиента помечен символом новой строки. Дойдя до этого символа, сервер должен отправить обратно веб-страницу, а затем выйти из цикла while() при помощи оператора break.

if (line.length() == 1 && line[0] == '\n')
{
    client.println(prepareHtmlPage());
    break;
}

Весь этот процесс завершается закрытием соединения с клиентом.

client.stop();

Скетч целиком

Ниже весь этот скетч представлен в полном виде:

#include <ESP8266WiFi.h>

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

WiFiServer server(80);


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

  Serial.printf("Connecting to %s ", ssid);
            //  "Подключение к "
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED)
  {
    delay(500);
    Serial.print(".");
  }
  Serial.println(" connected");
             //  " подключено"

  server.begin();
  Serial.printf("Web server started, open %s in a web browser\n", WiFi.localIP().toString().c_str());
            //  "Веб-сервер запущен, открываем %s в веб-браузере"
}


// подготавливаем веб-страницу для отправки клиенту (браузеру):
String prepareHtmlPage()
{
  String htmlPage =
     String("HTTP/1.1 200 OK\r\n") +
            "Content-Type: text/html\r\n" +
            "Connection: close\r\n" +  // после отправки ответа
                                       // соединение будет закрыто
            "Refresh: 5\r\n" +         // автоматически обновляем
                                       // страницу каждые 5 секунд
            "\r\n" +
            "<!DOCTYPE HTML>" +
            "<html>" +
            "Analog input:  " + String(analogRead(A0)) +
            "</html>" +
            "\r\n";
  return htmlPage;
}


void loop()
{
  WiFiClient client = server.available();
  // ждем подключения клиента (браузера):
  if (client)
  {
    Serial.println("\n[Client connected]");
               //  "Клиент подключен"
    while (client.connected())
    {
      // считываем запрос клиента (браузера) строчка за строчкой:
      if (client.available())
      {
        String line = client.readStringUntil('\r');
        Serial.print(line);
        // ждем конца запроса, помеченного пустой строкой:
        if (line.length() == 1 && line[0] == '\n')
        {
          client.println(prepareHtmlPage());
          break;
        }
      }
    }
    delay(1); // даем браузеру время получить данные

    // закрываем соединение:
    client.stop();
    Serial.println("[Client disonnected]");
               //  "Клиент отключен"
  }
}

Запускаем скетч

Меняем в скетче строчки с ssid и password на SSID и пароль к своей точке доступа. Загружаем скетч на ESP8266 и открываем монитор порта. Сначала в мониторе порта должно появиться подтверждение того, что модуль подключен к точке доступа, а веб-сервер – запущен.

Connecting to sensor-net ........ connected
Web server started, open 192.168.1.104 in a web browser

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

Эта страница будет обновляться каждые 5 секунд. С каждым новым обновлением в мониторе порта должен появляться новый запрос от клиента:

[Client connected]
GET / HTTP/1.1
Accept: text/html, application/xhtml+xml, */*
Accept-Language: en-US
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko
Accept-Encoding: gzip, deflate
Host: 192.168.1.104
DNT: 1
Connection: Keep-Alive
[client disonnected]

Что дальше?

Этот скетч отчасти похож на «обратный» клиентский скетч – в том, из чего состоит протокол. Во-первых, он начинается с заголовка, содержащего информацию о коммуникации. Во-вторых, содержит информацию об одобренном типе контента (вроде text/html). В-третьих, сообщает, останется ли соединение открытым, когда монитор порта закончит показывать заголовок, или будет закрыто. В-четвертых, содержит идентификатор отправителя вроде User-Agent: Mozilla/5.0 (Windows NT 6.1). Также включает информацию о языке, IP-адресе и т.д.

Итого

Этот пример демонстрирует, что в настройке веб-сервера на базе ESP8266 нет ничего сложного. Такой сервер может принимать запросы от мощных устройств и программ вроде ПК и веб-браузера. По этой ссылке можно почитать о других классах вроде ESP8266WebServer, благодаря которым свой веб-серверный скетч можно сделать еще более функциональным.

Если вы хотите попробовать другой скетч, использующий класс сервера, обратите внимание на WiFiWebServer.ino, позволяющий включать/выключать GPIO-контакт прямо из браузера.

Полный список функций для работы с классом сервера смотрите по [ссылка этой ссылке].

См.также

Внешние ссылки