Week 11: Networks & communications
Design, build, and connect wired or wireless node(s) with network or bus addresses and local input &/or output device

This week was an exercise in reading lots of Reddit pages and Seeed wiki pages to set up the AP on my ESP32S3 and then have my ESP32C3 connect to it.

I used my final project electronics to this assignment. But at first nothing was working. After checking with the multimeter, I used this code to see if it was an issue with the microcontroller.

#include <Wire.h>

// Set I2C bus to use: Wire, Wire1, etc.
#define WIRE Wire
void setup() {
  WIRE.begin();
  Serial.begin(9600);
  while (!Serial)
     delay(10);
  Serial.println("\nI2C Scanner");
}
void loop() {
  byte error, address;
  int nDevices;
  Serial.println("Scanning...");

  nDevices = 0;
  for(address = 1; address < 127; address++ )
  {
    // The i2c_scanner uses the return value of
    // the Write.endTransmisstion to see if
    // a device did acknowledge to the address.
    WIRE.beginTransmission(address);
    error = WIRE.endTransmission();
    if (error == 0)
    {
      Serial.print("I2C device found at address 0x");
      if (address<16)
        Serial.print("0");
      Serial.print(address,HEX);
      Serial.println("  !");

      nDevices++;
    }
    else if (error==4)
    {
      Serial.print("Unknown error at address 0x");
      if (address<16)
        Serial.print("0");
      Serial.println(address,HEX);
    }
  }
  if (nDevices == 0)
    Serial.println("No I2C devices found\n");
  else
    Serial.println("done\n");

  delay(5000);           // wait 5 seconds for next scan
}

It turned out that because I had an SD card dev board connected to the strapping pins on my ESP32S3 and C3 that it won't do any other signals. So I disconnected the SD card component for now, and will readd it if I need it. Luckily if my WIFI continues to work, I won't need it.


#include <Adafruit_NeoPixel.h>
#include <Wire.h>
#include <MPU6050.h>
#define NUM_PIXELS 60      // Number of NeoPixels in your strip
#define DATA_PIN 2         // GPIO pin connected to NeoPixel data line

Adafruit_NeoPixel pixels(NUM_PIXELS, DATA_PIN, NEO_GRB + NEO_KHZ800);
MPU6050 mpu;
float brightness = 0.2;  // Brightness factor (0.0 to 1.0)

void setup() {
  Serial.begin(115200);      // Begin serial communication for debugging
  pixels.begin();            // Initialize the NeoPixel strip
  pixels.show();             // Turn off all pixels initially
  Wire.begin();              // Begin I2C communication for MPU6050

  mpu.initialize();          // Initialize the MPU6050
  if (!mpu.testConnection()) {
    Serial.println("MPU6050 connection failed"); // Debug in case of issues
    while (1);               // Halt if connection fails
  }
}
void loop() {
  int16_t ax, ay, az;
  mpu.getAcceleration(&ax, &ay, &az); // Get accelerometer values

  // Map acceleration to RGB values
  int colorX = map(ax, -17000, 17000, 0, 255);  // Forward-backward
  int colorY = map(ay, -17000, 17000, 0, 255);  // Left-right
  int colorZ = map(az, -17000, 17000, 0, 255);  // Up-down

  // Update the NeoPixels with the mapped color
  setColor(colorX, colorY, colorZ);
  delay(100);  // Delay to allow time between sensor reads
}
// Function to set all pixels to a specific color with brightness adjustment
void setColor(uint8_t r, uint8_t g, uint8_t b) {
  // Scale the RGB values based on the brightness factor
  r = r * brightness;
  g = g * brightness;
  b = b * brightness;
  for (int i = 0; i < NUM_PIXELS; i++) {
    pixels.setPixelColor(i, pixels.Color(r, g, b));
  }
  pixels.show(); // Push the color to the strip
}

After that I wanted to confirm that the neopixel x mpu set up from a previous week worked on my new pcb. It did!

I used this to scan for wifi (pulled from the Seeed Xiao Wifi Usage page) - this worked well for me on the ESP32C3

