Self-hosted · Home Lab

The Family Wall Dashboard

A living, glanceable display that runs on a Mac mini and shows on the basement TV — weather, the family calendar, sleep & recovery, training, the home, and real daily news. No cloud, no subscriptions, and no AI tokens in the daily loop.

The family wall dashboard, rendered at the TV's native 1536×748
Live render at the TV's exact viewport (1536 × 748). Shown here with sample data — the real wall shows the family's own information, which never leaves the home network.
1 Mac mini 1 Samsung TV 6 live data sources 0 cloud services 0 AI tokens / day Launches 8:30 AM Mon–Fri

01 What it is

A single, dense HTML page generated fresh each morning and thrown full-screen onto a wall-mounted TV. Four cards carry the day's essentials — Weather, Calendar, Sleep & Recovery, and Training — over a strip of home stats and a four-category news band. It is built to stay on the wall all day and be readable from across the room.

☀️ Weather

Now plus a 3-day forecast — feels-like, wind, precip, UV — from Open-Meteo.

📅 Calendar

The next three days from the shared Google Calendar, all-day events and timed items.

🌙 Sleep & Recovery

Per-person sleep from the Sleep Number bed, plus WHOOP recovery with a live gauge.

💪 Training

This week's workouts from WHOOP — dated, named, with strain and time-in-zone toward a goal.

🏠 Home

Thermostat, humidity, lights and patio state from Home Assistant, plus sunrise/sunset.

📰 News

Top headlines in four lanes — Cincinnati, Tech & AI, Finance, Politics — from trusted feeds.

02 How it's hosted & fires to the TV

Everything lives on an always-on Mac mini. A tiny Python web server holds the page; a scheduled job opens it on the TV's browser and sends one key-press to go full-screen. The TV is a dumb display — it just points its browser at the mini over the home Wi-Fi.

🖥 Mac mini always-on home server · private LAN · reached over Tailscale Fetch scripts (cron-like) news_fetch.py · whoop_fetch.py → data.json · news.json pure Python · no LLM dashboard_gen.py renders one self-contained index.html (HTML + CSS + clock JS) python -m http.server :8099 · launchd keep-alive serves index.html on the LAN · restarts on crash or reboot launchd also runs the morning pipeline + a 4:25 AM data refresh Wi-Fi / LAN open_browser + KEY_ENTER 📺 Samsung Q80R basement · Tizen browser full-screen web page 1536 × 748 · dpr 1 clock ticks locally stays loaded all day
The mini generates and serves the page; a weekday-morning job points the TV's browser at it and full-screens it.

03 Where the data comes from

The dashboard draws on six sources. Three refresh on their own every morning — weather, WHOOP, and the news — via small Python scripts on the mini. The calendar and home / sleep panels show the most recent pull from Google Calendar and Home Assistant. Everything is baked into one static page; if a source is down, that card falls back and the rest still renders.

● REFRESHED EVERY MORNING Open-Meteo weather + 3-day forecast WHOOP API recovery · workouts · HR zones RSS feeds WLWT·WCPO·MIT TR·Ars·CNBC·NPR ◌ LATEST SNAPSHOT Google Calendar shared family calendar Home Assistant SleepIQ bed · thermostat · lights whoop_fetch.py → data.json news_fetch.py → news.json dashboard_gen.py reads the JSON snapshots, pulls weather live, bakes one page index.html one self-contained page served on the LAN
Weather, WHOOP and news refresh themselves each morning (solid); the calendar and home/sleep panels carry the latest pull (dashed). All of it bakes into one page.

04 How a day works

  1. 4:25 AM — quiet refresh. A launchd job pulls fresh news and WHOOP data and regenerates the page, so the file on disk is always current.
  2. 8:30 AM, Mon–Fri — morning launch. The pipeline fetches news + WHOOP again, regenerates, then opens the page on the TV and sends KEY_ENTER so it goes full-screen for the day.
  3. All day — it just sits there. The page never reloads, so full-screen never drops. Only the on-screen clock and greeting tick forward in the browser.
  4. Next morning — repeat. One fresh, full-screen page every weekday, with no one touching the remote.
4:25 AM · daily
Data refresh + regenerate (news, WHOOP, weather snapshot)
8:30 AM · weekdays
Full morning pipeline → launch full-screen on the basement TV
throughout the day
Static page, live clock; readable from across the room
No AI in the loop. The headlines come from trusted RSS feeds and the cards from plain APIs, so the daily run is pure Python on the mini — no language model, no per-day token cost. AI was used to design and build the dashboard, not to run it.

05 Notes for the curious

📐 Pixel-perfect

The TV's browser renders at exactly 1536 × 748. Every layout decision and screenshot is matched to that, so what's built is what shows.

🧱 One file

The whole dashboard is a single self-contained index.html — no build step, no framework, no external assets at runtime.

🔒 Stays home

Real family data never leaves the LAN. The page is served only on the home network; this public page uses sample data.

♻️ Self-healing

launchd keeps the web server alive across crashes and reboots, and the morning job re-establishes the display each weekday.

🩹 Graceful fallback

Each data source is independent. A down feed or API just thins one card; the rest of the wall renders fine.

🛰️ Reached anywhere

The mini is on Tailscale, so the dashboard and its scripts can be tended from a laptop on any network.