Your Name ecd4880a28
All checks were successful
Run tests / test (push) Successful in 1m0s
add a workflow for tests
2026-06-25 21:32:45 -06:00
2026-06-25 21:32:45 -06:00
2026-06-25 21:31:35 -06:00
2026-06-25 21:31:35 -06:00
2026-06-25 21:31:35 -06:00

Spectra

Display random Unsplash photos on an Inky Impression e-paper display, with a web interface for uploading your own images.



Requirements

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:

  1. $PWD/config.yaml
  2. ~/.config/spectra/config.yaml
  3. /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 loop
  • spectra-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.

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
├── 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
Description
No description provided
Readme 108 KiB
Languages
Python 70.5%
HTML 23.7%
CSS 2.4%
Shell 2.2%
JavaScript 1.2%