Smart Dashboard is a web interface that runs inside a browser in fullscreen kiosk mode, presenting a clean, app-grid layout similar to a smart TV home screen. Behind the scenes, a Python/Flask backend handles launching desktop apps, executing system commands, and opening web URLs - all triggered by clicking icons on the dashboard.
The key idea: everything is treated like an app. Whether it's a Flatpak desktop application (Plex, Kodi, Jellyfin), a system command (shutdown, settings), or a web URL (Twitch, a local dashboard) - they all appear as icons on the grid and launch with a single click. Web URLs don't just open in a browser tab - they launch as sandboxed web apps in their own kiosk-style Brave instance, each with its own .config directory, window class, and scaling factor. This gives web apps the same fullscreen, immersive feel as native apps.
The dashboard itself is designed to always be running. It launches on boot/login via autostart and sits as your home screen. Attempting to close it (via Alt+F4 or otherwise) triggers a confirmation prompt, so accidental exits won't happen. When you launch an app, it appears on top of the dashboard - when you close that app, you're right back at the home screen.
Everything is configurable through plain JSON files and CSS:
- apps.json - define which apps appear, their icons, launch commands, and per-app scaling
- tools.json - define system actions in the toolbar (upper right), like shutdown, settings, or custom scripts
- weather.json - set your location and weather API key
- CSS - customize colors, layout, sizing, and appearance to your taste
- static/backgrounds/ - drop in your own wallpaper images; they're auto-detected and rotate every 5 minutes with a dissolve transition
Smart Dashboard is flexible enough for many scenarios:
- Media center PC - a TV-connected mini PC with Plex, Jellyfin, Kodi, and YouTube one click away
- Workplace dashboard - a wall-mounted display showing internal tools, dashboards, or informational kiosks
- Infotainment kiosk - a public-facing screen with curated apps and no way for users to escape to the desktop
- Repurposed hardware - give an old laptop or mini PC a second life as a dedicated appliance
If you can think of a use case, you just set the apps and tools you want, point it at the URLs or Flatpak apps you need, and let it run.
- App Launcher - Click icons to launch Flatpak desktop apps (Plex, Jellyfin, Kodi, YouTube) or web apps (Twitch, custom URLs) that open as standalone kiosk windows via Brave
- Web App Management - Web apps launch in their own Brave instance with a unique window class, allowing the dashboard to cleanly close one web app before opening another
- Tools Panel - Quick access to system actions: Shutdown, Settings Manager, Input Remapper, and Close Dashboard
- Wallpaper Rotation - Automatically scans static/backgrounds/ for images and generates backgrounds.json at startup
- Weather Widget - Displays local weather using the OpenWeather API
- Kiosk Mode - The dashboard itself runs fullscreen in Brave kiosk mode, giving it the look and feel of a native smart TV interface
- Remote Friendly - Designed to work with FLIRC and input-remapper for IR remote or keyboard control; map a key to Alt+F4 to close web apps
The UI runs in a web browser and uses Python and Flask to route
The Flask backend (server.py) serves the dashboard frontend and handles two main routes:
| Route | Purpose |
|---|---|
| / | Renders the dashboard page with apps, tools, weather, and backgrounds |
| /launch?app=AppName | Launches a desktop app (Flatpak) or web app (Brave kiosk) |
| /tool?tool=ToolID | Executes a system tool/action |
Web apps (URLs starting with http:// or https://) are launched using:
/usr/bin/brave-origin-stable --app="<url>" --kiosk --class=WebApp-<Name> --name=WebApp-<Name> --user-data-dir=<unique-dir> --force-device-scale-factor=<factor>Each web app gets its own user data directory and window class, allowing the server to detect and cleanly terminate the previous web app before launching a new one.
Desktop apps are launched via their command (typically flatpak run ...).
This project was developed and tested on:
- OS: Debian 13 (Trixie)
- Desktop Environment: XFCE4
- Display Manager: LightDM
- Browser: Brave (Origin flavor)
- Target Hardware: 2011 Mac Mini (Intel HD 4000) - but should work on most Debian/XFCE setups
su -
usermod -aG sudo yourusername
exitsudo cp /etc/apt/sources.list /etc/apt/sources.list.backup
sudo nano /etc/apt/sources.listAdd contrib non-free non-free-firmware to each line:
deb http://deb.debian.org/debian trixie main contrib non-free non-free-firmware
deb http://deb.debian.org/debian trixie-updates main contrib non-free non-free-firmware
deb http://security.debian.org/debian-security trixie-security main contrib non-free non-free-firmwaresudo apt install systemd-timesyncd
sudo nano /etc/systemd/timesyncd.confNTP=time.cloudflare.com
FallbackNTP=0.debian.pool.ntp.org ntp.ubuntu.com pool.ntp.orgsudo systemctl restart systemd-timesyncd
sudo timedatectl set-ntp true
timedatectl statussudo apt install -y firmware-b43-installersudo apt install bluez blueman
sudo systemctl enable --now bluetoothsudo apt install -y net-tools network-manager pavucontrol curl wget python3-full python3-pip \
openjdk-21-jre-headless git openssh-client openssh-server gparted nfs-common python3-full \
xdotool xinput input-remapper unclutter ufw powertop v4l-utils lirc evtest onboard ffmpeg \
smartmontools flatpak lightdm lightdm-gtk-greeter lightdm-gtk-greeter-settings \
gnome-disk-utility apt-transport-https psmisc seahorse solaar curl -fsS https://dl.brave.com/install.sh | FLAVOR=origin shflatpak remote-add --if-not-exists --user flathub https://dl.flathub.org/repo/flathub.flatpakrepoflatpak install --user flathub -y \
com.github.tchx84.Flatseal \
org.localsend.localsend_app \
rocks.shy.VacuumTube \
tv.kodi.Kodi \
tv.plex.PlexHTPC \
org.jellyfin.JellyfinDesktopcurl apt.flirc.tv/install.sh | sudo bashmkdir ~/scripts
cd ~/scripts
git clone https://github.com/teklynk/smart-dashboard.git
cd smart-dashboard
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt./run.shAlways Run: You can use the run_always.sh script if you want the dashboard to re-open if it is closed. This will wait 3 seconds and launch the dashboard again. Great for when you absolutely do not want anyone to access to desktop.
The dashboard will be available at http://localhost:8080.
run.sh handles everything: generates backgrounds.json from images in static/backgrounds/, kills any existing instances, starts the Flask server, and launches Brave in kiosk mode pointing at the dashboard.
Defines the apps shown on the dashboard. Each entry includes:
| Field | Description |
|---|---|
| name | Display name (used in the launcher route) |
| icon | Path to the icon image |
| command | Flatpak command for desktop apps, or a URL for web apps |
| force-device-scale-factor | Browser zoom factor for web apps (e.g. 1.25) |
Desktop app example:
{
"name": "Plex",
"icon": "icons/plex.png",
"command": "flatpak run tv.plex.PlexHTPC",
"force-device-scale-factor": ""
}Web app example:
{
"name": "Twitch",
"icon": "icons/twitch.png",
"command": "https://twitchmultiview.teklynk.com",
"force-device-scale-factor": "1.25"
}Defines quick-action tools accessible from the dashboard. Fields:
| Field | Description |
|---|---|
| id | Unique identifier used in the /tool route |
| name | Display name |
| command | Shell command to execute |
| requires_confirmation | Whether the frontend should confirm before running |
| requires_sudo | (Currently informational; sudo is not prefixed) |
| icon | Path to the icon image |
{
"zipCode": "90210",
"apiKey": "YOUR_OPENWEATHER_API_KEY",
"units": "imperial"
}Replace the API key with your own from OpenWeather.
Place wallpaper images (.jpg, .png, .gif, .webp) in static/backgrounds/. The run.sh script auto-generates backgrounds.json at startup.
Edit the LightDM config:
sudo nano /etc/lightdm/lightdm.confUnder [Seat:*], set:
[Seat:*]
autologin-user=yourusername
autologin-user-timeout=0Add run.sh to XFCE's Session and Startup:
- Open Settings → Session and Startup
- Go to the Application Autostart tab
- Add a new entry pointing to the full path of run.sh
run.shincludesunclutterand setsxset -dpms s offto prevent the display from going to sleep.
mkdir -p ~/.local/share/applications
cp dashboard.desktop ~/.local/share/applications/The most reliable method is to tell the session manager explicitly not to launch the panel.
- Open Session and Startup (search for it in your application menu).
- Go to the Session tab (sometimes labeled Current Session).
- Locate xfce4-panel in the list of running applications.
- Change the Restart Style column for xfce4-panel to Never.
- Crucial Step: Save Session as the default and reboot.
To restore the panel, simply run xfce4-panel and go back to Session and Startup > Current Session. Set xfce4-panel to Immediately and Save Session.
Got to: Settings Manager > Keyboard. Select the Application Shortcuts and remove all keyboard shortcuts that you are not using.
You can completely disable the desktop. If you do this you may want to use the run_always.sh script so that the dashboard re-opens if it is closed.
Create a 'dummy' xfdesktop file.
sudo cp /usr/bin/xfdesktop /usr/bin/xfdesktop.realsudo rm /usr/bin/xfdesktopsudo nano /usr/bin/xfdesktopPaste the following content:
#!/bin/bash
# Fake xfdesktop script for Kiosk Mode
# This script prevents the desktop manager from running,
# effectively disabling the right-click menu, desktop icons, panels, applets...
# Do nothing. Exit immediately.
exit 0sudo chmod +x /usr/bin/xfdesktopThis does mean that you will now only be able to add apps, files via SSH. Which could be good depending on your use case.
Use input-remapper-gtk to map remote or keyboard buttons. Map a key to Alt+F4 so web apps can be closed without a keyboard.
Important: Save your preset to your home directory and set it to auto-load on login.
sudo systemctl mask sleep.target suspend.target hibernate.target hybrid-sleep.targetsudo ufw allow from 192.168.0.0/24 to any proto tcp port 22
sudo ufw enableMethod 1 - Power Manager GUI:
- Open Settings → Power Manager → Security tab
- Uncheck "Lock screen when system is going to sleep"
- Uncheck "Lock screen when system is idle"
Method 2 - Disable Screen Locker Autostart:
- Open Settings → Session and Startup → Application Autostart
- Uncheck Screen Locker (or
light-locker/xfce4-screensaver) - Reboot
- Open
pavucontrol(PulseAudio Volume Control) - Go to the Configuration tab
- Set "Built-in Audio" profile to Digital Stereo (HDMI) Output
- Go to the Output Devices tab and set HDMI as the fallback device
Find your audio device name
pactl list-sinks | grep -A1 indexSet your default audio device (replace with your device name)
pactl set-default-sink alsa_output.pci-0000_00_1b.0.hdmi-stereoDisable auto switching to other audio devices
pactl unload-module module-switch-on-port-availableMake the setting persist reboot:
nano ~/scripts/audio-setup.sh#!/bin/bash
sleep 10
pactl set-default-sink alsa_output.pci-0000_00_1b.0.hdmi-stereo
# Disable auto-switching via pactl
pactl unload-module module-switch-on-port-availableCreate a auto start application entry under Session and Startup Applications
If you are prompted to enter your password even though auto-login is enabled:
- Open
seahorsein the terminal - Delete current
Login - Create a new keyring named
Login(case-sensitive) with a blank password - Right-click it → Set as default
- Reboot - the blank-password Login keyring will auto-unlock during auto-login
Arrow keys will let you move through the main apps/icons.
Tab and Shift+Tab will let you access the Tool Bar apps/icons.
Alt+F4 will close most apps and web apps.

