adb only needs plain outbound TCP to the TV, so it runs fine in a container with normal bridge networking (no host networking or privileged mode). Bundles adb into the image via Dockerfile, adds docker-compose.yml with a persisted data/ volume, and documents two ways to fold this into another docker-compose-based repo (vendored build context vs. a published image). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RSVyYcrjrbmrMKT85G4fyn
138 lines
5.4 KiB
Markdown
138 lines
5.4 KiB
Markdown
# TV ADB Remote
|
|
|
|
A slick, installable web remote for Android TV, controlled over ADB. Run a
|
|
small Node server on any always-on machine on your home network (a Pi, NAS,
|
|
old laptop, home server); point your phone's browser at it and control the
|
|
TV from a mobile-optimized PWA.
|
|
|
|
Why a local web app instead of a native Android app: Android TV only
|
|
exposes control over ADB once you enable network debugging, and the
|
|
official ADB tooling is a desktop program. Rather than reimplement the ADB
|
|
protocol inside a phone app, this runs `adb` on a machine that already has
|
|
it, and serves a touch-friendly remote UI to any phone/tablet browser on the
|
|
LAN. Add to the home screen and it behaves like an installed app.
|
|
|
|
## Features
|
|
|
|
- Power, mute, input switch, volume rocker, channel rocker
|
|
- D-pad navigation, OK, back, home, menu
|
|
- Media transport (rewind / play-pause / fast-forward)
|
|
- Text entry (e.g. search boxes) sent as real keystrokes
|
|
- One-tap launch for common streaming apps (Netflix, YouTube, Prime Video,
|
|
Disney+, Spotify, Plex)
|
|
- Manage multiple TVs, each remembered with a friendly name
|
|
- Built-in pairing flow for Android 11+ ("Wireless debugging")
|
|
- Installable PWA with offline app shell
|
|
|
|
## Requirements
|
|
|
|
- Docker and Docker Compose on any always-on machine on your home network (a
|
|
Pi, NAS, old laptop, home server).
|
|
- The TV and that machine on the same local network.
|
|
|
|
`adb` does **not** need to run on bare metal — it's a plain TCP client that
|
|
dials out to the TV's IP once network/wireless debugging is on, so it works
|
|
fine from inside a container with normal bridge networking. No host
|
|
networking, USB passthrough, or privileged mode required. The container
|
|
image bundles `adb` itself, so nothing else needs installing on the host.
|
|
|
|
## Set up the TV
|
|
|
|
1. On the Android TV: Settings → System (or Device Preferences) → About →
|
|
tap "Build" repeatedly to enable Developer options.
|
|
2. Settings → Developer options → turn on **Network debugging** (older
|
|
Android TV) or **Settings → System → Developer options → Wireless
|
|
debugging** (Android 11+ / Google TV).
|
|
3. Note the IP address shown (Settings → Network & Internet).
|
|
- Android TV ≤ 10: that's it — the debug port (5555) is open.
|
|
- Android 11+ / Google TV: it shows a separate pairing IP:port and a
|
|
6-digit code. Use the app's "Pair a new Android 11+ TV" flow, then add
|
|
the TV using its regular IP (still port 5555 once paired).
|
|
|
|
## Run the server
|
|
|
|
```sh
|
|
docker compose up -d --build
|
|
```
|
|
|
|
This serves the app at `http://<this-machine's-LAN-IP>:8787`. Open that URL
|
|
on your phone, add your TV by IP in Settings (⚙), then optionally "Add to
|
|
Home Screen" for a full-screen, app-like remote.
|
|
|
|
Saved TVs persist in `./data/devices.json` on the host (bind-mounted into
|
|
the container), so they survive `docker compose down`/rebuilds. Override the
|
|
port by changing the `PORT` environment variable and the left side of the
|
|
`ports` mapping in `docker-compose.yml`.
|
|
|
|
### Adding this as a service in another docker-compose stack
|
|
|
|
If you're folding this into a larger compose project rather than running it
|
|
standalone, you have two straightforward options:
|
|
|
|
1. **Vendor the source** (git submodule or subtree at, say,
|
|
`services/tv-adb-remote/`) and point that stack's compose file at it:
|
|
```yaml
|
|
services:
|
|
tv-adb-remote:
|
|
build: ./services/tv-adb-remote
|
|
ports:
|
|
- "8787:8787"
|
|
volumes:
|
|
- ./services/tv-adb-remote/data:/app/data
|
|
restart: unless-stopped
|
|
```
|
|
2. **Build and push an image** (e.g. to GHCR or Docker Hub) from this repo's
|
|
CI, then reference it by tag instead of a build context — no vendored
|
|
source in the other repo at all:
|
|
```yaml
|
|
services:
|
|
tv-adb-remote:
|
|
image: ghcr.io/<you>/tv-adb-remote:latest
|
|
ports:
|
|
- "8787:8787"
|
|
volumes:
|
|
- ./tv-adb-remote-data:/app/data
|
|
restart: unless-stopped
|
|
```
|
|
This fits a "docker nearly exclusively" stack best if most of its other
|
|
services are already referenced as prebuilt images rather than local
|
|
build contexts — ask if you want a GitHub Actions workflow added here to
|
|
publish the image on push.
|
|
|
|
Either way, the only two things the other repo's compose file needs to get
|
|
right are the port mapping and a persistent volume for `/app/data`.
|
|
|
|
## Development
|
|
|
|
```sh
|
|
cd server
|
|
npm install
|
|
npm test
|
|
```
|
|
|
|
Runs the server's unit tests (command construction, input validation,
|
|
device persistence) using Node's built-in test runner — no real TV, and no
|
|
Docker, required. Useful for iterating on server code before rebuilding the
|
|
image.
|
|
|
|
## Project layout
|
|
|
|
```
|
|
Dockerfile Bundles adb + the server into one image
|
|
docker-compose.yml Standalone run config (port 8787, data/ volume)
|
|
server/ Express app + ADB bridge (source of truth for control logic)
|
|
src/adb.js Thin wrapper around the `adb` CLI (connect/pair/keyevent/…)
|
|
src/keycodes.js Android KeyEvent constants used by the remote buttons
|
|
src/deviceStore.js Persists saved TVs to data/devices.json
|
|
src/index.js HTTP API + static file serving
|
|
test/ Node test runner specs
|
|
public/ The PWA served to phones (HTML/CSS/vanilla JS, no build step)
|
|
scripts/ One-off dev scripts (icon generation)
|
|
```
|
|
|
|
## Security note
|
|
|
|
This server has no authentication and will happily run `adb` commands
|
|
against whatever IP you give it — it's designed to sit on your trusted home
|
|
LAN, not the public internet. Don't port-forward it.
|