🚀 Big upgrades in progress! New tools, faster pages, and more coming soon.

🌈 Rainbow Matrix Rain Clock — RGB LED Matrix Raspberry Pi Project | techlogics.net

Build a rainbow Matrix rain digital clock on a 64×32 RGB LED panel using Raspberry Pi, Adafruit RGB Matrix HAT and PCF8523 RTC. NTP sync with offline RTC fallback. Full Python source, wiring guide and install steps.

✓ Python (.py) ✓ Live code preview ✓ Free download
⚙️
Customise & Download
Adjust settings below — the code updates live in real time
Live preview
Configure your Rainbow Matrix Rain Clock
HAT type. Use 'adafruit-hat' for Adafruit RGB Matrix HAT. Use 'regular' if wired directly without a HAT.
Increase if the display flickers or shows corruption. Try 3 for Pi 3B+, 4 for Pi 4, 5 for Pi 5.
LED panel brightness percentage. 60 is comfortable for indoor use at night. 100 for bright environments.
Usually 0 for standard 32-row panels. Try 1 or 2 if display shows doubled/shifted rows. Check your panel datasheet.
Usually 1 for standard panels. Try 0, 2 or 3 if colours look wrong. Check your panel datasheet.
Your timezone offset from UTC. India (IST) = 5.5, UK (GMT) = 0, UK (BST) = 1, US Eastern = -5.
True for 24-hour format (00:00–23:59). False for 12-hour format (1:00–12:59).
Show the date (DD Mon YYYY) below the clock. Disable to show the clock only.
NTP server for time sync. pool.ntp.org works globally. Use time.google.com or time.cloudflare.com as alternatives.
How fast the rain drops fall (pixels per second). Higher = faster rain. Try values between 4 and 20.
How many rain drops per column. 1 = sparse, 2 = moderate, 3 = heavy rain effect.
How long each rain drop trail is. 6 = short, 10 = medium, 16 = long comet-like trails.
How fast the rainbow hue cycles across the panel. 0.1 = slow drift, 0.5 = moderate, 1.0 = fast cycling.
↓ Your settings are reflected in the code below
Generated code — live preview
Python (.py) 0 lines
# ============================================================
#  Rainbow Matrix Rain Clock
#  Generated by techlogics.net
#  https://techlogics.net/electronics/rainbow-matrix-rain-clock.php
# ============================================================
#
#  CAUTION: Review this code fully before running on any
#  hardware. Verify all pin connections and power requirements
#  match YOUR specific components. We are not responsible for
#  damage to hardware, fire, or injury resulting from incorrect
#  wiring, faulty components, or misuse of this code.
#
#  Generated on: 20 Jul 2026
# ============================================================

#!/usr/bin/env python3
"""
Rainbow Matrix Rain Clock
Raspberry Pi + Adafruit RGB Matrix HAT + RTC
64x32 RGB LED panel · HUB75 ribbon connector

Time source priority:
  1. NTP (WiFi) — syncs at startup and hourly
  2. PCF8523 RTC (I2C) — used when WiFi offline
  3. System clock — free-runs in between syncs

Display:
  Background: rainbow-cycling Matrix rain columns
  Foreground: HH:MM:SS digital clock (large pixel font)
  Date line:  DD Mon YYYY below the clock
"""

import time, datetime, threading, math, random, colorsys
from rgbmatrix import RGBMatrix, RGBMatrixOptions
from PIL import Image, ImageDraw, ImageFont

# ── Panel configuration ─────────────────────────────────────
COLS, ROWS       = 64, 32
HARDWARE_MAPPING = 'adafruit-hat'
GPIO_SLOWDOWN    = 4
BRIGHTNESS       = 60
ROW_ADDRESS_TYPE = 0
MULTIPLEXING     = 1

# ── Time configuration ──────────────────────────────────────
UTC_OFFSET_HOURS = 5.5
USE_24_HOUR      = True
SHOW_DATE        = True
NTP_HOST         = 'pool.ntp.org'

