Skip to content

About

LED Strip Light is a lightweight Python toolkit for a Raspberry Pi to drive APA102/SPI LED strips. It offers precise, PWM duty cycle driven color updates via pigpio, cron/systemd scheduling, RESTful HTTP endpoints for Homebridge/HomeKit and configurable lighting profiles.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

LED Strip Light

License Platform Python Quality Gate Status Bugs Coverage Security Rating GitGuardian

Feature-rich Raspberry Pi project for controlling an RGB LED strip light. Includes:

  • Web-based REST API (Flask) for remote control (on/off, color, brightness, effects)
  • Web-based interface for manual remote control
  • Homebridge integration for Apple HomeKit and Siri voice control
  • Command-line interface for scripting and manual control
  • Multiple built-in LED effects (breathing, fade, rainbow, random, campfire, candle, aurora, heartbeat, lightning, and more)
  • Time-based color profiles and scheduled automation (systemd, cron)
  • Modular, testable Python codebase with hardware abstraction and full unit test suite

Easily automate, script, or integrate your LED strip with smart home platforms and custom workflows.

Requirements

Hardware

  • Raspberry Pi (tested on Pi Zero W Rev 1.1)
  • LED strip light

The guide How to control a RGB LED Strip Light with a Raspberry Pi Zero W shows how to physically connect a 12 V RGB strip to a Raspberry Pi Zero W.

Software

  • Python 3.13+
  • pip dependencies: flask, waitress, pigpio (see pyproject.toml)

Architecture

graph TD
    subgraph Clients
        SIRI["Siri / HomeKit"]
        WEBUI["Web Browser\n(index.html)"]
        SHELL["Shell / Cron"]
    end

    subgraph Entry Points
        HB["Homebridge\n(homebridge-http-rgb-push)"]
        HTTP["http_server.py\n(Flask REST API)"]
        CLI["run.py\n(CLI)"]
    end

    subgraph Config
        CM["ConfigManager\n(config.toml)"]
        PA["PinAssignment"]
        PM["ProfileManager\n(time-based colors)"]
    end

    subgraph LED Control
        GPIO["GPIOService\n(pigpio PWM)"]
        CTRL["LEDStripLightController\n(color · brightness · thread)"]
        ER["EffectRunner\n(effect dispatch)"]
        EFX["effects.py\n(breathing · fade · campfire\ncandle · aurora · heartbeat · lightning\nrainbow · cycle · random)"]
    end

    HW["RGB LED Strip\n(hardware)"]

    SIRI -->|"HomeKit protocol"| HB
    HB -->|"HTTP"| HTTP
    WEBUI -->|"HTTP"| HTTP
    SHELL --> CLI

    HTTP --> CTRL
    CLI --> CTRL
    CM --> PA
    CM --> PM
    PA --> GPIO
    GPIO --> CTRL
    CTRL --> ER
    ER -->|"background thread"| EFX
    PM --> ER
    GPIO --> HW
Loading

Installing

Configure the application: config.toml

This project uses the pigpio library for PWM control of the GPIO pins. To install it on your Raspberry Pi:

sudo apt-get install pigpio
sudo systemctl enable pigpiod
sudo systemctl start pigpiod

Pi deployment

cd ~/raspberry/led-strip-light

# Create venv and install runtime dependencies
python3 -m venv --upgrade-deps .venv
.venv/bin/pip install .

# Install and start the systemd service
sudo cp deploy/systemd/ledstriplight-http-server.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable ledstriplight-http-server.service
sudo systemctl start ledstriplight-http-server.service

For full deployment instructions see the READMEs in deploy/:

Development Setup

Virtual Environment

# Create and activate virtual environment (from repo root)
python3 -m venv --upgrade-deps .venv
source .venv/bin/activate

# Install dependencies + test extras
pip install -e ".[dev]"

Running the Application

The application supports multiple effects via command-line arguments:

# Basic profile effect (morning/evening colors based on time of the day)
./run.py profile

# Breathing effect with custom color and duration
./run.py breathing --color red --duration 3000

# Use hex colors
./run.py breathing --color "#FF6347"

# Color cycling through multiple colors
./run.py cycle --colors red,green,blue,yellow --duration 500

# Fade between two colors
./run.py fade --from black --to white --duration 5000

# Random color changes
./run.py random --interval 2000

# Campfire effect (dynamic warm flicker)
./run.py campfire --duration 60000 --base-color "#FF4E04"

# Candle effect (gentler, slower flicker)
./run.py candle --duration 60000

# Aurora drift (slow HSV wander, green↔violet by default)
./run.py aurora --duration 120000

# Heartbeat (double-pulse thump-thump-rest)
./run.py heartbeat --color red

# Rainbow sweep (continuous HSV hue rotation)
./run.py rainbow --period-ms 8000

# Lightning (random bright flashes with fast decay)
./run.py lightning --max-gap-ms 5000

# Get help
./run.py --help

Running Tests

The project includes comprehensive unit tests with hardware mocking. Tests can be run from the repo root (pytest configuration is in pyproject.toml):

# Run all tests (from repo root)
pytest

# Run a specific test file
pytest tests/test_color.py

# Run tests with HTML coverage report
pytest --cov-report=html

Project Structure

led-strip-light/
├── deploy/
│   ├── cron/                    # Cron job for scheduled automation
│   ├── homebridge/              # Homebridge config for Apple HomeKit
│   │   ├── armv6/               # Pi Zero W (npm install method)
│   │   └── armv7/               # Pi Zero 2 W (apt install method)
│   ├── logrotate.d/             # Logrotate drop-in for the cron log
│   └── systemd/                 # Systemd service files
├── docs/                        # Documentation and wiring diagrams
├── src/
│   ├── cli/
│   │   └── cli_handler.py       # Command-line interface handler
│   ├── config/
│   │   ├── color_profile.py
│   │   ├── config_manager.py    # Reads config.toml
│   │   └── pin_assignment.py
│   ├── led/
│   │   ├── color.py
│   │   ├── effect_runner.py
│   │   ├── effects.py           # LED effects (breathing, fade, campfire, aurora, …)
│   │   ├── gpio_service.py      # pigpio PWM interface
│   │   ├── led_strip_light_controller.py
│   │   └── profile_manager.py   # Time-based color profiles
│   ├── static/
│   │   └── index.html           # Web UI
│   ├── utils/
│   │   └── graceful_shutdown.py
│   ├── config.toml              # GPIO pins and color profiles
│   ├── http_server.py           # Flask REST API entry point
│   └── run.py                   # CLI entry point
└── tests/                       # Unit tests with mocked hardware

REST API (Flask Server)

The project includes a Flask server for remote control via HTTP endpoints and a web-based control interface.

Web Interface

A responsive web interface is available for controlling the LED strip through your browser:

  • Access: Navigate to http://localhost:5000 (or http://YOUR_PI_IP:5000 from other devices)
  • Features:
    • Power control (On/Off) with visual status indicators
    • Color picker and preset color buttons (Red, Green, Blue, White, Yellow, Magenta, Cyan)
    • Brightness slider with real-time adjustment
    • Start/stop built‑in effects (breathing, campfire, candle, aurora, heartbeat, lightning, rainbow, random, fade) with parameter inputs
    • Live status + active effect display and error handling
    • Mobile-friendly responsive design

API Endpoints

Endpoints:

Core control:

  • POST /on — Turn the light on (restores last color; warm yellow by default)
  • POST /off — Turn the light off (black)
  • GET /status — Get on/off state (1/0)
  • GET /color — Get current color (hex with #)
  • POST /color/<value> — Set color (6‑digit hex, with or without #)
  • GET /brightness — Get current brightness (0–100)
  • POST /brightness/<int:value> — Set brightness (0–100)

Effects management:

  • GET /effects — List available effects + currently active
  • POST /effects/stop — Stop any running effect
  • POST /effects/breathing JSON: { "color": "FF0000", "duration": 2000 }
  • POST /effects/campfire (optional JSON overrides: base_color, duration, update_hz, min_brightness, max_brightness, hue_jitter, saturation, spark_chance, spark_gain, tau_ms, gamma)
  • POST /effects/candle (same override keys as campfire)
  • POST /effects/aurora (optional JSON overrides: duration, update_hz, hue_min, hue_max, saturation, min_brightness, max_brightness, hue_step, brightness_step, tau_ms, gamma)
  • POST /effects/heartbeat (optional JSON overrides: color, beat_ms, gap_ms, rest_ms, second_beat_scale)
  • POST /effects/rainbow (optional JSON overrides: period_ms, duration, update_hz, saturation, brightness, gamma)
  • POST /effects/lightning (optional JSON overrides: flash_color, background_color, min_gap_ms, max_gap_ms, flash_ms, intensity_min, intensity_max, aftershock_chance, max_aftershocks, duration, gamma)
  • POST /effects/random JSON: { "interval": 2000 }
  • POST /effects/cycle JSON: { "duration": 2000, "colors": ["FF0000","00FF00","0000FF"] }
  • POST /effects/fade JSON: { "from": "000000", "to": "FFFFFF", "duration": 5000 }
  • POST /effects/profile JSON: { "duration": 10000 } (fades from black to active profile color)

Starting the server:

cd src
./http_server.py

Example usage:

curl -X POST http://localhost:5000/on
curl -X POST http://localhost:5000/color/ff0000
curl -X POST http://localhost:5000/brightness/80
curl http://localhost:5000/status

# Start campfire effect
curl -X POST http://localhost:5000/effects/campfire

# Start candle effect for 30s
curl -X POST -H 'Content-Type: application/json' \
  -d '{"duration":30000}' http://localhost:5000/effects/candle

# Start aurora drift with a narrower hue range (teal→violet)
curl -X POST -H 'Content-Type: application/json' \
  -d '{"hue_min":0.45,"hue_max":0.78,"tau_ms":3000}' \
  http://localhost:5000/effects/aurora

# Heartbeat in pink with a softer second beat
curl -X POST -H 'Content-Type: application/json' \
  -d '{"color":"FF69B4","second_beat_scale":0.5}' \
  http://localhost:5000/effects/heartbeat

# Rainbow sweep at half-brightness, 5s per rotation
curl -X POST -H 'Content-Type: application/json' \
  -d '{"period_ms":5000,"brightness":0.5}' \
  http://localhost:5000/effects/rainbow

# Lightning with cyan flashes and shorter gaps
curl -X POST -H 'Content-Type: application/json' \
  -d '{"flash_color":"00FFFF","max_gap_ms":3000}' \
  http://localhost:5000/effects/lightning

# Breathing effect: blue, 3s cycles
curl -X POST -H 'Content-Type: application/json' \
  -d '{"color":"0000FF","duration":3000}' http://localhost:5000/effects/breathing

# Custom cycle effect
curl -X POST -H 'Content-Type: application/json' \
  -d '{"colors":["FF0000","00FF00","0000FF","FFFF00"],"duration":800}' http://localhost:5000/effects/cycle

# Fade from black to warm white over 10s
curl -X POST -H 'Content-Type: application/json' \
  -d '{"from":"000000","to":"FFC864","duration":10000}' http://localhost:5000/effects/fade

# Run current time-based profile color (10s fade in)
curl -X POST -H 'Content-Type: application/json' \
  -d '{"duration":12000}' http://localhost:5000/effects/profile

# Stop current effect
curl -X POST http://localhost:5000/effects/stop

Homebridge Integration

You can integrate the LED strip with Homebridge for Apple HomeKit support. All installation and configuration instructions, including example Homebridge accessory configuration, can be found in the deploy/homebridge/ directory of this repository.

See README.md for details on how to set up Homebridge integration and connect it to the Flask server endpoints.

Troubleshooting

Symptom Likely cause Fix
OSError: Cannot connect to pigpio daemon on startup pigpiod isn't running sudo systemctl enable --now pigpiod
App starts but the strip never lights up Wrong GPIO pins, or wiring doesn't match config.toml Verify the [pins] BCM numbers against your wiring (see the wiring guide)
BCM pin number N is out of range (0-27) A [pins] value uses a physical-header number instead of a BCM GPIO number Use BCM numbering (0–27) in config.toml
No [profile.*] sections found / Duplicate profile start_hour values config.toml has no profiles, or two share a start_hour Define at least one [profile.NAME] and give each a distinct start_hour (0–23)
POST /color or /effects/* returns 400 Unknown color Color name/hex isn't recognized Use a known name or 6-digit hex (e.g. red, FF6347)
POST /effects/* returns 503 previous effect is still stopping The prior effect hasn't stopped yet Retry after a moment; the running effect exits on its next interrupt poll
Server unreachable from other devices Bound to localhost, or blocked by the firewall Set FLASK_HOST=0.0.0.0 and allow the port (see deploy/ufw/)
LEDs stay lit after systemctl stop Old build without SIGTERM cleanup Update to a build where http_server turns the strip off on shutdown
Homebridge crashes with SIGILL on a Pi Zero W apt package ships an ARMv7+ Node.js binary Use the ARMv6 npm install method in deploy/homebridge/armv6/

Contributing

Found a bug or have an idea? Open an issue or send a PR. Run pytest before submitting and keep changes focused.

License

MIT © Jan Rothen — see LICENSE for details.

About

LED Strip Light is a lightweight Python toolkit for a Raspberry Pi to drive APA102/SPI LED strips. It offers precise, PWM duty cycle driven color updates via pigpio, cron/systemd scheduling, RESTful HTTP endpoints for Homebridge/HomeKit and configurable lighting profiles.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages