Python implementation of the NWWS-OI XMPP protocol for receiving weather data
Project description
NWWS-OI Receiver
A robust Python implementation of the NWWS-OI (NOAAPort Weather Wire Service - Open Interface) XMPP protocol for receiving real-time weather data from the National Weather Service. This client connects to the NWWS-OI XMPP server and joins Multi-User Chat (MUC) rooms to receive weather messages, alerts, and forecasts.
Requirements
- Python 3.12+ (Python 3.13 recommended for best performance)
- slixmpp - Modern XMPP library for Python
Overview
The NWWS-OI protocol uses XMPP (Extensible Messaging and Presence Protocol) to deliver weather data, forecasts, warnings, and other meteorological information in real-time. This Python client provides a robust, asynchronous implementation with automatic reconnection, comprehensive error handling, and flexible message consumption patterns.
Features
- Complete XMPP Protocol Implementation: Full support for NWWS-OI XMPP protocol
- Dual Consumption Patterns: Both async iterator and subscribe/unsubscribe patterns
- Multi-User Chat (MUC) Support: Automatic room joining and presence management
- Async Iterator Support: Modern async/await patterns with
async formessage streaming - Event-Driven Architecture: Subscribe to message events with custom handlers
- Automatic Reconnection: Intelligent reconnection with exponential backoff
- Health Monitoring: Idle timeout detection and connection monitoring
- Message Parsing: Structured NOAAPort message parsing with metadata extraction
- Configuration Management: Comprehensive configuration with validation
- Production Ready: Comprehensive logging, error handling, and type hints
- Graceful Shutdown: Proper cleanup and resource management
Installation
From PyPI (Recommended)
# Install latest version
pip install nwws-oi-receiver
# Install with optional dependencies
pip install nwws-oi-receiver[dev,test]
Using Modern Package Managers
Using UV (Fastest)
# Install in current environment
uv add nwws-oi-receiver
# Create new project with nwws-oi-receiver
uv init my-weather-app
cd my-weather-app
uv add nwws-oi-receiver
Using Poetry
# Add to existing project
poetry add nwws-oi-receiver
Using PDM
# Add to project
pdm add nwws-oi-receiver
From Source (Development)
# Clone the repository
git clone https://github.com/bradsjm/nwws-oi-receiver.git
cd nwws-oi-receiver
# Using UV (recommended for development)
uv sync --group dev --group test
source .venv/bin/activate # or `.venv\Scripts\activate` on Windows
# Using pip
pip install -e ".[dev,test]"
Verify Installation
# Test basic import
python -c "from nwws_receiver import WxWire; print('✅ Installation successful')"
# Run examples
python examples/usage_patterns.py
Quick Start
Simple Subscriber Pattern
import asyncio
import os
from nwws_receiver import WxWire, WxWireConfig, NoaaPortMessage
def handle_message(message: NoaaPortMessage) -> None:
"""Handle incoming weather messages."""
print(f"Received: {message.awipsid} - {message.subject}")
# Process message based on type
if message.awipsid.startswith("TOR"):
print(f"🌪️ TORNADO WARNING: {message.subject}")
elif message.awipsid.startswith("SVR"):
print(f"⛈️ SEVERE WEATHER: {message.subject}")
async def main():
# Configure the client
config = WxWireConfig(
username=os.getenv("NWWS_USERNAME", "your_username"),
password=os.getenv("NWWS_PASSWORD", "your_password"),
server="nwws-oi.weather.gov",
port=5222
)
# Create and configure client
client = WxWire(config)
client.subscribe(handle_message)
try:
# Connect and start receiving messages
success = await client.start()
if not success:
print("Failed to connect to NWWS-OI")
return
print("Connected! Receiving weather data...")
print("Press Ctrl+C to stop")
# Keep running until interrupted
await asyncio.Event().wait()
except KeyboardInterrupt:
print("\\nShutting down...")
finally:
await client.stop()
if __name__ == "__main__":
asyncio.run(main())
Async Iterator Pattern
import asyncio
import os
from nwws_receiver import WxWire, WxWireConfig
async def main():
config = WxWireConfig(
username=os.getenv("NWWS_USERNAME", "your_username"),
password=os.getenv("NWWS_PASSWORD", "your_password")
)
client = WxWire(config)
try:
await client.start()
# Process messages using async iterator
async for message in client:
print(f"Processing: {message.awipsid} - {message.subject}")
# Custom processing logic here
if "URGENT" in message.subject.upper():
print(f"🚨 URGENT: {message.content}")
except KeyboardInterrupt:
print("\\nStopping...")
finally:
await client.stop()
if __name__ == "__main__":
asyncio.run(main())
Advanced Usage
Dual Pattern Example
You can use both subscriber and async iterator patterns simultaneously:
import asyncio
from nwws_receiver import WxWire, WxWireConfig, NoaaPortMessage
def priority_handler(message: NoaaPortMessage) -> None:
"""Handle priority alerts immediately."""
if message.awipsid.startswith(("TOR", "FFW", "EWW")):
print(f"🚨 PRIORITY ALERT: {message.awipsid}")
async def background_processor(client: WxWire) -> None:
"""Background task processing all messages."""
async for message in client:
# Log all messages to database, file, etc.
print(f"[LOG] {message.awipsid}: {message.subject}")
async def main():
config = WxWireConfig(
username="your_username",
password="your_password"
)
client = WxWire(config)
# Set up priority subscriber
client.subscribe(priority_handler)
# Start background processor task
processor_task = asyncio.create_task(background_processor(client))
try:
await client.start()
await asyncio.Event().wait() # Run forever
except KeyboardInterrupt:
processor_task.cancel()
finally:
await client.stop()
asyncio.run(main())
Configuration Options
from nwws_receiver import WxWireConfig
config = WxWireConfig(
username="your_username", # NWWS-OI username
password="your_password", # NWWS-OI password
server="nwws-oi.weather.gov", # XMPP server (default)
port=5222, # XMPP port (default)
room="nwws-oi@conference.weather.gov", # MUC room (default)
nickname="your_nickname", # MUC nickname (optional)
history=0, # Message history to request (default: 0)
idle_timeout=300, # Idle timeout in seconds (default: 300)
max_reconnect_attempts=10, # Max reconnection attempts (default: 10)
reconnect_delay=5.0, # Initial reconnect delay (default: 5.0)
use_tls=True, # Use TLS encryption (default: True)
validate_certificates=True # Validate SSL certificates (default: True)
)
Message Structure
The NoaaPortMessage class provides structured access to weather data:
from nwws_receiver import NoaaPortMessage
def process_message(message: NoaaPortMessage) -> None:
print(f"AWIPS ID: {message.awipsid}") # Product identifier
print(f"Subject: {message.subject}") # Message subject
print(f"Content: {message.content}") # Message body
print(f"Timestamp: {message.timestamp}") # Message timestamp
print(f"Source: {message.source}") # Originating office
print(f"Raw XML: {message.raw_xml}") # Original XML
Authentication
To use NWWS-OI, you need to register for an account:
- Visit the NWWS-OI Registration Page
- Complete the registration process
- Wait for account approval (typically 1-2 business days)
- Use your approved credentials in the configuration
Error Handling
The client includes comprehensive error handling:
import logging
from nwws_receiver import WxWire, WxWireConfig
# Enable detailed logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
async def robust_client():
config = WxWireConfig(
username="your_username",
password="your_password",
max_reconnect_attempts=5,
reconnect_delay=10.0
)
client = WxWire(config)
try:
success = await client.start()
if not success:
logger.error("Failed to connect after all attempts")
return
# Client will automatically reconnect on network issues
async for message in client:
try:
# Process message
process_weather_data(message)
except Exception as e:
logger.error(f"Error processing message: {e}")
except Exception as e:
logger.error(f"Client error: {e}")
finally:
await client.stop()
Examples
The examples/ directory contains comprehensive examples:
usage_patterns.py- Complete example showing both consumption patterns- Run examples with:
python examples/usage_patterns.py
API Reference
WxWire Class
The main client class for connecting to NWWS-OI.
Methods
subscribe(handler)- Subscribe to message eventsunsubscribe(handler)- Remove message subscriptionstart()- Connect and start receiving messages (async)stop(reason=None)- Disconnect and cleanup (async)__aiter__()- Async iterator interface
Properties
subscriber_count- Number of active subscribersis_connected- Connection statusconfig- Current configuration
WxWireConfig Class
Configuration management with validation.
Parameters
username(str) - NWWS-OI usernamepassword(str) - NWWS-OI passwordserver(str) - XMPP server hostnameport(int) - XMPP server portroom(str) - MUC room to joinnickname(str) - MUC nicknamehistory(int) - Message history countidle_timeout(float) - Connection idle timeoutmax_reconnect_attempts(int) - Maximum reconnection attemptsreconnect_delay(float) - Initial reconnect delayuse_tls(bool) - Enable TLS encryptionvalidate_certificates(bool) - Validate SSL certificates
NoaaPortMessage Class
Structured weather message representation.
Attributes
awipsid(str) - AWIPS product identifiersubject(str) - Message subject linecontent(str) - Message content/bodytimestamp(datetime) - Message timestampsource(str) - Originating weather officeraw_xml(str) - Original XML message
Protocol Details
XMPP Connection Flow
- TLS Connection: Establish secure connection to XMPP server
- Authentication: SASL authentication with username/password
- Resource Binding: Bind to XMPP resource
- MUC Join: Join the NWWS-OI multi-user chat room
- Message Reception: Receive and parse weather messages
- Presence Management: Maintain presence and handle disconnections
Message Format
NWWS-OI messages are delivered as XMPP messages containing structured weather data in XML format. The client automatically parses these messages into NoaaPortMessage objects.
Reconnection Logic
The client implements exponential backoff reconnection:
- Initial delay: 5 seconds (configurable)
- Maximum attempts: 10 (configurable)
- Backoff multiplier: 2.0
- Maximum delay: 300 seconds
Testing
# Run all tests
pytest
# Run with coverage
pytest --cov=nwws_receiver
# Run specific test categories
pytest -m unit
pytest -m integration
Development
Code Quality
# Format code
ruff format .
# Check code quality
ruff check --fix .
# Type checking
basedpyright
Project Structure
src/nwws_receiver/
├── __init__.py # Package exports
├── config.py # Configuration management
├── message.py # Message parsing
└── wx_wire.py # Main XMPP client
Contributing
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Make your changes
- Add tests for new functionality
- Ensure all tests pass (
pytest) - Run code quality checks (
ruff check,basedpyright) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
License
This project is licensed under the MIT License - see the LICENSE file for details.
References
- NWWS-OI Official Documentation
- XMPP Protocol Specification
- NOAAPort Data Format
- AWIPS Product Identifiers
Support
For questions, issues, or contributions:
- Create an issue on GitHub
- Check the examples for usage patterns
- Review the comprehensive logging output for debugging
Acknowledgments
AI Assistance
This project has been developed with assistance from Large Language Models (LLMs), and we acknowledge their significant contributions to both the codebase and documentation:
- Anthropic Claude - Contributed to code architecture, implementation patterns, documentation structure, async/await patterns, error handling strategies, and comprehensive testing approaches
- OpenAI GPT - Assisted with protocol implementation details, API design decisions, code optimization suggestions, and example development
- Google Gemini - Provided insights on Python best practices, type annotation improvements, and packaging standards compliance
The LLMs have been instrumental in:
- Code Quality: Implementing modern Python 3.12+ features, type hints, and async patterns
- Documentation: Creating comprehensive README, API documentation, and example code
- Architecture: Designing modular, testable, and maintainable code structure
- Standards Compliance: Ensuring adherence to PEP standards and modern packaging practices
- Error Handling: Implementing robust error recovery and logging strategies
While AI has significantly accelerated development and improved code quality, all code has been reviewed, tested, and validated by human developers. The final implementation decisions, architecture choices, and quality standards remain under human oversight.
Human Contributors
We also acknowledge the human developers, domain experts, and community members who have contributed to the project through code review, testing, feedback, and domain expertise in weather data protocols.
Note: You need valid NWWS-OI credentials to use this client. Register at https://nwws-oi.weather.gov/ to obtain access.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file nwws_oi_receiver-1.0.0.tar.gz.
File metadata
- Download URL: nwws_oi_receiver-1.0.0.tar.gz
- Upload date:
- Size: 27.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.12.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
be74762ca3a44668cc98d562ddfd9cda49d23265b067e25370c1d8cc1ce91160
|
|
| MD5 |
e8ac4b61319ffaf0cca98318a55092ea
|
|
| BLAKE2b-256 |
7bcd26662147575422e31299870c3d27058abd860c402c15ecd02e5c4a512271
|
Provenance
The following attestation bundles were made for nwws_oi_receiver-1.0.0.tar.gz:
Publisher:
release.yml on bradsjm/nwws-oi-receiver
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
nwws_oi_receiver-1.0.0.tar.gz -
Subject digest:
be74762ca3a44668cc98d562ddfd9cda49d23265b067e25370c1d8cc1ce91160 - Sigstore transparency entry: 235641094
- Sigstore integration time:
-
Permalink:
bradsjm/nwws-oi-receiver@5b1d73cbfde2e6d9f69b14fa09f62ee28097c8bc -
Branch / Tag:
refs/tags/v1.0.0 - Owner: https://github.com/bradsjm
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@5b1d73cbfde2e6d9f69b14fa09f62ee28097c8bc -
Trigger Event:
push
-
Statement type:
File details
Details for the file nwws_oi_receiver-1.0.0-py3-none-any.whl.
File metadata
- Download URL: nwws_oi_receiver-1.0.0-py3-none-any.whl
- Upload date:
- Size: 19.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.12.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
adf8584ef8eb39e2dbefeca850a0228cc89e411d9605a7213a2fa543e3220c30
|
|
| MD5 |
12bb3f25e0d44626bf92c988c483dbb7
|
|
| BLAKE2b-256 |
ba9bcedcb73cd337e7d46d784625c31a7178501ff81f4de4303e85fc39cbc31d
|
Provenance
The following attestation bundles were made for nwws_oi_receiver-1.0.0-py3-none-any.whl:
Publisher:
release.yml on bradsjm/nwws-oi-receiver
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
nwws_oi_receiver-1.0.0-py3-none-any.whl -
Subject digest:
adf8584ef8eb39e2dbefeca850a0228cc89e411d9605a7213a2fa543e3220c30 - Sigstore transparency entry: 235641098
- Sigstore integration time:
-
Permalink:
bradsjm/nwws-oi-receiver@5b1d73cbfde2e6d9f69b14fa09f62ee28097c8bc -
Branch / Tag:
refs/tags/v1.0.0 - Owner: https://github.com/bradsjm
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@5b1d73cbfde2e6d9f69b14fa09f62ee28097c8bc -
Trigger Event:
push
-
Statement type: