126 lines
6.4 KiB
Markdown
126 lines
6.4 KiB
Markdown
---
|
||
name: digital-signage
|
||
description: |-
|
||
Build and maintain a multi-tenant digital signage CMS platform — Raspberry Pi kiosk players, customer upload portal, playlist management, device registration. Replaces OptiSigns ($15-30/mo).
|
||
author: Sho'Nuff
|
||
version: 1.0.0
|
||
tags: [raspberry-pi, signage, kiosk, multi-tenant, content-management]
|
||
platforms: [linux]
|
||
---
|
||
|
||
# Digital Signage CMS
|
||
|
||
Multi-tenant digital signage platform. Customers upload images/video via a web portal, create playlists, and Raspberry Pi players display content in fullscreen kiosk mode.
|
||
|
||
## Project Directory
|
||
|
||
All docs live at `/root/projects/digital-signage/`. Key files:
|
||
|
||
| File | Contents |
|
||
|------|----------|
|
||
| `README.md` | Full architecture, multi-tenant hierarchy, Pi registration flow, MVP scope |
|
||
| `optisigns-comparison.md` | Feature-by-feature comparison vs OptiSigns (what we build vs what we skip) |
|
||
| `cms/customer-setup-guide.md` | Customer-facing 9-step quick-start guide (printable) |
|
||
| `player/provisioning.md` | Zero-touch Pi provisioning — first-boot script, SD card imaging, recovery |
|
||
| `player/device-identification.md` | Hidden Ctrl+I overlay for support — device name, serial, IP, playlist |
|
||
| `mockups/` | Frontend HTML mockups (customer portal) |
|
||
|
||
## Architecture
|
||
|
||
```
|
||
Customer Web Portal Raspberry Pi Player
|
||
┌────────────────────────┐ ┌──────────────────────┐
|
||
│ Login (per tenant) │ │ Registration script │
|
||
│ Upload images/video │ API │ POST /api/register │
|
||
│ Create playlists │ ←───────→ │ Poll /api/playlist │
|
||
│ Manage devices │ │ Chromium kiosk mode │
|
||
│ Registration codes │ │ Fullscreen playback │
|
||
└────────────────────────┘ └──────────────────────┘
|
||
│
|
||
▼
|
||
FastAPI + SQLite + S3
|
||
```
|
||
|
||
### Multi-tenant hierarchy
|
||
```
|
||
Platform
|
||
├── Tenant: Joe's Diner
|
||
│ ├── Users: admin, staff@...
|
||
│ ├── Device: Main Lobby Pi
|
||
│ ├── Device: Menu Board Pi
|
||
│ └── Content: 8 items, 2 playlists
|
||
├── Tenant: Main Street Gym
|
||
│ └── Device: Front Desk Pi
|
||
└── Tenant: Third Coast Dental
|
||
├── Device: Waiting Room Pi
|
||
├── Device: Exam Room Pi
|
||
└── Device: Hallway Pi
|
||
```
|
||
|
||
Key rule: **one customer = one tenant = unlimited devices.** Content libraries are per-tenant. Playlists assignable to one or multiple devices.
|
||
|
||
## OptiSigns Replication
|
||
|
||
| Tier | What's Included | Timeline |
|
||
|------|----------------|----------|
|
||
| **Phase 1 — MVP** | Upload images/video, playlists (ordered + shuffle), multi-tenant, Pi registration, fullscreen kiosk, device identification overlay | ~2 weeks |
|
||
| **Phase 2 — Parity** | Content scheduling, multi-user per tenant, thumbnail previews, auto-update on content change | ~1 week |
|
||
| **Phase 3 — Surpass** | Sho'Nuff text-to-broadcast integration, ops portal dark theme, no OptiSigns logo, API for remote control | ~1 week |
|
||
|
||
**What we skip:** Power BI dashboards, touch interactivity, video walls, background music licensing, wireless presentation.
|
||
|
||
## Pi Provisioning — Zero Touch
|
||
|
||
1. **Image SD card** with Raspberry Pi OS lite + first-boot script (auto-login, Chromium, player service)
|
||
2. **Generate registration code** from CMS
|
||
3. **Ship Pi** to customer (HDMI + power cable included)
|
||
4. **Customer plugs in** — two cables: HDMI + power
|
||
5. **Pi boots**, auto-registers, fetches playlist, plays content
|
||
|
||
**On power loss/reboot:** Auto-restarts and resumes. Already registered → skips to content.
|
||
**On SD card failure:** Flash new card → 5 min fix → re-register from CMS.
|
||
**On TV change:** Pi auto-detects resolution via HDMI EDID. No config needed.
|
||
|
||
## Device Registration Flow
|
||
|
||
```
|
||
1. Customer portal → Devices → Register New Device → code: SIGN-4K7P-M9X2
|
||
2. Pi boots → runs registration script → POST /api/register with code + serial
|
||
3. Server: creates device under tenant → returns device_id + token
|
||
4. Pi stores token locally → starts polling GET /api/playlist/:device_id every 60s
|
||
5. CMS playlist change → Pi picks it up on next poll
|
||
```
|
||
|
||
## Device Identification Overlay
|
||
|
||
Hidden overlay triggered by Ctrl+I pressed 3 times in 2 seconds (or remote API call). Shows device name, serial, IP, playlist, model, last sync. Auto-hides after 30s. No customer sees it in normal operation.
|
||
|
||
### 3 trigger methods:
|
||
1. **Keyboard:** `Ctrl+I` × 3 within 2 seconds
|
||
2. **Remote API:** `POST /api/devices/:id/identify` (device polls `/status` every 10s)
|
||
3. **Boot flag:** `./kiosk.sh --identify`
|
||
|
||
## Resolution Handling
|
||
|
||
**Pi auto-detects via HDMI EDID.** Upload content at highest quality (4K if you have it). Pi scales to whatever display is connected. CMS does NOT need to know or care about output resolution — that's the Pi's job.
|
||
|
||
| Pi Model | Max Output | Best For |
|
||
|----------|-----------|----------|
|
||
| Pi 3 | 1080p @ 60fps | Stills, basic slideshows |
|
||
| Pi 4 | 4K @ 60fps | Mixed content, smooth video |
|
||
| Pi 5 | 4K @ 60fps HDR | Heavy video, multiple layers |
|
||
|
||
## Frontend Portal Mockup
|
||
|
||
The customer portal mockup lives at `ops.itpropartner.com/signage-mockup.html` — dark theme, 6 views (login, dashboard, content, playlists, devices, register Pi modal). Demo tenant: Joe's Diner with 3 devices.
|
||
|
||
## Pitfalls
|
||
|
||
- **Pi registration code expiry** — codes should auto-expire after 24h to prevent reuse/snooping
|
||
- **Offline playback** — player should cache the current playlist locally so it keeps playing if network drops
|
||
- **Content moderation** — uploaded files need type/size validation before storage. Allow common image formats (jpg, png, webp) and video (mp4, mov, webm). Reject executables, archives, scripts
|
||
- **Multi-user per tenant** — Phase 2 feature but plan the DB schema for it now (users table with tenant_id FK)
|
||
- **Scheduling complexity** — time-based playlists need a cron-like scheduler on the backend, not just the player polling interval
|
||
- **Player self-healing** — if Chromium crashes (OOM on Pi 3), the service should auto-restart. Player script needs `Restart=always` in the systemd unit
|
||
- **Bandwidth** — multiple Pis polling every 60s is negligible. Multiple Pis fetching 140MB video files simultaneously is not. Consider S3 signed URLs or CDN for content delivery at scale
|