Networking and Communications

Networking With ESP32C

Group Assignment Page

This week’s group assignment explores connectivity between two ESP32 boards, first using ESPNow, and then using UDP protocol over wifi.

Setting Up the Board in Arduino IDE

Before we set up the XIAO ESP32C, we have to add a link to it’s JSON file under “File >Preferences > Additional Boards Manager URLs”. The link can be found here in the Software Setup section..

Then, we check boards manager for “esp32” by “Espressif Systems”. Install it. From “Tools > Boards > esp32 > XIAO ESP32C3”, select the board. Now our board should be ready to go.

esp32 board manager

Connecting to WiFi

XIAO ESP32C comes with built in WiFi capabilites and an antenna. To make use of these, we first have to install the WiFi library in Arduino IDE. Go to Library Manager and search for WiFi, while filtering “Type: Arduino”. Install the latest version of “WiFi by Arduino”.

wifi library

After this, I ran the example code below. With this code, we make the XIAO connect to a WiFi, and print the IP address in the serial monitor. We have to specifiy the ssid and password of the WiFi in the code.

wifi connected
 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
#include <WiFi.h>

const char* ssid = "Fablab";
const char* password = "Fabricationlab1";

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

  //connect to wifi network

  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED){
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}

void loop() {
  // put your main code here, to run repeatedly:
}

I got the following error the first time: Multiple libraries were found for "WiFi.h"

After I looked it up, I found out that this was an expected error and does not affect the functionality of the WiFi.

Creating an Access Point

We can also use the XIAO as an access point. I tried the sample code below, and set the ssid and password of our AP under WiFi.softAP("ssid", "password").

Then, I used my phone to connect to the access point. Since we print the number of host connections to the serial monitor, I was able to see that I had indeed connected to the AP.

 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
#include "WiFi.h"
void setup()
{
  Serial.begin(115200);
  WiFi.softAP("bibet", "bibetbibet");
}

void loop()
{
  Serial.print("Host Name:");
  Serial.println(WiFi.softAPgetHostname());
  Serial.print("Host IP:");
  Serial.println(WiFi.softAPIP());
  Serial.print("Host SSID:");
  Serial.println(WiFi.SSID());
  Serial.print("Host Broadcast IP:");
  Serial.println(WiFi.softAPBroadcastIP());
  Serial.print("Host mac Address:");
  Serial.println(WiFi.softAPmacAddress());
  Serial.print("Number of Host Connections:");
  Serial.println(WiFi.softAPgetStationNum());
  Serial.print("Host Network ID:");
  Serial.println(WiFi.softAPNetworkID());
  Serial.print("Host Status:");
  Serial.println(WiFi.status());
  delay(1000);
}

Sending and Receiving Information with Wifi

Understanding how this works was the most challenging part for me. Basically, we are able to send information to the XIAO via WiFi, if we are connected to the same WiFi point. I followed the tutorial and the code below is the most basic example of how we can do this. Here is a step-by-step explanation of the code as far as I understand it:

  1. Include the WiFi library and connect the XIAO to a WiFi of our choice.
  2. WiFiServer server(80) specifies from which port the webserver will listen to our commands. This is 80 because webservers usually listen on port 80.
  1. Connect the XIAO to the WiFi network.
  2. With server.begin(), we start the webserver.
  3. Check if anyone is connected to the webserver (client).
  4. Read and print the input that is given in the terminal by the client.
  5. Respond with a message by printing to the terminal & serial monitor.
  6. Very short delay to allow the server to receive the data.
  7. Repeat the loop.

To communicate with the terminal, I just opened GitBASH anywhere and wrote:

curl [ip address]

To which the XIAO responds:

Thank you for connecting with us

connection message
 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
#include <WiFi.h>

const char* ssid = "Fablab";
const char* password = "Fabricationlab1";

WiFiServer server(80);  //webservers usually listen on port 80

int connectionCounter = 1;
int btn = D6;

