An Expo (React Native) companion app for OpenFlight. It connects to the OpenFlight server over Socket.IO and mirrors the web UI's live shot data. The goal (see ROADMAP.md) is a complete standalone interface so a builder can run the Pi headless and skip the kiosk touchscreen.
The app lives in its own repo and is self-contained — it has no build-time
dependency on the server. The Shot type and socket event names are
deliberately mirrored from the Python wire contract in
open-flight/openflight (src/openflight/server.py's shot_to_dict() and
its SocketIO events) rather than shared with the web ui/.
- Node.js — the version pinned in this repo's
.node-version(currently v24), and npm. - Expo Go on your phone — the app targets Expo SDK 54. Each Expo Go build supports exactly one SDK version and it must match the project's, so you need an SDK 54 build specifically; a newer Expo Go rejects the app with "Project is incompatible with this version of Expo Go." Getting the right build differs by platform — see Get an SDK 54 Expo Go and Expo's version-mismatch troubleshooting guide. Do not upgrade the Expo SDK without confirming the Expo Go / dev-build story first — the SDK is pinned to match the maintainer's Expo Go (see AGENTS.md).
- A running OpenFlight server to connect to (see Connecting to the server).
- Your phone and computer on the same Wi-Fi / LAN.
npm installOnce dependencies are installed:
npm start # equivalently: npx expo startThis just starts Metro (it doesn't reinstall). It launches the bundler and prints a QR code in the terminal.
Each Expo Go build supports exactly one SDK version, and neither store lets you pick one — so where an SDK 54 build comes from depends on your platform. The two stores have diverged: the App Store copy is frozen at SDK 54, while the Play Store tracks the latest SDK.
| Target | How to get an SDK 54 Expo Go |
|---|---|
| iPhone (physical) | Install from the App Store — it's capped at SDK 54 because SDK 55+ was never approved by Apple, so it already matches this project. (Needing a newer Expo Go later is the awkward case, not this one: sign.expo.dev re-signs a build with a free Apple ID but the certificate lapses after ~7 days, and npx eas-cli@latest go ships one via TestFlight but needs a paid Developer Program membership.) |
| Android (device or emulator) | The Play Store serves the latest (~SDK 57), which won't run the app, and it has no version picker. Sideload the SDK 54 build instead — see below. |
| iOS Simulator | Download the SDK 54 build from expo.dev/go. |
On Android, get the SDK 54 build one of two ways:
npx expo-go download android 54 # downloads the SDK 54 Expo Go, cached in ~/.expoor pick SDK 54 + your target at expo.dev/go and install the APK (you'll enable "install unknown apps"). The sideloaded build replaces the Play Store Expo Go — one Expo Go SDK per device at a time.
For anything beyond quick local testing, use a development build instead: a binary compiled for our exact SDK, independent of whatever Expo Go version the stores ship.
- Install an SDK 54 Expo Go (see above).
- Make sure your phone and dev machine are on the same Wi-Fi network.
- Start the dev server:
npm start. - Scan the QR code:
- iOS — open the built-in Camera app and point it at the QR; tap the Expo banner.
- Android — open Expo Go and use its Scan QR code option.
- The app downloads the JS bundle from Metro and opens on your phone. Saving a file hot-reloads it.
Some networks (guest Wi-Fi, corporate APs with client isolation) block the phone from reaching Metro on your machine. Use a tunnel instead:
npx expo start --tunnelTunnel mode routes through Expo's servers (slower, needs @expo/ngrok) but
works across network boundaries.
Metro caches aggressively. Clear it so changes take effect:
npx expo start -cIf you have Xcode or Android Studio set up, you can skip the phone:
npm run ios # iOS Simulator
npm run android # Android emulatorThe app talks to the OpenFlight Python server's Socket.IO endpoint on port 8080.
-
Start a server for the app to reach. The server lives in open-flight/openflight. For development without hardware, run the mock server from a checkout of that repo:
make dev # scripts/start-kiosk.sh --mockOr run the real server on the Pi (
make start). -
Find the server machine's LAN IP:
ipconfig getifaddr en0 # macOS hostname -I # Linux / Raspberry Pi
-
In the app's connection screen, enter
http://<server-ip>:8080(e.g.http://192.168.1.100:8080). A successful connection is remembered for next launch. The default guess ishttp://192.168.1.100:8080— change it to your server's address.
The phone and the server must be on the same LAN. There is a Simulate action to generate a fake shot end-to-end once connected.
npm test # Jest (jest-expo)
npm run test:watch| Symptom | Fix |
|---|---|
| "Project is incompatible with this version of Expo Go" | Your Expo Go isn't SDK 54. Install an SDK 54 build (see Get an SDK 54 Expo Go); don't bump the SDK (see AGENTS.md). |
| App loads but can't connect to the server | Confirm phone + server share the LAN, the server is running on port 8080, the IP is correct, and no firewall blocks 8080. |
| QR scan does nothing / times out | Use npx expo start --tunnel. |
| Stale code after editing babel/entry config | npx expo start -c to clear the Metro cache. |