NWS Weather TUI
A terminal weather app for the US and its territories, powered by the National Weather Service API. Built with Python and curses. Every view adapts to the size of your terminal, from an 80-column window up to an ultrawide one.
Developed and tested mainly on Linux. macOS works but gets less testing.
Screenshots show Columbus, Ohio.
Features
Current conditions (c)
- Temperature in large block digits, colored by how warm it is, plus conditions, dew point, wind, gusts, humidity, pressure and visibility from the nearest NWS station
- Heat index or wind chill when it differs meaningfully from the air temperature
- Air quality and UV index
- An animated windsock that droops, fills and flutters with the wind speed
- The moon, shaded to its current phase, in the space under the conditions
- A radar panel. On wide terminals it sits beside the conditions at full height, the map widens east and west to fill the space, and the NWS forecast for today and tonight fills the column under the conditions
Radar
- 256-color half-block rendering (▀/▄) on the NWS dBZ color scale, with an ASCII fallback for terminals without 256 colors
- Animation:
Aplays recent frames,</>step through them - While frames load, the panel shows a spinner and how many are in
- State borders, city labels, and polygons for active warnings drawn in red
◉ youmarks your location; click a city label to jump there- Three sources, tried in order: NOAA MRMS composite, Iowa State IEM NEXRAD, the NWS station WMS
oopens weather.gov radar in your browser
Forecast (f)
- A column per day, with all seven days side by side from about 120 columns wide (
←/→scroll on narrower terminals) - Each day shows the high and low (colored by temperature), the icon and summary, chance of precipitation, wind, and sunrise and sunset
- The NWS day and night forecast text fills the rest of each column
Hourly (h)
- The full hourly forecast the NWS publishes, about 6½ days
- An "at a glance" list that calls out what's notable instead of charting the obvious daily temperature curve: when rain starts and stops and how much, lightning risk, gusts, feels-like divergence, temperature swings that run against the day/night cycle (fronts), humidity, and clearing or clouding over
- A condition ribbon covering the whole period, with a tick for each day
- On wide terminals, a column per day with hours running down the rows, sunrise/sunset markers, and a summary for each day (daylight, feels-like range, strongest gust, precipitation total)
- On narrower terminals, a scrolling table grouped by day with feels-like, dew point, sky cover, gust and precipitation columns
Area Forecast Discussion (d)
- The latest forecaster narrative from your local NWS office, laid out in newspaper columns. The number of columns follows the terminal size while keeping lines a comfortable reading width
- The raw product is cleaned up: boilerplate and
&&/$$markers removed, section headings styled, prose reflowed, and tables such as point temps/PoPs kept intact j/kturn the page. Room left on the last page is filled with the Hazardous Weather Outlook, then earlier discussions (dimmed)
Hazardous Weather Outlook (H)
- Your office's rolling 7-day outlook for hazardous weather, in the same column layout
- Offices issue one only when there's something to flag; when there isn't, the view says so
Alerts (a)
- Active NWS alerts for your location, most severe first, with headline, timing, description and instructions
- When there are none, shows when that was last checked and lists anything active elsewhere in your state
Moon phase (m)
- A round, shaded moon showing the current illumination, sized to the terminal
- Phase name, illumination, age and lunation number
- Moonrise and moonset, and the dates of upcoming phases
Favorites (F, n/b, e, D)
- Save the current location with
F, and cycle through favorites withn/b - An editor (
e) to add, rename, delete and reorder favorites - A dashboard (
D) with current conditions, today's high/low, chance of precipitation and active alerts for every favorite, refreshed in the background
Startup splash
- While the first refresh loads, the splash shows the sky at your location right now: the sun and moon where they actually are (east on the left, west on the right), and stars after dark
- Underneath, each request ticks off as it arrives with what it found: current temperature and wind, the first forecast period, alerts, air quality and UV
- It gives way to the normal views a moment after everything is in, or right away on any key (
qstill quits); set"splash": falseto skip it
Weather tune (M)
- When conditions load, a short melody generated from the weather plays on a loop: 64 notes on a pentatonic scale, synthesized live (no audio files)
- Clear skies play in a major key; rain, snow, storms, fog or clouds in a minor one. Warmer weather pitches it higher and wind speeds it up
Mmutes it, or plays it again from the latest conditions- On Linux it plays through
pw-play,paplayoraplay, whichever is installed; on macOS it plays through CoreAudio with sounddevice, which is installed with the app there - Set
"music": falseto keep it from starting on its own
Outside the US
- At startup the app looks up roughly where your IP address is. If that's outside the US and its territories, a notice replaces the splash: the NWS has nothing for you there.
Entercontinues,qquits; set"detect_location": falseto skip the check - If the location itself is outside NWS coverage, every panel says so in place of its data, the header shows
[OUTSIDE US], and nothing more is fetched for it - Location search and adding a favorite refuse places the NWS doesn't cover (it decides, so Windsor, Ontario is refused while Detroit across the river works)
Everything else
- Location search by city/state, ZIP code, or
lat,lon(l) - US or SI units (
u), 12- or 24-hour clock (t) - Auto-refresh every 5 minutes by default; pause with
p - A footer of key hints that fits whatever width it has, most important first
- Offline mode: falls back to the last saved data when the network is down
- Times are shown in your computer's time zone
Installation
Install it as a standalone command with pipx or uv:
pipx install nws-weather-tui
# or
uv tool install nws-weather-tui
To run the latest unreleased code from main, install from git instead: pipx install git+https://github.com/crinderneck/nws-weather-tui.git. Releases are listed on the releases page.
From a checkout
git clone https://github.com/crinderneck/nws-weather-tui.git
cd nws-weather-tui
python -m venv .venv
. .venv/bin/activate
pip install -e .
Development
pip install -e '.[test]'
pytest # fast suite, ~3 s, offline
pytest -m slow # Python 3.9 and pipx install checks
python tests/profile_app.py # profile startup, data fetches and every screen
See tests/README.md for the snapshot harness, re-recording fixtures, and the profiler's options.
Usage
nws-weather-tui
# or
python -m nws_weather_tui
Keyboard shortcuts
| Key | Action |
|---|---|
c |
Current conditions |
f |
Forecast |
h |
Hourly |
a |
Alerts |
m |
Moon phase |
d |
Area Forecast Discussion |
H |
Hazardous Weather Outlook |
D |
Favorites dashboard |
? |
Help |
l |
Search location |
r |
Refresh now |
u |
Toggle US / SI units |
t |
Toggle 12h / 24h clock |
p |
Pause / resume auto-refresh |
M |
Mute / replay the weather tune |
F |
Save / remove the current location as a favorite |
n / b |
Next / previous favorite |
e |
Favorites editor |
A |
Play / pause radar animation |
< / > |
Step radar frames |
o |
Open weather.gov radar in a browser |
j / k, ↓ / ↑ |
Scroll, or turn the page in the discussion |
← / → |
Scroll forecast days |
PgDn / PgUp |
Scroll by 10 lines |
G |
Jump to the end |
Esc |
Back to current conditions |
q |
Quit |
In the favorites editor: j/k move, J/K reorder, Enter jumps, a adds, r renames, d deletes, e/Esc exits. In the dashboard: j/k move, Enter jumps, r refreshes, D/Esc returns.
Configuration
Settings live in ~/.config/nws-weather-tui/config.json, which is created with defaults on first run and updated as you change location, units or favorites. The last fetched data is kept in state.json alongside it for offline use. If config.json can't be parsed (for example after a hand-edit typo), it's renamed to config.json.broken-<timestamp> and the app starts with defaults, so nothing is lost.
| Setting | Default | Description |
|---|---|---|
location_name, lat, lon |
built-in default | Current location; easiest to set with l |
units |
"us" |
"us" or "si" |
use_24h |
false |
24-hour clock |
auto_refresh_seconds |
300 |
Auto-refresh interval |
http_timeout |
10 |
Seconds before an API request gives up |
hourly_hours |
0 |
Hours shown in the hourly view; 0 shows everything the NWS provides |
show_radar_map |
true |
Show radar on the current conditions view |
music |
true |
Play the weather tune once conditions load (M mutes it either way) |
splash |
true |
Show the sky and load progress at startup |
detect_location |
true |
At startup, ask ipinfo.io for your IP address's country and warn if it's outside the US (see the privacy note at the top). It never changes your location |
favorites |
[] |
Saved locations (name, lat, lon) |
radar.animation_frames |
8 |
Frames in the radar animation |
radar.animation_interval_s |
0.5 |
Seconds between animation frames |
radar.animation_step_min |
5 |
Minutes between animation frames |
radar.show_state_lines |
true |
State border overlay |
radar.show_city_labels |
true |
City labels on the radar |
radar.max_city_labels |
20 |
Most city labels drawn at once |
radar.show_alert_polygons |
true |
Warning polygons on the radar |
radar.ascii_ramp |
" .:-=+*#%@" |
Characters for the ASCII radar fallback |
cache_ttls |
per endpoint | Seconds to cache each kind of API response |
Set WEATHER_APP_UA to override the User-Agent sent to the NWS API.
Code layout
All code lives in the src/nws_weather_tui/ package.
| Module | Purpose |
|---|---|
__main__.py |
Entry point (nws-weather-tui, python -m nws_weather_tui) |
app.py |
App class, main loop and drawing dispatch |
input_handler.py |
Key and mouse handling, prompts |
weather_refresh.py |
Background fetch of all weather data |
models.py |
Data classes and API response extraction |
text_product.py |
Cleanup and reflow of NWS text products (AFD, HWO) |
api/ |
HTTP clients: client.py (NWS API, delegates to the others), geocoding, state boundaries, air quality, UV, and the TTL cache |
radar/ |
Radar fetching, decoding, rendering, palette, map overlays, city data and radar state |
views/ |
One module per screen, plus chrome.py for the header and footer and splash.py for the startup splash |
dashboard.py, favorites.py |
Favorites dashboard fetch and favorites editing |
moon.py, windsock.py, icons.py |
Moon math, windsock animation, weather icons |
music.py |
The weather tune: composition and live synthesis |
constants.py, persistence.py |
Default config, config and state files |
helpers.py, formatting.py, geo.py, conversions.py |
Shared utilities |
Requirements
- Python 3.9+
- Linux (primary, tested) or macOS (supported, less tested), in a terminal with curses support. Windows is not supported: Python on Windows has no
cursesmodule, so the app won't start there - A 256-color terminal is recommended for radar; it falls back to ASCII automatically
astral,numpy,pillowandrequests, plussounddeviceon macOS (installed automatically)- Optional on Linux, for the weather tune:
pw-play(PipeWire),paplay(PulseAudio) oraplay(ALSA)
Data sources
Weather data comes from the National Weather Service API, which is free, needs no API key, and covers the United States and its territories. Air quality and UV index come from the free Open-Meteo API (no key needed) and never take the app offline if unavailable. Radar comes from NOAA's MRMS composite (mapservices.weather.noaa.gov), Iowa State's IEM and the NWS (opengeo.ncep.noaa.gov). Location search uses Nominatim (OpenStreetMap) for places and Zippopotam.us for ZIP codes. The startup location check asks ipinfo.io for your IP address's country (see the privacy note at the top and detect_location).
Metadata
Release files for nws-weather-tui 0.8.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| nws_weather_tui-0.8.0.tar.gz | 155.5 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| nws_weather_tui-0.8.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 293.4 kB
Release files / nws_weather_tui-0.8.0.tar.gz
| Download URL | nws_weather_tui-0.8.0.tar.gz |
|---|---|
| Size | 155.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
22bc0bdf6ebc1d169bf3ae1298397d65bd70198dfe4fd5085d5d6df2d7850b41
|
|
BLAKE2b-256 checksum How to use checksums |
939b6d2cc527c613348abd9b3cd42044d6a05f0faa7e4da059a5e4031fabc0fa
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 20, 2026.
Transparency logRelease files / nws_weather_tui-0.8.0-py3-none-any.whl
| Download URL | nws_weather_tui-0.8.0-py3-none-any.whl |
|---|---|
| Size | 137.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
3f5e10be5bd5b567683317dc03a1c09f499bacc0af9a1866c2923ff9800d494a
|
|
BLAKE2b-256 checksum How to use checksums |
bef9d9c534e417422a377db069b0bac9b14737bd3adc2caafd84daaa7339031d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 20, 2026.
Transparency logSecurity for nws-weather-tui 0.8.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for nws_weather_tui-0.8.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 20, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.