Skip to content

About

ESP32 + 4x8x8 MAX7219 dot-matrix display: NTP clock and scrolling text, controlled over a plain HTTP GET API or an included PHP web page. Night-mode brightness below the hardware minimum, settings persisted to flash.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

3 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ESP32 Dot-Matrix Display

A small, self-contained controller for a 4 × 8×8 LED matrix (MAX7219 / FC-16) driven by an ESP32. It shows either an NTP-synced clock or a scrolling text message, and everything about it — mode, brightness, scroll speed, orientation — is controlled over a plain HTTP GET API or from an included PHP web page.

No app, no cloud, no MQTT broker: the ESP32 runs a tiny web server on a fixed IP in your LAN, and every setting survives a power cut because it is stored in the ESP32's flash.

Four chained 8x8 matrices scrolling a message, driven by a Wemos D1 Mini ESP32

/api?mode=text&text=Hello%20World&speed=30&bright=12

Features

  • Clock mode, time via NTP, in two styles:
    • HH:mm:ss in a custom 3-pixel-wide digit font (fits 8 characters onto 32 px)
    • HH:mm in the regular font — much easier to read from a distance
  • Text mode: free scrolling message with adjustable speed (5–200 ms per frame), UTF-8 aware — umlauts, ß, accents, ° and € render correctly
  • 26 brightness levels, including 10 extra-dim "night" levels below the MAX7219's darkest hardware step, done with software PWM — genuinely usable as a bedside clock
  • 180° rotation, with the scroll direction rotated along with it
  • Persistent settings: mode, clock style, brightness, flip, speed and the message text are restored after a reboot
  • Everything is a GET request — trivial to drive from a shell script, a home automation system, or a browser bookmark
  • Optional PHP front-end that proxies the API server-side (no CORS issues), with a German/English language switch

Hardware

Matrix module ESP32 pin
VCC 5V
GND GND
DIN GPIO23
CS GPIO5
CLK GPIO18
  • Developed on a Wemos D1 Mini ESP32 (ESP32-WROOM-32); any ESP32 board works, adjust the pins in the sketch if needed.
  • Connect to the IN side of the first module (the arrows point away from the cable), then chain the modules IN → OUT → IN.
  • Power the matrix from 5V, not 3V3 — the MAX7219 needs at least ~4 V. The logic inputs are happy with the ESP32's 3.3 V levels.

Getting started

1. Libraries

Install via the Arduino IDE library manager:

  • MD_Parola (MajicDesigns)
  • MD_MAX72XX (MajicDesigns) — pulled in as a dependency

Plus the ESP32 board package by Espressif. Preferences is part of that package, nothing extra to install.

The header is spelled MD_MAX72xx.h with a lower-case xx. Getting this wrong is the single most common build error with these libraries.

2. Wi-Fi credentials

cp matrix_control/secrets.h.example matrix_control/secrets.h

Then edit secrets.h:

const char* WIFI_SSID     = "YOUR_WIFI_SSID";
const char* WIFI_PASSWORD = "YOUR_WIFI_PASSWORD";

secrets.h is in .gitignore, so your credentials stay on your machine.

3. Network settings

The sketch uses a static IP so the web page always finds the display. Adjust the CONFIGURATION block near the top of matrix_control.ino to your network:

IPAddress local_IP(192, 168, 178, 18);   // free address for the ESP32
IPAddress gateway (192, 168, 178, 1);    // your router
IPAddress subnet  (255, 255, 255, 0);
IPAddress dns     (192, 168, 178, 1);

While you are there, TZ_INFO holds the POSIX timezone string — the default is Central European Time with automatic DST (CET-1CEST,M3.5.0,M10.5.0/3).

4. Flash

Select your ESP32 board and port, hit upload. The display shows WiFi... while connecting; the assigned IP is printed on the serial monitor at 115200 baud and also served at http://<esp-ip>/.


HTTP API

Base URL: http://<esp-ip>

Parameter Values Meaning
mode clock | text display mode
text up to 150 characters, UTF-8 scroll message (implies mode=text)
clockstyle full | short HH:mm:ss compact font, or HH:mm regular font
bright 0–25 0–9 = night levels, 10 = hardware minimum, 25 = maximum
speed 5–200 milliseconds per frame — smaller is faster
flip 0 | 1 180° rotation

All parameters can be combined freely, and every response is the full current state as JSON:

$ curl "http://192.168.178.18/api?mode=text&text=Hello&speed=30"
{"mode":"text","brightness":15,"brightmax":25,"flip":0,"speed":30,
 "speedmin":5,"speedmax":200,"clockstyle":"full","text":"Hello",
 "ip":"192.168.178.18"}

GET /status returns the same JSON without changing anything, and GET / serves a short overview page. Responses carry Access-Control-Allow-Origin: *, so a browser-side page can talk to the ESP32 directly if you prefer that over the PHP proxy.

Every change is written back to flash automatically (see Persistence below).


PHP web interface

The web interface: mode buttons, clock format, message field, speed and brightness sliders

web/matrix.php is a single self-contained file — drop it into any webroot with PHP available and set the IP at the top:

$ESP_IP = "192.168.178.18";

