Update readme to increase readability
This commit is contained in:
235
README.md
235
README.md
@@ -1,65 +1,65 @@
|
|||||||
# Spectra
|
# Spectra
|
||||||
|
|
||||||
Display random Unsplash photos on an Inky Impression e-paper display, with a web interface for uploading your own images.
|
Display random Unsplash photos on an Inky Impression e-paper display, with a web
|
||||||
|
interface for uploading your own images.
|
||||||
|
|
||||||
## Features
|
---
|
||||||
|
|
||||||
- Fetches random high-resolution photos from Unsplash (cached to gallery)
|
- [Requirements](#requirements)
|
||||||
- Upload your own images via the web interface (drag-and-drop, multi-file)
|
- [Quick start](#quick-start)
|
||||||
- Centres, scales, and rotates images to fit the display
|
- [Configuration](#configuration)
|
||||||
- Colour saturation tuning for e-paper
|
- [Display orientation](#display-orientation)
|
||||||
- Display orientation — configure the physical mounting direction (0°, 90°, 180°, 270°)
|
- [MQTT](#mqtt)
|
||||||
— Unsplash orientation filter is auto-derived (portrait/landscape/squarish)
|
- [Usage](#usage)
|
||||||
- Web dashboard with preview, gallery, rotation queue, and config editor
|
- [Display loop](#display-loop)
|
||||||
- MQTT integration for remote commands and status reporting
|
- [Web interface](#web-interface)
|
||||||
- Simulation mode for testing without hardware (configurable resolution)
|
- [systemd services](#systemd-services)
|
||||||
- systemd integration for automatic updates on a schedule
|
- [Running tests](#running-tests)
|
||||||
- Randomised update intervals to avoid predictable refreshes
|
- [Project structure](#project-structure)
|
||||||
- Config hot-reload — no service restart needed for setting changes
|
|
||||||
|
---
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
- Raspberry Pi (any model with GPIO)
|
- Raspberry Pi with GPIO
|
||||||
- [Pimoroni Inky Impression](https://shop.pimoroni.com/products/inky-impression) (4.0", 7.3", or 13.3")
|
- [Pimoroni Inky Impression](https://shop.pimoroni.com/products/inky-impression) (4.0", 7.3", or 13.3")
|
||||||
- Python 3.9+
|
- Python 3.9+
|
||||||
- [Unsplash API access key](https://unsplash.com/developers)
|
- [Unsplash API access key](https://unsplash.com/developers)
|
||||||
|
|
||||||
## Installation
|
## Quick start
|
||||||
|
|
||||||
Run the installer on a Raspberry Pi:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
./install.sh
|
|
||||||
```
|
|
||||||
|
|
||||||
The installer will:
|
|
||||||
|
|
||||||
1. Install the Pimoroni Inky library (skipped if not a Raspberry Pi)
|
|
||||||
2. Install Python dependencies (including web server and MQTT)
|
|
||||||
3. Install the `spectra` package
|
|
||||||
4. Copy the default config to `/etc/spectra/config.yaml`
|
|
||||||
5. Install and enable both the display and web interface systemd services
|
|
||||||
|
|
||||||
### Manual installation
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
# Install
|
||||||
|
cp config.example.yaml config.yaml # edit with your Unsplash key
|
||||||
pip install -r requirements.txt
|
pip install -r requirements.txt
|
||||||
pip install -e .
|
pip install -e .
|
||||||
|
|
||||||
# Optional: install dev dependencies for running tests
|
# Run once in simulation mode
|
||||||
pip install -e ".[dev]"
|
spectra --once --simulate
|
||||||
|
|
||||||
|
# Start the web interface
|
||||||
|
spectra web
|
||||||
|
|
||||||
|
# Run the display loop continuously
|
||||||
|
spectra
|
||||||
|
```
|
||||||
|
|
||||||
|
Or on a Pi with systemd:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo ./install.sh
|
||||||
|
sudo systemctl start spectra spectra-web
|
||||||
```
|
```
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
Copy `config.example.yaml` to `config.yaml` and fill in your Unsplash access key.
|
spectra looks for `config.yaml` in this order:
|
||||||
spectra searches for `config.yaml` in this order:
|
|
||||||
|
|
||||||
1. `$PWD/config.yaml`
|
1. `$PWD/config.yaml`
|
||||||
2. `~/.config/spectra/config.yaml`
|
2. `~/.config/spectra/config.yaml`
|
||||||
3. `/etc/spectra/config.yaml`
|
3. `/etc/spectra/config.yaml`
|
||||||
|
|
||||||
Or pass a custom path: `spectra -c /path/to/config.yaml`
|
Pass a custom path with `spectra -c /path/to/config.yaml`.
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
unsplash:
|
unsplash:
|
||||||
@@ -69,7 +69,7 @@ unsplash:
|
|||||||
|
|
||||||
display:
|
display:
|
||||||
saturation: 0.5
|
saturation: 0.5
|
||||||
orientation: 0 # 0, 90, 180, 270 (degrees clockwise)
|
orientation: 0
|
||||||
resolution:
|
resolution:
|
||||||
width: 1600
|
width: 1600
|
||||||
height: 1200
|
height: 1200
|
||||||
@@ -91,83 +91,67 @@ paths:
|
|||||||
cache: /var/cache/spectra
|
cache: /var/cache/spectra
|
||||||
```
|
```
|
||||||
|
|
||||||
> **Note:** The `unsplash.orientation` key is no longer used. The Unsplash
|
### Display orientation
|
||||||
> orientation filter (`landscape`/`portrait`/`squarish`) is now derived
|
|
||||||
> automatically from `display.orientation` + `display.resolution`.
|
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](docs/mqtt.md) for
|
||||||
|
commands, Home Assistant examples, and debugging.
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
### Display loop
|
### Display loop
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Run once and exit
|
spectra # run continuously
|
||||||
spectra --once
|
spectra --once # fetch one photo and exit
|
||||||
|
spectra --once --simulate # save to /tmp/spectra_last.png
|
||||||
# Run once in simulation mode
|
spectra --simulate --width 800 --height 480
|
||||||
spectra --once --simulate
|
|
||||||
|
|
||||||
# Simulate at a specific resolution
|
|
||||||
spectra --once --simulate --width 800 --height 480
|
|
||||||
|
|
||||||
# Run with a custom config
|
|
||||||
spectra -c /path/to/config.yaml
|
spectra -c /path/to/config.yaml
|
||||||
|
|
||||||
# Run continuously
|
|
||||||
spectra
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Web interface
|
### Web interface
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Start the web interface (default: http://0.0.0.0:5000)
|
spectra web # http://0.0.0.0:5000
|
||||||
spectra web
|
spectra web --port 8080
|
||||||
|
spectra web -v # verbose (debug mode only on localhost)
|
||||||
# With custom host/port
|
|
||||||
spectra web --host 0.0.0.0 --port 5000
|
|
||||||
|
|
||||||
# Verbose logging (debug mode is limited to localhost)
|
|
||||||
spectra web -v
|
|
||||||
```
|
```
|
||||||
|
|
||||||
The web interface provides:
|
| Page | What it does |
|
||||||
|
|------|-------------|
|
||||||
- **Dashboard** — display status, schedule info, quick actions (refresh, clear)
|
| **Dashboard** | Display status, schedule, quick actions (refresh, clear) |
|
||||||
- **Gallery** — browse all uploaded and cached Unsplash images, trigger "show now"
|
| **Gallery** | Browse images, trigger "show now", delete |
|
||||||
- **Upload** — drag-and-drop multiple image files with progress tracking
|
| **Upload** | Drag-and-drop multi-file upload with progress |
|
||||||
- **Settings** — live-edit Unsplash, display (including orientation), schedule, and MQTT configuration
|
| **Settings** | Live-edit Unsplash, display, schedule, MQTT |
|
||||||
- **Preview** — preview how an image will look on the display (respects current orientation)
|
| **Preview** | See how an image looks on the display |
|
||||||
|
|
||||||
### Display orientation
|
|
||||||
|
|
||||||
Set `display.orientation` in config or via Settings > Display > Display Orientation:
|
|
||||||
|
|
||||||
| Value | Unsplash filter | Use case |
|
|
||||||
|-------|----------------|-------------------------|
|
|
||||||
| 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 to match
|
|
||||||
the physical panel. The preview and thumbnails reflect the configured orientation.
|
|
||||||
|
|
||||||
### MQTT
|
|
||||||
|
|
||||||
When MQTT is enabled in the config, the display loop subscribes to commands and publishes status. See [MQTT integration docs](docs/mqtt.md) for details.
|
|
||||||
|
|
||||||
## systemd services
|
## systemd services
|
||||||
|
|
||||||
Two systemd services are installed:
|
Two units are installed by `install.sh`:
|
||||||
|
|
||||||
- `spectra.service` — the display loop (fetches Unsplash, processes triggers)
|
- `spectra.service` — display loop
|
||||||
- `spectra-web.service` — the web interface (Flask + htmx)
|
- `spectra-web.service` — web interface
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo systemctl start spectra
|
sudo systemctl start spectra
|
||||||
sudo systemctl stop spectra-web
|
sudo systemctl stop spectra-web
|
||||||
sudo systemctl status spectra-web
|
|
||||||
|
|
||||||
# View logs
|
|
||||||
journalctl -u spectra -f
|
journalctl -u spectra -f
|
||||||
journalctl -u spectra-web -f
|
journalctl -u spectra-web -f
|
||||||
```
|
```
|
||||||
@@ -180,48 +164,45 @@ pytest tests/
|
|||||||
```
|
```
|
||||||
|
|
||||||
107 tests covering config loading, display processing (crop, resize, rotation),
|
107 tests covering config loading, display processing (crop, resize, rotation),
|
||||||
trigger atomicity, MQTT parsing, and the full web API (all 19 routes).
|
trigger atomicity, MQTT parsing, and all 19 API routes.
|
||||||
|
|
||||||
## Project structure
|
## Project structure
|
||||||
|
|
||||||
```
|
```
|
||||||
spectra/
|
spectra/
|
||||||
├── config.example.yaml # Example config (copy to config.yaml)
|
├── config.example.yaml
|
||||||
├── .gitignore # Ignores config.yaml (contains secrets)
|
├── .gitignore
|
||||||
├── install.sh # Installer script
|
├── install.sh
|
||||||
├── pyproject.toml # Package metadata
|
├── pyproject.toml
|
||||||
├── requirements.txt # Python dependencies
|
├── requirements.txt
|
||||||
├── spectra/
|
├── spectra/
|
||||||
│ ├── __init__.py
|
│ ├── cli.py # CLI, display loop, config hot-reload
|
||||||
│ ├── __main__.py # python -m spectra entry point
|
│ ├── config.py # Config loader with deep-merge
|
||||||
│ ├── cli.py # CLI argument parsing and main loop
|
│ ├── config_manager.py # Config read/write
|
||||||
│ ├── config.py # Configuration loader
|
│ ├── display.py # Image processing, rotation, hardware abstraction
|
||||||
│ ├── config_manager.py # Config read/write with YAML write-back
|
│ ├── fetcher.py # Unsplash API client
|
||||||
│ ├── display.py # Inky display abstraction and image processing
|
│ ├── library.py # Unsplash image caching to SQLite
|
||||||
│ ├── fetcher.py # Unsplash API client
|
│ ├── mqtt.py # MQTT client (commands + heartbeat)
|
||||||
│ ├── library.py # Unsplash image caching to SQLite library
|
│ ├── trigger.py # Thread-safe trigger file (web → display loop)
|
||||||
│ ├── mqtt.py # MQTT client (commands + status)
|
|
||||||
│ ├── trigger.py # Shared trigger file (web server → display loop)
|
|
||||||
│ └── web/
|
│ └── web/
|
||||||
│ ├── server.py # Flask app factory and API routes
|
│ ├── server.py # Flask app, 19 API routes
|
||||||
│ ├── models.py # SQLAlchemy models
|
│ ├── models.py # SQLAlchemy models
|
||||||
│ ├── templates/ # Jinja2 templates (6 pages)
|
│ ├── templates/ # 6 Jinja2 pages
|
||||||
│ ├── static/ # CSS and JS
|
│ └── static/ # CSS + JS
|
||||||
│ └── __init__.py
|
|
||||||
├── tests/
|
├── tests/
|
||||||
│ ├── test_api.py # 42 API endpoint tests
|
│ ├── test_api.py
|
||||||
│ ├── test_config.py # Config loading and deep-merge
|
│ ├── test_config.py
|
||||||
│ ├── test_display.py # Display processing and orientation
|
│ ├── test_display.py
|
||||||
│ ├── test_gallery.py # Upload + delete flow
|
│ ├── test_gallery.py
|
||||||
│ ├── test_mqtt.py # MQTT path and lookup
|
│ ├── test_mqtt.py
|
||||||
│ ├── test_orientation.py # Orientation edge cases
|
│ ├── test_orientation.py
|
||||||
│ ├── test_trigger.py # Trigger atomicity
|
│ ├── test_trigger.py
|
||||||
│ └── conftest.py # Test fixtures
|
│ └── conftest.py
|
||||||
├── systemd/
|
├── systemd/
|
||||||
│ ├── spectra.service # Display loop systemd unit
|
│ ├── spectra.service
|
||||||
│ └── spectra-web.service # Web interface systemd unit
|
│ └── spectra-web.service
|
||||||
└── docs/
|
└── docs/
|
||||||
├── display-orientation.md # Display orientation design doc
|
├── display-orientation.md
|
||||||
├── web-interface.md # Web interface documentation
|
├── web-interface.md
|
||||||
└── mqtt.md # MQTT integration documentation
|
└── mqtt.md
|
||||||
```
|
```
|
||||||
|
|||||||
Reference in New Issue
Block a user