ESP32 представляет собой мощный и в то же время простой в обращении микроконтроллер со встроенными возможностями беспроводной связи. В данном примере будет представлен простой проект, показывающий, как установить соединение между двумя устройствами на основе ESP32. Это работает как в локальной сети, так и через интернет.

Обычно подключаемые проекты имеют веб-интерфейс или мобильный интерфейс. Если вы хотите контролировать одну вещь посредством другой, особенно с низкой задержкой и через Интернет, это довольно сложно достичь. В этом деле пригодится такой проект как этот. Это шаблон инфраструктуры Arduino, показывающий, как соединить две платы на основе ESP32 через Интернет, сводя к минимуму задержку с помощью функции автоматического восстановления в случае обрыва соединения Wi-Fi или временного отключения питания одной из подключенных плат. Эта концепция работает, если платы ESP32 находятся в одной сети Wi-Fi и если они находятся в разных сетях, даже на разных континентах.
Функциональность шаблона проекта по умолчанию – двунаправленное управление светодиодами кнопками разных плат ESP32. Вы также можете рассматривать этот шаблон как интернет-коммуникатор с азбукой Морзе. Не стесняйтесь заменять код для управления кнопками и светодиодами на любые необходимые операции ввода/вывода.
В проекте мы создаем две задачи: первая для управления подключением Wi-Fi, а вторая – для обмена данными между устройствами.
Задача Wi-Fi создается для автоматического переключения на другую сеть Wi-Fi в случае разрыва текущего соединения. В разделе конфигурации (строки 7–40 исходного кода) вы можете жестко закодировать несколько учетных данных сети Wi-Fi – это удобное решение, так вам не нужно перепрограммировать свои платы, если вы включаете их в разных местах. Вот код данной задачи:
void taskWifi( void * parameter ) {
while (1) {
for (int i = 0; i < NUM_NETWORKS; i++) {
Serial.print("Connecting to ");
Serial.print(ssidTab[i]);
WiFi.begin(ssidTab[i], passwordTab[i]);
for (int j = 0; j < 10; j++) {
if (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
} else {
Serial.println("done");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
#if DEV_TYPE == 0
Husarnet.join(husarnetJoinCode, hostName0);
#elif DEV_TYPE == 1
Husarnet.join(husarnetJoinCode, hostName1);
#endif
Husarnet.start();
while (WiFi.status() == WL_CONNECTED) {
delay(500);
}
}
}
}
}
По сути, благодаря этим двум строкам создается сеть виртуальной локальной сети между устройствами ESP32:
Husarnet.join(husarnetJoinCode, hostNameX);
Husarnet.start();
Устройства идентифицируются по именам хостов, поэтому вам не нужно беспокоиться о поиске IP-адресов. Соединение также полностью зашифровано, безопасно и конфиденциально. Это работает не только в локальной сети, но и через Интернет, потому что подключение осуществляется через Husarnet (husarnet.com). Husarnet помогает только в установлении соединения через Интернет, а пользовательские данные не пересылаются его серверами. Благодаря этому задержка меньше.
Устройства ESP32 пингуют друг друга каждые 4 секунды. Если в течение более 6 секунд пинг не получен, цикл соединения разрывается и ожидает подключения второго устройства. Поскольку цель проекта состояла в том, чтобы сделать его простым, мы не создаем двоичные кадры, не используем буфер протокола и т. д. В зависимости от вашего приложения вы можете легко изменить это.
void taskConnection( void * parameter ) {
uint8_t oldState = btn.getLastButtonState();
while (1) {
while (WiFi.status() != WL_CONNECTED) {
delay(500);
}
#if DEV_TYPE == 0
server.begin();
Serial.println("Waiting for client");
do {
delay(500);
client = server.available();
client.setTimeout(3);
} while (client < 1);
#elif DEV_TYPE == 1
Serial.printf("Connecting to %s\r\n", hostName0);
while (client.connect(hostName0, port) == 0) {
delay(500);
}
#endif
Serial.printf("Client connected: %d\r\n", (int)client.connected());
unsigned long lastMsg = millis();
auto lastPing = 0;
while (client.connected()) {
//ping RX
if (millis() - lastMsg > 6000) {
Serial.println("ping timeout");
break;
}
//ping TX
auto now = millis();
if (now > lastPing + 4000) {
client.print('p');
lastPing = now;
}
if (oldState != btn.getLastButtonState()) {
oldState = btn.getLastButtonState();
if (oldState == 0) {
client.print('a');
} else {
client.print('b');
}
}
if (client.available()) {
char c = client.read();
if (c == 'p') {
lastMsg = millis();
}
if (c == 'a') {
digitalWrite(LED_PIN, HIGH);
}
if (c == 'b') {
digitalWrite(LED_PIN, LOW);
}
Serial.printf("read: %c\r\n", c);
}
}
client.stop();
Serial.println("Client disconnected.");
Serial.println("");
}
}
Поговорим теперь о подключении аппаратной части. Подключите кнопку между контактом P22 и GND. Подключите светодиод и резистор последовательно между контактом P16 и GND. Подключите аккумулятор к вашей плате на базе ESP32. В проекте мы используем ESP32 devkit со встроенным LDO. Посмотрите на максимальный уровень входного напряжения на вашей плате на базе ESP32, чтобы избежать повреждения.
Теперь позаботимся о программном обеспечении. Подключите библиотеку acebutton, найдя ее в менеджере библиотек.
Затем установим поддержку ESP32-Husarnet. Откройте Настройки Aduino IDE (Preferences), добавьте ссылку https://files.husarion.com/arduino/package_esp32_husarnet_index.json через Additional Board Manager URLs. Откройте менеджер плат (Boards manager) и найдите esp32-husarnet. Нажмите кнопку установки.

Из списка плат выберете ESP32 Arduino (Husarnet). Откройте проект ESP32_ledstrip_webserver.ino. Измените строку 25 вашим кодом присоединения Husarnet (возьмите на https://app.husarnet.com).

Измените строки 28 - 38, чтобы добавить свои учетные данные сети Wi-Fi. Сделайте все то же самое со второй платой, изменив только значение в строке 9 с 0 на 1. Включите оба модуля ESP32 и подождите около 15 секунд, чтобы устройства ESP32 подключились к сети Wi-Fi и установили соединение P2P (работает как в локальной сети, так и через Интернет). Вот полный код программы.
#include <WiFi.h>
#include <Husarnet.h>
#include <AceButton.h>
using namespace ace_button;
#define DEV_TYPE 0 // type "0" for 1st ESP32, and "1" for 2nd ESP32
const int BUTTON_PIN = 22;
const int LED_PIN = 16;
const char* hostName0 = "esp2esp0";
const char* hostName1 = "esp2esp1";
const char* husarnetJoinCode = "xxxxxxxxxxxxxxxxxxxxxx";
#define NUM_NETWORKS 2
const char* ssidTab[NUM_NETWORKS] = {
"wifi-ssid-one",
"wifi-ssid-two",
};
const char* passwordTab[NUM_NETWORKS] = {
"wifi-pass-one",
"wifi-pass-two",
};
AceButton btn(BUTTON_PIN);
HusarnetClient client;
uint16_t port = 8001;
#if DEV_TYPE == 0
HusarnetServer server(port);
#endif
void handleEvent(AceButton*, uint8_t, uint8_t);
void taskWifi( void * parameter );
void taskConnection( void * parameter );
void setup() {
Serial.begin(115200);
pinMode(BUTTON_PIN, INPUT_PULLUP);
btn.setEventHandler(handleEvent);
pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN, HIGH);
xTaskCreate(
taskWifi,
"taskWifi",
10000,
NULL,
1,
NULL);
xTaskCreate(
taskConnection,
"taskConnection",
10000,
NULL,
1,
NULL);
}
void loop() {
while (1) {
btn.check();
delay(1);
}
}
void handleEvent(AceButton* button, uint8_t eventType,
uint8_t buttonState) {
switch (eventType) {
case AceButton::kEventPressed:
Serial.println("pressed");
break;
case AceButton::kEventReleased:
Serial.println("released");
break;
}
}
void taskWifi( void * parameter ) {
while (1) {
for (int i = 0; i < NUM_NETWORKS; i++) {
Serial.print("Connecting to ");
Serial.print(ssidTab[i]);
WiFi.begin(ssidTab[i], passwordTab[i]);
for (int j = 0; j < 10; j++) {
if (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
} else {
Serial.println("done");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
#if DEV_TYPE == 0
Husarnet.join(husarnetJoinCode, hostName0);
#elif DEV_TYPE == 1
Husarnet.join(husarnetJoinCode, hostName1);
#endif
Husarnet.start();
while (WiFi.status() == WL_CONNECTED) {
delay(500);
}
}
}
}
}
}
void taskConnection( void * parameter ) {
uint8_t oldState = btn.getLastButtonState();
while (1) {
while (WiFi.status() != WL_CONNECTED) {
delay(500);
}
#if DEV_TYPE == 0
server.begin();
Serial.println("Waiting for client");
do {
delay(500);
client = server.available();
client.setTimeout(3);
} while (client < 1);
#elif DEV_TYPE == 1
Serial.printf("Connecting to %s\r\n", hostName0);
while (client.connect(hostName0, port) == 0) {
delay(500);
}
#endif
Serial.printf("Client connected: %d\r\n", (int)client.connected());
unsigned long lastMsg = millis();
auto lastPing = 0;
while (client.connected()) {
if (millis() - lastMsg > 6000) {
Serial.println("ping timeout");
break;
}
auto now = millis();
if (now > lastPing + 4000) {
client.print('p');
lastPing = now;
}
if (oldState != btn.getLastButtonState()) {
oldState = btn.getLastButtonState();
if (oldState == 0) {
client.print('a');
} else {
client.print('b');
}
}
if (client.available()) {
char c = client.read();
if (c == 'p') {
lastMsg = millis();
}
if (c == 'a') {
digitalWrite(LED_PIN, HIGH);
}
if (c == 'b') {
digitalWrite(LED_PIN, LOW);
}
Serial.printf("read: %c\r\n", c);
}
}
client.stop();
Serial.println("Client disconnected.");
Serial.println("");
}
}
© digitrode.ru