It gives you mode buttons, the clock-format switch, a text field, and sliders for brightness and scroll speed. Requests are proxied server-side, so the browser never talks to the ESP32 directly — no CORS setup, and the page also works when only the web server can reach the display.

The interface is bilingual (German / English). The DE / EN buttons in the header switch instantly without a page reload, the choice is remembered in localStorage, and first-time visitors get whatever their browser prefers. All strings live in a single I18N object at the top of the script block — adding a third language means adding one more block of key/value pairs.

Requires allow_url_fopen = On (the PHP default); otherwise switch the proxy in matrix.php over to cURL.


How it works

The compact clock font

HH:mm:ss is 8 characters. In the default font (5 px per character plus spacing, ≈ 40 px) that does not fit onto four modules (32 px). The sketch therefore embeds clockFont[], a hand-built font containing only 0–9 and : at 3 px per digit — about 27 px in total. Text mode switches back to the stock font with setFont(nullptr).

If you prefer legibility over seconds, clockstyle=short shows HH:mm in the regular font.

Umlauts and special characters

Browsers send text as UTF-8, where every non-ASCII character occupies two or more bytes — ä is 0xC3 0xA4. The MD_MAX72xx font, on the other hand, is a plain single-byte table:

Range Contents
0x20–0x7E ASCII
0x80–0x99 extra symbols: €, Greek letters, ≥, ≤, √, ™
0xA0–0xFF ISO-8859-1 — all umlauts, ß, °, accented letters

Handing the raw UTF-8 bytes to MD_Parola therefore drew two wrong glyphs per umlaut. utf8ToFont() decodes the byte stream into code points and emits the matching font byte instead. Characters with no glyph but an obvious ASCII equivalent are transliterated (– → -, „ → ", … → ...); anything genuinely unavailable, an emoji for instance, becomes ?.

The message is kept in two buffers: textStr[] holds the original UTF-8 (that is what /status returns and what goes into flash, so the web page keeps showing the text as typed), while dispStr[] holds the converted bytes MD_Parola scrolls.

Rotation and scroll direction

180° rotation is done with the zone effects PA_FLIP_UD + PA_FLIP_LR. The catch: PA_FLIP_LR mirrors the motion as well, so with the display flipped a PA_SCROLL_LEFT message visibly scrolls to the right. setModeText() therefore swaps the direction to PA_SCROLL_RIGHT whenever the flip is active, so text always reads right-to-left.

Because MD_Parola only picks up the direction at displayText() time, any change to flip, speed or mode re-issues the call through applyMode().

Brightness below hardware minimum

The MAX7219 offers 16 intensity steps, and even step 0 is bright enough to light up a dark bedroom. To get below it, the sketch rapidly toggles the chip's shutdown register at 100 Hz (updateDimming()), giving 10 additional night levels at 2–50 % duty cycle:

bright Effect
0–9 intensity 0 + software PWM at 2/3/4/5/7/10/15/22/33/50 %
10 hardware minimum, permanently on
11–25 hardware intensity 1–15

The night levels live in NIGHT_DUTY[] and can be re-tuned or extended freely — the scale, NIGHT_COUNT and the brightmax field in the JSON all follow via sizeof. Below roughly 3 % duty the on-window starts colliding with the MAX7219's internal multiplexing and a level can look almost dark; that is the physical floor of this approach. Night levels can shimmer slightly under fast scrolling, but they are ideal for the static clock.

Persistence

Mode, clock style, brightness, flip, scroll speed and the message text are kept in the ESP32's NVS flash (Preferences, namespace matrix) and restored by loadSettings() at boot.

Writes are deferred: a change only sets a flag, and saveIfDue() commits everything in one go three seconds after the last change. Dragging a slider across its full range therefore costs a single flash write instead of dozens, which matters for flash wear. On first boot, before the namespace exists, the defaults from the sketch apply.

To reset everything: Arduino IDE → Tools → Erase All Flash Before Sketch Upload: Enabled, upload once, then set it back to Disabled.


Troubleshooting

Symptom Likely cause
MD_MAX72XX.h: No such file or directory header must be MD_MAX72xx.h, lower-case xx
secrets.h: No such file or directory copy secrets.h.example to secrets.h
Only the first module lights up, steady wiring — check the IN side, CS and a common GND
Text mirrored or scrambled try a different HARDWARE_TYPE: FC16_HW → GENERIC_HW → PAROLA_HW → ICSTATION_HW
Web page says the ESP is unreachable check $ESP_IP, whether the ESP32 joined the Wi-Fi, and allow_url_fopen
Display dark or flickering powered from 3V3 instead of 5V, or an undersized supply
Umlauts show as two wrong glyphs an older MD_MAX72xx (< 3.x) whose default font stops at ASCII 127 — update the library

Repository layout

matrix_control/
  matrix_control.ino    ESP32 firmware
  secrets.h.example     template for your Wi-Fi credentials
web/
  matrix.php            optional PHP web interface (DE/EN)
docs/                   photos and screenshots used in this README

License

MIT — see LICENSE.

Built on the excellent MD_Parola and MD_MAX72XX libraries by MajicDesigns.

About

ESP32 + 4x8x8 MAX7219 dot-matrix display: NTP clock and scrolling text, controlled over a plain HTTP GET API or an included PHP web page. Night-mode brightness below the hardware minimum, settings persisted to flash.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages