A self-hosted, Docker-based family home dashboard designed for a living-room wall display. Shows live weather, Swiss public transport departures, Google Calendar events, public holidays, a background photo slideshow, and a scrolling news ticker — all in one always-on screen.
git clone https://github.com/techlotse/TL-Dashboard-Core.git
cd TL-Dashboard-Core
cp .env.example .envOpen .env in a text editor and fill in your values (see Configuration below). At minimum, set your coordinates (WEATHER_LAT / WEATHER_LON) and your SBB station name (SBB_STATION_NAME).
Place .jpg, .jpeg, .png, or .webp photos in the ./backgrounds/ folder inside the project directory:
TL-Dashboard-Core/
└── backgrounds/
├── family-photo-1.jpg
├── holiday-2024.jpg
└── ...
The slideshow rotates through all images automatically. If the folder is empty, a dark gradient is shown instead.
docker compose up -dOpen http://localhost:18181 in a browser (or point your kiosk browser at it).
# View logs
docker compose logs -f
# Stop
docker compose downRaspberry Pi? The images are built for both
linux/amd64andlinux/arm64— the same command works on Pi 4/5.
All configuration lives in your .env file. Copy .env.example to .env and edit as needed.
| Variable | Default | Description |
|---|---|---|
APP_TIMEZONE |
Europe/Zurich |
IANA timezone for the clock and scheduling |
| Variable | Default | Description |
|---|---|---|
WEATHER_LAT |
47.3769 |
Latitude of your location |
WEATHER_LON |
8.5417 |
Longitude of your location |
REFRESH_WEATHER_MINUTES |
30 |
How often to refresh weather data |
Powered by Open-Meteo — no API key required.
| Variable | Default | Description |
|---|---|---|
SBB_STATION_NAME |
Zürich HB |
Exact station name (e.g. Bern, Basel SBB, Lausanne) |
REFRESH_TRANSPORT_SECONDS |
60 |
How often to refresh the departure board |
COMMUTE_ENABLED |
true |
Show commute route options |
COMMUTE_FROM_STATION |
(empty) | Commute origin — defaults to SBB_STATION_NAME if blank |
COMMUTE_TO_STATION |
(empty) | Commute destination — leave blank to hide the commute section |
COMMUTE_DEPARTURE_TIME |
07:30 |
Morning departure time (HH:mm) |
COMMUTE_RETURN_TIME |
17:30 |
Evening return time (HH:mm) |
COMMUTE_WINDOW_MINUTES |
120 |
Minutes after target time before switching to next-day options |
COMMUTE_MAX_OPTIONS |
3 |
Number of route options shown per direction |
Powered by transport.opendata.ch — no API key required.
| Variable | Default | Description |
|---|---|---|
CALENDAR_ICAL_URL |
(empty) | iCal URL from Google Calendar settings (easiest option) |
GOOGLE_CALENDAR_ID |
(empty) | Calendar ID for API access (alternative to iCal) |
GOOGLE_SERVICE_ACCOUNT_KEY_FILE |
/run/secrets/google_sa_key.json |
Container path to service account JSON |
CALENDAR_LOOKAHEAD_DAYS |
14 |
How many days ahead to fetch |
CALENDAR_DISPLAY_DAYS |
14 |
How many days of events to show in the widget |
REFRESH_CALENDAR_MINUTES |
5 |
How often to refresh calendar |
See Google Calendar Setup below.
| Variable | Default | Description |
|---|---|---|
HOLIDAY_COUNTRY |
CH |
ISO country code |
HOLIDAY_TOWN_1 |
ZH |
Canton code for cantonal holidays (e.g. ZH, BE, GE) |
HOLIDAY_TOWN_2 |
(empty) | Second canton code (optional) |
HOLIDAYS_MAX_ITEMS |
8 |
Maximum number of upcoming holidays to display |
Powered by Nager.Date — no API key required.
| Variable | Default | Description |
|---|---|---|
RSS_FEEDS |
BBC World + SRF | Comma-separated list of RSS/Atom feed URLs |
REFRESH_RSS_MINUTES |
10 |
How often to refresh feeds |
RSS_MAX_ITEMS |
20 |
Maximum headlines per feed |
RSS_ITEM_DURATION_SECONDS |
10 |
Seconds each headline is shown in the ticker |
| Variable | Default | Description |
|---|---|---|
BACKGROUND_IMAGE_PATH |
/app/backgrounds |
Container path for images (leave as-is) |
BACKGROUND_INTERVAL_SECONDS |
15 |
Seconds between photo changes |
- Open Google Calendar in a browser
- Click Settings (gear icon) → Settings
- In the left sidebar, click your calendar name
- Scroll down to Integrate calendar
- Copy the "Secret address in iCal format" link
- Paste it into
.env:
CALENDAR_ICAL_URL=https://calendar.google.com/calendar/ical/...
- Go to Google Cloud Console → APIs & Services → Library
- Enable the Google Calendar API
- Go to Credentials → Create Credentials → Service Account, give it a name and click Done
- Click the new service account → Keys → Add Key → JSON → download the file
- Open Google Calendar → Settings → [Your Calendar] → Share with specific people
- Add the service account email (
name@project.iam.gserviceaccount.com) with "See all event details" permission - Copy your Calendar ID from Calendar settings → Integrate calendar
- Place the downloaded JSON key file on your server (e.g.
/home/user/google-sa-key.json) - Uncomment the volume line in
docker-compose.yml:
- /home/user/google-sa-key.json:/run/secrets/google_sa_key.json:ro- Set in
.env:
GOOGLE_CALENDAR_ID=your-calendar-id@group.calendar.google.com
GOOGLE_SERVICE_ACCOUNT_KEY_FILE=/run/secrets/google_sa_key.json
To launch the dashboard automatically in full-screen on startup:
sudo apt install chromium-browser
mkdir -p ~/.config/autostart
cat > ~/.config/autostart/dashboard.desktop << EOF
[Desktop Entry]
Type=Application
Name=TL-Dashboard
Exec=chromium-browser --kiosk --noerrdialogs --disable-infobars --app=http://localhost:18181
EOFFor a dedicated Pi display, also add to /etc/xdg/lxsession/LXDE-pi/autostart:
@xset s off
@xset -dpms
@xset s noblank
Pull the latest images and restart:
docker compose pull
docker compose up -dNo background photos visible — check that .jpg/.jpeg/.png/.webp files are present in ./backgrounds/. The folder must exist even if empty.
Calendar shows "unavailable" — verify your iCal URL or service account key path. Check backend logs: docker compose logs backend.
SBB shows no departures — ensure SBB_STATION_NAME matches exactly how the station appears on the SBB website (e.g. Zürich HB, not Zurich HB).
Port 18181 already in use — change the host port in docker-compose.yml from 18181:80 to another port.
Technical details, API endpoint reference, project structure, and local development setup are documented in docs/ARCHITECTURE.md.
MIT