Skip to content

๐ŸŒ Fab Academy: Week 11 - Networking and Communications

This week for networking I connected 2 ESP32-S3 boards and made them communicate wirelessly.

๐Ÿ”ง I soldered header pins onto the ESP32 boards so that I can attach components onto it.

Image

๐Ÿค– Then I worked with ChatGPT to learn how to code and network between the boards.


Group Assignment

The networking of 2 different projects was done in the second spiral of my weekly assignment where I got the MAC address of one board and used it to communicate with another ESP32. You can find it here.
My learning from this was, its better to not connect 2 boards to your laptop simulataneously while uploading code. Upload the code on one board, disconnect it and then do the next. Connect them to power after the fact. This was the least buggiest way that I found to network between the 2 boards I used.


๐Ÿงญ Step 1: Getting the MAC Address

๐Ÿ“Ÿ The first step was to get the MAC address for one board.
๐Ÿงช It took a couple of tries to get the code just right but then it worked!

The working code:

Mac Adress
#include <WiFi.h>

void setup() {
  Serial.begin(115200);
  WiFi.mode(WIFI_STA);  // Set to Station mode
  delay(1000);
  Serial.print("MAC Address: ");
  Serial.println(WiFi.macAddress());
}

void loop() {}
Image

๐Ÿ“ฌ I had the MAC address for the receiver.


๐Ÿ—ฃ๏ธ Step 2: Saying Hello

๐Ÿ“ก I used this MAC address to do a simple serial print code that made them say hello to each other, to establish a connection.

Sender Code:

Transmission code
#include <WiFi.h>
#include <esp_now.h>

uint8_t peerAddress[] = {0x74, 0x4D, 0xBD, 0x97, 0x65, 0xFC};

String incomingMsg;
unsigned long lastSent = 0;

void OnDataRecv(const esp_now_recv_info_t *info, const uint8_t *data, int len) {
  incomingMsg = "";
  for (int i = 0; i < len; i++) {
    incomingMsg += (char)data[i];
  }
  Serial.print("Received: ");
  Serial.println(incomingMsg);
}

void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
  Serial.print("Send Status: ");
  Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Success" : "Fail");
}

void setup() {
  Serial.begin(115200);
  WiFi.mode(WIFI_STA);
  WiFi.disconnect();

  if (esp_now_init() != ESP_OK) {
    Serial.println("ESP-NOW init failed");
    return;
  }

  esp_now_register_recv_cb(OnDataRecv);
  esp_now_register_send_cb(OnDataSent);

  esp_now_peer_info_t peerInfo = {};
  memcpy(peerInfo.peer_addr, peerAddress, 6);
  peerInfo.channel = 0;
  peerInfo.encrypt = false;
  if (!esp_now_is_peer_exist(peerAddress)) {
    esp_now_add_peer(&peerInfo);
  }
}

void loop() {
  if (millis() - lastSent > 1000) {
    const char *msg = "Hello from A";
    esp_now_send(peerAddress, (uint8_t *)msg, strlen(msg));
    lastSent = millis();
  }
}

Reciever code:

Reciever code
#include <WiFi.h>
#include <esp_now.h>

String incomingMsg;

void OnDataRecv(const esp_now_recv_info_t *info, const uint8_t *data, int len) {
  incomingMsg = "";
  for (int i = 0; i < len; i++) {
    incomingMsg += (char)data[i];
  }
  Serial.print("Received: ");
  Serial.println(incomingMsg);

  // Add sender as peer before replying
  if (!esp_now_is_peer_exist(info->src_addr)) {
    esp_now_peer_info_t peerInfo = {};
    memcpy(peerInfo.peer_addr, info->src_addr, 6);
    peerInfo.channel = 0;
    peerInfo.encrypt = false;
    esp_now_add_peer(&peerInfo);
  }

  const char *reply = "Hello from B";
  esp_now_send(info->src_addr, (uint8_t *)reply, strlen(reply));
}

void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
  Serial.print("Send Status: ");
  Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Success" : "Fail");
}

