Getting Started with ESP32 and Arduino (Part 4): Random Display of Classical Poetry on OLED Screen

Introduction

I believe that working on some simple and fun projects is a great way to get started.

During the practical process, you will encounter many requirements and issues, and solving these requirements and problems is part of the learning process.

Today, I will share a project that randomly displays classical poetry. If you are interested, feel free to join me in practicing.

Project Effect:

Getting Started with ESP32 and Arduino (Part 4): Random Display of Classical Poetry on OLED Screen

Task Breakdown

Now let’s break down the requirements.

The goal is to send a GET request to a web service to retrieve data and then display the data on the OLED screen, using segmented display for better effect.

Getting Started with ESP32 and Arduino (Part 4): Random Display of Classical Poetry on OLED Screen
image-20250411113018703

First, we need to connect the OLED screen, which was covered in Tutorial (Part 2).

ESP32 + Arduino Getting Started Tutorial (Part 2): Connecting the OLED Screen

How do we output classical poetry or other content?

We need to create a web service and connect it to a large model to output classical poetry or other content and return it.

Even if you have never written a web service, it’s okay; this tutorial uses Python to create a very simple web service that even beginners can implement.

In Arduino, we will write code for the ESP32 to connect to WiFi, send a GET request to retrieve results, and display the results in segments on the OLED screen.

Setting up the development environment is covered in Tutorial (Part 1).

ESP32 + Arduino Getting Started (Part 1): Setting Up the Development Environment

Creating a Web Service

Create a Python virtual environment and install Flask and OpenAI.

Write an app.py as shown below:

from flask import Flask
from openai import OpenAI

app = Flask(__name__)

client = OpenAI(api_key="your api key", 
                base_url="https://api.siliconflow.cn/v1")

@app.route('/OutputClassicalPoetry', methods=['GET'])
def output_classical_poetry():
    response = client.chat.completions.create(
    model="internlm/internlm2_5-20b-chat",
    messages=[
        {'role': 'user', 
        'content': "Output a line of classical poetry."}
    ],
    stream=False,
    temperature=0.7
    )
    response_text = response.choices[0].message.content
    return response_text

if __name__ == '__main__':
    app.run(host='0.0.0.0', debug=True)

After running, check your IP address.

Open cmd and type ipconfig:

Getting Started with ESP32 and Arduino (Part 4): Random Display of Classical Poetry on OLED Screen
image-20250411175926507

Open your browser and enter<span>http://your ip address:5000/OutputClassicalPoetry</span>, and you should see the following effect:

Getting Started with ESP32 and Arduino (Part 4): Random Display of Classical Poetry on OLED Screen
image-20250411180147479

This indicates that the simple web service is up and running.

ESP32 Connects to WiFi and Sends GET Request

The code is as follows:

#include <WiFi.h>
#include <HTTPClient.h>
const char* ssid = "your WIFI name";
const char* password = "your WIFI password";
const char* serverUrl = "the above interface address";
void setup() {
  Serial.begin(115200);

// Connect to WiFi
  WiFi.begin(ssid, password);
  Serial.print("Connecting to WiFi...");

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

  Serial.println("\nWiFi connected");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
}
void loop() {
// Ensure WiFi remains connected
if (WiFi.status() != WL_CONNECTED) {
    Serial.println("WiFi disconnected, attempting to reconnect...");
    WiFi.reconnect();
    delay(2000);  // Wait for reconnection
    return;
  }
  HTTPClient http;

  Serial.println("\nSending GET request...");
  http.begin(serverUrl); 
// Set timeout
  http.setTimeout(10000);

// Send request and get status code
int httpCode = http.GET();

// Handle response
if (httpCode > 0) {
    Serial.printf("HTTP status code: %d\n", httpCode);
    
    if (httpCode == HTTP_CODE_OK) {
      String payload = http.getString();
      Serial.println("Response content:");
      Serial.println(payload);
    } else {
      Serial.println("Non-200 response, full response header:");
      Serial.println(http.getString());  // Output error message
    }
  } else {
    Serial.printf("Request failed, error: %s\n", http.errorToString(httpCode).c_str());
  }

  http.end();  // Must release resources

  delay(5000); // Wait 5 seconds
}

Your computer needs to be connected to the same WiFi.

Upload to ESP32 and run.

Now open the serial monitor to check the effect:

Getting Started with ESP32 and Arduino (Part 4): Random Display of Classical Poetry on OLED Screen
image-20250411181807720

Segmented Display on OLED Screen

The code is as follows:

#include <WiFi.h>
#include <HTTPClient.h>
#include <U8g2lib.h>
U8G2_SSD1306_128X32_UNIVISION_F_SW_I2C u8g2(U8G2_R0, 0, 1, U8X8_PIN_NONE);
// WiFi configuration
const char* ssid = "your WIFI name";
const char* password = "your WIFI password";
const char* serverUrl = "the above interface address";
// Display related variables
uint8_t fontHeight;
uint8_t yPos;
const uint16_t screenWidth = 128;
const unsigned long segmentDisplayTime = 2000;
unsigned long lastSegmentChange = 0;
int currentSegmentStart = 0;
bool needFullCycleReset = false;  // New cycle reset flag
// Text storage
String receivedText = "";
bool newTextReceived = false;
// UTF-8 character measurement
int utf8CharBytes(char c) {
if ((c &amp; 0x80) == 0) return 1;
else if ((c &amp; 0xE0) == 0xC0) return 2;
else if ((c &amp; 0xF0) == 0xE0) return 3;
else if ((c &amp; 0xF8) == 0xF0) return 4;
return 1;
}
// Segmented calculation (add cycle reset detection)
int getNextSegmentStart(const char* text, int startIndex, int maxWidth) {
if (!text || strlen(text) == 0 || startIndex >= strlen(text)) return 0;

int bytePos = startIndex;
int segmentWidth = 0;
int lastValidPos = bytePos;
bool hasAdvanced = false;  // Detect if advanced

while (text[bytePos] != '\0') {
    hasAdvanced = true;
    int charBytes = utf8CharBytes(text[bytePos]);
    char buffer[10] = {0};
    for (int i = 0; i < charBytes; i++) buffer[i] = text[bytePos + i];
    
    int charWidth = u8g2.getUTF8Width(buffer);
    if (segmentWidth + charWidth > maxWidth) break;
    
    segmentWidth += charWidth;
    lastValidPos = bytePos + charBytes;
    bytePos += charBytes;
  }

// When not advanced and not at the initial position, it indicates a need to reset
if (!hasAdvanced &amp;&& startIndex != 0) return 0;
return (text[bytePos] == '\0') ? 0 : lastValidPos;
}
// Display handling
void drawSegment(const char* text, int startIndex) {
if (!text || strlen(text) == 0) {
    u8g2.clearBuffer();
    u8g2.setCursor(0, yPos);
    u8g2.print("No content");
    u8g2.sendBuffer();
    return;
  }

  u8g2.clearBuffer();
char segment[256] = {0};
int bytePos = startIndex;
int segmentWidth = 0;
int segIndex = 0;

while (text[bytePos] != '\0') {
    int charBytes = utf8CharBytes(text[bytePos]);
    char temp[10] = {0};
    for (int i = 0; i < charBytes; i++) temp[i] = text[bytePos + i];
    int charWidth = u8g2.getUTF8Width(temp);
    
    if (segmentWidth + charWidth > screenWidth) break;
    
    for (int i = 0; i < charBytes; i++) segment[segIndex++] = text[bytePos + i];
    segmentWidth += charWidth;
    bytePos += charBytes;
  }
  segment[segIndex] = '\0';

  u8g2.setCursor(0, yPos);
  u8g2.print(segment);
  u8g2.sendBuffer();
}
// Data fetching
void fetchTextFromServer() {
if (WiFi.status() != WL_CONNECTED) return;

  HTTPClient http;
  http.begin(serverUrl);
  Serial.print("[GET] Sending request to: ");
  Serial.println(serverUrl);

int httpCode = http.GET();
if (httpCode == HTTP_CODE_OK) {
    String newText = http.getString();
    Serial.print("[GET] Received result: ");
    Serial.println(newText);
    
    if (newText != receivedText) {
      receivedText = newText;
      newTextReceived = true;
      needFullCycleReset = true;  // Mark for full cycle
    }
  }
  http.end();
}
void setup() {
  Serial.begin(115200);
  WiFi.begin(ssid, password);
  Serial.print("Connecting to WiFi: ");
  Serial.println(ssid);

while (WiFi.status() != WL_CONNECTED) delay(500);
  Serial.println("WiFi connected successfully");

  u8g2.begin();
  u8g2.enableUTF8Print();
  u8g2.setFont(u8g2_font_wqy12_t_gb2312);

  fontHeight = u8g2.getMaxCharHeight();
  yPos = (32 + fontHeight) / 2;
  drawSegment("Waiting for data...", 0);
  fetchTextFromServer();
}
void loop() {
static unsigned long lastFetchTime = 0;
unsigned long currentTime = millis();
// Fetch data every 60 seconds
if (currentTime - lastFetchTime >= 60000) {
    lastFetchTime = currentTime;
    fetchTextFromServer();
  }
// Handle new text
if (newTextReceived) {
    newTextReceived = false;
    currentSegmentStart = 0;
    lastSegmentChange = currentTime;
    drawSegment(receivedText.c_str(), currentSegmentStart);
    needFullCycleReset = false;  // Reset flag
  }

// Segmented switching logic
if (currentTime - lastSegmentChange >= segmentDisplayTime) {
    int prevStart = currentSegmentStart;
    currentSegmentStart = getNextSegmentStart(receivedText.c_str(), currentSegmentStart, screenWidth);
    
    // Reset after full cycle
    if (currentSegmentStart == 0 &amp;&& prevStart != 0) {
      needFullCycleReset = true;
    }
    
    // Execute actual switch
    if (needFullCycleReset) {
      currentSegmentStart = 0;
      needFullCycleReset = false;
      lastSegmentChange = currentTime;  // Reset timer
    } else {
      lastSegmentChange = currentTime;
    }
    
    drawSegment(receivedText.c_str(), currentSegmentStart);
  }

  delay(100);
}

Upload to ESP32 and run to achieve the above effect.

 // Fetch data every 60 seconds
  if (currentTime - lastFetchTime >= 60000) {
    lastFetchTime = currentTime;
    fetchTextFromServer();
  }

You can change the data fetching time here.

Leave a Comment