Files
tajniak81andClaude Opus 5.5 bc41d8b128 Split the automatic logging path by the app that logged the flight
logging_path is now manual, automatic_flyapp or automatic_flyagentapp. The
Fly App's entries are backed by the aircraft's flight recorder and keep the
missing-FDR red flag; the Fly Agent App's come from Remote ID, which is not a
flight recorder, so they must carry the § 5 fields like a manual entry. The API
maps the old "automatic" onto automatic_flyapp so Fly App builds already on
devices keep filing. The migration has been applied to the remote PocketBase.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 19:36:16 +02:00

66 lines
3.3 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# PilotVault Fly Agent
Android companion app that runs **next to DJI Fly**. DJI Fly flies the aircraft;
the Agent listens to the aircraft's **Remote ID** broadcast, streams the paired
aircraft's position to PilotVault, and files the flight in the logbook. It uses
no DJI SDK and never sends a command, so it works with every DJI Fly aircraft
(Mavic 4 Pro, Air 3S, Mini 5 Pro, …) as long as Remote ID is broadcasting.
Plan and research: `REA/DJI Fly/PilotVault_FlyAgentApp_Plan.md` (outside this repo).
Built so far: phases **A0–A3** (login, Remote ID receiver, live uplink, flight
session → logbook). Not yet: RTMP video (A4), flight-record import (A5), media
metadata (A6), missions to DJI Fly (A7).
## Build
```bash
flutter build apk --debug
```
`build/app/outputs/flutter-apk/app-debug.apk`, package `com.pilotvault.flyagent`.
- `permission_handler` is pinned to 12.x: 13.x needs compileSdk 37.
- `kotlin.incremental=false` in `android/gradle.properties`: the project and the
pub cache are on different drives, which breaks Kotlin's incremental caches.
## How it fits
| Piece | Where |
|---|---|
| Remote ID scanners (BLE legacy + BT5, Wi-Fi NaN, Wi-Fi Beacon) in a foreground service | `android/.../flyagent/*.kt` |
| OpenDroneID decoder (ASTM F3411 / EN 4709-002) | `lib/rid/odid_decoder.dart` |
| Frames → aircraft (merged by serial across transports), pairing | `lib/rid/rid_aircraft.dart`, `rid_service.dart` |
| Live uplink to the hub, `/ws/device?id=agent-<serial>` | `lib/uplink/uplink.dart` |
| Session state machine (armed → active → landed), auto start/stop | `lib/session/flight_session.dart` |
| Filing to `POST /api/flights`, offline queue | `lib/session/session_controller.dart` |
The scanners only strip transport framing; all decoding is in Dart and unit
tested against byte-built messages (`test/`).
**API Server contract.** The only server change is the logging-path split:
- Live map: the hub already ingests `telemetry` events (`latitude`, `longitude`,
`altitude` = height above take-off, `velocityX/Y/Z` = north/east/down,
`isFlying`, `phoneLatitude/Longitude`). The Agent adds `source: "remote-id"`,
`ridSerial`, `pilotLatitude/Longitude`, `uaClass`, which ride along in the raw
event. It never sends `flightControllerSerial`, so the Web App's fleet
auto-add does not mint a drone from a Remote ID serial.
- Logbook: entries are filed with `loggingPath: "automatic_flyagentapp"`
(migration `1720301200_split_logging_path.js`; the paths are `manual`,
`automatic_flyapp`, `automatic_flyagentapp`). Remote ID is not the aircraft's
own flight recorder, so the API Server still requires every § 5 field on this
path, and the session fills them all in.
- Pairing lives on the phone (SharedPreferences), not on the drone record; a
`remote_id_serial` drone field is a later server change.
**Privacy.** Every aircraft in range is decoded, but only the paired one is
uploaded or logged. Other operators' broadcasts stay in memory on the phone.
## Limits worth knowing
- Wi-Fi Beacon Remote ID needs Android 11+ and Android throttles Wi-Fi scans to
4 per 2 minutes (turn off "Wi-Fi scan throttling" in Developer options).
An aircraft that only broadcasts over Beacon updates every ~30 s.
- Not yet checked on a real aircraft: which transport each DJI Fly aircraft uses
(research R1), and NaN on the SHT-AL09 tablet (Android 9: no Beacon IEs).