#include "WiFi.h"

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

  // Set WiFi to station mode and disconnect from an AP if it was previously connected
  WiFi.mode(WIFI_STA);
  WiFi.disconnect();
  delay(100);

  Serial.println("Setup done");
}
void loop() {
  Serial.println("scan start");

  // WiFi.scanNetworks will return the number of networks found
  int n = WiFi.scanNetworks();
  Serial.println("scan done");
  if (n == 0) {
    Serial.println("no networks found");
  } else {
    Serial.print(n);
    Serial.println(" networks found");
    for (int i = 0; i < n; ++i) {
      // Print SSID and RSSI for each network found
      Serial.print(i + 1);
      Serial.print(": ");
      Serial.print(WiFi.SSID(i));
      Serial.print(" (");
      Serial.print(WiFi.RSSI(i));
      Serial.print(")");
      Serial.println((WiFi.encryptionType(i) == WIFI_AUTH_OPEN) ? " " : "*");
      delay(10);
    }
  }
  Serial.println("");

  // Wait a bit before scanning again
  delay(5000);
}


I used this to make my C3 an access point (making it a http server)

#include <WiFi.h>
#include <WebServer.h>
// AP credentials
const char* ssid = "Jana_esp32-c3";
const char* password = "xx";

// Create an HTTP server
WebServer server(80);

void handlePostMessage() {
  if (server.hasArg("plain")) {
    String message = server.arg("plain"); // Get the POST body
    Serial.print("Received message: ");
    Serial.println(message);
    server.send(200, "text/plain", "Message received!");
  } else {
    server.send(400, "text/plain", "No message received!");
  }
}
void setup() {
  Serial.begin(115200);

  // Set up the AP
  WiFi.softAP(ssid, password);
  Serial.print("AP IP address: ");
  Serial.println(WiFi.softAPIP());
  // Define the POST endpoint
  server.on("/send-message", HTTP_POST, handlePostMessage);

  // Start the server
  server.begin();
  Serial.println("HTTP server started");
}
void loop() {
  server.handleClient();
}


I struggled to get the S3 to connect to the C3's AP. After reading through a few forums online of other people who had a similar problem, i found that if you added "WiFi.setMinSecurity(WIFI_AUTH_WEP)" below "WiFi.begin(ssid, password) that fixed it!

#include <WiFi.h>
#include <HTTPClient.h>
// AP credentials
const char* ssid = "Jana_esp32-c3";
const char* password = "xx";

const char* serverAddress = "192.168.4.x"; // Default IP of ESP32-C3 in AP mode

void connectToWiFi() {
  WiFi.begin(ssid, password);
  WiFi.setMinSecurity(WIFI_AUTH_WEP);
  WiFi.setTxPower(WIFI_POWER_8_5dBm);
  Serial.print("Connecting to WiFi ..");
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print('.');
    delay(1000);
  }
  Serial.println("\nConnected to WiFi!");
  Serial.println(WiFi.localIP());
}
void sendMessage(String message) {
  if (WiFi.status() == WL_CONNECTED) {
    HTTPClient http;
    // Construct the full URL
    String url = String("http://") + serverAddress + "/send-message";

    // Start the request
    http.begin(url);
    http.addHeader("Content-Type", "text/plain");

    // Send the POST request
    int httpResponseCode = http.POST(message);
    if (httpResponseCode > 0) {
      String response = http.getString();
      Serial.println("Server response: " + response);
    } else {
      Serial.println("Error sending POST request");
    }
    http.end();
  } else {
    Serial.println("WiFi not connected!");
  }
}
void setup() {
  Serial.begin(115200);

  // Connect to the ESP32-C3's AP
  connectToWiFi();
  // Send a test message
  sendMessage("Hello from ESP32-S3!");
}
void loop() {
  delay(5000); // Send a message every 5 seconds
  sendMessage("Another message from ESP32-S3!");
}

You can see below I was able to send a message! :) But for my final project, the ESP32S3 would be the AP receiving data from the C3, so I needed to flip this and make the S3 the server and the C3 the client.


I did end up having trouble flipping it - my S3 would barely create an AP and then turn off.

Anthony helped me trouble shoot why the S3 might be able to send messages but not create its own AP. After looking at it under a microscope, it looked like the wifi antenna port on the S3 had been pulled slightly. So Anthony helped me resolder it.

This kind of worked, the S3's AP would become visible from my laptop wifi scanner, but it would not be strong enough to allow my C3 to establish a connection.

Luckily, we tried out a new ESP32-S3 chip - and it worked perfectly! :) 

Here is the server code that worked for ESP32S3: 

#include <WiFi.h>
#include <WebServer.h>
// AP credentials
const char* ssid = "Jana_ESP32S3_AP";
const char* password = "xxx";

