---
name: TV Kiosk Dashboard (Mi TV)
description: MagicMirror-style kiosk Android app + web dashboard for Mi LED TV 4 PRO, served from GCP VM
type: project
---

## Mi TV Setup
- **TV:** Mi LED TV 4 PRO 55" (L55M5-AN, 2018), Android 6.0 (SDK 23), 2GB RAM, Mali 450 GPU, 4K (3840x2160)
- **TV IP on local network:** 192.168.0.4:5555 (ADB wireless debugging)
- **ADB connected via Mac** — Mac is on same LAN

## Android Kiosk App
- **Package:** `com.icedoutai.tvkiosk`
- **App name:** IcedOut TV
- **Source:** `/home/mail2arnav99/arnav/random/tv-kiosk/` (Gradle project, Java)
- **URL loaded:** `http://34.93.99.180:8880` (direct IP, not domain — TV's old WebView has DNS/HTTPS issues)
- **minSdk:** 21, **targetSdk:** 34
- **Features:**
  - Full-screen kiosk WebView, no status/nav bars
  - Auto-refresh every 5 minutes
  - Cache disabled (LOAD_NO_CACHE)
  - Menu button on remote = manual refresh (shows toast)
  - Play/Pause button = also refresh
  - Back button disabled (kiosk mode)
  - Boot receiver — auto-launches on TV power-on (`BootReceiver.java`)
  - Screen stays on (FLAG_KEEP_SCREEN_ON)
  - Landscape orientation locked

**Why:** TV's old Android 6 WebView can't handle HTTPS well (SSL cert issues), can't resolve some DNS, doesn't support CSS Grid, `backdrop-filter`, or `async/await`. Everything must be HTTP, flexbox, ES5 JS, and webkit-prefixed.

**How to apply:** When updating the app, always use ES5 JS, flexbox (not grid), webkit prefixes, and serve everything via HTTP from the VM.

## Build Environment (on GCP VM)
- **Java:** openjdk-17 at `/usr/lib/jvm/java-17-openjdk-amd64`
- **Android SDK:** `/home/mail2arnav99/android-sdk` (platforms;android-23, build-tools;30.0.3)
- **Gradle:** 7.6.4 at `/tmp/gradle-7.6.4/bin/gradle` (NOT using wrapper, using direct gradle)
- **Build command:** `cd /home/mail2arnav99/arnav/random/tv-kiosk && export ANDROID_HOME=/home/mail2arnav99/android-sdk && export ANDROID_SDK_ROOT=$ANDROID_HOME && export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64 && export PATH=$PATH:/tmp/gradle-7.6.4/bin && gradle assembleDebug`
- **APK output:** `app/build/outputs/apk/debug/app-debug.apk`

## Web Dashboard
- **Served from:** `/home/mail2arnav99/arnav/tv-dashboard/`
- **Served by:** Caddy on port 8880, proxied through nginx for `tv.icedoutai.com` on port 80
- **Style:** MagicMirror-inspired — pure black #000 bg, Roboto Condensed font (served locally as woff2), #999/#666/#fff text hierarchy
- **Layout:** Clock top-left, Weather top-right, Compliment centered, Rates bottom-left, News bottom-bar
- **Fonts:** Local woff2 files at `/home/mail2arnav99/arnav/tv-dashboard/fonts/`

### Modules
1. **Clock** — HH:MM, date, week number. Updates every 1s.
2. **Weather (Noida)** — Current temp, description, humidity, wind + 4-day forecast. From `/weather.json` and `/forecast.json`.
3. **Compliments** — MagicMirror-style time-of-day compliments (morning/afternoon/evening/anytime). Fades and rotates every 30s.
4. **Rates** — USD/INR, EUR/INR, Petrol (Noida), Diesel (Noida). From `/rates.json`.
5. **Newsfeed** — NDTV, Times of India, BBC headlines. Rotates every 15s. From `/news.json`.

### Data Feed Scripts & Crons
| Data | Script | Cron Interval | Output File |
|------|--------|---------------|-------------|
| Weather (current) | cron: curl Open-Meteo (Noida coords 28.5355,77.3910) | Every 10 min | weather.json |
| Weather (forecast) | cron: curl Open-Meteo daily endpoint | Every 6 hours | forecast.json |
| News | `fetch-news.py` (RSS: NDTV, TOI, BBC) | Every 15 min | news.json |
| Rates | `fetch-rates.py` (exchange: open.er-api.com, fuel: OpenFuel GitHub API) | Every 3 hours | rates.json |

### APIs Used (all free, no keys)
- **Weather:** `https://api.open-meteo.com/v1/forecast` (Noida: lat=28.5355, lon=77.3910)
- **Exchange rates:** `https://open.er-api.com/v6/latest/USD`
- **Fuel prices:** `https://raw.githubusercontent.com/SHN2004/OpenFuel/main/prices.json` (daily updated, has Noida)

## Reverse SSH Tunnel (VM → Mac)
- Mac can't be reached from VM directly (private IP 192.168.0.102 behind router)
- **Setup on Mac:** `ssh -i ~/.ssh/gcp-key -R 2222:localhost:22 mail2arnav99@34.93.99.180 -N -f`
- **Then from VM:** `ssh -p 2222 asharma@localhost` to access Mac
- **ADB path on Mac:** `/opt/homebrew/Caskroom/android-platform-tools/36.0.2/platform-tools/adb`
- **Requires:** Remote Login enabled on Mac (System Settings → General → Sharing)
- **VM's SSH key** (`~/.ssh/id_ed25519.pub`) is authorized on Mac's `~/.ssh/authorized_keys`
- Tunnel drops when Mac disconnects — needs to be re-established each time

## Push APK to TV (full command via SSH)
```bash
ssh -p 2222 asharma@localhost "export PATH=/opt/homebrew/Caskroom/android-platform-tools/36.0.2/platform-tools:\$PATH && curl -L -o /tmp/tvkiosk.apk 'CATBOX_URL' && adb install -r /tmp/tvkiosk.apk && adb shell am force-stop com.icedoutai.tvkiosk && adb shell am start -n com.icedoutai.tvkiosk/.MainActivity"
```

## Pending
- Latest APK (with boot receiver) not yet pushed to TV — needs SSH tunnel active
- Fonts (woff2) may not load on TV's old WebView — needs testing, may need to fallback to system sans-serif
- Dashboard stats (CPU/RAM/uptime) are fake random numbers — could hook into real VM stats
- Arnav lives in Noida, UP (not Mohali) — weather and fuel prices set to Noida

## DNS
- `tv.icedoutai.com` A record exists → 34.93.99.180 (Cloudflare proxied)
- nginx site at `/etc/nginx/sites-enabled/tv.icedoutai.com` proxies to localhost:8880
- App uses direct IP `http://34.93.99.180:8880` because TV can't resolve the domain
