Hotel Pi - Raspberry Pi TV Kiosk System
A production-grade, hotel-style TV kiosk application built with SvelteKit, Node.js, and Directus CMS.
Overview
Hotel Pi provides a fullscreen, remote-controlled kiosk interface for Raspberry Pi 4/5, designed to mimic modern hotel TV systems with:
- Idle Screen: Time, date, and welcome message with ambient visuals
- Home Menu: Gridded navigation to main features
- Dynamic Content: Restaurants and attractions from Directus CMS
- Media Integration: Seamless Plex/Kodi launch support
- Remote Control: HDMI-CEC input handling via Node.js service
- WebSocket Communication: Real-time event delivery between control service and frontend
Architecture
┌─────────────────────────────────────────────────────┐
│ Chromium Kiosk (fullscreen) │
│ SvelteKit Frontend (localhost:5173) │
└───────────────────┬─────────────────────────────────┘
│ WebSocket
┌───────────────────▼─────────────────────────────────┐
│ Node.js Control Service (localhost:3001) │
│ - HDMI-CEC listener (cec-client) │
│ - System command executor │
│ - WebSocket event emitter │
└───────────────────┬─────────────────────────────────┘
│
┌───────────┴────────────┬──────────────┐
│ │ │
┌───────▼──────────┐ ┌──────────▼────────┐ │
│ Directus CMS │ │ PostgreSQL DB │ │
│ REST API │ │ │ │
└──────────────────┘ └───────────────────┘ │
│
┌───────────▼─────────┐
│ System Services │
│ - Plex │
│ - Kodi │
│ - Chromium │
└─────────────────────┘
Quick Start
Prerequisites
- Node.js 18+
- Docker & Docker Compose
- Raspberry Pi 4 or 5 (or Linux/macOS for development)
Setup
-
Clone and install dependencies:
git clone <repo> cd Hotel_Pi cp .env.example .env -
Start services with Docker Compose:
docker-compose up -d -
Run frontend (development):
cd frontend npm install npm run dev -
Run control service (in separate terminal):
cd control-service npm install npm run dev -
Access the system:
- Frontend: http://localhost:5173
- Directus: http://localhost:8055
- Control Service: ws://localhost:3001
Directory Structure
Hotel_Pi/
├── frontend/ # SvelteKit application
│ ├── src/
│ │ ├── routes/ # Page components
│ │ ├── lib/ # Shared utilities
│ │ ├── components/ # Reusable UI components
│ │ └── app.svelte # Root layout
│ ├── svelte.config.js
│ └── package.json
├── control-service/ # Node.js control service
│ ├── src/
│ │ ├── server.js # Main entry point
│ │ ├── cec-handler.js # HDMI-CEC listener
│ │ └── commands.js # System command executor
│ └── package.json
├── directus/ # CMS configuration
│ ├── extensions/
│ └── snapshots/
├── docker/ # Docker Compose files
│ └── docker-compose.yml
├── scripts/ # Launch and control scripts
│ ├── launch-kiosk.sh
│ ├── launch-plex.sh
│ └── return-to-kiosk.sh
└── docker-compose.yml # Main orchestration
Configuration
See .env.example for all available configuration options.
Key settings:
VITE_API_URL: Directus API endpointVITE_WS_URL: Control service WebSocket endpointCEC_DEVICE: Serial device for HDMI-CEC (typically/dev/ttyAMA0)IDLE_TIMEOUT_MINUTES: Auto-return to idle screen after this duration
Development
Frontend Development
cd frontend
npm run dev
Hot-reload enabled. Access at http://localhost:5173
Control Service Development
cd control-service
npm run dev
WebSocket server available at ws://localhost:3001
CMS Setup
Directus runs at http://localhost:8055
Default credentials (change in production):
- Email: admin@example.com
- Password: (set during first run)
Deployment (Raspberry Pi)
-
Install system dependencies:
sudo apt-get update sudo apt-get install -y docker.io docker-compose chromium-browser libcec-dev -
Build production bundle:
cd frontend npm run build -
Deploy with Docker Compose:
docker-compose -f docker/docker-compose.yml up -d -
Launch kiosk (runs on startup):
./scripts/launch-kiosk.sh
Input Handling
HDMI-CEC Remote Events
- Arrow Keys: Navigate menu
- Select/OK: Choose item
- Back: Return to previous screen
- Any key: Wake from idle screen
Control service translates CEC codes and emits WebSocket events.
Performance Optimization
- CSS animations preferred over JavaScript
- Lazy loading for images
- Optimized SVG assets
- Minimal JavaScript dependencies
- Service worker caching
Production Considerations
- Change all default credentials
- Set up HTTPS for Directus (if public)
- Configure CORS properly
- Set environment-specific secrets
- Enable log rotation
- Set up health checks
- Configure automatic restarts
Troubleshooting
HDMI-CEC not working
- Check device:
ls -la /dev/ttyAMA0 - Test with
cec-clientcommand directly - Verify CEC is enabled on TV
WebSocket connection fails
- Check firewall rules
- Ensure control service is running:
curl http://localhost:3001/health - Review browser console for connection errors
Frontend not loading
- Check Docker logs:
docker logs hotel_pi_frontend - Verify API URL in
.env - Clear browser cache
Contributing
- Create a feature branch
- Make changes following the code style
- Test on Raspberry Pi if possible
- Submit a pull request
License
MIT
Support
For issues and questions, please open an issue on GitHub.