ESP32 Клиент-Серверная Wi-Fi связь между двумя платами

Это руководство показывает, как настроить HTTP-связь между двумя платами ESP32 для обмена данными по Wi-Fi без подключения к интернету (роутера). Простыми словами, вы узнаете, как отправлять данные с одной платы на другую с помощью HTTP-запросов. Платы ESP32 будут программироваться с использованием Arduino IDE.

ESP32 Клиент-Серверная Wi-Fi связь между двумя платами

Для демонстрации мы будем отправлять показания датчика BME280 с одной платы на другую. Приёмник будет отображать показания на OLED-дисплее.

Если у вас плата ESP8266, вы можете прочитать специальное руководство: ESP8266 NodeMCU Клиент-Серверная Wi-Fi связь.

Смотрите видеодемонстрацию

Чтобы увидеть, как работает проект, вы можете посмотреть следующую видеодемонстрацию:

Обзор проекта

Одна плата ESP32 будет работать как сервер, а другая плата ESP32 будет работать как клиент. Следующая схема показывает обзор того, как всё работает.

Обзор проекта ESP32 Клиент-Сервер HTTP GET связь
  • ESP32-сервер создаёт собственную беспроводную сеть (ESP32 Soft-Access Point). Таким образом, другие Wi-Fi устройства могут подключаться к этой сети (SSID: ESP32-Access-Point, Пароль: 123456789).

  • ESP32-клиент настроен как станция (station). Таким образом, он может подключаться к беспроводной сети ESP32-сервера.

  • Клиент может выполнять HTTP GET-запросы к серверу для запроса данных с датчиков или любой другой информации. Ему нужно лишь использовать IP-адрес сервера для выполнения запроса на определённый маршрут: /temperature, /humidity или /pressure.

  • Сервер прослушивает входящие запросы и отправляет соответствующий ответ с показаниями.

  • Клиент получает показания и отображает их на OLED-дисплее.

В качестве примера, ESP32-клиент запрашивает температуру, влажность и давление у сервера, выполняя запросы на IP-адрес сервера с добавлением /temperature, /humidity и /pressure соответственно.

ESP32-сервер прослушивает эти маршруты, и когда поступает запрос, он отправляет соответствующие показания датчика через HTTP-ответ.

Необходимые компоненты

Компоненты для ESP32 Клиент-Серверной связи

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

Вы можете использовать ссылки выше или перейти напрямую на MakerAdvisor.com/tools для поиска всех компонентов для ваших проектов по лучшей цене!

Установка библиотек

Для этого руководства вам необходимо установить следующие библиотеки:

Библиотеки асинхронного веб-сервера

Мы будем использовать следующие библиотеки для обработки HTTP-запросов:

Вы можете установить эти библиотеки через Менеджер библиотек Arduino IDE. Перейдите в Sketch > Include Library > Manage Libraries и найдите библиотеки по названию.

Смотрите также: Создание асинхронного веб-сервера с ESP32

Библиотеки BME280

Следующие библиотеки можно установить через Менеджер библиотек Arduino. Перейдите в Sketch > Include Library > Manage Libraries и найдите библиотеку по названию.

Смотрите также: Подключение BME280 к ESP32 (Руководство)

Библиотеки I2C SSD1306 OLED

Для работы с OLED-дисплеем вам понадобятся следующие библиотеки. Их можно установить через Менеджер библиотек Arduino. Перейдите в Sketch > Include Library > Manage Libraries и найдите библиотеку по названию.

Смотрите также: I2C SSD1306 OLED-дисплей с ESP32 (Руководство)

#1 ESP32 Сервер (Точка доступа)

ESP32 Сервер с датчиком BME280 температура влажность давление

ESP32-сервер является точкой доступа (AP), которая прослушивает запросы на URL-адресах /temperature, /humidity и /pressure. Когда он получает запросы на эти URL, он отправляет последние показания датчика BME280.

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

Схема подключения

Подключите ESP32 к датчику BME280 как показано на следующей схеме.

Схема подключения ESP32 BME280

BME280

ESP32

VIN/VCC

3.3V

GND

GND

SCL

GPIO 22

SDA

GPIO 21

Скетч Arduino для #1 ESP32 Сервера

Загрузите следующий код на вашу плату.

/*
  Rui Santos & Sara Santos - Random Nerd Tutorials
  Complete project details at https://RandomNerdTutorials.com/esp32-client-server-wi-fi/
  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 "WiFi.h"
#include "ESPAsyncWebServer.h"

#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>

// Set your access point network credentials
const char* ssid = "ESP32-Access-Point";
const char* password = "123456789";

/*#include <SPI.h>
#define BME_SCK 18
#define BME_MISO 19
#define BME_MOSI 23
#define BME_CS 5*/

Adafruit_BME280 bme; // I2C
//Adafruit_BME280 bme(BME_CS); // hardware SPI
//Adafruit_BME280 bme(BME_CS, BME_MOSI, BME_MISO, BME_SCK); // software SPI

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

String readTemp() {
  return String(bme.readTemperature());
  //return String(1.8 * bme.readTemperature() + 32);
}

String readHumi() {
  return String(bme.readHumidity());
}

String readPres() {
  return String(bme.readPressure() / 100.0F);
}

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

  // Setting the ESP as an access point
  Serial.print("Setting AP (Access Point)…");
  // Remove the password parameter, if you want the AP (Access Point) to be open
  WiFi.softAP(ssid, password);

  IPAddress IP = WiFi.softAPIP();
  Serial.print("AP IP address: ");
  Serial.println(IP);

  server.on("/temperature", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send(200, "text/plain", readTemp().c_str());
  });
  server.on("/humidity", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send(200, "text/plain", readHumi().c_str());
  });
  server.on("/pressure", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send(200, "text/plain", readPres().c_str());
  });

  bool status;

  // default settings
  // (you can also pass in a Wire library object like &Wire2)
  status = bme.begin(0x76);
  if (!status) {
    Serial.println("Could not find a valid BME280 sensor, check wiring!");
    while (1);
  }

  // Start server
  server.begin();
}

void loop(){

}

Посмотреть исходный код

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

Начните с подключения необходимых библиотек. Подключите библиотеку WiFi.h и библиотеку ESPAsyncWebServer.h для обработки входящих HTTP-запросов.

#include "WiFi.h"
#include "ESPAsyncWebServer.h"

Подключите следующие библиотеки для работы с датчиком BME280.

#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>

В следующих переменных определите учётные данные вашей сети точки доступа:

const char* ssid = "ESP32-Access-Point";
const char* password = "123456789";

Мы устанавливаем SSID как ESP32-Access-Point, но вы можете дать ему любое другое имя. Вы также можете изменить пароль. По умолчанию он установлен как 123456789.

Создайте экземпляр для датчика BME280 с именем bme.

Adafruit_BME280 bme;

Создайте асинхронный веб-сервер на порту 80.

AsyncWebServer server(80);

Затем создайте три функции, которые возвращают температуру, влажность и давление как переменные типа String.

String readTemp() {
  return String(bme.readTemperature());
  //return String(1.8 * bme.readTemperature() + 32);
}

String readHumi() {
  return String(bme.readHumidity());
}

String readPres() {
  return String(bme.readPressure() / 100.0F);
}

В setup() инициализируйте Serial Monitor для отладки.

Serial.begin(115200);

Установите ваш ESP32 в качестве точки доступа с ранее определёнными SSID и паролем.

WiFi.softAP(ssid, password);

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

Например, когда ESP32-сервер получает запрос на URL /temperature, он отправляет температуру, возвращаемую функцией readTemp(), как char (именно поэтому мы используем метод c_str()).

server.on("/temperature", HTTP_GET, [](AsyncWebServerRequest *request){
  request->send_P(200, "text/plain", readTemp().c_str());
});

То же самое происходит, когда ESP получает запрос на URL /humidity и /pressure.

server.on("/humidity", HTTP_GET, [](AsyncWebServerRequest *request){
  request->send_P(200, "text/plain", readHumi().c_str());
});
server.on("/pressure", HTTP_GET, [](AsyncWebServerRequest *request){
  request->send_P(200, "text/plain", readPres().c_str());
});

Следующие строки инициализируют датчик BME280.

bool status;

// default settings
// (you can also pass in a Wire library object like &Wire2)
status = bme.begin(0x76);
if (!status) {
  Serial.println("Could not find a valid BME280 sensor, check wiring!");
  while (1);
}

Наконец, запустите сервер.

server.begin();

Поскольку это асинхронный веб-сервер, в loop() ничего нет.

void loop(){

}

Тестирование ESP32 Сервера

Загрузите код на вашу плату и откройте Serial Monitor. Вы должны увидеть что-то подобное:

Тестирование ESP32 Сервера Serial Monitor Arduino IDE

Это означает, что точка доступа была успешно настроена.

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

На вашем смартфоне перейдите в настройки Wi-Fi и подключитесь к ESP32-Access-Point. Пароль: 123456789.

Подключение к точке доступа ESP32 Server Access Point

Подключившись к точке доступа, откройте браузер и введите 192.168.4.1/temperature

Вы должны получить значение температуры в браузере:

Тестирование запроса температуры ESP32 Server Access Point

Попробуйте этот URL для влажности 192.168.4.1/humidity:

Тестирование запроса влажности ESP32 Server Access Point

Наконец, перейдите по URL 192.168.4.1/pressure:

Тестирование запроса давления ESP32 Server Access Point

Если вы получаете корректные показания, значит всё работает правильно. Теперь вам нужно подготовить другую плату ESP32 (клиент), чтобы она выполняла эти запросы за вас и отображала результаты на OLED-дисплее.

#2 ESP32 Клиент (Станция)

ESP32 Клиент получение показаний через HTTP GET запрос BME280

ESP32-клиент является Wi-Fi станцией, которая подключена к сети ESP32-сервера. Клиент запрашивает температуру, влажность и давление у сервера, выполняя HTTP GET-запросы на URL-маршруты /temperature, /humidity и /pressure. Затем он отображает показания на OLED-дисплее.

Схема подключения

Подключите ESP32 к OLED-дисплею как показано на следующей схеме.

Схема подключения ESP32 к OLED-дисплею

OLED

ESP32

VIN/VCC

VIN

GND

GND

SCL

GPIO 22

SDA

GPIO 21

Скетч Arduino для #2 ESP32 Клиента

Загрузите следующий код на другой ESP32:

/*
  Rui Santos
  Complete project details at https://RandomNerdTutorials.com/esp32-client-server-wi-fi/

  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.
*/

#include <WiFi.h>
#include <HTTPClient.h>

const char* ssid = "ESP32-Access-Point";
const char* password = "123456789";

//Your IP address or domain name with URL path
const char* serverNameTemp = "http://192.168.4.1/temperature";
const char* serverNameHumi = "http://192.168.4.1/humidity";
const char* serverNamePres = "http://192.168.4.1/pressure";

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels

// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
#define OLED_RESET     4 // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

String temperature;
String humidity;
String pressure;

unsigned long previousMillis = 0;
const long interval = 5000;

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

  // Address 0x3C for 128x64, you might need to change this value (use an I2C scanner)
  if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    Serial.println(F("SSD1306 allocation failed"));
    for(;;); // Don't proceed, loop forever
  }
  display.clearDisplay();
  display.setTextColor(WHITE);

  WiFi.begin(ssid, password);
  Serial.println("Connecting");
  while(WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.print("Connected to WiFi network with IP Address: ");
  Serial.println(WiFi.localIP());
}

void loop() {
  unsigned long currentMillis = millis();

  if(currentMillis - previousMillis >= interval) {
     // Check WiFi connection status
    if(WiFi.status()== WL_CONNECTED ){
      temperature = httpGETRequest(serverNameTemp);
      humidity = httpGETRequest(serverNameHumi);
      pressure = httpGETRequest(serverNamePres);
      Serial.println("Temperature: " + temperature + " *C - Humidity: " + humidity + " % - Pressure: " + pressure + " hPa");

      display.clearDisplay();

      // display temperature
      display.setTextSize(2);
      display.setTextColor(WHITE);
      display.setCursor(0,0);
      display.print("T: ");
      display.print(temperature);
      display.print(" ");
      display.setTextSize(1);
      display.cp437(true);
      display.write(248);
      display.setTextSize(2);
      display.print("C");

      // display humidity
      display.setTextSize(2);
      display.setCursor(0, 25);
      display.print("H: ");
      display.print(humidity);
      display.print(" %");

      // display pressure
      display.setTextSize(2);
      display.setCursor(0, 50);
      display.print("P:");
      display.print(pressure);
      display.setTextSize(1);
      display.setCursor(110, 56);
      display.print("hPa");

      display.display();

      // save the last HTTP GET Request
      previousMillis = currentMillis;
    }
    else {
      Serial.println("WiFi Disconnected");
    }
  }
}

String httpGETRequest(const char* serverName) {
  WiFiClient client;
  HTTPClient http;

  // Your Domain name with URL path or IP address with path
  http.begin(client, serverName);

  // Send HTTP POST request
  int httpResponseCode = http.GET();

  String payload = "--";

  if (httpResponseCode>0) {
    Serial.print("HTTP Response code: ");
    Serial.println(httpResponseCode);
    payload = http.getString();
  }
  else {
    Serial.print("Error code: ");
    Serial.println(httpResponseCode);
  }
  // Free resources
  http.end();

  return payload;
}

Посмотреть исходный код

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

Подключите необходимые библиотеки для Wi-Fi соединения и выполнения HTTP-запросов:

#include <WiFi.h>
#include <HTTPClient.h>

Введите учётные данные сети ESP32-сервера. Если вы изменили учётные данные по умолчанию на ESP32-сервере, вы должны изменить их здесь, чтобы они совпадали.

const char* ssid = "ESP32-Access-Point";
const char* password = "123456789";

Затем сохраните URL-адреса, по которым клиент будет выполнять HTTP-запросы. ESP32-сервер имеет IP-адрес 192.168.4.1, и мы будем выполнять запросы на URL /temperature, /humidity и /pressure.