void setup() {
  Serial.begin(115200);
  WiFi.mode(WIFI_STA);
  WiFi.disconnect();

  if (esp_now_init() != ESP_OK) {
    Serial.println("ESP-NOW init failed");
    return;
  }

  esp_now_register_recv_cb(OnDataRecv);
  esp_now_register_send_cb(OnDataSent);
}

void loop() {
  // Waiting for incoming messages...
}

Output from this transmission. Image Image


๐Ÿ’ก Step 3: Blinking the Onboard LED

๐Ÿ”จ Next, I built upon this code to make an onboard LED blink .
๐Ÿงฉ It was a task to figure out which pin the built-in LED was on, but I got it eventually!

Code for a simple LED blink:

Onboard LED blink
#ifndef LED_BUILTIN
  #define LED_BUILTIN 38  // fallback if not defined
#endif

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
}

void loop() {
  digitalWrite(LED_BUILTIN, HIGH);
  delay(500);
  digitalWrite(LED_BUILTIN, LOW);
  delay(500);
}

Development for Final project!

I am going to use ESP32s as my main board for my final project, It will be used for controlling the gas release and trigger the plasma pulse from the glove. I have strated tinkering and I will post updates when I have breakthroughs! Image

code:

Servo wireless control_Receiver
#include <esp_now.h>
#include <WiFi.h>
#include <ESP32Servo.h>

Servo myServo;

typedef struct struct_message {
  int xVal;
} struct_message;

struct_message receivedData;

void onReceive(const esp_now_recv_info_t *info, const uint8_t *incomingData, int len) {
  memcpy(&receivedData, incomingData, sizeof(receivedData));

  int angle = map(receivedData.xVal, 0, 4095, 0, 180);
  myServo.write(angle);

  Serial.print("Received X: ");
  Serial.print(receivedData.xVal);
  Serial.print(" | Mapped Angle: ");
  Serial.println(angle);
}

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

  myServo.attach(0); // D0 = GPIO 0
  WiFi.mode(WIFI_STA);
  WiFi.disconnect();

  if (esp_now_init() != ESP_OK) {
    Serial.println("ESP-NOW Init Failed");
    return;
  }

  esp_now_register_recv_cb(&onReceive);
}

void loop() {
  // nothing here; waiting for joystick input
}
Servo Wireless Control_Transmission
#include <esp_now.h>
#include <WiFi.h>

#define JOYSTICK_X_PIN 0  // D0 -> GPIO 0

uint8_t receiverMac[] = {0x74, 0x4D, 0xBD, 0x97, 0x65, 0xFC};  // Updated MAC

typedef struct {
  int xVal;
} JoystickData;

JoystickData dataToSend;

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

  // Set device as a Wi-Fi Station
  WiFi.mode(WIFI_STA);
  Serial.println("Transmitter MAC: " + WiFi.macAddress());

  // Init ESP-NOW
  if (esp_now_init() != ESP_OK) {
    Serial.println("ESP-NOW Init Failed");
    return;
  }

  // Register peer
  esp_now_peer_info_t peerInfo = {};
  memcpy(peerInfo.peer_addr, receiverMac, 6);
  peerInfo.channel = 0;
  peerInfo.encrypt = false;

  if (!esp_now_add_peer(&peerInfo)) {
    Serial.println("Failed to add peer");
  } else {
    Serial.println("Peer added");
  }

  // Read Joystick X only
  pinMode(JOYSTICK_X_PIN, INPUT);
}

void loop() {
  dataToSend.xVal = analogRead(JOYSTICK_X_PIN);
  esp_now_send(receiverMac, (uint8_t*)&dataToSend, sizeof(dataToSend));
  Serial.print("Sent X: ");
  Serial.println(dataToSend.xVal);
  delay(100);  // Adjust as needed
}

I also tried using text prompts like 'open' and 'close sent wirelessly, between the two ESP32's. If you are using ChatGPT to generate the code for this it will first give a code like this:

Wifi Adress
#include <WiFi.h>

void setup() {
  Serial.begin(115200);
  Serial.println("Receiver MAC Address:");
  Serial.println(WiFi.macAddress());
}

void loop() {}

This is a code to get your IP address, use this code instead:

Mac address.cpp
#include <WiFi.h>

void setup() {
  Serial.begin(115200);
  WiFi.mode(WIFI_STA);  // Important: Set to station mode (no Wi-Fi connection)
  delay(1000);          

  Serial.println("ESP32-S3 MAC Address:");
  Serial.println(WiFi.macAddress());  // This is the MAC you'll use for ESP-NOW
}

void loop() {}
Once I had my MAC address I could begin with coding the servos and sending commands.

After discarding a lot of outdated libraries, I finally got a set of code that works hand in hand. Using the MAC address that I had gotten from my reciever. these are the code files:

Sender's code.cpp
#include <esp_now.h>
#include <WiFi.h>

// Replace with your receiver's MAC address
uint8_t receiverMAC[] = { 0x74, 0x4D, 0xBD, 0x97, 0x65, 0xFC };

void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
  Serial.print("Send Status: ");
  Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Success" : "Fail");
}

void setup() {
  Serial.begin(115200);
  WiFi.mode(WIFI_STA);
  Serial.println("ESP-NOW Sender Ready. Type 'open' or 'close' and press Enter.");

  if (esp_now_init() != ESP_OK) {
    Serial.println("ESP-NOW init failed!");
    return;
  }

  esp_now_register_send_cb(OnDataSent);

  esp_now_peer_info_t peerInfo = {};
  memcpy(peerInfo.peer_addr, receiverMAC, 6);
  peerInfo.channel = 0;  
  peerInfo.encrypt = false;

  if (esp_now_add_peer(&peerInfo) != ESP_OK) {
    Serial.println("Failed to add peer");
    return;
  }
}

void loop() {
  if (Serial.available()) {
    String cmd = Serial.readStringUntil('\n');
    cmd.trim();

    if (cmd == "open" || cmd == "close") {
      const char *msg = cmd.c_str();
      esp_now_send(receiverMAC, (uint8_t *)msg, strlen(msg) + 1);
      Serial.print("Command sent: ");
      Serial.println(cmd);
    } else {
      Serial.println("Invalid command. Use: open / close");
    }
  }
}

Reciever's code.cpp
#include <esp_now.h>
#include <WiFi.h>
#include <ESP32Servo.h>  // Make sure this library is installed

Servo myServo;

void OnDataRecv(const esp_now_recv_info_t *info, const uint8_t *incomingData, int len) {
  String cmd = String((char *)incomingData);
  cmd.trim();

  Serial.print("Received from MAC: ");
  char macStr[18];
  snprintf(macStr, sizeof(macStr), "%02X:%02X:%02X:%02X:%02X:%02X",
           info->src_addr[0], info->src_addr[1], info->src_addr[2],
           info->src_addr[3], info->src_addr[4], info->src_addr[5]);
  Serial.println(macStr);

  Serial.print("Command: ");
  Serial.println(cmd);

  if (cmd == "open") {
    myServo.write(90);  // Open position
  } else if (cmd == "close") {
    myServo.write(0);   // Close position
  }
}

void setup() {
  Serial.begin(115200);
  WiFi.mode(WIFI_STA);
  Serial.println("ESP-NOW Receiver Ready");

  myServo.setPeriodHertz(50);    // Set frequency to 50Hz
  myServo.attach(10);            // GPIO 10 (D10)
  myServo.write(0);              // Initial position: closed

  if (esp_now_init() != ESP_OK) {
    Serial.println("ESP-NOW init failed");
    return;
  }

  esp_now_register_recv_cb(OnDataRecv);
}

void loop() {
  // Nothing here
}
Connecting the servos pins to 5V,GND & D10 of the reeciever ESP32.

Image The setup of the 2 ESP's

This is the link for the ChatGPT spiral that I followed.