Skip to content

Latest commit

 

History

13 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 

Repository files navigation

GIF to LED Matrix

Python syntax License: GPL v3

Turn animated GIFs into playable animations for a NeoPixel-compatible LED matrix. The project combines a browser-based editor with MicroPython firmware that serves the editor, stores animation data on a microSD card, and plays it back on a microcontroller.

This is a hardware project. It has been developed around MicroPython, an ESP8266-style SPI configuration, a microSD card, and NeoPixel/WS2812 LEDs.

Demo

Watch the project in action: GIF to LED Matrix demo on YouTube.

Related project

This project was originally developed for the ESP32 LED Motor Driver board on Hackaday. Its MicroPython-based design can be adapted to other compatible boards with the appropriate pin, storage, and NeoPixel configuration.

What it does

  • Loads an animated GIF from your computer or a URL.
  • Crops and scales frames to the dimensions of an LED display.
  • Lets you touch up individual pixels in a browser-based editor.
  • Transfers animation data to the device over WebSocket.
  • Stores animations on the SD card and plays autoplay after boot.

Repository layout

firmware/
├── boot.py                 # Wi-Fi setup and SD-card mount
├── led_server.py            # Web server, upload protocol, and playback
├── web/                     # Browser editor served by the device
├── src/                    # Source for modules deployed as .mpy files
└── *.mpy                   # Precompiled MicroPython dependencies

Hardware and software

  • A board running MicroPython with NeoPixel support. The original target was the ESP32 LED Motor Driver board; the included SD wiring uses ESP8266-style pin assignments and should be adjusted for other hardware.
  • A NeoPixel/WS2812-compatible display. Configure its data pin and dimensions in the web editor.
  • A microSD card formatted for MicroPython/FAT storage.
  • A microSD SPI breakout wired as defined in boot.py:
    • SCK: GPIO 14
    • MOSI: GPIO 13
    • MISO: GPIO 12
    • CS: GPIO 15
  • A modern browser on the same Wi-Fi network as the device.

The browser editor is self-contained: its jQuery and jQuery UI dependencies are included in firmware/web/vendor, so the device does not need Internet access to serve the editor.

Getting started

  1. Flash a compatible MicroPython build to the board.
  2. Copy the contents of firmware to the device filesystem. Keep the web directory intact and deploy the included .mpy files alongside boot.py and led_server.py.
  3. Edit ssid and password in firmware/boot.py before uploading it. Do not commit real credentials.
  4. Insert the SD card and reset the board. Its serial output prints the assigned IP address.
  5. Visit http://<device-ip>/ from a computer on the same network.
  6. Load a GIF, define the crop and display properties, add the NeoPixel device, edit frames if needed, then upload.

Uploaded animations are stored on the SD card under /sd/<name>/ as cfg.dat and dat.dat. The current editor uploads to the autoplay slot, which the firmware attempts to play at startup.

Animation file format and playback

Each animation lives in /sd/<name>/ and consists of a text configuration file and a raw binary data file. The upload protocol writes the configuration first, then appends the binary data in 512-byte WebSocket chunks.

cfg.dat

cfg.dat is a UTF-8, newline-delimited file. The WebSocket upload header contains S and the animation name first; those two values are not written to cfg.dat.

Line Field Meaning
1 frame_count Number of frames in the animation. Retained as metadata; the current player loops when it reaches the end of dat.dat.
2 width Animation width metadata. The current browser uploader writes 0; playback does not use this value to size a device.
3 height Animation height metadata. The current browser uploader writes 0; playback does not use this value to size a device.
4 delay Delay between frames in centiseconds (6 = 60 ms).
5 device_count Number of output devices.
6 onward device records One three-line record per device: type, pin, then data_length in bytes.

The current firmware implements device type 2, a NeoPixel-compatible output. Its data_length must be pixel_count × 3. Other type values are not supported by the current player.

For example, a three-frame animation for one 8×8 NeoPixel matrix on pin 2, at 60 ms per frame, has this configuration:

3
0
0
6
1
2
2
192

dat.dat

dat.dat is raw binary. Its payload is ordered by frame, then by device record order within that frame:

frame 0: device 0 bytes, device 1 bytes, ...
frame 1: device 0 bytes, device 1 bytes, ...
...

For a type-2 NeoPixel device, each pixel occupies three bytes in GRB order. The browser editor converts its canvas pixels from RGBA to GRB and removes alpha. For a well-formed finite animation, the expected file size is:

frame_count × sum(all device data_length values)

In the 8×8 example above, each frame is 192 bytes and a three-frame dat.dat is 576 bytes.

Player behavior

At boot, the firmware attempts to play /sd/autoplay/cfg.dat and /sd/autoplay/dat.dat. During playback, Player.render() reads one data_length payload for each configured device, assigns it to the device, then waits delay / 100 seconds. When a read reaches the end of dat.dat, the player seeks back to byte zero and continues, so the animation loops indefinitely.

When an editor connects, it sends R; the firmware stops active playback and replies READY. The editor then sends the configuration header and waits for OK before streaming binary chunks. Sending E ends the transfer, the firmware replies DONE, and playback starts after the WebSocket closes.

Development checks

The Python files are checked for parse errors on every pull request and push. You can run the same check locally:

python -m compileall -q firmware

This verifies Python syntax only; hardware behavior must be tested on a device with the intended LED matrix and SD card.

Rebuilding MicroPython modules

The deployable .mpy modules are generated from the snake_case sources in firmware/src. They target MicroPython v1.11 and must be rebuilt with the matching cross-compiler; .mpy bytecode is version-specific.

python -m pip install "mpy-cross==1.11"
python -m mpy_cross -o firmware/micro_web_server.mpy firmware/src/micro_web_server.py
python -m mpy_cross -o firmware/micro_web_socket.mpy firmware/src/micro_web_socket.py
python -m mpy_cross -o firmware/micro_web_template.mpy firmware/src/micro_web_template.py
python -m mpy_cross -o firmware/sd_card.mpy firmware/src/sd_card.py

The led_server.py application is intentionally deployed as source because it is the user-facing entry point imported by boot.py.

Notes and limitations

  • GIFs loaded from a URL must allow cross-origin browser requests; uploading a local GIF avoids that restriction.
  • Large GIFs can exceed the available memory in the browser or on the board. Start with short, low-resolution animations.
  • The web editor currently exposes NeoPixel output. The firmware's upload format is tailored to the included player.

Third-party software

This project includes or uses the following upstream open-source projects:

See the vendored source headers and the linked upstream repositories for their license terms. This project itself is licensed under the GNU GPL v3.0.

Contributing

Issues and pull requests are welcome. Please keep changes compatible with MicroPython's constrained runtime, avoid committing Wi-Fi credentials or generated firmware artifacts, and test both the browser editor and target hardware when changing the transfer or playback path.

About

Javascript client for converting GIF animations to data suitable for driving LED matrices. Server side code is written in Micropython and optimized for the ESP32. Compatible with raspberry pi, beagle board and anything that runs MicroPython.

Resources

Stars

5 stars

Watchers

2 watching

Forks

Releases

Packages

Contributors

Languages