const char* serverNameTemp = "http://192.168.4.1/temperature";
const char* serverNameHumi = "http://192.168.4.1/humidity";
const char* serverNamePres = "http://192.168.4.1/pressure";

Подключите библиотеки для работы с OLED-дисплеем:

#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

Установите размер OLED-дисплея:

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels

Создайте объект дисплея с ранее определённым размером и протоколом связи I2C.

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

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

String temperature;
String humidity;
String pressure;

Установите интервал времени между каждым запросом. По умолчанию он установлен на 5 секунд, но вы можете изменить его на любой другой интервал.

const long interval = 5000;

В setup() инициализируйте OLED-дисплей:

// Address 0x3C for 128x64, you might need to change this value (use an I2C scanner)
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
  Serial.println(F("SSD1306 allocation failed"));
  for(;;); // Don't proceed, loop forever
}
display.clearDisplay();
display.setTextColor(WHITE);

Примечание: если ваш OLED-дисплей не работает, проверьте его I2C-адрес с помощью скетча I2C сканера и измените код соответственно.

Подключите ESP32-клиент к сети ESP32-сервера.

WiFi.begin(ssid, password);
Serial.println("Connecting");
while(WiFi.status() != WL_CONNECTED) {
  delay(500);
  Serial.print(".");
}
Serial.println("");
Serial.print("Connected to WiFi network with IP Address: ");

В loop() мы выполняем HTTP GET-запросы. Мы создали функцию httpGETRequest(), которая принимает в качестве аргумента URL-путь, по которому мы хотим выполнить запрос, и возвращает ответ как String.

Вы можете использовать следующую функцию в своих проектах для упрощения кода:

String httpGETRequest(const char* serverName) {
  HTTPClient http;

  // Your IP address with path or Domain name with URL path
  http.begin(serverName);

  // Send HTTP POST request
  int httpResponseCode = http.GET();

  String payload = "--";

  if (httpResponseCode>0) {
    Serial.print("HTTP Response code: ");
    Serial.println(httpResponseCode);
    payload = http.getString();
  }
  else {
    Serial.print("Error code: ");
    Serial.println(httpResponseCode);
  }
  // Free resources
  http.end();

  return payload;
}

Мы используем эту функцию для получения показаний температуры, влажности и давления от сервера.

temperature = httpGETRequest(serverNameTemp);
humidity = httpGETRequest(serverNameHumi);
pressure = httpGETRequest(serverNamePres);

Выводим эти показания в Serial Monitor для отладки.

Serial.println("Temperature: " + temperature + " *C - Humidity: " + humidity + " % - Pressure: " + pressure + " hPa");

Затем отображаем температуру на OLED-дисплее:

display.setTextSize(2);
display.setTextColor(WHITE);
display.setCursor(0,0);
display.print("T: ");
display.print(temperature);
display.print(" ");
display.setTextSize(1);
display.cp437(true);
display.write(248);
display.setTextSize(2);
display.print("C");

Влажность:

display.setTextSize(2);
display.setCursor(0, 25);
display.print("H: ");
display.print(humidity);
display.print(" %");

Наконец, показания давления:

display.setTextSize(2);
display.setCursor(0, 50);
display.print("P:");
display.print(pressure);
display.setTextSize(1);
display.setCursor(110, 56);
display.print("hPa");

display.display();

Мы используем таймеры вместо задержек для выполнения запроса каждые x секунд. Именно поэтому у нас есть переменные previousMillis, currentMillis и мы используем функцию millis(). У нас есть статья, которая показывает разницу между таймерами и задержками, которая может быть вам полезна (или прочитайте ESP32 Таймеры).

Загрузите скетч на #2 ESP32 (клиент), чтобы проверить, всё ли работает правильно.

Тестирование ESP32 Клиента

Расположив обе платы достаточно близко друг к другу и подключив питание, вы увидите, что ESP #2 получает новые показания температуры, влажности и давления каждые 5 секунд от ESP #1.

Вот что вы должны увидеть в Serial Monitor ESP32-клиента.

Тестирование ESP32 Клиента Serial Monitor Arduino IDE

Показания датчика также отображаются на OLED-дисплее.

Пример обмена данными ESP32 Клиент-Сервер показания датчиков

Вот и всё! Ваши две платы общаются друг с другом.

ESP32 к ESP32 беспроводная связь между платами

Заключение

В этом руководстве вы узнали, как отправлять данные с одной платы ESP32 на другую через Wi-Fi с помощью HTTP-запросов без необходимости подключения к интернету. Для демонстрации мы показали, как отправлять показания датчика BME280, но вы можете использовать любой другой датчик или отправлять любые другие данные. Другие рекомендуемые датчики:

У нас есть аналогичное руководство для ESP8266, которое может быть полезным:

Надеемся, это руководство было полезным.


Источник: ESP32 Client-Server Wi-Fi Communication Between Two Boards