void setup() {
  pinMode(btn, INPUT_PULLUP);

  Serial.begin(115200);
  delay(10);

  // We start by connecting to a WiFi network

  Serial.println();
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());

  server.begin();  //start website
}

void loop() {

  // do we have someone connecting?
  WiFiClient client = server.available();

  if (client) {
    Serial.println("Client connected.");

    //Reading in the input
    if (client.connected()){ 
      String incoming = ""; //creating an empty string
      while (client.available()){
        char c = client.read();
        incoming += c;
      }

      //Printing the input
      Serial.println(incoming);

      //Responding with a message
      client.println("HTTP/1.1 200 OK");
      client.println("Content-Type: text/html");
      client.println("Connection: close");
      client.println();
      client.println("Thank you for connecting with us");

      //give the browser time to receive the data
      delay(1);

      client.stop();
      Serial.println("Client disconnected");
    }
  }
}

Sending String Commands

We can also give commands as a “string”, which means a sequence of characters. In other words, a word. To do that, we make use of the code below.

I modified the tutorial code made by Kris, to accomodate for the specific board that I had. With typing specific commands, I can turn on and off individual LEDs, read a button state and a potentiometer state.

Controlling a Board With Terminal Messages

  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
#include <WiFi.h>

const char* ssid     = "Fablab";
const char* password = "Fabricationlab1";   

WiFiServer server(80); // Webservers usually listen on port 80

int connectionCounter = 1;
int btn = D4;
int led0 = D0;
int led1 = D1;
int pot = D3;

void setup()
{
  pinMode(btn, INPUT_PULLUP);
  pinMode(pot, INPUT);
  pinMode(led0, OUTPUT);
  pinMode(led1, OUTPUT);

  Serial.begin(115200);
  delay(10);

  // We start by connecting to a WiFi network

  Serial.println();
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());

  server.begin(); // Start webserver
} 

void loop()
{
  // Do we have someone connecting?
  WiFiClient client = server.available();

  if (client) {
    Serial.println();
    Serial.println("Client connected.");

    if (client.connected()) {

      String incoming = "";
      while (client.available()) {
        char c = client.read();
        incoming += c;
      }

      // Extract just the first line
      
      int charCounter = 0;
      String firstLine = "";
      while (incoming.charAt(charCounter) != '\n') {
        firstLine += incoming.charAt(charCounter);
        charCounter++;
      }

      Serial.println(firstLine);

      // Extract query
      charCounter = 0;
      bool firstSpace = false;
      String query = "";
      while (charCounter < firstLine.length()) {
        char c = firstLine.charAt(charCounter);
        
        if (c == ' ') {
          if (firstSpace) {
            break;
          } else {
            firstSpace = true;
          }
        }
        
        if (firstSpace == true && c != ' ') {
          query += c;
        }

        charCounter++;
      }

      Serial.println(query);

      String response = "";

      if (query == "/turnLed0On") {
        response = "Turning LED 0 on.";
        digitalWrite(led0, HIGH);
      } else if (query == "/turnLed1On") {
        response = "Turning LED 1 on.";
        digitalWrite(led1, HIGH);
      } else if (query == "/turnLed0Off") {
        response = "Turning LED 0 off";
        digitalWrite(led0, LOW);
      } else if (query == "/turnLed1Off") {
        response = "Turning LED 1 off";
        digitalWrite(led1, LOW);
      }else if (query == "/getButtonState") {
        response = "Button state is ";
        int buttonState = digitalRead(btn);
        response += String(buttonState);
      } else if (query == "/getPotState"){
        response = "Potentiometer value is ";
        int potState = analogRead(pot);
        response += String(potState);
      } else {
        response = "Unknown request: ";
        response += query;
      }

      client.println("HTTP/1.1 200 OK");
      client.println("Content-Type: text/html");
      client.println("Connection: close");
      client.println();
      client.println(response);

      // give the web browser time to receive the data
      delay(1);

      client.stop();
      Serial.println("Client disconnected");
    }
  }
}