Jump to content

IPDL - 12: TCP/UDP Server for Sensor Data

From cognifront

ESP32 TCP Sensor Data Server

Objective

To develop a basic IoT system in which an ESP32 reads sensor data and sends the requested data to a laptop over a TCP connection using a Wi-Fi router.

The system uses a DHT11 and an LDR as example sensors. The same basic TCP server can be extended to integrate any other sensor supported by the ESP32.

Introduction to TCP

TCP (Transmission Control Protocol) is a communication protocol used to exchange data reliably between two devices over a network.

TCP works using a client-server model:

  • The server waits for a connection.
  • The client connects to the server.
  • The client sends a request.
  • The server processes the request and sends a response.

In this project:

  • ESP32 = TCP Server
  • Laptop = TCP Client
  • Wi-Fi Router = Network
  • DHT11 and LDR = Sensors

The ESP32 and laptop are connected to the same Wi-Fi router. The ESP32 gets an IP address from the router and starts a TCP server on a specific port.

Working of TCP/IP Protocol

How Will It Work?

The ESP32 first connects to the existing Wi-Fi router. Once connected, it starts a TCP server.

The laptop is also connected to the same router. A Python program running on the laptop connects to the ESP32 using its IP address and TCP port.

The Python program asks the user which sensor data is required.

If the user selects 1 (DHT11), the laptop sends:

DHT

The ESP32 receives the command, reads the DHT11 and sends the temperature and humidity back to the laptop.

If the user selects 2 (LDR), the laptop sends:

LDR

The ESP32 reads the LDR through its analog input and sends the LDR value back.

Therefore, the basic communication is:

User → Laptop → TCP → ESP32 → Sensor → ESP32 → TCP → Laptop

The sensor is not directly connected to the laptop. The ESP32 acts as the sensor interface and TCP server.

This architecture can be extended by connecting additional sensors to the ESP32 and defining additional commands for them.

ESP32 TCP Server

The ESP32 program performs three main tasks:

  1. Connects to the Wi-Fi router.
  2. Creates a TCP server.
  3. Receives commands and sends the requested sensor data.

ESP32 Server Code

Put this in ESP32 via Arduino IDE.

#include <WiFi.h>
#include "DHT.h"

// Wi-Fi Router
const char* ssid = "YOUR_WIFI_NAME";
const char* password = "YOUR_WIFI_PASSWORD";

// TCP Server
WiFiServer server(5000);

#define DHTPIN 4
#define DHTTYPE DHT11

DHT dht(DHTPIN, DHTTYPE);

#define LDR_PIN 34

void setup() {

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

  // Start DHT11
  dht.begin();

  // LDR is analog input
  pinMode(LDR_PIN, INPUT);

  // Connect ESP32 to Wi-Fi Router
  Serial.println();
  Serial.print("Connecting to Wi-Fi");

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {

    delay(500);
    Serial.print(".");
  }

  Serial.println();
  Serial.println("Wi-Fi connected!");

  // Display ESP32 IP address
  Serial.print("ESP32 IP Address: ");
  Serial.println(WiFi.localIP());

  // Start TCP Server
  server.begin();

  Serial.println("TCP Server started");
  Serial.println("Port: 5000");
  Serial.println("Waiting for TCP client...");
}