// Create an HTTP server
WebServer server(80);

void handleMessage() {
  if (server.hasArg("message")) { // Check for the "message" argument
    String message = server.arg("message");
    Serial.print("Received message: ");
    Serial.println(message);
    server.send(200, "text/plain", "Message received: " + message);
  } else {
    server.send(400, "text/plain", "No message received");
  }
}
void setup() {
  Serial.begin(115200);
  delay(1000);

  // Start the AP
  WiFi.softAP(ssid, password);
  Serial.print("AP IP address: ");
  Serial.println(WiFi.softAPIP());
  // Configure the HTTP server
  server.on("/send", handleMessage); // Handle requests to /send
  server.begin();
  Serial.println("HTTP server started");
}
void loop() {
  server.handleClient();
}

Here is the client code that worked for the ESP32C3: 

#include <WiFi.h>
#include <HTTPClient.h>
// AP credentials for connecting to the ESP32-S3
const char* ssid = "Jana_ESP32S3_AP";
const char* password = "xxx";

// ESP32-S3 server IP (default AP IP)
const char* serverAddress = "192.168.4.x";

void connectToWiFi() {
  WiFi.begin(ssid, password);
  Serial.print("Connecting to WiFi...");
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.print(".");
  }
  Serial.println("\nConnected to WiFi!");
  Serial.print("Client IP: ");
  Serial.println(WiFi.localIP());
}
void sendMessage(String message) {
  if (WiFi.status() == WL_CONNECTED) {
    HTTPClient http;
    // Construct the URL with the message as a query parameter
    String url = String("http://") + serverAddress + "/send?message=" + message;
    http.begin(url);
    // Send the GET request
    int httpCode = http.GET();
    if (httpCode > 0) {
      Serial.println("Message sent successfully!");
      Serial.print("Server response: ");
      Serial.println(http.getString());
    } else {
      Serial.print("Error sending message. HTTP code: ");
      Serial.println(httpCode);
    }
    http.end();
  } else {
    Serial.println("Not connected to WiFi!");
  }
}
void setup() {
  Serial.begin(115200);
  delay(1000);

  connectToWiFi();
  // Send a test message
  sendMessage("Hello from ESP32-C3!");
}
void loop() {
  // You can send messages periodically or trigger them based on events
  delay(5000);
}


Now to send motion data between my input device to my output device

For my final project, I wanted to be able to send motion data from a token to the display device. Since I've figured out the code for the other components of the system it was relatively easy to get it working.

Before getting the whole system to work, I just confirmed that the S3 could recieve the RBG values from the C3 as motion data was collected live. Here is the server code for the S3: 

#include <WiFi.h>
#include <WebServer.h>
const char* ssid = "Jana_ESP32S3_AP";
const char* password = "xxx";

WebServer server(80);

void handleMotionData() {
  if (server.hasArg("red") && server.hasArg("green") && server.hasArg("blue")) {
    int red = server.arg("red").toInt();
    int green = server.arg("green").toInt();
    int blue = server.arg("blue").toInt();

    // Print received data to the Serial Monitor
    Serial.print("Received RGB values - R: ");
    Serial.print(red);
    Serial.print(", G: ");
    Serial.print(green);
    Serial.print(", B: ");
    Serial.println(blue);
    server.send(200, "text/plain", "RGB values received");
  } else {
    server.send(400, "text/plain", "Missing RGB parameters");
  }
}
void setup() {
  Serial.begin(115200);
  WiFi.softAP(ssid, password);
  Serial.print("AP IP address: ");
  Serial.println(WiFi.softAPIP());
  server.on("/send", handleMotionData); // Endpoint for receiving motion data
  server.begin();
  Serial.println("HTTP server started");
}
void loop() {
  server.handleClient();
}


Here is the client code for the C3. It's still visualizing the lights on the C3 end using neopixels, and sending RBG values to the S3.

#include <WiFi.h>
#include <HTTPClient.h>
#include <Adafruit_NeoPixel.h>
#include <Wire.h>
#include <MPU6050.h>
#define NUM_PIXELS 60      // Number of NeoPixels in your strip
#define DATA_PIN 2         // GPIO pin connected to NeoPixel data line

const char* ssid = "Jana_ESP32S3_AP";      // ESP32-S3 AP credentials
const char* password = "connect123";
const char* serverAddress = "192.168.4.x"; // ESP32-S3 server IP

Adafruit_NeoPixel pixels(NUM_PIXELS, DATA_PIN, NEO_GRB + NEO_KHZ800);
MPU6050 mpu;
// Dimming factor (e.g., 0.5 for 50% brightness)
const float dimmingFactor = 0.2;

void connectToWiFi() {
  WiFi.begin(ssid, password);
  Serial.print("Connecting to WiFi...");
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.print(".");
  }
  Serial.println("\nConnected to WiFi!");
  Serial.print("Client IP: ");
  Serial.println(WiFi.localIP());
}
void sendMotionData(int r, int g, int b) {
  if (WiFi.status() == WL_CONNECTED) {
    HTTPClient http;
    // Construct the URL with RGB values as parameters
    String url = String("http://") + serverAddress + "/send?red=" + r + "&green=" + g + "&blue=" + b;
    http.begin(url);
    // Send the GET request
    int httpCode = http.GET();
    if (httpCode > 0) {
      Serial.println("Motion data sent successfully!");
      Serial.print("Server response: ");
      Serial.println(http.getString());
    } else {
      Serial.print("Error sending motion data. HTTP code: ");
      Serial.println(httpCode);
    }
    http.end();
  } else {
    Serial.println("Not connected to WiFi!");
  }
}
void setup() {
  Serial.begin(115200);
  pixels.begin();
  pixels.show(); // Turn off all pixels initially
  Wire.begin();
  mpu.initialize();
  if (!mpu.testConnection()) {
    Serial.println("MPU6050 connection failed");
    while (1); // Halt if connection fails
  }
  connectToWiFi(); // Connect to ESP32-S3's AP
}
void loop() {
  int16_t ax, ay, az;
  mpu.getAcceleration(&ax, &ay, &az); // Get accelerometer values

  // Map acceleration values to RGB values
  int colorX = map(ax, -17000, 17000, 0, 255);
  int colorY = map(ay, -17000, 17000, 0, 255);
  int colorZ = map(az, -17000, 17000, 0, 255);

  // Apply dimming factor
  colorX = int(colorX * dimmingFactor);
  colorY = int(colorY * dimmingFactor);
  colorZ = int(colorZ * dimmingFactor);
  // Update NeoPixels with dimmed values
  setColor(colorX, colorY, colorZ);
  // Send dimmed RGB values to the ESP32-S3
  sendMotionData(colorX, colorY, colorZ);
  delay(100); // Delay to avoid spamming requests
}
// Function to set all pixels to a specific color
void setColor(uint8_t r, uint8_t g, uint8_t b) {
  for (int i = 0; i < NUM_PIXELS; i++) {
    pixels.setPixelColor(i, pixels.Color(r, g, b));
  }
  pixels.show();
}


Finally done!

Here I was able to get the server (S3) end to visualize the motion data from the client side (C3).
Here is the server code for the ESP32S3 - note that I used the FastLED library not the Adafruit neopixel library.

#include <WiFi.h>
#include <WebServer.h>
#include <FastLED.h>
#define LED_PIN 3          // GPIO pin connected to the NeoPixel data line
#define NUM_LEDS 144        // Number of LEDs in the strip
#define BRIGHTNESS 64      // Brightness of the LEDs
#define LED_TYPE WS2812B   // Type of LED strip
#define COLOR_ORDER GRB    // Color order for the LEDs

const char* ssid = "Jana_ESP32S3_AP";
const char* password = "xxx";

CRGB leds[NUM_LEDS];
WebServer server(80);

