В этой статье мы рассмотрим как установить соединение Wi-Fi (HTTP) между двумя платами ESP8266 NodeMCU для обмена данными без необходимости подключения к Интернету (вам не нужен маршрутизатор).
Мы установим один ESP8266 как точку доступа (сервер), а другой ESP8266 как станцию (клиент). Затем сервер и клиент будут обмениваться данными (показаниями датчиков) через HTTP-запросы. Мы запрограммируем платы ESP8266 с помощью Arduino IDE.
В этом примере мы отправим показания датчика BME280 с одной платы на другую. Приемник отобразит показания на OLED-дисплее.
Необходимые компоненты
- NodeMCU ESP8266 (2 шт.) (купить на AliExpress).
- Датчик BME280 (купить на AliExpress).
- Модуль OLED дисплея с диагональю 0.96 дюйма и интерфейсом I2C (купить на AliExpress).
- Макетная плата.
- Соединительные провода.
Реклама: ООО "АЛИБАБА.КОМ (РУ)" ИНН: 7703380158
Обзор проекта
Чтобы лучше понять, как все работает, взгляните на следующую схему.
- Сервер ESP8266 создает собственную беспроводную сеть ( ESP8266 Soft-Access Point ). Таким образом, другие устройства Wi-Fi могут подключаться к этой сети ( SSID: ESP8266-Access-Point, Пароль: 123456789).
- Клиент ESP8266 настроен как станция. Таким образом, он может подключаться к беспроводной сети сервера ESP8266.
- Клиент может делать запросы HTTP GET к серверу, чтобы запросить данные датчика или любую другую информацию. Ему просто нужно использовать IP-адрес сервера, чтобы сделать запрос по определенному маршруту: /temperature (температура), /humidity (влажность) или /pressure (давление).
- Сервер прослушивает входящие запросы и отправляет соответствующий ответ с показаниями.
- Клиент получает показания и отображает их на OLED-дисплее.
Например, клиент ESP8266 запрашивает температуру, влажность и давление на сервере, отправляя запросы на IP-адрес сервера, за которым следует /температура ,/влажность и /давление, соответственно (HTTP GET).
Сервер ESP8266 прослушивает эти маршруты и при поступлении запроса отправляет соответствующие показания датчика через HTTP-ответ.
Собранная конструкция проекта показана на следующем рисунке.
Установка библиотек
Для этого урока вам необходимо установить следующие библиотеки:
Библиотеки асинхронного веб-сервера
Для обработки HTTP-запросов мы будем использовать следующие библиотеки:
- Библиотека ESPAsyncWebServer ( скачать библиотеку ESPAsyncWebServer )
- Библиотека ESPAsync TCP ( скачать библиотеку ESPAsyncTCP )
Эти библиотеки не доступны для установки через Library Manager. Поэтому вам нужно распаковать библиотеки и переместить их в папку библиотек установки Arduino IDE.
Либо вы можете перейти в меню Sketch > Подключить библиотеку > Добавить библиотеку .ZIP… и выбрать библиотеки, которые вы только что скачали.
Библиотеки BME280
Следующие библиотеки можно установить через Arduino Library Manager. Перейдите в Sketch > Include Library > Manage Libraries и найдите имя библиотеки.
Библиотеки I2C SSD1306 OLED
Для взаимодействия с OLED-дисплеем вам понадобятся следующие библиотеки. Их можно установить через Arduino Library Manager. Перейдите в Sketch > Include Library > Manage Libraries и найдите имя библиотеки.
#1 Сервер ESP8266 (Точка доступа)
Сервер ESP8266 — это точка доступа (AP), которая прослушивает запросы на /temperature (температура), /humidity (влажность) или /pressure (давление) по заданным URL-адресам. Когда он получает запросы по этим URL-адресам, он отправляет последние показания датчика BME280.
Для тестирования мы используем датчик BME280, но вы можете использовать любой другой датчик, изменив несколько строк кода (например: DHT11/DHT22 или DS18B20 ).
Принципиальная схема
Подключите ESP8266 к датчику BME280, как показано на следующей принципиальной схеме.
BME280 | ESP8266 |
VIN/VCC | 3.3V |
GND | GND |
SCL | GPIO 5 (D1) |
SDA | GPIO 4 (D2) |
Как видите, соединения достаточно просты.
Скетч Arduino для сервера ESP8266 №1
Загрузите следующий код на свою плату.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
/* Rui Santos Complete project details at https://RandomNerdTutorials.com/esp8266-nodemcu-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 <ESP8266WiFi.h> #include "ESPAsyncWebServer.h" #include <Wire.h> #include <Adafruit_Sensor.h> #include <Adafruit_BME280.h> // Set your access point network credentials const char* ssid = "ESP8266-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_P(200, "text/plain", readTemp().c_str()); }); 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()); }); 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(){ } |
Как работает код
Начните с подключения необходимых библиотек. Подключите библиотеку ESP8266WiFi.h и библиотеку ESPAsyncWebServer.h для обработки входящих HTTP-запросов.
1 2 |
#include <ESP8266WiFi.h> #include "ESPAsyncWebServer.h" |
Включите следующие библиотеки для взаимодействия с датчиком BME280.
1 2 3 |
#include <Wire.h> #include <Adafruit_Sensor.h> #include <Adafruit_BME280.h> |
В следующих переменных определите сетевые учетные данные вашей точки доступа:
1 2 |
const char* ssid = "ESP8266-Access-Point"; const char* password = "123456789"; |
Мы устанавливаем SSID на ESP8266-Access-Point, но вы можете дать ему любое другое имя. Вы также можете изменить пароль. По умолчанию он установлен на123456789.
Создайте экземпляр для датчика BME280 под названием bme.
1 |
Adafruit_BME280 bme; |
Создайте асинхронный веб-сервер на порту 80.
1 |
AsyncWebServer server(80); |
Затем создайте три функции, которые возвращают температуру, влажность и давление в виде строковых переменных.
1 2 3 4 5 6 7 8 9 10 11 12 |
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() инициализируйте последовательный монитор для демонстрационных целей.
1 |
Serial.begin(115200); |
Настройте ESP8266 как точку доступа с указанным ранее именем SSID и паролем.
1 |
WiFi.softAP(ssid, password); |
Затем обработайте маршруты, на которых ESP8266 будет прослушивать входящие запросы.
Например, когда сервер ESP8266 получает запрос /temperature, он отправляет температуру, возвращаемую функцией readTemp() в виде символов (вот почему мы используем метод c_str()).
1 2 3 |
server.on("/temperature", HTTP_GET, [](AsyncWebServerRequest *request){ request->send_P(200, "text/plain", readTemp().c_str()); }); |
То же самое происходит, когда ESP получает запрос на /humidity и /pressure.
1 2 3 4 5 6 |
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.
1 2 3 4 5 6 7 8 9 |
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); } |
Наконец, запустите сервер.
1 |
server.begin(); |
Поскольку это асинхронный веб-сервер, то в функции loop() у него ничего нет.
1 2 3 |
void loop(){ } |
Тестирование сервера ESP8266
Загрузите код на плату и откройте Serial Monitor. Вы должны получить что-то вроде этого:
Это означает, что точка доступа настроена успешно.
Теперь, чтобы убедиться, что он прослушивает запросы температуры, влажности и давления, вам необходимо подключиться к его сети.
В смартфоне зайдите в настройки Wi-Fi и подключитесь к ESP8266-Access-Point . Пароль — 123456789.
Подключившись к точке доступа, откройте браузер и введите 192.168.4.1/temperature.
Вы должны получить значение температуры в своем браузере:
Попробуйте этот URL-адрес для влажности - 192.168.4.1/humidity.
Наконец, перейдите к 192.168.4.1/pressure.
Если вы получаете правильные показания, это значит, что все работает правильно. Теперь вам нужно подготовить другую плату ESP8266 (клиент), чтобы она делала эти запросы для вас и отображала их на OLED-дисплее.
#2 Клиент ESP8266 (Станция)
Клиент ESP8266 — это станция Wi-Fi, которая подключается к серверу ESP8266. Клиент запрашивает температуру, влажность и давление с сервера, отправляя запросы HTTP GET на URL-маршруты /temperature, /humidity и /pressure. Затем он отображает показания на OLED-дисплее.
Принципиальная схема
Подключите OLED-дисплей к плате ESP8266, как показано на следующей принципиальной схеме.
OLED-дисплей | ESP8266 |
Vin | 3.3В |
GND | GND |
SCL | GPIO 5 (D1) |
SDA | GPIO 4 (D2) |
Как видите, соединения крайне просты.
Скетч Arduino для клиента ESP8266
Загрузите следующий код на другую плату ESP8266 (клиент):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 |
/* Rui Santos Complete project details at https://RandomNerdTutorials.com/esp8266-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 <ESP8266WiFi.h> #include <ESP8266HTTPClient.h> #include <WiFiClient.h> #include <ESP8266WiFiMulti.h> ESP8266WiFiMulti WiFiMulti; const char* ssid = "ESP8266-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 -1 // 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); Serial.println(); // 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); Serial.print("Connecting to "); Serial.println(ssid); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println(""); Serial.println("Connected to WiFi"); } void loop() { unsigned long currentMillis = millis(); if(currentMillis - previousMillis >= interval) { // Check WiFi connection status if ((WiFiMulti.run() == 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.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 IP address with path or Domain name with URL 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-запросов:
1 2 3 4 5 |
#include <ESP8266WiFi.h> #include <ESP8266HTTPClient.h> #include <WiFiClient.h> #include <ESP8266WiFiMulti.h> |
Вам необходимо создать объект WiFiMulti.
1 |
ESP8266WiFiMulti WiFiMulti; |
Вставьте сетевые учетные данные сервера ESP8266. Если вы изменили сетевые учетные данные по умолчанию на сервере ESP8266, вам следует изменить их здесь, чтобы они совпадали.
1 2 |
const char* ssid = "ESP8266-Access-Point"; const char* password = "123456789"; |
Затем сохраните URL-адреса, по которым клиент будет делать HTTP-запросы. Сервер ESP8266 имеет IP-адрес 192.168.4.1, и мы будем делать запросы по URL-адресам с /temperature, /humidity и /pressure.
1 2 3 |
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-дисплеем:
1 2 3 |
#include <Wire.h> #include <Adafruit_GFX.h> #include <Adafruit_SSD1306.h> |
Установите размер OLED-дисплея:
1 2 |
#define SCREEN_WIDTH 128 // OLED display width, in pixels #define SCREEN_HEIGHT 64 // OLED display height, in pixels |
Создайте объект для работы с дисплеем с размером, который вы определили ранее, и с протоколом связи I2C.
1 |
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); |
Инициализируйте строковые переменные, которые будут содержать показания температуры, влажности и давления, полученные сервером.
1 2 3 |
String temperature; String humidity; String pressure; |
Установите временной интервал между каждым запросом. По умолчанию он установлен на 5 секунд, но вы можете изменить его на любой другой интервал.
1 |
const long interval = 5000; |
В функции setup() инициализируйте OLED-дисплей:
1 2 3 4 5 6 7 |
// 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 и измените код соответствующим образом.
Подключите клиент ESP8266 к сети сервера ESP8266.
1 2 3 4 5 6 |
while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println(""); Serial.println("Connected to WiFi"); |
В функции loop() мы делаем HTTP GET запросы. Мы создали функцию под названием httpGETRequest(), которая принимает в качестве аргумента URL-путь, по которому мы хотим сделать запрос, и возвращает ответ в виде строки.
Для упрощения кода вы можете использовать в своих проектах следующую функцию:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
String httpGETRequest(const char* serverName) { WiFiClient client; HTTPClient http; // Your IP address with path or Domain name with URL 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; } |
Мы используем эту функцию для получения показаний температуры, влажности и давления с сервера.
1 2 3 |
temperature = httpGETRequest(serverNameTemp); humidity = httpGETRequest(serverNameHumi); pressure = httpGETRequest(serverNamePres); |
Распечатайте эти показания в последовательном мониторе для отладки.
1 |
Serial.println("Temperature: " + temperature + " *C - Humidity: " + humidity + " % - Pressure: " + pressure + " hPa"); |
Затем отобразите температуру на OLED-дисплее:
1 2 3 4 5 6 7 8 9 10 11 |
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"); |
Влажность:
1 2 3 4 5 |
display.setTextSize(2); display.setCursor(0, 25); display.print("H: "); display.print(humidity); display.print(" %"); |
Наконец, показания давления:
1 2 3 4 5 6 7 8 9 |
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().
Загрузите скетч на #2 ESP8266 (клиент), чтобы проверить, все ли работает правильно.
Тестирование клиента ESP8266
Расположив обе платы достаточно близко и включив питание, вы увидите, что ESP №2 получает новые показания температуры, влажности и давления каждые 5 секунд от ESP №1.
Вот что вы должны увидеть на клиентском последовательном мониторе ESP8266.
Показания датчика также отображаются на OLED-дисплее.
Вот и все! Ваши две платы ESP8266 общаются друг с другом.
Подведение итогов
В этом уроке мы показали вам, как отправлять данные с одной платы ESP8266 на другую с помощью HTTP-запросов. Этот проект может быть очень полезен, если вам нужно настроить беспроводную связь между двумя или более платами, а поблизости нет маршрутизатора.
Для демонстрационных целей мы показали, как отправлять показания датчика BME280, но вы можете использовать любой другой датчик или отправлять любые другие данные.
56 просмотров