- Python 72.5%
- TypeScript 26.4%
- Dockerfile 0.5%
- JavaScript 0.3%
- CSS 0.1%
- Other 0.1%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
|
All checks were successful
CI / Pre-commit hooks (push) Successful in 1m5s
CI / Dockerfile lint (push) Successful in 8s
CI / Alembic migration check (push) Successful in 46s
CI / Python lint & type-check (push) Successful in 1m30s
CI / Frontend lint, test & build (push) Successful in 2m15s
CI / Python tests (push) Successful in 5m18s
CI / Docker build, health smoke & E2E (push) Successful in 5m56s
|
||
| .forgejo/workflows | ||
| backend | ||
| config | ||
| data | ||
| docs | ||
| frontend | ||
| schemes | ||
| .dockerignore | ||
| .editorconfig | ||
| .env.example | ||
| .gitattributes | ||
| .gitignore | ||
| .pre-commit-config.yaml | ||
| CHANGELOG.md | ||
| CONTRIBUTING.md | ||
| docker-compose.registry.yml | ||
| docker-compose.yml | ||
| Dockerfile | ||
| LICENSE | ||
| README.md | ||
| renovate.json | ||
| startup.sh | ||
Iris
A self-hosted WLED holiday lighting system. Maintains a year-round calendar of events, generates progressive lighting schemes, and pushes approved schemes to a WLED controller on a sunrise/sunset schedule.
Full specification: docs/iris-spec.md
Changelog: CHANGELOG.md · Planned work: Forgejo Issues
60-second quickstart
Prerequisites: Docker and Docker Compose.
# 1. Clone and configure
git clone https://git.rhoving.com/rbrooks/Iris-WLED.git
cd Iris-WLED
cp .env.example .env
# 2. Edit .env — at minimum set:
# LATITUDE, LONGITUDE, TZ, and your OIDC credentials
# (or set DISABLE_AUTH=true for local testing)
$EDITOR .env
# 3. Make the data directory writable by the container's non-root user
mkdir -p ./data && sudo chown -R 1000:1000 ./data
# 4. Start
docker compose up -d
# 5. Open http://localhost:7842
Step 3 is needed because the container runs as uid 1000 rather than root, and
./data is a host bind mount. If you would rather not chown, set IRIS_UID /
IRIS_GID in .env to the directory's existing owner instead — see
docs/setup.md.
The data directory (./data/) is created automatically on first run and mounted as a volume. The SQLite database lives at ./data/iris.db.
Trying it without a WLED controller
Set DEMO_MODE=true in .env and Iris runs against an in-process simulator
instead of hardware. The whole workflow works — the year generates, the review
queue fills, schemes preview as an animated virtual strip, pushes and preset
sync succeed — so you can decide whether you want it before wiring anything up.
An empty database also gets a few segments and a handful of approved schemes, so the calendar has colour in it rather than being a blank grid. It seeds only an empty install: existing segments and approvals are never touched, so turning this on against a real database does nothing rather than something regrettable.
Two things to know. Nothing on your network lights up while it is on, and a warning at startup says so. And the simulator never fails, so it exercises none of the retry, fallback or unreachable-controller paths — it is a demo, not a test rig.
Changing the port
Set HOST_PORT in .env to use a different host port:
HOST_PORT=8042
The container always listens on 7842 internally; only the host-side port changes.
Configuration
All settings are documented in .env.example. WLED, location, schedule, AI provider, and backup values can be changed from the Settings page after first boot. Key bootstrap variables:
| Variable | Default | Description |
|---|---|---|
HOST_PORT |
7842 |
Host port exposed by Docker |
WLED_HOST |
(none) | Startup default; editable in Settings |
LATITUDE / LONGITUDE |
(required for solar mode) | Startup default; editable in Settings |
TZ |
UTC |
Startup default; editable in Settings |
OIDC_ISSUER_URL |
(required) | OIDC provider discovery URL |
DISABLE_AUTH |
false |
Bypass auth for local testing |
See .env.example for the full reference.
WLED firmware compatibility
| Version | Status |
|---|---|
| 16.0.0 | Verified on hardware |
| 0.15.x | Expected to work, untested |
| 0.14.x | Minimum supported |
| 0.13.x and older | Untested — Iris warns but still drives it |
WLED's JSON API drifts between releases, so Iris pins its expectations with recorded responses from each version above and tests the translator against all of them. Note that WLED released 16.0.0 directly after 0.15.x, not 0.16.0 — so 16.x is the newest line, not an old one.
One consequence worth knowing: WLED effect ids are positional and get reassigned between releases (id 77 was "Meteor Smooth" on 0.14 and is "Copy Segment" on 16.0.0). Schemes store the id, so the effect picker reads the live list from your controller rather than a built-in table.
Full details, including what Iris reads and writes and how to add a version: docs/wled-compatibility.md.
Authentication
Iris uses standard OIDC. Any compliant provider works (Authentik, Keycloak, Google, etc.).
Set the OIDC_* variables in .env. The redirect URI must be registered in your provider:
https://<your-iris-host>/auth/callback
For local development with no IdP available, set DISABLE_AUTH=true. A warning banner will be displayed in the UI.
Development
See CONTRIBUTING.md for the full development setup.
Quick start:
# Backend
cd backend && uv sync --group dev
uv run uvicorn app.main:app --reload
# Frontend (separate terminal)
cd frontend && npm install && npm run dev
Status
v1.0.0 shipped on 2026-09-01 with the full feature set: events, schemes, WLED integration,
scheduler, auth, review UI, AI suggestions, notifications, and import/export. Work now targets
v1.1.0 — observability, previews, exports, remote control, and onboarding — tracked in
Forgejo Issues under the v1.1.0 label;
shipped work is recorded in the CHANGELOG.
Authoritative container images are published to the Forgejo registry at
git.rhoving.com/rbrooks/iris-wled for linux/amd64.