Ten poradnik jest częścią: Matryca LED RGB ESP32-S3
Fajny projekt do stworzenia dla zabawy i praktycznych zastosowań z wykorzystaniem modułu matrycy RGB ESP32-S3. Linki do innych filmów znajdują się poniżej tego artykułu.
Projekt ESP32-S3 z matrycą LED RGB 3 - Tekst z telefonu komórkowego
Projekt 3 – Sterowanie tekstem matrycy z telefonu (HTTP Text)
W tym projekcie matryca LED RGB ESP32-S3 hostuje małą stronę internetową, dzięki czemu możesz zmieniać przewijany tekst, kolor, kierunek i prędkość bezpośrednio z telefonu lub komputera. Nie potrzebujesz osobnej aplikacji – wystarczy przeglądarka internetowa. To sprawia, że moduł staje się miniaturowym wyświetlaczem tekstowym Wi-Fi, który możesz aktualizować w czasie rzeczywistym.
Wszystkie sześć projektów z tej serii jest wyjaśnionych i zaprezentowanych w jednym filmie na YouTube. Ten sam film jest osadzony na tej stronie, więc możesz dokładnie zobaczyć, jak wygląda interfejs internetowy i jak tekst natychmiast aktualizuje się na matrycy. Pełny kod źródłowy tego projektu jest automatycznie ładowany poniżej artykułu, a moduł ESP32-S3 RGB LED Matrix możesz kupić w sklepach partnerskich wymienionych pod sekcją z kodem.
W tym artykule skupiamy się na tym, jak działa logika sieciowa (domowe Wi-Fi vs punkt dostępowy) oraz które ustawienia możesz zmienić w kodzie, aby dostosować zachowanie.



Przegląd modułu ESP32-S3 RGB LED Matrix
Sprzęt jest taki sam jak we wszystkich innych projektach z tej serii: płytka mikrokontrolera ESP32-S3 z wbudowaną matrycą LED RGB 8×8 oraz czujnikiem ruchu QMI8658C z tyłu. Port USB-C służy do zasilania i programowania, a piny na krawędziach są nadal dostępne dla innych wejść/wyjść.:contentReference[oaicite:0]{index=0}

- ESP32-S3 – mikrokontroler z obsługą Wi-Fi i Bluetooth.
- Matryca RGB 8×8 – 64 adresowalne diody LED RGB do tekstu i grafiki.
- Akcelerometr QMI8658C – używany w projektach z przechylaniem i grach.
- Port USB – zasila płytkę i przesyła szkice z Arduino IDE.
- Wyprowadzone piny – umożliwiają podłączenie dodatkowych czujników lub elementów wykonawczych, jeśli to konieczne.
- Przyciski Boot/Reset – do wgrywania oprogramowania i restartowania.
Dla Projektu 3 najważniejszą funkcją jest Wi-Fi ESP32, które pozwala płytce działać jako miniaturowy serwer internetowy dla strony sterowania tekstem.:contentReference[oaicite:1]{index=1}