# ── Rain configuration ──────────────────────────────────────
RAIN_SPEED       = 10
RAIN_DENSITY     = 1
RAIN_TRAIL_LEN   = 8
RAINBOW_SPEED    = 0.15

# ── Matrix options ──────────────────────────────────────────
options = RGBMatrixOptions()
options.rows                 = ROWS
options.cols                 = COLS
options.hardware_mapping     = HARDWARE_MAPPING
options.gpio_slowdown        = GPIO_SLOWDOWN
options.brightness           = BRIGHTNESS
options.row_address_type     = ROW_ADDRESS_TYPE
options.multiplexing         = MULTIPLEXING
options.disable_hardware_pulsing = False

# ── NTP time sync ───────────────────────────────────────────
import socket, struct

def get_ntp_time(host=NTP_HOST, timeout=5):
    try:
        client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        client.settimeout(timeout)
        data = b'\x1b' + 47 * b'\0'
        client.sendto(data, (host, 123))
        data, _ = client.recvfrom(1024)
        t = struct.unpack('!12I', data)[10]
        t -= 2208988800  # NTP epoch to Unix epoch
        return datetime.datetime.utcfromtimestamp(t)
    except Exception:
        return None
    finally:
        client.close()

# ── RTC read (PCF8523 via I2C) ──────────────────────────────
def bcd_to_dec(v): return (v >> 4) * 10 + (v & 0x0F)

def get_rtc_time():
    try:
        from smbus2 import SMBus
        with SMBus(1) as bus:
            d = bus.read_i2c_block_data(0x68, 0x03, 7)
        return datetime.datetime(
            2000 + bcd_to_dec(d[6]),
            bcd_to_dec(d[5] & 0x1F),
            bcd_to_dec(d[3] & 0x3F),
            bcd_to_dec(d[2] & 0x3F),
            bcd_to_dec(d[1] & 0x7F),
            bcd_to_dec(d[0] & 0x7F)
        )
    except Exception:
        return None

# ── Shared time state ───────────────────────────────────────
_time_lock = threading.Lock()
_base_utc  = datetime.datetime.utcnow()
_base_mono = time.monotonic()
_time_src  = 'system'

def current_local():
    with _time_lock:
        drift = time.monotonic() - _base_mono
        utc   = _base_utc + datetime.timedelta(seconds=drift)
    return utc + datetime.timedelta(hours=UTC_OFFSET_HOURS)

def sync_from_ntp():
    global _base_utc, _base_mono, _time_src
    t = get_ntp_time()
    if t:
        with _time_lock:
            _base_utc  = t
            _base_mono = time.monotonic()
            _time_src  = 'NTP'
        return True
    t = get_rtc_time()
    if t:
        with _time_lock:
            _base_utc  = t
            _base_mono = time.monotonic()
            _time_src  = 'RTC'
        return True
    return False

def time_sync_thread():
    while True:
        sync_from_ntp()
        time.sleep(3600)

# ── Rain engine ─────────────────────────────────────────────
class RainDrop:
    def __init__(self, col):
        self.col   = col
        self.y     = random.uniform(-ROWS, 0)
        self.speed = random.uniform(*RAIN_SPEED) if isinstance(RAIN_SPEED, (list,tuple)) else RAIN_SPEED
        self.len   = RAIN_TRAIL_LEN

    def step(self, dt):
        self.y += self.speed * dt
        if self.y - self.len > ROWS:
            self.y     = random.uniform(-self.len, 0)
            self.speed = random.uniform(6, 14)

# Build initial drops — RAIN_DENSITY drops per column
rains = []
for c in range(COLS):
    for _ in range(RAIN_DENSITY if isinstance(RAIN_DENSITY, int) else 1):
        rains.append(RainDrop(c))

