Spectra
Display random Unsplash photos on an Inky Impression e-paper display, with a web interface for uploading your own images.
Requirements
- Raspberry Pi with GPIO
- Pimoroni Inky Impression (4.0", 7.3", or 13.3")
- Python 3.9+
- Unsplash API access key
Quick start
# Install
cp config.example.yaml config.yaml # edit with your Unsplash key
pip install -r requirements.txt
pip install -e .
# Run once in simulation mode
spectra --once --simulate
# Start the web interface
spectra web
# Run the display loop continuously
spectra
Or on a Pi with systemd:
sudo ./install.sh
sudo systemctl start spectra spectra-web
Configuration
spectra looks for config.yaml in this order:
$PWD/config.yaml~/.config/spectra/config.yaml/etc/spectra/config.yaml
Pass a custom path with spectra -c /path/to/config.yaml.
unsplash:
access_key: "your_access_key_here"
query: "nature"
collections: ""
display:
saturation: 0.5
orientation: 0
resolution:
width: 1600
height: 1200
schedule:
interval_hours: 1
random_delay_seconds: 300
mqtt:
enabled: false
broker: localhost
port: 1883
topic_prefix: spectra
client_id: spectra-display
username: ""
password: ""
paths:
cache: /var/cache/spectra
Display orientation
Set display.orientation to match how the panel is physically mounted. The
Unsplash orientation filter (landscape/portrait/squarish) is derived
automatically — the old unsplash.orientation config key is ignored.
| Value | Unsplash filter | Effect |
|---|---|---|
| 0 | landscape | Default horizontal mount |
| 90 | portrait | Vertical mount |
| 180 | landscape | Upside-down horizontal |
| 270 | portrait | Upside-down vertical |
Images are cropped to the effective aspect ratio, resized, then rotated for the physical panel. Preview and thumbnails reflect the configured orientation. Change it live from Settings > Display Orientation or via config hot-reload.
MQTT
When enabled, the display loop subscribes to {prefix}/command/# and publishes
status to {prefix}/status. See MQTT integration docs for
commands, Home Assistant examples, and debugging.
Usage
Display loop
spectra # run continuously
spectra --once # fetch one photo and exit
spectra --once --simulate # save to /tmp/spectra_last.png
spectra --simulate --width 800 --height 480
spectra -c /path/to/config.yaml
Web interface
spectra web # http://0.0.0.0:5000
spectra web --port 8080
spectra web -v # verbose (debug mode only on localhost)
| Page | What it does |
|---|---|
| Dashboard | Display status, schedule, quick actions (refresh, clear) |
| Gallery | Browse images, trigger "show now", delete |
| Upload | Drag-and-drop multi-file upload with progress |
| Settings | Live-edit Unsplash, display, schedule, MQTT |
| Preview | See how an image looks on the display |
systemd services
Two units are installed by install.sh:
spectra.service— display loopspectra-web.service— web interface
sudo systemctl start spectra
sudo systemctl stop spectra-web
journalctl -u spectra -f
journalctl -u spectra-web -f
Running tests
pip install -e ".[dev]"
pytest tests/
107 tests covering config loading, display processing (crop, resize, rotation), trigger atomicity, MQTT parsing, and all 19 API routes.
A Gitea Actions workflow runs tests on every push.
See bug-tracking.md for known issues and recent fixes.
Project structure
spectra/
├── config.example.yaml
├── .gitignore
├── install.sh
├── pyproject.toml
├── requirements.txt
├── spectra/
│ ├── cli.py # CLI, display loop, config hot-reload
│ ├── config.py # Config loader with deep-merge
│ ├── config_manager.py # Config read/write
│ ├── display.py # Image processing, rotation, hardware abstraction
│ ├── fetcher.py # Unsplash API client
│ ├── library.py # Unsplash image caching to SQLite
│ ├── mqtt.py # MQTT client (commands + heartbeat)
│ ├── trigger.py # Thread-safe trigger file (web → display loop)
│ └── web/
│ ├── server.py # Flask app, 19 API routes
│ ├── models.py # SQLAlchemy models
│ ├── templates/ # 6 Jinja2 pages
│ └── static/ # CSS + JS
├── .gitea/
│ └── workflows/
│ └── test.yml # CI workflow
├── tests/
│ ├── test_api.py
│ ├── test_config.py
│ ├── test_display.py
│ ├── test_gallery.py
│ ├── test_mqtt.py
│ ├── test_orientation.py
│ ├── test_trigger.py
│ └── conftest.py
├── systemd/
│ ├── spectra.service
│ └── spectra-web.service
└── docs/
├── display-orientation.md
├── web-interface.md
└── mqtt.md