squawk 1.0.2
dotnet tool install --global squawk --version 1.0.2
dotnet new tool-manifest
dotnet tool install --local squawk --version 1.0.2
#tool dotnet:?package=squawk&version=1.0.2
nuke :add-package squawk --version 1.0.2
<div align="center">
π Language / Dil: English | TΓΌrkΓ§e
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β β SQUAWK βΈ Ankara 39.9476Β°N 32.6097Β°E 03:12:48 β
β βββββββββββββββββββββββββββββββββββββββββββββββ¦ββββββββββββββββββββ£
β N β AIRCRAFT β
β . . Β· . . . β βββββββββββββββββ β
β Β· THY448 Β· β CALLSIGN DIST HDG β
β Β· β Β· β ββββββββββββββββββ
β Β· Β· β β THY448 8.2km Eβ
β WΒ·----------β----------Β·E β FL280 480kt β
β Β· β Β· β SQ:2341 β
β Β· PGT891 20km Β· β β PGT891 14.7km Sβ
β Β· Β· β FL320 510kt β
β . . Β· . . . β SQ:4412 β
β S β β
β βββββββββββββββββββββββββββββββββββββββββββββββ©ββββββββββββββββββββ£
β β Son gΓΌncelleme: 03:12:35 Β· 2 uΓ§ak Sonraki: 18s β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
squawk β
A terminal-based ATC radar that shows real aircraft flying near you β in real time.
</div>
squawk pulls live flight data from the OpenSky Network API every 30 seconds and renders it in your terminal as a green phosphor radar β just like the ones air traffic controllers use.
Table of Contents
- Quick Install β start here
- Features
- Requirements
- First Run β Setup Wizard
- OpenSky Network API Setup
- Usage
- Understanding the Display
- Keyboard Shortcuts
- Reconfiguring
- Building a Single-File Binary
- Publishing to NuGet
- Security
- How It Works
- License
Features
- π’ Green phosphor radar β rotating sweep line, concentric range rings, compass labels
- β Live aircraft from OpenSky Network β updates every 30 seconds
- π‘ Configurable radius β default 20 km, overridable per-run with
--radius - π’ Rich aircraft data β flight level, speed, heading, transponder (squawk) code
- π¨ Emergency squawk highlighting β 7700/7500/7600 codes turn yellow automatically
- πΎ Credentials stored safely β your API keys and location live in your OS user data folder, never in the repo
- π₯οΈ Cross-platform β Windows Terminal, PowerShell 7+, macOS Terminal
Requirements
| Requirement | Details |
|---|---|
| .NET 10 SDK | Download here |
| Terminal | Windows Terminal or PowerShell 7+ (Windows) Β· Terminal.app or iTerm2 (macOS) |
| OpenSky Account | Free at opensky-network.org β anonymous access also works |
Why not CMD?
Classiccmd.exehas limited support for the Unicode characters (β, β, β, etc.) and ANSI colour sequences this app uses. Windows Terminal or PowerShell 7+ handle them perfectly.
Quick Install
Requires .NET 10 SDK or Runtime β the only prerequisite.
Install squawk as a global .NET tool in one command:
dotnet tool install -g squawk
Then run it from anywhere in your terminal:
squawk
The first time it launches, the Setup Wizard will ask for your location and (optionally) your OpenSky API credentials.
Updating
dotnet tool update -g squawk
Uninstalling
dotnet tool uninstall -g squawk
Installation from Source
For contributors or if you want to hack on the code:
1. Clone
git clone https://github.com/cankatabaci/squawk.git
cd squawk/src/Squawk
2. Run
dotnet run
No Docker, no npm, no Python β just .NET.
First Run β Setup Wizard
The first time you run squawk, an interactive wizard starts automatically:
dotnet run
ββββββββββββββββββββββββββββββββββββββββββββ
β β SQUAWK β Δ°lk Kurulum β
ββββββββββββββββββββββββββββββββββββββββββββ
π Konum
βΈ Konum adΔ± (ΓΆrn. Istanbul): Ankara
βΈ Enlem (Latitude, ΓΆrn. 41.0082): 39.9476
βΈ Boylam (Longitude, ΓΆrn. 28.9784): 32.6097
π‘ Radar
βΈ YarΔ±Γ§ap (km) [20]: 20
π OpenSky Network API
βΈ Client ID: YOUR_CLIENT_ID
βΈ Client Secret: YOUR_CLIENT_SECRET
β Ayarlar kaydedildi.
Your answers are saved to a config file outside the project:
| OS | Config file location |
|---|---|
| Windows | %APPDATA%\squawk\config.json |
| macOS | ~/.config/squawk/config.json |
| Linux | ~/.config/squawk/config.json |
This means your credentials and location are never committed to Git.
OpenSky Network API Setup
OpenSky provides two access levels:
Option A β Anonymous (simplest)
Just leave Client ID and Client Secret blank during setup. Anonymous access works, but has a lower daily request quota. With a 30-second refresh interval, this is usually fine for personal use.
Option B β Authenticated (recommended)
Authenticated access gives you a higher rate limit and is free.
- Create a free account at opensky-network.org
- Log in β Account β API Clients β Create new client
- You'll get a
client_idandclient_secret - Enter them when the setup wizard asks, or run
dotnet run -- --setupto re-configure
Note: As of March 2026, OpenSky uses OAuth2 client credentials (not username/password). squawk handles the token fetch and automatic renewal for you.
Usage
# Default β use whatever you configured in the wizard
dotnet run
# Override the radar radius for this session only (doesn't change saved config)
dotnet run -- --radius 50
# Override your location for this session
dotnet run -- --lat 41.0082 --lon 28.9784
# Combine options
dotnet run -- --lat 41.0082 --lon 28.9784 --radius 30
# Re-run the setup wizard (to change location, radius, or API keys)
dotnet run -- --setup
# Help
dotnet run -- --help
All CLI options
| Option | Type | Description |
|---|---|---|
--radius <km> |
float |
Radar radius in km (default: value from config, fallback 20) |
--lat <degrees> |
float |
Your latitude (overrides config for this session) |
--lon <degrees> |
float |
Your longitude (overrides config for this session) |
--setup |
flag | Re-run the interactive setup wizard |
--help |
flag | Show help |
Understanding the Display
The Radar (Left Panel)
N
. . Β· . . .
Β· Β·
Β· β Β·
Β· THY448 Β·
WΒ·---------β---------Β·E
Β· β Β·
Β· PGT891 20kmΒ·
Β· Β·
. . Β· . . .
S
| Element | Meaning |
|---|---|
β |
Your position β the center of the radar |
N / S / E / W |
Compass labels β North, South, East, West |
. . Β· . . |
Range rings β three concentric circles at 1/3, 2/3, and full radius |
20km |
Range label β the outermost ring's distance (your configured radius) |
β |
Aircraft β positioned on the radar according to their real bearing and distance from you |
Callsign below β |
Flight identifier β the aircraft's callsign (e.g., THY448) or ICAO address if no callsign is available |
| Rotating bright line | Sweep line β completes one full rotation every 30 seconds, in sync with the API refresh |
| Fading trail behind sweep | Persistence effect β mimics the phosphor glow fade on real radar screens |
How to read where an aircraft is:
The radar is a top-down map. If a β appears in the upper-right area of the circle, that aircraft is to your northeast. If it's near the edge, it's close to your maximum range. If it's near the center, it's close to you.
Aircraft List (Right Panel)
Each aircraft gets two lines:
β THY448 8.2km E β
FL280 480kt SQ:2341
Line 1
| Field | Example | Meaning |
|---|---|---|
β |
β |
Aircraft indicator |
| Callsign | THY448 |
The flight's radio callsign. Airlines use codes like THY (Turkish Airlines), PGT (Pegasus), SXS (SunExpress). If no callsign is broadcast, the ICAO hex address is shown instead. |
| Distance | 8.2km |
Straight-line distance from your location to the aircraft, calculated using the Haversine formula |
| Heading | E |
The direction the aircraft is flying toward (not the direction from you to the aircraft β that's shown by where the β icon sits on the radar). See Compass Directions. |
| Vertical | β β β |
Whether the aircraft is climbing (β), descending (β), or in level flight (β) |
Line 2
| Field | Example | Meaning |
|---|---|---|
| Flight Level | FL280 |
Altitude expressed as a Flight Level β FL280 means approximately 28,000 feet (about 8,534 metres). Divide FL by 10 to get a rough kilometre figure: FL280 β 8.5 km up. |
| Speed | 480kt |
Groundspeed in knots (kt). 1 knot = 1.852 km/h. Typical cruising speed is 450β500 kt for commercial jets. |
| Squawk | SQ:2341 |
The transponder code the pilot has dialled in. A 4-digit code assigned by air traffic control to identify the flight on radar. See Special Squawk Codes. |
Compass Directions
The HDG (Heading) column shows which direction the aircraft is flying, split into 8 compass points:
| Code | Full name | Meaning |
|---|---|---|
N |
North | Flying toward north (roughly 0Β° / 360Β°) |
NE |
Northeast | Flying toward northeast (~45Β°) |
E |
East | Flying toward east (~90Β°) |
SE |
Southeast | Flying toward southeast (~135Β°) |
S |
South | Flying toward south (~180Β°) |
SW |
Southwest | Flying toward southwest (~225Β°) |
W |
West | Flying toward west (~270Β°) |
NW |
Northwest | Flying toward northwest (~315Β°) |
-- |
Unknown | The aircraft is not broadcasting its heading |
Example: A flight showing SW in the HDG column is heading toward southwestern Europe or the Mediterranean. A flight showing NE might be heading toward Russia or Central Asia.
Heading vs. position on radar:
HDGtells you where the aircraft is going.
Where theβicon sits on the radar circle tells you where the aircraft is relative to you.
These are two different things β a plane can be to your north while flying south (it already passed you and is heading away).
Special Squawk Codes
These codes are internationally standardised emergency transponder codes. When squawk detects one, it highlights the aircraft row in yellow:
| Code | Display | Meaning |
|---|---|---|
7700 |
SQ:7700β |
General emergency β the aircraft has declared an emergency (engine failure, medical, fuel, etc.) |
7600 |
SQ:7600π» |
Radio failure β the aircraft has lost communication with ATC |
7500 |
SQ:7500π¨ |
Hijacking β the aircraft is being hijacked |
All other codes (e.g., SQ:2341) are normal ATC-assigned codes with no special meaning visible to the public.
Status Bar
β Son gΓΌncelleme: 03:12:35 Β· 2 uΓ§ak Sonraki: 18s
| Element | Meaning |
|---|---|
β |
Green = data loaded successfully |
β |
Blinking = currently fetching from API |
β |
Yellow = last API request failed |
Son gΓΌncelleme: HH:MM:SS |
Timestamp of the last successful data refresh |
N uΓ§ak |
Number of aircraft currently detected within your radius |
Sonraki: Ns |
Countdown in seconds until the next API request |
Keyboard Shortcuts
| Key | Action |
|---|---|
R |
Force an immediate API refresh (don't wait for the 30s timer) |
Q or Esc |
Quit squawk |
Ctrl+C |
Graceful shutdown |
Reconfiguring
Changed location? New OpenSky credentials? Run the setup wizard again:
dotnet run -- --setup
Or edit the config file directly:
Windows: %APPDATA%\squawk\config.json
macOS/Linux: ~/.config/squawk/config.json
{
"OpenSky": {
"ClientId": "your-client-id",
"ClientSecret": "your-client-secret",
"TokenUrl": "https://auth.opensky-network.org/auth/realms/opensky-network/protocol/openid-connect/token"
},
"Location": {
"Latitude": 39.9476,
"Longitude": 32.6097,
"Name": "Ankara"
},
"Radar": {
"RadiusKm": 20,
"RefreshSeconds": 30
}
}
Tip: You can also use environment variables to override any setting without touching the file, using the prefix
SQUAWK_. For example:SQUAWK_Radar__RadiusKm=50 dotnet run
Building a Single-File Binary
To get a standalone squawk executable you can run from anywhere without dotnet run:
Windows (x64):
dotnet publish -c Release -r win-x64 --self-contained -p:PublishSingleFile=true -o out/win
# Result: out/win/squawk.exe
macOS (Apple Silicon):
dotnet publish -c Release -r osx-arm64 --self-contained -p:PublishSingleFile=true -o out/mac
# Result: out/mac/squawk
macOS (Intel):
dotnet publish -c Release -r osx-x64 --self-contained -p:PublishSingleFile=true -o out/mac-intel
Linux (x64):
dotnet publish -c Release -r linux-x64 --self-contained -p:PublishSingleFile=true -o out/linux
After publishing, add the binary to your PATH to run it from anywhere as just squawk.
Publishing to NuGet
This is how you publish a new version so anyone can dotnet tool install -g squawk.
One-time setup
1. Create a NuGet account
Go to nuget.org β Sign in with your GitHub or Microsoft account β API Keys β Create β name it squawk-publish, set Glob pattern to squawk, copy the key.
2. Add the key to your GitHub repo
GitHub repo β Settings β Secrets and variables β Actions β New repository secret
Name: NUGET_API_KEY, Value: the key you just copied.
3. Fill in your details in Squawk.csproj
Replace YOUR_NAME and YOUR_GITHUB_USERNAME with your actual name and GitHub username β or just leave them as Cankat ABACI and cankatabaci if you've already filled them in.
Check the package name! Before publishing, search nuget.org/packages/squawk to see if
squawkis taken. If it is, change<PackageId>to something unique likesquawk-radarorsquawk-atc. The<ToolCommandName>squawk</ToolCommandName>can stay assquawkβ that's the command users type in the terminal.
Publishing (automated via GitHub Actions)
# 1. Commit all your changes
git add .
git commit -m "feat: first release"
# 2. Tag the release β this triggers the workflow
git tag v1.0.0
git push origin main --tags
That's it. The GitHub Actions workflow automatically:
- Builds the NuGet package with version
1.0.0 - Pushes it to nuget.org
- Creates a GitHub Release
Publishing (manual)
dotnet pack src/Squawk/Squawk.csproj -c Release -p:Version=1.0.0 -o nupkg
dotnet nuget push nupkg/squawk.1.0.0.nupkg \
--api-key YOUR_NUGET_API_KEY \
--source https://api.nuget.org/v3/index.json
Releasing a new version
# bump <Version> in Squawk.csproj to 1.0.1, then:
git add .
git commit -m "fix: something"
git tag v1.0.1
git push origin main --tags
Security
| What | Where it lives | In the repo? |
|---|---|---|
| OpenSky Client ID & Secret | %APPDATA%\squawk\config.json |
β No |
| Your latitude & longitude | %APPDATA%\squawk\config.json |
β No |
| Default config template | src/Squawk/appsettings.json |
β Yes β all values are empty strings |
| Source code | src/Squawk/ |
β Yes β no secrets anywhere |
The appsettings.json file that ships with the source code contains only empty placeholders. Your real credentials are saved to your OS user data folder, which is listed in .gitignore.
How It Works
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Every 30 seconds β
β 1. Compute bounding box around your location β
β 2. GET /api/states/all?lamin=...&lomin=... β
β with Bearer token (OAuth2 client_credentials) β
β 3. Parse JSON state vectors β
β 4. Calculate Haversine distance for each aircraft β
β 5. Filter to radius, sort by distance β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Every ~80ms (12 FPS) β
β 1. Advance sweep angle by 1.2Β° β
β (360Β° / 30s = 12Β°/s = 1.2Β° per 80ms frame) β
β 2. Draw to off-screen char buffer (clear β rings β β
β crosshairs β sweep trail β sweep line β aircraft) β
β 3. Diff render: only write changed terminal cells β
β β no flicker, minimal I/O β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Key design choices:
- No external UI library β raw ANSI escape codes for full control and minimal dependencies
- Diff rendering β the canvas compares current and previous frame; only changed characters are written to the terminal, eliminating flicker
- Aspect ratio correction β terminal character cells are roughly 2Γ taller than wide, so the vertical radar radius is set to half the horizontal radius to produce a visually circular display
- Bearing β screen position β aircraft are placed using
sin(bearing)for X and-cos(bearing)for Y, which correctly maps geographic bearings (0Β° = North, clockwise) to screen coordinates (Y increases downward)
License
MIT β do whatever you want with it.
<div align="center"> Made with β and too much curiosity about the planes overhead. </div>
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
This package has no dependencies.