void handleMotionData() {
  // Check if all required RGB parameters are present
  if (server.hasArg("red") && server.hasArg("green") && server.hasArg("blue")) {
    int red = server.arg("red").toInt();
    int green = server.arg("green").toInt();
    int blue = server.arg("blue").toInt();

    // Print received RGB values to the Serial Monitor
    Serial.print("Received RGB values - R: ");
    Serial.print(red);
    Serial.print(", G: ");
    Serial.print(green);
    Serial.print(", B: ");
    Serial.println(blue);
    // Update the LEDs with the received values
    setColor(red, green, blue);
    // Send acknowledgment to the client
    server.send(200, "text/plain", "RGB values received and applied");
  } else {
    // Handle missing parameters
    Serial.println("Error: Missing RGB parameters in request");
    server.send(400, "text/plain", "Missing RGB parameters");
  }
}
// Function to set all LEDs to a specific color
void setColor(uint8_t r, uint8_t g, uint8_t b) {
  Serial.print("Setting color: R=");
  Serial.print(r);
  Serial.print(", G=");
  Serial.print(g);
  Serial.print(", B=");
  Serial.println(b);
  for (int i = 0; i < NUM_LEDS; i++) {
    leds[i] = CRGB(r, g, b); // Set each LED to the specified RGB color
  }
  FastLED.show(); // Update the LEDs with the new color
}
void setup() {
  Serial.begin(115200);

  // Initialize FastLED
  FastLED.addLeds<LED_TYPE, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS).setCorrection(TypicalLEDStrip);
  FastLED.setBrightness(BRIGHTNESS);
  setColor(0, 0, 0); // Turn off all LEDs initially

  // Start the WiFi access point
  WiFi.softAP(ssid, password);
  Serial.print("AP IP address: ");
  Serial.println(WiFi.softAPIP());
  // Set up the HTTP server
  server.on("/send", handleMotionData); // Endpoint for receiving motion data
  server.begin();
  Serial.println("HTTP server started");
}


Client side code: 

#include <WiFi.h>
#include <HTTPClient.h>
#include <Adafruit_NeoPixel.h>
#include <Wire.h>
#include <MPU6050.h>
#define NUM_PIXELS 5      // Number of NeoPixels in your strip
#define DATA_PIN 2         // GPIO pin connected to NeoPixel data line

const char* ssid = "Jana_ESP32S3_AP";      // ESP32-S3 AP credentials
const char* password = "xxx";
const char* serverAddress = "192.168.4.x"; // ESP32-S3 server IP

Adafruit_NeoPixel pixels(NUM_PIXELS, DATA_PIN, NEO_GRB + NEO_KHZ800);
MPU6050 mpu;
// Dimming factor (optional, e.g., 0.5 for 50% brightness)
const float dimmingFactor = 0.5;

void connectToWiFi() {
  WiFi.begin(ssid, password);
  Serial.print("Connecting to WiFi...");
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.print(".");
  }
  Serial.println("\nConnected to WiFi!");
  Serial.print("Client IP: ");
  Serial.println(WiFi.localIP());
}
void sendMotionData(int r, int g, int b) {
  if (WiFi.status() == WL_CONNECTED) {
    HTTPClient http;
    // Construct the URL with RGB values as parameters
    String url = String("http://") + serverAddress + "/send?red=" + r + "&green=" + g + "&blue=" + b;
    http.begin(url);
    // Send the GET request
    int httpCode = http.GET();
    if (httpCode > 0) {
      Serial.println("Motion data sent successfully!");
      Serial.print("Server response: ");
      Serial.println(http.getString());
    } else {
      Serial.print("Error sending motion data. HTTP code: ");
      Serial.println(httpCode);
    }
    http.end();
  } else {
    Serial.println("Not connected to WiFi!");
  }
}
void setup() {
  Serial.begin(115200);
  pixels.begin();
  pixels.show(); // Turn off all pixels initially
  Wire.begin();
  mpu.initialize();
  if (!mpu.testConnection()) {
    Serial.println("MPU6050 connection failed");
    while (1); // Halt if connection fails
  }
  connectToWiFi(); // Connect to ESP32-S3's AP
}
void loop() {
  int16_t ax, ay, az;
  mpu.getAcceleration(&ax, &ay, &az); // Get accelerometer values

  // Map acceleration values to RGB values
  int colorX = map(ax, -17000, 17000, 0, 255);
  int colorY = map(ay, -17000, 17000, 0, 255);
  int colorZ = map(az, -17000, 17000, 0, 255);

  // Apply dimming factor
  colorX = int(colorX * dimmingFactor);
  colorY = int(colorY * dimmingFactor);
  colorZ = int(colorZ * dimmingFactor);
  // Update NeoPixels
  setColor(colorX, colorY, colorZ);
  // Send RGB values to the ESP32-S3
  sendMotionData(colorX, colorY, colorZ);
  delay(100); // Delay to avoid spamming requests
}
// Function to set all pixels to a specific color
void setColor(uint8_t r, uint8_t g, uint8_t b) {
  for (int i = 0; i < NUM_PIXELS; i++) {
    pixels.setPixelColor(i, pixels.Color(r, g, b));
  }
  pixels.show();
}


Here is a video of the wifi at work :)