# Factory Deployment

This process provisions a clean Raspberry Pi OS device for a customer. Remote
update ZIPs are for software upgrades; a new device must first receive the
application, dependencies and system service.

## Build The Initial Release

Build on the Windows development computer:

```powershell
cd "C:\path\to\plane-tracker"

python tools\build_update.py `
  --version 1.0.9 `
  --base-url "https://planesintheclouds.com/pitc-core/core-deployment" `
  --notes "Factory release"
```

The generated ZIP deliberately excludes `config`, `.cache`, `data`, logs and
secrets. Never copy the development directory directly to a customer device.

## Prepare Raspberry Pi OS

1. Flash current Raspberry Pi OS Lite.
2. Create the `admin` user and enable SSH for factory work.
3. Attach the RGB panel hardware.
4. Copy the release ZIP to the Pi, for example `/tmp/plane-tracker.zip`.
5. Extract it to a temporary directory:

```bash
mkdir -p /tmp/plane-tracker-release
unzip /tmp/plane-tracker.zip -d /tmp/plane-tracker-release
cd /tmp/plane-tracker-release
```

## Install

```bash
sudo bash tools/factory_install.sh \
  --user admin \
  --install-rgb-matrix
```

The installer:

- installs operating-system and Python dependencies;
- increases swap to 1 GB on Pis with less than 1 GB RAM when required;
- builds the official `hzeller/rpi-rgb-led-matrix` Python binding;
- copies the sanitized release to `/home/admin/its-a-plane-python`;
- creates clean configuration and database directories;
- installs and enables `its-a-plane.service`;
- enables NetworkManager;
- grants only the required `nmcli` and service-restart sudo commands;
- generates a device-specific setup Wi-Fi password;
- validates the installation and starts the service.

Record the displayed setup password on the device label.

The RGB matrix source and binding are supplied by the upstream project:

https://github.com/hzeller/rpi-rgb-led-matrix/tree/master/bindings/python

The installer limits the CMake build to one compiler job. This is important on
512 MB Pi models, where parallel compilation can exhaust memory and swap. It
also configures a 1 GB swap file automatically before compiling. Use
`--skip-swap-setup` only when swap is managed separately.

## Customer First Run

With no saved home Wi-Fi, the tracker creates a setup network after boot:

```text
SSID: PlaneTracker-Setup-XXXXXX
Page: http://10.42.0.1:8080/wifi-setup
```

The customer joins that network using the password on the device label,
selects their home Wi-Fi, and enters its password. The tracker then connects to
the home network.

Complete location, panel count, units, API sources and remote-update settings
at:

```text
http://<device-ip>:8080/config
```

Use this manifest URL:

```text
https://planesintheclouds.com/pitc-core/core-deployment/manifest.json
```

## Factory Validation

Run at any time:

```bash
cd /home/admin/its-a-plane-python
sudo -u admin .venv/bin/python tools/factory_check.py
sudo systemctl status its-a-plane.service --no-pager
```

## Preparing A Master SD Image

After validating one device, stop the service before capturing the image:

```bash
sudo systemctl stop its-a-plane.service
```

Remove customer/runtime state:

```bash
cd /home/admin/its-a-plane-python
sudo rm -rf config data .cache .updates
sudo rm -f api_calls.log api_usage.json airlabs_usage.json
sudo rm -f flightaware_usage.json tracked_flight.json wifi_connect.log
sudo nmcli connection delete its-a-plane-setup 2>/dev/null || true
```

Do not remove `/etc/default/its-a-plane`; it contains that physical device's
setup password. For cloned images, rerun the factory installer once on each
device so the password is derived from its own serial number.

Shut down cleanly before imaging:

```bash
sudo poweroff
```

The first application start recreates clean configuration and databases.
