Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
120 changes: 120 additions & 0 deletions LifeTrac-v25/DESIGN-CONTROLLER/BASE_STATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,126 @@ All topics under `lifetrac/v25/`. Mosquitto runs in a container on the X8 and th
- Firewall: allow inbound 80/443 from LAN only; Mosquitto 1883 LAN-only; never expose to public internet
- TLS: self-signed cert acceptable for LAN; use Let's Encrypt only if the base station is behind a publicly-routable hostname

## HTTPS / PWA setup

The operator console ships as a **Progressive Web App (PWA)**: it includes a
web-app manifest (`/manifest.json`) and a service worker (`/sw.js`) that
caches the app shell for fast load and provides a graceful offline page when
the base station is temporarily unreachable.

**PWA features require a secure origin** (HTTPS or `http://localhost`). On a
LAN the practical options are:

### Option A — Self-signed certificate + `/setup` page (recommended)

**1. Generate the cert on the base station** (one-time):

```sh
openssl req -x509 -newkey rsa:2048 -nodes \
-keyout /etc/lifetrac/key.pem \
-out /etc/lifetrac/cert.pem \
-days 3650 \
-subj "/CN=lifetrac-base" \
-addext "subjectAltName=IP:192.168.1.42,DNS:lifetrac-base.local,DNS:localhost"
```

Replace `192.168.1.42` with the base station's actual LAN IP. Add additional
`IP:` entries if the address can vary.

**2. Start uvicorn with TLS:**

```sh
uvicorn web_ui:app --host 0.0.0.0 --port 8443 \
--ssl-keyfile /etc/lifetrac/key.pem \
--ssl-certfile /etc/lifetrac/cert.pem \
--env-var LIFETRAC_TLS_CERT=/etc/lifetrac/cert.pem \
--env-var LIFETRAC_HTTPS_PORT=8443
```

Or export the env vars separately before launching uvicorn:

```sh
export LIFETRAC_TLS_CERT=/etc/lifetrac/cert.pem
export LIFETRAC_HTTPS_PORT=8443
uvicorn web_ui:app --host 0.0.0.0 --port 8443 \
--ssl-keyfile /etc/lifetrac/key.pem \
--ssl-certfile /etc/lifetrac/cert.pem
```

**3. Use the built-in `/setup` page to distribute the cert:**

Navigate to `http://<base-station-ip>:8080/setup` on each operator device.
The page:

- Shows a **Download lifetrac-cert.pem** button that fetches the public cert
directly from the base station over plain HTTP.
- Provides step-by-step install instructions for Android, iPhone/iPad, Windows,
macOS, and Linux.
- Has an **Open HTTPS Site** button that links directly to
`https://<host>:8443/` once the cert is installed.

> **Security note:** Only the public certificate is served at `/cert.pem`.
> The private key is never exposed through the web UI.

**4. Install the cert on each phone (one-time per device):**

- **Android:** tap the downloaded `.pem` → follow the CA certificate installer
→ Chrome trusts it immediately.
- **iOS:** open the `.pem` from Files or Mail → Settings → General → VPN &
Device Management → install profile → Settings → About → Certificate Trust
Settings → toggle on.

After the cert is trusted, browse to `https://<ip>:8443/`, then use **Add to
Home Screen** (Android: ⋮ menu; iOS: Share → Add to Home Screen). The app
launches in landscape full-screen mode.

### Option B — `mkcert` (easiest if you can install tools)

[`mkcert`](https://github.com/FiloSottile/mkcert) creates a local CA that is
automatically trusted by the OS cert store on the machine where it runs, and
the CA cert can be imported to phones with one step:

```sh
# On the base-station device:
apt install mkcert # or brew install mkcert
mkcert -install # installs local CA into the system store
mkcert 192.168.1.42 lifetrac-base.local localhost

# Use the generated cert with uvicorn:
uvicorn web_ui:app --host 0.0.0.0 --port 8443 \
--ssl-keyfile 192.168.1.42+2-key.pem \
--ssl-certfile 192.168.1.42+2.pem
```

Distribute `~/.local/share/mkcert/rootCA.pem` (Linux path) or
`$(mkcert -CAROOT)/rootCA.pem` to each phone using the same steps as Option A,
step 4. Phones that trust the `mkcert` root CA will trust *all* certs
generated by it, so you only distribute the root CA once.

### Option C — Reverse proxy (nginx or Caddy)

Place an HTTPS proxy in front of the FastAPI server on port 8080. Caddy with
`tls internal` issues a locally-trusted cert automatically if the `mkcert`
root CA has been installed on client devices.

### Option D — localhost only

If the operator tablet *is* the base-station device, access the UI at
`http://localhost:8080`. Browsers treat `localhost` as a secure origin and
the service worker will register normally without any certificate setup.

### What works without HTTPS

The full operator UI — joystick control, live telemetry, video stream — works
over plain HTTP. Only the PWA-specific features are gated on a secure origin:

| Feature | Plain HTTP | HTTPS / localhost |
|--------------------------|:----------:|:-----------------:|
| Operator console | ✅ | ✅ |
| Manifest (install prompt)| ✅ link only| ✅ with install |
| Service worker / offline | ❌ | ✅ |
| Add to Home Screen | ❌ | ✅ |

## Link-loss behavior

When the LoRa link to the tractor is lost (no telemetry for 30 s), the base UI shows a banner, stops sending joystick `ControlFrame`s, and leaves E-stop available. There is no Cat-M1 or MQTT-over-cellular fallback in v25; recovery is LoRa link restoration or a local hardware/service intervention.
Expand Down
Loading