Projekty omówione w filmie (znaczniki czasu)
Jeden film dla tej serii obejmuje wszystkie sześć projektów. Dla szybkiego odniesienia:
- 00:00 – Wprowadzenie
- 02:01 – Instalacja płytek ESP32
- 03:32 – Instalacja bibliotek
- 05:32 – Projekt 1: Ruchoma kropka
- 11:11 – Projekt 2: Przewijanie tekstu
- 12:59 – Projekt 3: HTTP Text (ten projekt)
- 16:41 – Projekt 4: Kropka przechylana
- 18:55 – Projekt 5: Strzałka w górę
- 20:02 – Projekt 6: Gra w cel
Zachęcamy do obejrzenia sekcji HTTP Text w filmie podczas pracy z tym artykułem. Film pokazuje, jak strona internetowa jest generowana przez ESP32 i jak zmiana tekstu, koloru i prędkości jest natychmiast odzwierciedlana na matrycy LED.:contentReference[oaicite:2]{index=2}
Instalacja płytek ESP32 w Arduino IDE
Jeśli ukończyłeś już Projekty 1 lub 2, konfiguracja płytek jest zakończona i możesz pominąć tę sekcję. W przeciwnym razie wykonaj następujące kroki w Arduino IDE:
- Otwórz
Plik > Preferencjei dodaj adres URL płytek ESP32 do pola „Dodatkowe menedżery płytek”. - Przejdź do
Narzędzia > Płytka > Menedżer płytek…, wyszukajESP32i zainstaluj oficjalny pakiet ESP32. - Wybierz właściwą płytkę ESP32-S3 RGB Matrix z
Narzędzia > Płytka. - Podłącz moduł przez USB i wybierz właściwy port szeregowy w
Narzędzia > Port.
Bez odpowiedniego wsparcia płytek ESP32 i właściwego portu szkic serwera internetowego nie zostanie wgrany.
Instalacja NeoMatrix i wymaganych bibliotek
Ten projekt używa tych samych bibliotek co poprzedni projekt przewijania tekstu:
Adafruit NeoMatrixAdafruit NeoPixelAdafruit GFX Library
Zainstaluj przez Menedżer bibliotek:
- Otwórz
Szkic > Dołącz bibliotekę > Zarządzaj bibliotekami…. - Wyszukaj
Adafruit NeoMatrixi kliknij Zainstaluj. - Zaakceptuj instalację zależności (
Adafruit GFXiAdafruit NeoPixel).
Po zainstalowaniu powinieneś zobaczyć przykładowe szkice NeoMatrix i NeoPixel w Plik > Przykłady.
Dwa tryby Wi-Fi w Projekcie 3
Najważniejszą koncepcją w tym projekcie jest to, że ESP32 może pracować w dwóch różnych trybach:
- Tryb stacji (STA) – ESP32 łączy się z istniejącą domową siecią Wi-Fi.
- Tryb punktu dostępowego (AP) – ESP32 tworzy własną sieć Wi-Fi, jeśli domowe Wi-Fi nie jest dostępne.
Oba tryby korzystają z tego samego interfejsu internetowego: strony HTML serwowanej przez samego ESP32, na której możesz zmieniać tekst, kolor, kierunek przewijania i prędkość.:contentReference[oaicite:3]{index=3}
Tryb 1 – Połączenie z domowym Wi-Fi (tryb stacji)
W trybie stacji ESP32 dołącza do Twojej domowej lub biurowej sieci Wi-Fi. Jest to preferowany tryb, gdy router jest dostępny, ponieważ:
- Twój telefon i komputer są już podłączone do tej samej sieci Wi-Fi.
- Możesz wpisać adres IP ESP32 w przeglądarce i sterować tekstem z dowolnego urządzenia w tej sieci.
W sekcji ustawień szkicu podajesz swoją nazwę SSID Wi-Fi i hasło:
// Poświadczenia domowego Wi-Fi (tryb stacji) const char* WIFI_SSID = "YourHomeWiFi"; const char* WIFI_PASS = "YourHomePassword";Po uruchomieniu płytki próbuje ona połączyć się z WIFI_SSID. Jeśli połączenie się powiedzie, kod wypisuje przypisany adres IP do Serial Monitor, na przykład:
Connected to WiFi
IP address: 192.168.1.16
Aby sterować tekstem:
- Upewnij się, że telefon lub komputer jest podłączony do tej samej sieci Wi-Fi (na przykład
YourHomeWiFi). - Otwórz przeglądarkę i wpisz wydrukowany adres IP, taki jak
http://192.168.1.16/. - Pojawi się strona sterowania, umożliwiająca wpisanie tekstu, wybór koloru, kierunku oraz regulację prędkości przewijania.
Tryb 2 – Samodzielny punkt dostępowy (tryb AP)
Jeśli ESP32 nie może połączyć się z domowym Wi-Fi (błędne hasło, brak sieci lub używasz modułu poza domem), szkic automatycznie przełącza się w tryb punktu dostępowego. W trybie AP sam ESP32 staje się hotspotem Wi-Fi z własną nazwą sieci i hasłem.
W tym projekcie ustawienia AP są stałe:
// Poświadczenia punktu dostępowego (AP) (tryb zapasowy)
const char* AP_SSID = "ESP32";
const char* AP_PASS = "password";
Gdy tryb stacji zawiedzie, moduł przełącza się w tryb AP i zaczyna nadawać sieć Wi-Fi o nazwie ESP32. Aby sterować matrycą:
- Na telefonie lub komputerze otwórz ustawienia Wi-Fi i połącz się z siecią ESP32.
- Wpisz hasło password (zgodnie z definicją w kodzie).
- Po połączeniu otwórz przeglądarkę i przejdź do
http://192.168.4.1/(domyślny adres IP dla trybu AP ESP32). - Pojawi się ta sama strona sterowania, umożliwiająca zmianę tekstu, koloru, prędkości i kierunku.
To zachowanie zapasowe sprawia, że projekt jest użyteczny wszędzie: w domu, laboratorium lub w środowisku demonstracyjnym, gdzie nie ma routera.
Projekt 3 – Główne ustawienia w kodzie
Pełny szkic HTTP Text jest ładowany poniżej tego artykułu przez stronę internetową. Tutaj dokumentujemy tylko najważniejsze opcje konfiguracji, które prawdopodobnie będziesz edytować.
Ustawienia Wi-Fi i punktu dostępowego
Na górze szkicu znajdziesz sekcję konfiguracji Wi-Fi. Zmieniaj tylko poświadczenia stacji (domowe Wi-Fi); ustawienia AP zwykle pozostają domyślne:
// ---------- USTAWIENIA WI-FI ----------
// Domowe Wi-Fi (tryb stacji)
const char* WIFI_SSID = "YourHomeWiFi"; // wpisz tutaj SSID routera
const char* WIFI_PASS = "YourHomePassword"; // wpisz tutaj hasło routera
// Zapasowy punkt dostępowy (tryb AP)
const char* AP_SSID = "ESP32"; // stała nazwa AP
const char* AP_PASS = "password"; // stałe hasło AP
Zachowanie:
- Jeśli
WIFI_SSIDiWIFI_PASSsą poprawne, a sieć jest dostępna → ESP32 łączy się jako normalne urządzenie Wi-Fi (tryb stacji). - Jeśli połączenie nie powiedzie się po upływie limitu czasu → ESP32 uruchamia własny AP przy użyciu
AP_SSIDiAP_PASS.
Pin matrycy, rozmiar i jasność
Te ustawienia są takie same jak w poprzednich projektach:
// Konfiguracja matrycy
const int MATRIX_PIN = 14; // pin danych matrycy RGB
const int MATRIX_WIDTH = 8;
const int MATRIX_HEIGHT = 8;
// Ogólna jasność wyświetlacza (0–255)
uint8_t matrixBrightness = 40; // dostosuj do swojego otoczenia
Zachowaj MATRIX_PIN na poziomie 14 dla tej płytki. Możesz zwiększyć matrixBrightness, jeśli potrzebujesz więcej światła, ale niższe wartości są wygodniejsze przy oglądaniu z bliska.
Domyślny tekst i ustawienia przewijania
Po uruchomieniu płytka wyświetla początkową wiadomość, dopóki nie otworzysz strony internetowej i nie wpiszesz nowej. Możesz zmienić domyślny tekst w konfiguracji:
// Domyślna wiadomość wyświetlana przy starcie
String currentText = "Robojax"; // nadpisywana później z interfejsu WWW
Reszta zachowania przewijania jest kontrolowana przez zestaw zmiennych aktualizowanych przez interfejs internetowy:
// Opóźnienie przewijania w milisekundach (niższe = szybsze)
int scrollDelayMs = 50;
// Kierunek przewijania: 0=lewo, 1=prawo, 2=góra, 3=dół
int scrollDirection = 0; // domyślnie: przewijanie w lewo
Strona internetowa wysyła nowe wartości na podstawie wyborów suwaka i przycisków. Ze strony Arduino musisz wiedzieć tylko, że:
- Zmniejszenie
scrollDelayMssprawia, że tekst porusza się szybciej. - Zwiększenie
scrollDelayMssprawia, że porusza się wolniej. - Zmiana
scrollDirectionprzełącza między trybami przewijania w lewo, prawo, górę lub dół.
Kolor tekstu (sterowany ze strony internetowej)
Kolor tekstu jest kontrolowany przez trzy wartości 0–255 (czerwony, zielony, niebieski). Są one aktualizowane za każdym razem, gdy wybierzesz nowy kolor na stronie internetowej:
// Aktualny kolor tekstu (R, G, B)
uint8_t textRed = 255;
uint8_t textGreen = 255;
uint8_t textBlue = 255;
Gdy wybierzesz kolor w przeglądarce i klikniesz Zastosuj, ESP32 analizuje wartości RGB i aktualizuje te trzy zmienne; tekst natychmiast zmienia kolor na matrycy. W filmie to zachowanie jest demonstrowane z wieloma zmianami kolorów, w tym przykładami czerwonego, zielonego i niebieskiego.
Podsumowanie
Projekt 3 zamienia twoją matrycę LED RGB ESP32-S3 w w pełni bezprzewodowy wyświetlacz tekstu, którym możesz sterować za pomocą dowolnego urządzenia z przeglądarką internetową. Szkic został zaprojektowany tak, aby był niezawodny:
- Najpierw próbuje połączyć się z domowym Wi-Fi, używając skonfigurowanego SSID i hasła.
- Jeśli to się nie powiedzie, automatycznie staje się punktem dostępowym o nazwie
ESP32i haślepassword. - W obu trybach otwarcie poprawnego adresu IP w przeglądarce wyświetla tę samą stronę sterowania tekstem, kolorem, kierunkiem i prędkością.
Pełny kod HTTP Text jest dostępny poniżej tego artykułu (ładowany automatycznie na stronie internetowej). Aby uzyskać szczegółowe omówienie krok po kroku oraz praktyczną demonstrację aktualizacji tekstu w czasie rzeczywistym, obejrzyj sekcję Projekt 3 w filmie. Jeśli chcesz zbudować projekt samodzielnie, możesz również zakupić moduł ESP32-S3 RGB LED Matrix, korzystając z linków partnerskich umieszczonych pod kodem.
Ten poradnik jest częścią: Matryca LED RGB ESP32-S3
- Projekt matrycy LED RGB ESP32-S3 1 – podstawowa kropka
- Projekt matrycy LED RGB ESP32-S3 2 - Przewijany tekst
- Projekt ESP32-S3 z matrycą LED RGB 4 - Punkt przechyłu
- Projekt matrycy LED RGB ESP32-S3 5 - Strzałka zawsze w górę
- Projekt ESP32-S3 z matrycą LED RGB 6 - gra w cel
- Projekt zegara czasu Wi-Fi + NTP z matrycą LED RGB ESP32-S3 -1 Zegar podstawowy
- Projekt zegara internetowego z matrycą LED RGB ESP32-S3 - 2 zegary wielokolorowe z wyświetlaniem czasu i daty
- Projekt zegara internetowego z matrycą LED RGB ESP32-S3 - 3 kolory nocne z datą
- Projekt zegara internetowego z matrycą LED RGB ESP32-S3 - 5 kolorów tęczy
- Projekt zegara internetowego z matrycą LED RGB ESP32-S3 - 4 losowe kolory
- ESP32-S3 RGB LED Matrix test for RGB, GRB setting
/*
Project 4: HTTP Text Scroll – ESP32-S3 RGB LED Matrix (Waveshare)
- Connects to your home WiFi (station mode, with AP fallback).
- Serves a web page where you can set:
* Text
* Color
* Display ON/OFF
* Scroll direction (Left / Right / Up / Down)
* Scroll delay (speed)
- Supports 8×8 RGB LED matrix using Adafruit_NeoMatrix.
▶️ Video Tutorial:
https://youtu.be/JKLuYrRcLMI
📄 Resources & Code Page:
https://robojax.com/your-resources-page-here
HTTP_Text_Scroll
*/
#include <Arduino.h>
#include <WiFi.h>
#include <WebServer.h>
#include <Adafruit_GFX.h>
#include <Adafruit_NeoMatrix.h>
#include <Adafruit_NeoPixel.h>
// ======================= WIFI SETTINGS =========================
// Home WiFi (change these to your router credentials)
const char* WIFI_SSID = "Biseem";
const char* WIFI_PASS = "wan9&Jang~";
// Fallback Access Point
const char* AP_SSID = "ESP32";
const char* AP_PASS = "password";
// ======================= MATRIX SETTINGS =======================
#define MATRIX_PIN 14
#define MATRIX_WIDTH 8
#define MATRIX_HEIGHT 8
// 0, 1, 2, or 3 – adjust if text orientation is wrong with USB up
#define MATRIX_ROTATION 0
#define BRIGHTNESS 15
Adafruit_NeoMatrix matrix = Adafruit_NeoMatrix(
MATRIX_WIDTH, MATRIX_HEIGHT, MATRIX_PIN,
NEO_MATRIX_TOP + NEO_MATRIX_LEFT +
NEO_MATRIX_ROWS + NEO_MATRIX_PROGRESSIVE,
NEO_RGB + NEO_KHZ800
);
// ======================= SCROLL STATE ==========================
enum ScrollDir {
DIR_LEFT = 0,
DIR_RIGHT,
DIR_UP,
DIR_DOWN
};
String scrollText = "Robojax";
uint16_t textColor = 0xFFFF; // default white
bool displayOn = true;
ScrollDir currentDir = DIR_LEFT;
// 1 step every this many ms (lower = faster)
unsigned long scrollInterval = 80;
unsigned long lastScrollTime = 0;
// Horizontal scroll position
int scrollX = MATRIX_WIDTH;
int scrollY = 0; // top row
// State for vertical per-letter scroll
int vertCharIndex = 0; // which character of the string
int vertY = MATRIX_HEIGHT; // vertical position of that character
// ======================= WEB SERVER ============================
WebServer server(80);
// ======================= HTML PAGE ============================
const char MAIN_page[] PROGMEM = R"rawliteral(
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>ESP32 Text Scroll</title>
<style>
body {
font-family: Arial, sans-serif;
background: #111;
color: #eee;
text-align: center;
margin: 0;
padding: 10px;
}
.container {
max-width: 360px;
width: 100%%;
margin: 0 auto;
background: #222;
padding: 12px;
border-radius: 10px;
box-sizing: border-box;
}
input[type="text"] {
width: 100%%;
padding: 8px;
box-sizing: border-box;
border-radius: 5px;
border: 1px solid #444;
background: #111;
color: #eee;
margin-bottom: 10px;
}
.row {
margin: 10px 0;
}
.label {
display: block;
margin-bottom: 5px;
text-align: left;
}
.toggle {
display: inline-flex;
align-items: center;
gap: 8px;
}
.arrow-grid {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
grid-template-rows: repeat(3, 50px);
gap: 8px;
justify-content: center;
margin-top: 10px;
}
.arrow-btn {
background: #333;
border: 1px solid #555;
color: #eee;
font-size: 18px;
border-radius: 10px;
cursor: pointer;
width: 100%%;
height: 100%%;
}
.arrow-btn.active {
background: #0a84ff;
}
.arrow-btn:disabled {
opacity: 0.5;
cursor: default;
}
button#applyBtn {
margin-top: 15px;
padding: 10px 20px;
border-radius: 8px;
border: none;
background: #0a84ff;
color: #fff;
font-size: 16px;
cursor: pointer;
}
button#applyBtn:active {
transform: scale(0.97);
}
</style>
</head>
<body>
<div class="container">
<h2>Robojax ESP32-S3 Matrix Text Scroll</h2>
<div class="row">
<span class="label">Text to scroll:</span>
<input type="text" id="text" value="Hello" />
</div>
<div class="row">
<span class="label">Color:</span>
<input type="color" id="color" value="#ffffff" />
</div>
<div class="row">
<span class="label">Scroll Delay (fast → slow):</span>
<input
type="range"
id="speed"
min="20"
max="300"
value="80"
oninput="document.getElementById('speedVal').innerText = this.value + ' ms';"
/>
<div id="speedVal" style="text-align:right;font-size:12px;margin-top:4px;">
80 ms
</div>
</div>
<div class="row">
<label class="toggle">
<input type="checkbox" id="power" checked />
<span>Display ON</span>
</label>
</div>
<div class="row">
<span class="label">Scroll Direction:</span>
<div class="arrow-grid">
<div></div>
<button class="arrow-btn" id="btnUp" onclick="setDir('up')">▲</button>
<div></div>
<button class="arrow-btn" id="btnLeft" onclick="setDir('left')">◀</button>
<div></div>
<button class="arrow-btn" id="btnRight" onclick="setDir('right')">▶</button>
<div></div>
<button class="arrow-btn" id="btnDown" onclick="setDir('down')">▼</button>
<div></div>
</div>
</div>
<button id="applyBtn" onclick="sendUpdate()">Apply</button>
<p id="status"></p>
</div>
<script>
let currentDir = 'left';
function setDir(dir) {
currentDir = dir;
document.querySelectorAll('.arrow-btn').forEach(b => b.classList.remove('active'));
if (dir === 'up') document.getElementById('btnUp').classList.add('active');
if (dir === 'down') document.getElementById('btnDown').classList.add('active');
if (dir === 'left') document.getElementById('btnLeft').classList.add('active');
if (dir === 'right') document.getElementById('btnRight').classList.add('active');
sendUpdate();
}
function sendUpdate() {
const text = document.getElementById('text').value;
const color = document.getElementById('color').value;
const power = document.getElementById('power').checked ? '1' : '0';
const speed = document.getElementById('speed').value;
const url = `/update?text=${encodeURIComponent(text)}&color=${encodeURIComponent(color)}&power=${power}&dir=${currentDir}&speed=${speed}`;
fetch(url)
.then(r => r.text())
.then(t => {
document.getElementById('status').innerText = t;
})
.catch(err => {
document.getElementById('status').innerText = 'Error sending update';
});
}
// Set default active
setDir('left');
</script>
</body>
</html>
)rawliteral";
// ======================= HELPERS ===============================
bool isHexChar(char c) {
return (c >= '0' && c <= '9') ||
(c >= 'a' && c <= 'f') ||
(c >= 'A' && c <= 'F');
}
String urlDecode(const String &src) {
String result;
result.reserve(src.length());
for (size_t i = 0; i < src.length(); i++) {
char c = src[i];
if (c == '+') {
result += ' ';
} else if (c == '%' && i + 2 < src.length()) {
char h1 = src[i + 1];
char h2 = src[i + 2];
if (isHexChar(h1) && isHexChar(h2)) {
char hex[3] = {h1, h2, 0};
int val = (int)strtol(hex, nullptr, 16);
result += (char)val;
i += 2;
} else {
result += c;
}
} else {
result += c;
}
}
return result;
}
uint16_t colorFromHex(const String &hex) {
// Expect "#RRGGBB" or "RRGGBB"
String c = hex;
if (c.startsWith("#")) c.remove(0, 1);
if (c.length() != 6) {
// default white
return matrix.Color(255, 255, 255);
}
long value = strtol(c.c_str(), NULL, 16);
uint8_t r = (value >> 16) & 0xFF;
uint8_t g = (value >> 8) & 0xFF;
uint8_t b = (value) & 0xFF;
return matrix.Color(r, g, b);
}
void resetScrollPosition() {
int textWidth = scrollText.length() * 6; // default font ~6 px per char
int textHeight = 8; // 5x7 font fits in 8
switch (currentDir) {
case DIR_LEFT:
// Start from just outside the right edge
scrollX = MATRIX_WIDTH;
scrollY = 0;
break;
case DIR_RIGHT:
// Start from just outside the left edge
scrollX = -textWidth;
scrollY = 0;
break;
case DIR_UP:
// Per-letter vertical scroll, starting with first character below matrix
vertCharIndex = 0;
vertY = MATRIX_HEIGHT; // 8 → enters from bottom
break;
case DIR_DOWN:
// Per-letter vertical scroll, starting with first character above matrix
vertCharIndex = 0;
vertY = -textHeight; // -8 → enters from top
break;
}
}
// ======================= HTTP HANDLERS =========================
void handleRoot() {
server.send_P(200, "text/html", MAIN_page);
}
void handleUpdate() {
if (server.hasArg("text")) {
String txt = urlDecode(server.arg("text"));
if (txt.length() == 0) {
scrollText = " ";
} else {
scrollText = txt;
}
}
if (server.hasArg("color")) {
String hex = server.arg("color");
textColor = colorFromHex(hex);
}
if (server.hasArg("power")) {
String p = server.arg("power");
displayOn = (p == "1");
}
if (server.hasArg("dir")) {
String d = server.arg("dir");
if (d == "left") currentDir = DIR_LEFT;
else if (d == "right") currentDir = DIR_RIGHT;
else if (d == "up") currentDir = DIR_UP;
else if (d == "down") currentDir = DIR_DOWN;
}
if (server.hasArg("speed")) {
String s = server.arg("speed");
int val = s.toInt();
// simple safety clamp
if (val < 10) val = 10; // very fast
if (val > 1000) val = 1000; // 1 second max
scrollInterval = (unsigned long)val;
// Serial.print("Scroll interval set to ");
// Serial.print(scrollInterval);
// Serial.println(" ms");
}
resetScrollPosition();
server.send(200, "text/plain", "Updated");
}
// ======================= SCROLL LOGIC ==========================
void drawScroll() {
if (!displayOn) {
matrix.fillScreen(0);
matrix.show();
return;
}
int textWidth = scrollText.length() * 6;
int textHeight = 8;
matrix.fillScreen(0);
matrix.setTextSize(1);
matrix.setTextWrap(false);
matrix.setTextColor(textColor);
// -------- HORIZONTAL SCROLL (LEFT / RIGHT) --------
if (currentDir == DIR_LEFT || currentDir == DIR_RIGHT) {
matrix.setCursor(scrollX, 0);
matrix.print(scrollText);
matrix.show();
if (currentDir == DIR_LEFT) {
scrollX--;
if (scrollX < -textWidth) {
scrollX = MATRIX_WIDTH;
}
} else { // DIR_RIGHT
scrollX++;
if (scrollX > MATRIX_WIDTH) {
scrollX = -textWidth;
}
}
return;
}
// -------- VERTICAL SCROLL (UP / DOWN) – PER LETTER --------
if (scrollText.length() == 0) {
matrix.show();
return;
}
// Current character
char c = scrollText[vertCharIndex];
int charWidth = 6;
int baseX = (MATRIX_WIDTH - charWidth) / 2; // center horizontally
matrix.setCursor(baseX, vertY);
matrix.print(c);
matrix.show();
if (currentDir == DIR_UP) {
// Move character upwards
vertY--;
if (vertY < -textHeight) {
// This character is fully passed, go to next
vertY = MATRIX_HEIGHT;
vertCharIndex++;
if (vertCharIndex >= scrollText.length()) {
vertCharIndex = 0; // loop back to first character
}
}
} else if (currentDir == DIR_DOWN) {
// Move character downwards
vertY++;
if (vertY > MATRIX_HEIGHT) {
// This character is fully passed, go to next
vertY = -textHeight;
vertCharIndex++;
if (vertCharIndex >= scrollText.length()) {
vertCharIndex = 0; // loop back
}
}
}
}
// ======================= WIFI INIT =============================
void startAPFallback() {
Serial.println("Starting AP fallback...");
WiFi.mode(WIFI_AP);
bool apOk = WiFi.softAP(AP_SSID, AP_PASS);
if (apOk) {
Serial.print("AP started. SSID: ");
Serial.print(AP_SSID);
Serial.print(" IP: ");
Serial.println(WiFi.softAPIP());
} else {
Serial.println("Failed to start AP.");
}
}
void connectWiFi() {
WiFi.mode(WIFI_STA);
WiFi.begin(WIFI_SSID, WIFI_PASS);
Serial.print("Connecting to WiFi ");
Serial.print(WIFI_SSID);
unsigned long startAttempt = millis();
const unsigned long timeout = 10000; // 10s
while (WiFi.status() != WL_CONNECTED && (millis() - startAttempt) < timeout) {
Serial.print(".");
delay(500);
}
Serial.println();
if (WiFi.status() == WL_CONNECTED) {
Serial.print("Connected. IP address: ");
Serial.println(WiFi.localIP());
} else {
Serial.println("WiFi connect failed, starting AP fallback.");
startAPFallback();
}
}
// ======================= SETUP & LOOP ==========================
void setup() {
Serial.begin(115200);
delay(500);
// Matrix init
matrix.begin();
matrix.setRotation(MATRIX_ROTATION);
matrix.setBrightness(BRIGHTNESS);
matrix.fillScreen(0);
matrix.show();
// WiFi
connectWiFi();
// Web server routes
server.on("/", handleRoot);
server.on("/update", handleUpdate);
server.onNotFound([]() {
server.send(404, "text/plain", "Not found");
});
server.begin();
Serial.println("HTTP server started.");
resetScrollPosition();
}
void loop() {
server.handleClient();
unsigned long now = millis();
if (now - lastScrollTime >= scrollInterval) {
lastScrollTime = now;
drawScroll();
}
}
Rzeczy, których możesz potrzebować
-
Amazon
-
Allegro
-
AliExpressPurchase ESP32-S3 RGB Matrix from AliExpresss.click.aliexpress.com
-
AliExpressPurchase ESP32-S3 RGB Matrix from AliExpress (2)s.click.aliexpress.com
Zasoby i odniesienia
-
Wewnętrzny🎨 Color picker Toolrobojax.com
Pliki📁
Plik Fritzing
-
esp32-S3-supermini-tht fritzing part
esp32-S3-supermini-tht.fzpz0.02 MB