# ── Main display loop ────────────────────────────────────────
def main():
    matrix = RGBMatrix(options=options)
    canvas = matrix.CreateFrameCanvas()

    # Start time sync in background
    sync_from_ntp()
    threading.Thread(target=time_sync_thread, daemon=True).start()

    hue    = 0.0
    prev_t = time.monotonic()

    while True:
        now_t = time.monotonic()
        dt    = now_t - prev_t
        prev_t = now_t
        hue   = (hue + RAINBOW_SPEED * dt) % 1.0

        img  = Image.new('RGB', (COLS, ROWS), (0, 0, 0))
        draw = ImageDraw.Draw(img)

        # Draw rain
        for drop in rains:
            drop.step(dt)
            for i in range(drop.len):
                py = int(drop.y) - i
                if 0 <= py < ROWS:
                    # Hue shifts across columns, brightness fades along trail
                    h = (hue + drop.col / COLS) % 1.0
                    v = max(0, 1 - i / drop.len)
                    r, g, b = colorsys.hsv_to_rgb(h, 1.0, v)
                    draw.point((drop.col, py),
                               (int(r*255), int(g*255), int(b*255)))

        # Draw clock overlay (dark region behind text)
        local = current_local()
        if USE_24_HOUR:
            t_str = local.strftime('%H:%M:%S')
        else:
            t_str = local.strftime('%I:%M:%S').lstrip('0') or '0'
        d_str = local.strftime('%d %b %Y') if SHOW_DATE else ''

        # Render text (small font fits 64px wide)
        try:
            fnt = ImageFont.truetype('/usr/share/fonts/truetype/dejavu/DejaVuSansMono-Bold.ttf', 8)
        except Exception:
            fnt = ImageFont.load_default()

        # Background rect for readability
        tw = draw.textlength(t_str, font=fnt)
        tx = int((COLS - tw) / 2)
        ty = 6 if SHOW_DATE else 12
        draw.rectangle([tx-1, ty-1, tx+tw+1, ty+9], fill=(0,0,0))
        draw.text((tx, ty), t_str, font=fnt, fill=(255,255,255))

        if SHOW_DATE and d_str:
            dw = draw.textlength(d_str, font=fnt)
            dx = int((COLS - dw) / 2)
            draw.rectangle([dx-1, 17, dx+dw+1, 26], fill=(0,0,0))
            draw.text((dx, 18), d_str, font=fnt, fill=(200,200,200))

        canvas.SetImage(img)
        canvas = matrix.SwapOnVSync(canvas)

if __name__ == '__main__':
    main()

# ============================================================
#  End of generated code — techlogics.net
#  Found this useful? Visit https://techlogics.net/electronics/rainbow-matrix-rain-clock.php
#  for more free CCTV, networking, electronics & finance tools.
#
#  Questions or issues? https://techlogics.net/contact.php
# ============================================================
How to use

Step 1: Assemble hardware — stack the Adafruit RGB Matrix HAT + RTC on your Pi GPIO header. Connect the 64×32 LED matrix HUB75 ribbon cable to the HAT. Power the matrix panel from a dedicated 5V 4A supply, not the Pi rail. Insert a CR1220 coin cell into the RTC holder.

Step 2: Install the rpi-rgb-led-matrix library:
git clone https://github.com/hzeller/rpi-rgb-led-matrix.git
cd rpi-rgb-led-matrix/bindings/python
sudo make build-python PYTHON=$(which python3)
sudo make install-python PYTHON=$(which python3)

Step 3: Install Python dependencies:
sudo $(which python3) -m pip install --break-system-packages pillow smbus2

Step 4: Set the RTC time (first run only):
sudo $(which python3) -c "from smbus2 import SMBus; print('RTC OK')"

Step 5: Fill in your config values using the form above, then download your customised file.

Step 6: Run as root (required for GPIO):
sudo $(which python3) rainbow_matrix_rain_clock.py

To run on boot, add to /etc/rc.local before exit 0:
sudo $(which python3) /home/admin/rainbow_matrix_rain_clock.py &