Typically connected projects has some kind of web or mobile UI. If you want to control one thing by another thing, espacially with a low latency and over the Internet that's quite hard to achieve. That is why I created this project. It's an Arduino framework template showing you how to connect two ESP32-based boards over the Internet, minimizing the latency with auto-recovery functionality in case of broken Wi-Fi connection or temporary power down of one of connected boards. The cool thing is that, it works if ESP32 boards are in the same Wi-Fi network and if are in separate networks. Even on different continents.

The template we are describing here can be a base for variety of cool interfaces to your ESP32-based projects, like:

smart glove to control your RC car

remote control for your smart home devices

secure and private Wi-Fi key to your home (while connection is P2P, no 3rd party has access to encryption key)

a really fast Internet button to your things

and much, much more.

Default functionality of the template is two-directional control of LEDs by buttons of oposite ESP32 boards. You can also treat this template as a Morse code Internet communicator :). Feel free to replace code to controll buttons and LEDs by any input/output operation you need.

In the project we create two tasks: the first one to manage Wi-Fi connection and the second one to handle data exchange between devices.

Wi-Fi task

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);

}

}

}

}

}

}

Wi-Fi task is written to auto-switch to another Wi-Fi network if a current connection is broken. In the configuration section (lines 7 - 40 of the source code) you can hardcode more than one Wi-Fi network credentials - that is a comfortable solution, because you don't need to reprogram your boards if you power them on in different locations.

Basically a Virtual LAN network between ESP32 devices is created thanks to these two lines:

Husarnet.join(husarnetJoinCode, hostNameX);

Husarnet.start();

Devices are identified by their hostnames, so you don't need to worry, about finding IP addresses. Connection is also fully encrypted, secure, and private. It works not only in LAN, but also through the internet, because connection is powered by Husarnet. Husarnet only helps in establishing a connection over the internet and user data isn't forwarded by it's servers. Thanks to that latency is lower.

Connection task

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

", hostName0);

while (client.connect(hostName0, port) == 0) {

delay(500);

}

#endif

Serial.printf("Client connected: %d\r

", (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

", c);

}

}

client.stop();

Serial.println("Client disconnected.");

Serial.println("");

}

}

ESP32 devices ping each other every 4s. If no ping is received for more than 6s, the connection loop is broken and is waiting for second device to be online. Because the aim of the project was to keep it simple, we don't create binary frames, use Protocol Buffers etc. . Depending on your application you can easily modify that.

Assembling

Connect push button between pin P22 and GND

Connect LED diode and resistor in series between pin P16 and GND

Connect battery to your ESP32-based board. In the project we use ESP32 devkit with a built-in LDO. Take a look at maximum input voltage level in case of your ESP32-based board to avoid damage.

Prepare a Firmware

Open Arduino IDE and follow these steps:

1. Install AceButton library:

open Tools -> Manage Libraries...

seach for acebutton library and click Install button

2. Install ESP32-Husarnet support:

open File -> Preferences

in a field Additional Board Manager URLs add this link:

https://files.husarion.com/arduino/beta/package_esp32_husarnet_index.json

open Tools -> Board: ... -> Boards Manager ...

Search for esp32-husarnet

Click Install button

3. Select ESP32 dev board:

open Tools -> Board

select ESP32 Dev Module under ESP32 Arduino (Husarnet) section

4. Program your ESP32 boards:

Open ESP32_ledstrip_webserver.ino project

modify line 25 with your Husarnet join code (get on https://app.husarnet.com )

modify lines 28 - 38 to add your Wi-Fi network credentials

upload project to your ESP32 board. Repeat the previous steps with ( line 9 ):

#define DEV_TYPE 0 // type "0" for 1st ESP32, and "1" for 2nd ESP32

power both ESP32 modules and wait about 15 seconds to allow your ESP32 devices connect to Wi-Fi network and establish P2P connection (works both in LAN and through the Internet).

And that's all! I hope you will like it. Would be happy to see your feedback.

Cheers!