void loop() {

  // Check for TCP client
  WiFiClient client = server.available();

  if (client) {

    Serial.println();
    Serial.println("Client connected");

    // Send welcome message
    client.println("ESP32 Sensor Server");
    client.println("Available commands: DHT or LDR");

    while (client.connected()) {

      // Check whether client sent a command
      if (client.available()) {

        String command = client.readStringUntil('\n');

        // Remove spaces and convert to uppercase
        command.trim();
        command.toUpperCase();

        Serial.print("Received command: ");
        Serial.println(command);

        // DHT11 COMMAND
        if (command == "DHT") {

          float temperature = dht.readTemperature();
          float humidity = dht.readHumidity();

          if (isnan(temperature) || isnan(humidity)) {

            client.println("ERROR: DHT11 read failed");

            Serial.println("DHT11 read failed");
          }

          else {

            client.print("Temperature: ");
            client.print(temperature, 1);
            client.print(" C");

            client.print(" | Humidity: ");
            client.print(humidity, 1);
            client.println(" %");

            Serial.println("DHT11 data sent");
          }
        }

        // LDR COMMAND
        else if (command == "LDR") {

          int ldrValue = analogRead(LDR_PIN);

          client.print("LDR Value: ");
          client.println(ldrValue);

          Serial.print("LDR Value: ");
          Serial.println(ldrValue);
        }


        // INVALID COMMAND
        else {

          client.println("Invalid command!");
          client.println("Type DHT for DHT11 data");
          client.println("Type LDR for LDR data");
        }
      }
    }

    client.stop();

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

Server Code Explanation

The ESP32 first connects to the Wi-Fi router using WiFi.begin(). After a successful connection, WiFi.localIP() displays the IP address assigned to the ESP32.

The TCP server is created on port 5000 using:

WiFiServer server(5000);

The server is started using server.begin().

The ESP32 continuously checks for a connected TCP client using server.available(). Once a client is connected, the ESP32 waits for a command.

The command is received using readStringUntil('\n'). The received text is then cleaned using trim() and converted to uppercase using toUpperCase().

If the command is DHT, the ESP32 reads the DHT11 using dht.readTemperature() and dht.readHumidity(). The values are then sent to the TCP client.

If the command is LDR, the ESP32 reads the LDR using analogRead(LDR_PIN) and sends the value to the client.

If an unknown command is received, the ESP32 sends a message showing the valid commands.

Python TCP Client

The Python program runs on the laptop and acts as the TCP client.

Its main tasks are:

  1. Connect to the ESP32 TCP server.
  2. Ask the user which sensor is required.
  3. Send the selected sensor command.
  4. Receive the sensor data.
  5. Display the data on the terminal.

Client Code

import socket

# Replace ESP32 IP Address seen in serial monitor
ESP32_IP = "192.168.1.9"
PORT = 5000

# Connect to ESP32
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

client.connect((ESP32_IP, PORT))

print("Connected to ESP32")

# Receive welcome message
response = client.recv(1024).decode()

print(response)

# Sensor selection
while True:

    print()
    print("Select sensor:")
    print("1. DHT11")
    print("2. LDR")
    print("3. Exit")

    choice = input("Enter your choice: ")

    if choice == "1":
        command = "DHT"
    elif choice == "2":
        command = "LDR"
    elif choice == "3":
        break
    else:
        print("Invalid choice")
        continue

    # Send command to ESP32
    client.send((command + "\n").encode())

    # Receive response
    response = client.recv(1024).decode()

    print()
    print("ESP32:", response.strip())

client.close()
print("Connection closed")

Client Code Explanation

The Python program imports the socket module to provide TCP networking functionality.

The ESP32 IP address and TCP port are specified using:

ESP32_IP = "192.168.1.9"

PORT = 5000

The TCP socket is created using:

socket.socket(socket.AF_INET, socket.SOCK_STREAM)

The laptop then connects to the ESP32 using:

client.connect((ESP32_IP, PORT))

After connecting, the program displays a menu asking the user which sensor data is required.

If the user enters 1, the program sets the command to DHT.

If the user enters 2, the program sets the command to LDR.

The selected command is sent to the ESP32 using:

client.send((command + "\n").encode())

The newline character is used so that the ESP32 can identify the end of the command.

The client then waits for the ESP32 response using:

client.recv(1024).decode()

The received sensor data is displayed on the laptop terminal.

How to Run the Python Client

Before running the Python client, make sure that:

  • The ESP32 is powered on.
  • The ESP32 is connected to the Wi-Fi router.
  • The ESP32 TCP server is running.
  • The laptop is connected to the same Wi-Fi network.
  • The ESP32 IP address is known from the Arduino Serial Monitor.

Open the Python client file and update the ESP32 IP address:

ESP32_IP = "192.168.1.9" PORT = 5000

Replace 192.168.1.9 with the IP address displayed by the ESP32.

Open Command Prompt or Terminal in the folder containing the Python file and run:

python tcp-client-esp-data-receiver.py

If the connection is successful, the terminal displays:

Connected to ESP32

ESP32 Sensor Server Available commands: DHT or LDR

The client then displays the sensor selection menu:

Select sensor: 1. DHT11 2. LDR 3. Exit

Enter 1 to request DHT11 data, 2 to request LDR data, or 3 to close the connection.

Example here, we've saved the tcp client file as "tcp-client-esp-data-receiver.py" on desktop, video below shows how to run this python file.

Example Output

When DHT11 is selected:

Select sensor: 1. DHT11 2. LDR 3. Exit

Enter your choice: 1

ESP32: Temperature: 27.0 C | Humidity: 61.0 %

When LDR is selected:

Select sensor: 1. DHT11 2. LDR 3. Exit

Enter your choice: 2

ESP32: LDR Value: 1847

Extending the Project

The DHT11 and LDR used in this project are only example sensors. The same TCP server-client architecture can be used with any sensor supported by the ESP32.

For each new sensor, a new command can be defined. The TCP communication mechanism remains the same. Only the sensor-reading section and the corresponding command need to be added.

Conclusion

This project demonstrates how an ESP32 can act as a TCP-based sensor server and provide sensor data to a computer over a Wi-Fi network.

The project combines:

ESP32 + Sensors + Wi-Fi + TCP + Python

The command-based design makes the system simple to understand and provides a basic framework that can be extended with additional sensors and commands.