Metadata-Version: 2.4
Name: air-status
Version: 0.1.1
Summary: Live in-flight status from airline Wi-Fi portals, with a terminal map and flight history
License-Expression: MIT
Project-URL: Homepage, https://github.com/max2697/air-status
Project-URL: Issues, https://github.com/max2697/air-status/issues
Keywords: flight,in-flight wifi,terminal,tui,map,aviation
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: End Users/Desktop
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Topic :: Utilities
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: rich>=13
Provides-Extra: dev
Requires-Dist: pytest>=8; extra == "dev"
Requires-Dist: ruff>=0.6; extra == "dev"
Requires-Dist: build>=1; extra == "dev"
Requires-Dist: twine>=5; extra == "dev"
Dynamic: license-file

# air-status

Live flight status in the terminal while you're on board, read from the airline's
in-flight Wi-Fi portal: altitude, speed, ETA, a Braille map of the route, and a
saved history of every flight.

![air-status live view: route bar, flight stats and a Braille map of the flown path](https://raw.githubusercontent.com/max2697/air-status/main/docs/screenshot.png)

<sub>Made-up flight. Regenerate with `python scripts/screenshot.py`.</sub>

## Install

```bash
pipx install air-status        # or: pip install air-status
air-status
```

From a checkout, for development:

```bash
python3 -m venv .venv
source .venv/bin/activate
pip install -e '.[dev]'
```

## Use

```bash
air-status                               # live view, airline detected from the Wi-Fi, saves history
air-status live -p american              # pick the airline: aircanada, american
air-status live -p aircanada --every 10  # refresh every 10 s
air-status history                       # list saved flights
```

Run it in a real terminal for the live full-screen view. In a plain output window
(e.g. PyCharm's Run tab) it prints one frame per update instead.

Files go in the current folder (change with `--data-dir`):

- `history/<provider>/` — one file per flight, in that provider's own format.
  Air Canada (Gogo) stores the raw portal data as change-only JSON Lines: the
  first line is the full reading, later lines hold only the fields that changed.
  Your device's IP/MAC address is never saved.
  American Airlines stores the Viasat flight feed plus the route's airport
  locations (looked up once from the portal) in the same change-only format.
  Its feed has no vertical speed, so climb/descent is worked out from the
  altitude change over the last minute (and saved too).
- `mapdata/` — map outlines from [Natural Earth](https://www.naturalearthdata.com/),
  downloaded on first run.

The map draws the flown path from history (solid red). Where there is no history,
such as before recording started or during gaps over 60 s, it draws an estimated
shortest-path line between the known points (dashed red).

## Adding an airline

Providers live in `src/air_status/providers/`. A provider:

- `fetch()` — gets a raw reading from its portal,
- `parse(reading)` — turns it into the shared `FlightStatus` (`models.py`),
- `history(directory)` — returns its `FlightHistory` (`flightlog.py`), which
  decides how readings are written and read back. Reuse `ChangeLog` for
  change-only JSON Lines, or implement your own format.

Auto-detect (the default, `-p auto`) asks every provider's portal at once via
`detect()` and uses the first that returns flight data. The default `detect()`
is "fetch and parse succeed"; override it when portals are shared (Gogo
providers also check `airline_code`).

Same Wi-Fi system as an existing provider (e.g. another Gogo/Intelsat airline):
subclass it and set `id`, `name` and `airline_code`, like `aircanada.py`. Then add an instance
to `PROVIDERS` in `providers/__init__.py`.

## Tests and lint

```bash
pytest
ruff check .
ruff format .
```

GitHub Actions (`.github/workflows/ci.yml`) runs the same lint plus tests on
Python 3.9–3.14 for every push to `main` and every pull request.

## Releasing

1. Bump `__version__` in `src/air_status/__init__.py` and commit.
2. Tag and push: `git tag v0.2.0 && git push origin v0.2.0`.

`.github/workflows/release.yml` checks the tag matches the version, runs lint
and tests, builds the package, publishes it to PyPI (trusted publishing, no
token) and creates a GitHub release with the built files.

## License

MIT, see [LICENSE](LICENSE).
