A comprehensive Python implementation of the EMWIN Quick Block Transfer (QBT) protocol for receiving real-time weather data from the National Weather Service. This protocol is also commonly known as ByteBlaster.
- Python 3.12+ (Python 3.13 recommended for best performance)
- Zero runtime dependencies - pure Python implementation
The EMWIN QBT protocol uses Quick Block Transfer (QBT) to efficiently deliver weather data, forecasts, warnings, and satellite imagery. This Python client provides a robust, asynchronous implementation with automatic reconnection, server failover, and comprehensive error handling.
- Complete Protocol Implementation: Full support for EMWIN QBT protocol (v1 and v2)
- High-Level File Manager: Simplified interface for receiving complete, reconstructed files, abstracting away low-level data segments.
- Async Iterator Support: Modern async/await patterns with
stream_files()
andstream_segments()
methods - Automatic Reconnection: Intelligent failover across multiple servers
- Server List Management: Dynamic server list updates with persistence
- Async/Await Support: Built on asyncio for high performance
- Data Validation: Checksum verification and error detection
- Compression Support: Automatic handling of zlib-compressed v2 data
- Watchdog Monitoring: Connection health monitoring with configurable timeouts
- Observable Pattern: Easy subscription to data events
- Production Ready: Comprehensive logging, error handling, and type hints
The package is available on PyPI and works with all modern Python package managers:
# Install latest version
pip install byte-blaster
# Install with optional dependencies
pip install byte-blaster[dev,test]
# Install in current environment
uv pip install byte-blaster
# Create new project with byte-blaster
uv init my-weather-app
cd my-weather-app
uv add byte-blaster
# Install with dependency groups
uv sync --group dev --group test
# Add to existing project
poetry add byte-blaster
# Add development dependencies
poetry add --group dev byte-blaster[dev]
poetry add --group test byte-blaster[test]
# Add to project
pdm add byte-blaster
# Add with dependency groups
pdm add -dG dev byte-blaster[dev]
pdm add -dG test byte-blaster[test]
# Install from conda-forge (if available) or pip
conda install byte-blaster
# or
conda install pip && pip install byte-blaster
# Clone the repository
git clone <repository-url>
cd byte-blaster
# 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 .
pip install -e ".[dev,test]"
# Using Poetry
poetry install --with dev,test
# Using PDM
pdm install -dG dev -dG test
# Run comprehensive verification script
python scripts/verify_installation.py
# Test basic import
python -c "from byteblaster import ByteBlasterClient; print('âś… Installation successful')"
# Run examples
python examples/example.py
This project uses modern Python packaging standards and is compatible with:
Package Manager | Version | Installation Command | Dependency Groups |
---|---|---|---|
pip | 21.3+ | pip install byte-blaster |
pip install byte-blaster[dev,test] |
UV | 0.1.0+ | uv add byte-blaster |
uv sync --group dev --group test |
Poetry | 1.2+ | poetry add byte-blaster |
poetry install --with dev,test |
PDM | 2.0+ | pdm add byte-blaster |
pdm install -dG dev -dG test |
Conda | Any | pip install byte-blaster |
Via pip in conda env |
Pipenv | Any | pipenv install byte-blaster |
pipenv install --dev |
Requirements:
- Python 3.12+ (Python 3.13 recommended)
- Modern package manager supporting PEP 621 (pyproject.toml)
- No system dependencies required
Features:
- âś… Pure Python (no compiled extensions)
- âś… Type hints included (
py.typed
marker) - âś… Dependency groups for dev/test separation
- âś… Wheel and source distributions available
- âś… Cross-platform compatibility (Windows, macOS, Linux)
- âś… PEP 621 compliant (pyproject.toml-based configuration)
- âś… PEP 517/518 build system (setuptools backend)
- âś… PEP 440 version scheme
- âś… PEP 508 dependency specifications
If you encounter issues with specific package managers:
# Update UV to latest version
uv self update
# Clear cache and retry
uv cache clean
uv add byte-blaster
# Force reinstall
uv pip install --force-reinstall byte-blaster
# Update pip and build tools
pip install --upgrade pip setuptools wheel
# Install with verbose output for debugging
pip install -v byte-blaster
# Clear pip cache
pip cache purge
# Update Poetry
poetry self update
# Clear cache
poetry cache clear pypi --all
# Force update lock file
poetry lock --no-update
poetry install
- Python Version: Ensure Python 3.12+ is installed
- Virtual Environment: Always use a virtual environment
- Dependencies: Check for conflicting packages with
pip check
- Permissions: Use
--user
flag if encountering permission errors - Network: Check proxy settings if behind corporate firewall
ByteBlaster is designed to work seamlessly with all modern Python package managers:
Feature | Status | Notes |
---|---|---|
pip compatibility | âś… Full | Standard pip install byte-blaster |
UV compatibility | âś… Full | Fastest installation with uv add byte-blaster |
Poetry compatibility | âś… Full | poetry add byte-blaster |
PDM compatibility | âś… Full | pdm add byte-blaster |
Conda compatibility | âś… Via pip | pip install byte-blaster in conda env |
Pipenv compatibility | âś… Full | pipenv install byte-blaster |
Zero dependencies | âś… Yes | Pure Python, no runtime dependencies |
Type hints | âś… Full | Complete type annotations included |
Wheels available | âś… Yes | Fast binary installation |
Source builds | âś… Yes | pip install from source works |
Recommended installation methods:
- For new projects:
uv add byte-blaster
(fastest) - For existing pip projects:
pip install byte-blaster
- For Poetry projects:
poetry add byte-blaster
- For development:
uv sync --group dev --group test
(after cloning)
import asyncio
from byteblaster import ByteBlasterClientOptions, ByteBlasterFileManager, CompletedFile
async def handle_file(file: CompletedFile):
"""Handler for completed files."""
print(f"Received file: {file.filename}, Size: {len(file.data)} bytes")
async def main():
# Create client options - email is required for authentication
options = ByteBlasterClientOptions(email="[email protected]")
# Use the high-level file manager, the recommended client for most use cases.
manager = ByteBlasterFileManager(options)
# Subscribe to completed file events
manager.subscribe(handle_file)
# Start receiving data
await manager.start()
# Keep running (use Ctrl+C to stop)
try:
# Wait indefinitely until the program is interrupted
await asyncio.Event().wait()
except asyncio.CancelledError:
print("\nClient shutting down...")
finally:
await manager.stop()
print("Client stopped.")
if __name__ == "__main__":
try:
asyncio.run(main())
except KeyboardInterrupt:
pass
The library supports modern async iterator patterns for reactive programming:
import asyncio
from byteblaster import ByteBlasterClientOptions, ByteBlasterFileManager
async def main():
options = ByteBlasterClientOptions(email="[email protected]")
manager = ByteBlasterFileManager(options)
await manager.start()
# Use async iterator pattern
async with manager.stream_files() as files:
async for completed_file in files:
print(f"Processing: {completed_file.filename}")
# Process file here
await manager.stop()
asyncio.run(main())
import asyncio
from byteblaster import ByteBlasterClientOptions, ByteBlasterClient
async def main():
options = ByteBlasterClientOptions(email="[email protected]")
client = ByteBlasterClient(options)
await client.start()
# Stream individual segments
async with client.stream_segments() as segments:
async for segment in segments:
print(f"Segment: {segment.filename} ({segment.block_number}/{segment.total_blocks})")
await client.stop()
asyncio.run(main())
See examples/example.py
for a comprehensive example that demonstrates:
- File reconstruction from multiple segments
- Data persistence to disk
- Graceful shutdown handling
- Progress monitoring
- Concurrent processing with multiple handlers
python examples/example.py
For advanced async iterator examples, see:
python examples/example_async_iterators.py
- Uses email-based authentication with XOR obfuscation
- Automatic re-authentication every 2 minutes
- Configurable authentication parameters
- Connection: Client connects to ByteBlaster servers
- Authentication: Sends XOR-encoded logon message
- Data Reception: Receives and decodes data segments
- Reconstruction: Assembles complete files from segments
- Validation: Verifies checksums and data integrity
- Data Blocks: Weather data, forecasts, imagery
- Server Lists: Dynamic server list updates
The recommended high-level client for most use cases. It abstracts away segment handling and provides a simple interface for receiving complete files.
from byteblaster import ByteBlasterFileManager, ByteBlasterClientOptions
# Configure the client with your email
options = ByteBlasterClientOptions(email="[email protected]")
# Create the file manager
manager = ByteBlasterFileManager(options)
subscribe(handler)
: Subscribe toCompletedFile
events.unsubscribe(handler)
: Remove event subscription.stream_files(max_queue_size=100)
: Create async iterator for streaming files.start()
: Start the client (async).stop(shutdown_timeout=None)
: Stop the client (async).
client
: Access the underlyingByteBlasterClient
instance.assembler
: Access theFileAssembler
instance.
The low-level client for handling the EMWIN QBT protocol. Use this if you need to work directly with data segments instead of complete files.
from byteblaster import ByteBlasterClient, ByteBlasterClientOptions
client = ByteBlasterClient(
options=ByteBlasterClientOptions(
email="[email protected]",
server_list_path="servers.json", # Server persistence file
watchdog_timeout=20.0, # Connection timeout
max_exceptions=10, # Max errors before reconnect
reconnect_delay=5.0, # Delay between reconnects
connection_timeout=10.0, # TCP connection timeout
)
)
subscribe(handler)
: Subscribe to data segment events.unsubscribe(handler)
: Remove event subscription.stream_segments(max_queue_size=1000)
: Create async iterator for streaming segments.start()
: Start the client (async).stop(shutdown_timeout=None)
: Stop the client (async).get_server_list()
: Get the currentByteBlasterServerList
instance.
is_connected
: Connection status.is_running
: Client running status.server_count
: Number of available servers.email
: Authentication email.
Configuration class for client initialization.
from byteblaster import ByteBlasterClientOptions
options = ByteBlasterClientOptions(
email="[email protected]", # Required: Email for authentication
server_list_path="servers.json", # Server persistence file path
watchdog_timeout=20.0, # Connection watchdog timeout
max_exceptions=10, # Max errors before reconnect
reconnect_delay=5.0, # Delay between reconnection attempts
connection_timeout=10.0, # TCP connection establishment timeout
)
Data structure representing a single QBT data block.
@dataclass
class QBTSegment:
filename: str # Original filename
block_number: int # Block sequence number
total_blocks: int # Total blocks in file
content: bytes # Block data
checksum: int # Block checksum
length: int # Block length
version: int # Protocol version (1 or 2)
timestamp: datetime # File timestamp
received_at: datetime # Reception timestamp
header: str # Raw header
source: str # Server address
Data structure representing a fully reconstructed file.
class CompletedFile(NamedTuple):
filename: str # Original filename
data: bytes # Complete file content
The library provides async iterator classes for streaming data:
FileStream
: Async iterator for completed files (fromstream_files()
)SegmentStream
: Async iterator for data segments (fromstream_segments()
)
Both support context manager protocol and backpressure handling.
The client automatically manages server lists. You can access the list through the client instance:
# Get current server list from the file manager
server_list = manager.client.get_server_list()
# Or directly from a client instance
# server_list = client.get_server_list()
Server lists are automatically saved to servers.json
(configurable):
{
"servers": [
"w2.2y.net:2211",
"2.pool.iemwin.net:2211"
],
"sat_servers": [],
"received_at": "2024-01-01T12:00:00",
"version": "1.0"
}
Configure logging to monitor client behavior:
import logging
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s"
)
Based on the EMWIN ByteBlaster protocol:
- Frame Sync: 6 consecutive 0xFF bytes (for TCP stream)
- XOR Encoding: All data XOR'ed with 0xFF
- Header Format: 80-byte ASCII header with metadata
- Compression: V2 uses zlib compression
- Checksum: Simple byte sum validation
/PF<filename> /PN <block_num> /PT <total_blocks> /CS <checksum> /FD<date> [/DL<length>]
The client includes comprehensive error handling:
- Connection Errors: Automatic reconnection with exponential backoff
- Protocol Errors: State machine reset and resynchronization
- Data Errors: Checksum validation and corruption detection
- Timeout Handling: Watchdog monitoring with configurable timeouts
# Run tests
pytest
# Run with coverage
pytest --cov=byteblaster
# Run specific test categories
pytest -m unit # Unit tests only
pytest -m integration # Integration tests only
This project follows strict code quality standards:
- Type Hints: Complete type annotations with Python 3.12+ syntax
- Linting: Ruff for code formatting and linting
- Type Checking: Pyright/basedpyright for static analysis
- Testing: Comprehensive test suite with pytest
# Format code
ruff format .
# Check code quality
ruff check --fix .
# Type checking
basedpyright
The client is built with a modular architecture:
client.py
: Main client implementationfile_manager.py
: High-level file management interfaceprotocol/
: Protocol implementationdecoder.py
: State machine decodermodels.py
: Data modelsauth.py
: Authentication handling
utils/
: Utility functionscrypto.py
: XOR encoding and compressionserverlist.py
: Server list management
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests for new functionality
- Ensure all tests pass
- Submit a pull request
This project is licensed under the MIT License - see the LICENSE file for details.
For questions, issues, or contributions:
- Create an issue on GitHub
- Check the examples and documentation
- Review the comprehensive logging output
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.
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: Replace [email protected]
with your actual email address when using the client. Some ByteBlaster servers may require registration.