Xcalibur.Weather.Helpers
1.1.7
dotnet add package Xcalibur.Weather.Helpers --version 1.1.7
NuGet\Install-Package Xcalibur.Weather.Helpers -Version 1.1.7
<PackageReference Include="Xcalibur.Weather.Helpers" Version="1.1.7" />
<PackageVersion Include="Xcalibur.Weather.Helpers" Version="1.1.7" />
<PackageReference Include="Xcalibur.Weather.Helpers" />
paket add Xcalibur.Weather.Helpers --version 1.1.7
#r "nuget: Xcalibur.Weather.Helpers, 1.1.7"
#:package Xcalibur.Weather.Helpers@1.1.7
#addin nuget:?package=Xcalibur.Weather.Helpers&version=1.1.7
#tool nuget:?package=Xcalibur.Weather.Helpers&version=1.1.7
Xcalibur.Weather.Helpers
A comprehensive .NET helper library providing utility functions for weather-related operations. Includes conversion helpers for temperature, wind speed, length, and pressure, along with specialized helpers for Open-Meteo, Geocodio, IpGeolocation.io, Atmospore, SunriseSunset.io, OpenStreetMap, and combined weather alert operations (Meteoalarm, NWS, GDACS, Environment Canada, BOM, EMSC, DWD).
Created by: Joshua Arzt | Company: Xcalibur Systems, LLC.
Purpose
Xcalibur.Weather.Helpers is designed to:
- Provide high-level helper utilities that simplify working with weather data
- Enable easy conversion between common weather measurement units (temperature, wind speed, pressure, length)
- Offer convenient wrapper methods around Xcalibur.Weather.Services for common use cases
- Deliver intelligent alert consolidation to eliminate duplicate weather alerts
- Support geographic region detection and routing for multi-provider weather services
- Reduce boilerplate code when building weather applications
- Provide strongly-typed, easy-to-use APIs for weather data transformation
๐ก Use Cases
This library is ideal for:
- Weather Applications: Mobile and desktop apps requiring weather data with automatic unit conversion
- Dashboard & UI Development: Applications needing consolidated, display-ready weather alerts without duplicates
- Smart Home Systems: IoT devices requiring weather-based automation with simplified data access
- Agricultural Solutions: Farm management systems with easy access to weather, pollen, and alert data
- Travel & Navigation Apps: Location-based weather with intelligent multi-provider alert aggregation
- Health & Wellness Apps: Allergy tracking with simplified pollen data access
- Emergency Management: Systems requiring consolidated multi-source weather alerts
- Data Transformation: Backend services needing unit conversion and data normalization
- Prototyping & MVPs: Rapid development with high-level helper methods
- Web APIs: REST services exposing weather data with built-in unit conversion
๐ What's New in v1.1.7
Meteoalarm Feed Reliability Update - Replaced runtime slug generation with an explicit country-lookup table:
- โ
Meteoalarm Country Lookup:
WeatherAlertService.GetMeteoalarmAlertsAsyncnow resolves country names against a curatedMeteoalarmFeedSlugsdictionary (40 entries, case-insensitive)- Unsupported country names short-circuit immediately with a warning log and
nullreturn โ no speculative HTTP requests - Irregular slugs such as
czechia(Czech Republic) andrepublic-of-north-macedonia(North Macedonia) are mapped correctly, which the old runtime slugifier could not guarantee - Leading/trailing whitespace is trimmed before the lookup
- Unsupported country names short-circuit immediately with a warning log and
- โ
BuildCombinedAlertsAsyncEnhancement: Added optionalcountryNameparameter- When coordinates resolve to the Europe region, callers can supply a specific country name (e.g.,
"Austria") for a targeted feed, or omit it to default to the"Europe"aggregate feed
- When coordinates resolve to the Europe region, callers can supply a specific country name (e.g.,
- ๐ Updated: Dependency on Xcalibur.Weather.Services v1.1.6
Benefits: Meteoalarm alert retrieval is now predictable and fail-fast for unsupported regions, and callers can target specific European country feeds instead of always using the aggregate feed.
Previous Release - v1.1.5
Native AOT Observation Serialization Update - Hardened JSON metadata coverage for weather observation flows:
- โ
Native AOT Compatibility Improvements: NWS and METAR observation deserialization now include explicit source-generated JSON metadata coverage
- Ensures observation payloads can be deserialized correctly in Native AOT scenarios
- Reduces runtime serializer metadata gaps for NWS and METAR-backed responses
- Improves reliability for trimmed and ahead-of-time compiled applications
- ๐ Updated: Dependency on Xcalibur.Weather.Services v1.1.5
- ๐ Maintained: Dependency on Microsoft.Extensions.Hosting v10.0.11
- ๐งช Testing: Expanded helper coverage for
WeatherObservationHelperandTimeZoneHelper - ๐ฆ Packaging: README and package metadata aligned for v1.1.5
Benefits: Applications using weather observation flows now have stronger compatibility with Native AOT deployments while retaining resilient NWS and METAR deserialization behavior.
Previous Release - v1.1.0
Observation, Timezone, and API Modernization Update - Expanded helper coverage and cleaner public APIs:
- โ
New
WeatherObservationHelper: Added simplified access to regional weather observation servicesGetObservationAsyncfor nearest observation lookup by string or numeric coordinatesGetMultipleObservationsAsyncfor nearby observation listsDetermineRegionhelpers for observation-region routing- Regional convenience methods for NWS, ECCC, and METAR observation retrieval
- โ
New
TimeZoneHelper: Added reusable timezone conversion extensionsConvertFromTimezonefor local timezone conversionsConvertFromTimezoneUtcfor UTC-based timezone conversions
- โ
OpenMeteo Enhancements: Expanded forecast capabilities and improved timezone-aware mapping
- New
BuildShortTermForecastAsyncfor 15-minute forecast retrieval BuildHourlyForecastAsync,BuildDailyForecastAsync, andBuildHourlyAirQualityAsyncsupportforecastDaysandpastDays- Current-day and current-hour mapping now use timezone-aware conversions
- New
- โ
OpenStreetMap Improvements: Enhanced geocoding helper inputs
BuildAddressLocationsAsyncnow acceptslanguageCodeandcountry- Better request filtering for localized and country-specific searches
- โ
Weather Alert API Cleanup: Streamlined public helper surface
BuildCombinedAlertsAsync,BuildCombinedAlertsConsolidatedAsync, andConsolidateAlertsremain the supported public APIs- Consolidation logic keeps the highest-severity overlapping alert and logs consolidation decisions
- ๐ Updated: Dependency on Xcalibur.Weather.Services v1.1.0
- ๐ Updated: Dependency on Microsoft.Extensions.Hosting v10.0.11
- ๐งช Testing: Added coverage for
WeatherObservationHelperandTimeZoneHelper, and synchronized helper tests with the latest signatures - ๐ฆ Packaging: README and package metadata aligned for v1.1.0
Benefits: Applications can now retrieve observation data through a simple helper API, correctly map weather data across timezones, use more focused OpenStreetMap searches, and rely on a cleaner, consolidated alert surface.
Previous Release - v1.0.24
Historic Data Retrieval for OpenMeteo Functions - Comprehensive forecast and historical data support:
- โ
Historic Forecast Support: All OpenMeteo forecast functions now support historic data retrieval
BuildDailyForecastAsyncnow acceptsforecastDaysandpastDaysparametersBuildHourlyForecastAsyncnow acceptsforecastDaysandpastDaysparameters- Enables consistent API pattern across all OpenMeteo forecast methods
- โ
Flexible Date Range Queries: Query both future forecasts and historical weather data in a single call
- Supports time-series analysis across past and future dates
- Enables comparative studies and trend analysis
- Preserves current-hour/current-day marking in returned points
- ๐ Updated: Dependency on Xcalibur.Weather.Services v1.0.24
- ๐ Maintained: Dependency on Xcalibur.Weather.Models v1.0.21
- ๐งช Testing: Updated all forecast tests for the new method signatures
- ๐ฆ Packaging: Package references aligned for v1.0.24
Benefits: Applications can now seamlessly retrieve weather forecast data spanning both historical and future periods, enabling richer visualizations, comparisons, and analytics.
Previous Release - v1.0.22
Historic Hourly Air Quality Support - Expanded OpenMeteo air quality retrieval options:
- โ
Historic Hourly Air Quality Retrieval:
BuildHourlyAirQualityAsyncnow supports both forecast and past-day ranges- Added
forecastDaysandpastDaysparameters for more flexible hourly air quality queries - Supports retrieval of historic air quality data alongside forecasted data
- Improves range-based air quality analysis scenarios
- Added
- โ
OpenMeteo Air Quality API Enhancements: Hourly air quality requests now support broader date coverage
- Better support for historical and comparative air quality experiences
- Preserves current-hour mapping for returned hourly points
- ๐ Updated: Dependency on Xcalibur.Weather.Services v1.0.22
- ๐ Maintained: Dependency on Xcalibur.Weather.Models v1.0.21
- ๐งช Testing: Updated affected hourly air quality tests for the new method signature
- ๐ฆ Packaging: Package references aligned for v1.0.22
Benefits: Applications can now retrieve hourly air quality data across both forecast and recent historical periods, enabling richer charts, comparisons, and trend analysis.
Previous Release - v1.0.21
Air Quality Index (AQI) Enhancements - Comprehensive US and EU metrics support:
- โ
US AQI Metrics: Full support for United States Air Quality Index standards
- Individual pollutant tracking: PM2.5, PM10, NOโ, Oโ, SOโ, CO
- US AQI value with severity classification and health recommendations
- Detailed descriptions for air quality levels (Good, Moderate, Unhealthy, etc.)
- โ
EU AQI Metrics: Complete European Air Quality Index implementation
- European pollutant standards and measurements
- EU AQI value with European classification system
- Separate metrics aligned with European air quality directives
- โ
Hourly Air Quality Forecasts: New
BuildHourlyAirQualityAsyncmethod- Retrieve hourly air quality forecasts with configurable forecast hours
- Automatic current hour detection and marking
- Comprehensive pollutant data for both US and EU standards
- ๐ Updated: Dependencies updated to v1.0.21
- Xcalibur.Weather.Services v1.0.21
- Xcalibur.Weather.Models v1.0.21
- ๐งช Testing: Added 7 comprehensive tests for BuildHourlyAirQualityAsync
- ๐ฆ Packaging: All dependencies synchronized for .NET 10.0
Benefits: Applications can now provide detailed air quality information for both US and European users with region-specific AQI values, pollutant breakdowns, and health recommendations.
Previous Release - v1.0.20
Air Quality Enhancements - Improved air quality data support:
- โ Enhanced AQI Data: Improved Air Quality Index data models
- ๐ Updated: Dependency on Xcalibur.Weather.Services v1.0.20
- ๐ง Improved: Air quality point data structures
Previous Release - v1.0.19
Enhanced OpenMeteo Functionality - Expanded weather data support:
- โ
Relative Humidity Support: Added relative humidity data to daily forecast models
- Daily forecasts now include humidity information for better weather planning
- Enhanced daily weather models with additional moisture data
- Improved data completeness for agricultural and outdoor applications
- ๐ Updated: Dependency on Xcalibur.Weather.Services v1.0.19
- Latest OpenMeteo API improvements
- Enhanced data models with additional parameters
- ๐ง Improved: Daily forecast models enhanced with more meteorological data
- ๐ฆ Packaging: Updated dependencies for better compatibility
Previous Release - v1.0.18
Supplemental Weather Data - Enhanced forecast capabilities with additional data:
- โ
Supplemental Hourly Forecasts: Added support for supplemental hourly weather data
- Automatically fetches and merges additional forecast parameters
- Provides more comprehensive hourly forecasts with extended data points
- Enhanced
BuildHourlyForecastmethod with supplemental data integration
- โ
Supplemental Daily Forecasts: Added support for supplemental daily weather data
- Enriched daily forecasts with additional meteorological parameters
- Improved data completeness for multi-day forecasts
- Enhanced
BuildDailyForecastmethod with supplemental data support
- ๐ Updated: Dependencies updated to v1.0.18
- Xcalibur.Weather.Services v1.0.18
- Xcalibur.Weather.Models v1.0.18
- ๐ง Improved: OpenMeteoHelper refactored for better data handling and integration
- ๐ฆ Packaging: All dependencies up to date for .NET 10.0
Benefits: Applications now receive more complete weather forecasts with additional parameters automatically merged from supplemental API calls.
Previous Release - v1.0.17
Enhanced Multi-Language Support - Improved compatibility and performance:
- โ
Weather Code Value Retired: Removed
WeatherCodeValuestring property for improved multi-language compatibility- The WMO weather code integer is still available in forecast data
- Applications can now implement locale-specific descriptions based on their language requirements
- Reduces data model size and improves performance
- ๐ Bug Fixes: Several improvements and bug fixes for model handling
- ๐ง Model Changes: Optimized data models for better performance
- โก Performance: MVVM performance improvements
- ๐งช Testing: Updated test suite with improved coverage
Migration Note: If your application used the WeatherCodeValue property, you'll need to implement your own locale-specific weather code descriptions based on the WMO code integer.
Previous Release - v1.0.16
Consolidated Weather Alert Methods - A complete suite of consolidated alert methods for cleaner, more efficient alert handling:
- โ All 7 providers now have consolidated versions: NWS, Meteoalarm, Environment Canada, BOM, GDACS, DWD, and EMSC
- โ Automatic duplicate removal: Overlapping alerts of the same event type are consolidated, keeping only the highest severity
- โ
Clean, simple API: Returns
IReadOnlyList<WeatherAlertItem>directly - no tuples, no null checks needed - โ Optimized for UI display: Perfect for weather apps that need to show unique, relevant alerts without duplicates
- โ Smart consolidation: Handles escalating alerts (e.g., Winter Weather Advisory โ Winter Storm Warning) intelligently
Example:
// Build a full combined alert payload
var alerts = await WeatherAlertHelper.BuildCombinedAlertsAsync(lat, lon, logger, token);
// Or return only unique consolidated alerts for UI display
var consolidated = await WeatherAlertHelper.BuildCombinedAlertsConsolidatedAsync(lat, lon, logger, token);
foreach (var alert in consolidated)
{
Console.WriteLine($"[{alert.Severity}] {alert.Event}");
}
Available Consolidation APIs:
BuildCombinedAlertsConsolidatedAsync- All providers combinedConsolidateAlerts- Manual consolidation for existing alert collections
๐ Table of Contents
- Purpose
- Use Cases
- What's New
- Features
- Installation
- Requirements
- Usage
- API Overview
- Best Practices
- Testing
- Dependencies
- Changelog
- License
- Related Projects
- Contributing
Features
Conversion Utilities
- Temperature Conversion: Celsius โ Fahrenheit conversions with formatting options
- Wind Speed Conversion: Convert between km/h, mph, ft/s, m/s, and knots
- Length Conversion: Convert between millimeters and inches
- Pressure Conversion: Convert between hPa, inHg, and mmHg
- Smart Formatting: Format values with or without unit symbols
Weather Service Helpers
- OpenMeteoHelper: Build air quality points, current forecasts, short-term forecasts, hourly forecasts, daily forecasts, and yesterday's data
- GeocodioHelper: Test API keys, build address locations from geocoding queries
- IpGeoHelper: Build sun/moon points and test API connectivity for astronomical data
- AtmosporeHelper: Test API keys, retrieve pollen forecasts from the Atmospore API
- SunriseSunsetHelper: Fetch sunrise/sunset and astronomical data from SunriseSunset.io โ no API key required
- OpenStreetMapHelper: Geocode addresses using the OpenStreetMap Nominatim API โ no API key required
- WeatherAlertHelper: Build combined weather alert information from multiple global services (Meteoalarm, NWS, GDACS, Environment Canada, BOM, EMSC, DWD)
- WeatherObservationHelper: Retrieve nearest and nearby weather observations with regional service routing
- WeatherRegionHelper: Determine geographic regions, check if coordinates are in Germany, determine Canadian provinces and Australian states
- TimeZoneHelper: Convert
DateTimevalues using named timezone identifiers
Installation
NuGet Package Manager
Install-Package Xcalibur.Weather.Helpers
.NET CLI
dotnet add package Xcalibur.Weather.Helpers
Package Reference
<PackageReference Include="Xcalibur.Weather.Helpers" Version="1.1.6" />
Requirements
- .NET 10.0 or later
- Xcalibur.Weather.Services 1.1.6 (included as dependency)
- Microsoft.Extensions.Hosting 10.0.11 (included as dependency)
Usage
Temperature Conversion
using Xcalibur.Weather.Helpers;
using Xcalibur.Weather.Models;
// Convert Celsius to Fahrenheit
double celsius = 25.0;
double fahrenheit = celsius.CelsiusToFahrenheit(); // 77.0
// Convert Fahrenheit to Celsius
double temp = 77.0;
double celsiusValue = temp.FahrenheitToCelsius(); // 25.0
// Format temperature with unit
string formatted = celsius.FormatTemperature(TemperatureUnits.Fahrenheit, includeUnit: true);
// Output: "77ยฐF"
Wind Speed Conversion
using Xcalibur.Weather.Helpers;
using Xcalibur.Weather.Models;
// Convert wind speed from km/h to various units
double windSpeed = 100.0; // km/h
double mph = windSpeed.ConvertWindSpeed(WindSpeedUnits.Mph); // 62.14
double mps = windSpeed.ConvertWindSpeed(WindSpeedUnits.MSec); // 27.78
double knots = windSpeed.ConvertWindSpeed(WindSpeedUnits.Knots); // 53.99
double fps = windSpeed.ConvertWindSpeed(WindSpeedUnits.FtSec); // 91.13
Length Conversion
using Xcalibur.Weather.Helpers;
using Xcalibur.Weather.Models;
// Format precipitation in different units
double? precipitation = 25.4; // millimeters
string metric = precipitation.FormatLength(DistanceUnits.Metric, includeUnit: true);
// Output: "25.40 mm"
string imperial = precipitation.FormatLength(DistanceUnits.Imperial, includeUnit: true);
// Output: "1.00 in"
Pressure Conversion
using Xcalibur.Weather.Helpers;
using Xcalibur.Weather.Models;
// Format atmospheric pressure in different units
double? pressure = 1013.25; // hectopascals
string hPa = pressure.FormatPressure(BarometerUnits.HPa, includeUnit: true);
// Output: "1013.25 hPa"
string inHg = pressure.FormatPressure(BarometerUnits.InHg, includeUnit: true);
// Output: "29.92 inHg"
string mmHg = pressure.FormatPressure(BarometerUnits.MmHg, includeUnit: true);
// Output: "760.00 mmHg"
OpenMeteo Helper
using Xcalibur.Weather.Helpers.Services;
using Microsoft.Extensions.Logging;
// Build air quality data point
var airQuality = await OpenMeteoHelper.BuildAirQualityPointAsync(
latitude: "40.7128",
longitude: "-74.0060",
logger: logger,
token: CancellationToken.None
);
// Build current weather forecast
var currentForecast = await OpenMeteoHelper.BuildCurrentForecastAsync(
latitude: "40.7128",
longitude: "-74.0060",
logger: logger,
token: CancellationToken.None
);
// Build short-term (15-minute) forecast
var shortTermForecast = await OpenMeteoHelper.BuildShortTermForecastAsync(
latitude: "40.7128",
longitude: "-74.0060",
logger: logger,
token: CancellationToken.None
);
// Build hourly forecast
var hourlyForecast = await OpenMeteoHelper.BuildHourlyForecastAsync(
latitude: "40.7128",
longitude: "-74.0060",
forecastDays: 2,
pastDays: 0,
logger: logger,
token: CancellationToken.None
);
// Build daily forecast
var dailyForecast = await OpenMeteoHelper.BuildDailyForecastAsync(
latitude: "40.7128",
longitude: "-74.0060",
forecastDays: 7,
pastDays: 0,
logger: logger,
token: CancellationToken.None
);
// Build hourly air quality forecast/history
var hourlyAirQuality = await OpenMeteoHelper.BuildHourlyAirQualityAsync(
latitude: "40.7128",
longitude: "-74.0060",
forecastDays: 2,
pastDays: 1,
logger: logger,
token: CancellationToken.None
);
// Build yesterday's hourly forecast
var yesterdayHourlyForecast = await OpenMeteoHelper.BuildYesterdayHourlyForecastAsync(
latitude: "40.7128",
longitude: "-74.0060",
dateValue: "2026-01-14",
logger: logger,
token: CancellationToken.None
);
// Build yesterday's daily forecast
var yesterdayDailyForecast = await OpenMeteoHelper.BuildYesterdayDailyForecastAsync(
latitude: "40.7128",
longitude: "-74.0060",
startDateValue: "2026-01-13",
endDateValue: "2026-01-14",
logger: logger,
token: CancellationToken.None
);
Geocodio Helper
using Xcalibur.Weather.Helpers.Services;
using Microsoft.Extensions.Logging;
// Test Geocodio API key
bool isValid = await GeocodioHelper.TestApiKeyAsync(
apiKey: "your-api-key",
logger: logger
);
// Build address locations from query
var locations = await GeocodioHelper.BuildAddressLocationsAsync(
apiKey: "your-api-key",
query: "1600 Pennsylvania Avenue NW, Washington, DC",
country: "US",
logger: logger
);
IpGeolocation Helper
using Xcalibur.Weather.Helpers.Services;
using Microsoft.Extensions.Logging;
// Test IpGeolocation API key
bool isValid = await IpGeoHelper.TestApiKeyAsync(
apiKey: "your-api-key",
logger: logger
);
// Build sun/moon astronomical data
var sunMoonData = await IpGeoHelper.BuildSunMoonPointAsync(
ipGeoApiKey: "your-api-key",
latitude: "40.7128",
longitude: "-74.0060",
logger: logger
);
Atmospore Helper
using Xcalibur.Weather.Helpers.Services;
using Microsoft.Extensions.Logging;
// Test Atmospore API key
bool isValid = await AtmosporeHelper.TestApiKeyAsync(
apiKey: "your-api-key",
logger: logger
);
// Build pollen forecast
var pollenForecast = await AtmosporeHelper.BuildPollenForecastAsync(
apiKey: "your-api-key",
latitude: "39.43",
longitude: "-77.80",
date: "2024-05-27", // Optional, defaults to today
forecastDays: 1,
logger: logger
);
if (pollenForecast is not null)
{
Console.WriteLine($"Date: {pollenForecast.ForecastDate}");
foreach (var entry in pollenForecast.Entries)
{
Console.WriteLine($"{entry.DisplayName}: {entry.RiskLevel}");
}
}
SunriseSunset Helper
using Xcalibur.Weather.Helpers.Services;
using Microsoft.Extensions.Logging;
// Build sun/moon data โ no API key required
var sunMoonData = await SunriseSunsetHelper.BuildSunMoonPointAsync(
latitude: "40.7128",
longitude: "-74.0060",
logger: logger
);
OpenStreetMap Helper
using Xcalibur.Weather.Helpers.Services;
using Microsoft.Extensions.Logging;
// Geocode an address โ no API key required
var locations = await OpenStreetMapHelper.BuildAddressLocationsAsync(
query: "1600 Pennsylvania Avenue NW, Washington, DC",
languageCode: "en",
country: "US",
logger: logger
);
Weather Alert Helper
using Xcalibur.Weather.Helpers.Services;
using Microsoft.Extensions.Logging;
// Build combined weather alerts from multiple sources
// (Meteoalarm, NWS, GDACS, Environment Canada, BOM, EMSC, DWD)
// Intelligently selects services based on geographic location
var alerts = await WeatherAlertHelper.BuildCombinedAlertsAsync(
latitude: "52.52",
longitude: "13.41",
logger: logger,
token: CancellationToken.None,
provinceCode: null, // Optional: for Canada (e.g., "ON", "BC")
stateCode: null // Optional: for Australia (e.g., "NSW", "VIC")
);
if (alerts is not null && alerts.Alerts.Any())
{
Console.WriteLine($"Active Alerts: {alerts.TotalAlerts}");
foreach (var alert in alerts.Alerts)
{
Console.WriteLine($"[{alert.Severity}] {alert.Event}");
Console.WriteLine($" Source: {alert.Source}");
Console.WriteLine($" Effective: {alert.Effective}");
Console.WriteLine($" Expires: {alert.Expires}");
}
}
// BUILD WITH AUTOMATIC CONSOLIDATION (Recommended for UI display)
// Automatically consolidates overlapping alerts (e.g., Winter Weather Advisory + Winter Storm Warning)
// Keeps only the highest severity alert from each overlapping group
var consolidatedAlerts = await WeatherAlertHelper.BuildCombinedAlertsConsolidatedAsync(
latitude: "39.4300996",
longitude: "-77.804161",
logger: logger,
token: CancellationToken.None
);
// Simple and clean - just iterate the results
foreach (var alert in consolidatedAlerts)
{
Console.WriteLine($"[{alert.Severity}] {alert.Event}");
Console.WriteLine($" Source: {alert.Source}");
Console.WriteLine($" Effective: {alert.Effective}");
Console.WriteLine($" Expires: {alert.Expires}");
}
// MANUAL CONSOLIDATION (if you need access to the full CombinedWeatherAlertInformation object)
var fullAlerts = await WeatherAlertHelper.BuildCombinedAlertsAsync(
"39.4300996", "-77.804161", logger, CancellationToken.None);
if (fullAlerts is not null)
{
Console.WriteLine($"Total Alerts: {fullAlerts.TotalAlerts}");
Console.WriteLine($"Data Sources: {string.Join(", ", fullAlerts.DataSources)}");
// Manually consolidate if needed
var consolidated = WeatherAlertHelper.ConsolidateAlerts(fullAlerts.Alerts, logger);
foreach (var alert in consolidated)
{
Console.WriteLine($"[{alert.Severity}] {alert.Event}");
}
}
// Region-aware combined alerts are now the supported public alert API.
// Use optional provinceCode/stateCode when you want to override automatic region detection.
var canadaAlerts = await WeatherAlertHelper.BuildCombinedAlertsAsync(
latitude: "43.65",
longitude: "-79.38",
logger: logger,
token: CancellationToken.None,
provinceCode: "ON"
);
var australiaAlerts = await WeatherAlertHelper.BuildCombinedAlertsAsync(
latitude: "-33.87",
longitude: "151.21",
logger: logger,
token: CancellationToken.None,
stateCode: "NSW"
);
// For UI display, prefer the consolidated list.
var consolidated = await WeatherAlertHelper.BuildCombinedAlertsConsolidatedAsync(
latitude: "52.52",
longitude: "13.41",
logger: logger,
token: CancellationToken.None
);
foreach (var alert in consolidated)
{
Console.WriteLine($"[{alert.Severity}] {alert.Event}");
}
Weather Observation Helper
using Xcalibur.Weather.Helpers.Services;
using Microsoft.Extensions.Logging;
// Get the nearest observation for coordinates
var observation = await WeatherObservationHelper.GetObservationAsync(
latitude: "40.7128",
longitude: "-74.0060",
logger: logger,
token: CancellationToken.None
);
// Get several nearby observations
var nearbyObservations = await WeatherObservationHelper.GetMultipleObservationsAsync(
latitude: "40.7128",
longitude: "-74.0060",
maxResults: 5,
logger: logger,
token: CancellationToken.None
);
// Determine the observation routing region
var observationRegion = WeatherObservationHelper.DetermineRegion("40.7128", "-74.0060");
Console.WriteLine($"Observation Region: {observationRegion}");
Weather Region Helper
using Xcalibur.Weather.Helpers.Services;
// Determine geographic region from coordinates
var region = WeatherRegionHelper.DetermineRegion(
latitude: 52.52,
longitude: 13.41
);
Console.WriteLine($"Region: {region}"); // Output: Europe
// Check if coordinates are in Germany
bool isGermany = WeatherRegionHelper.IsInGermany(
latitude: 52.52,
longitude: 13.41
);
// Determine Canadian province from coordinates
var province = WeatherRegionHelper.DetermineCanadianProvince(
latitude: 43.65,
longitude: -79.38
);
Console.WriteLine($"Province: {province}"); // Output: ON
// Determine Australian state from coordinates
var state = WeatherRegionHelper.DetermineAustralianState(
latitude: -33.87,
longitude: 151.21
);
Console.WriteLine($"State: {state}"); // Output: NSW
API Overview
ConversionHelper
| Method | Description |
|---|---|
CelsiusToFahrenheit(double) |
Converts temperature from Celsius to Fahrenheit |
CelsiusToFahrenheit(double?, double) |
Converts nullable Celsius to Fahrenheit; returns defaultValue when null |
FahrenheitToCelsius(double) |
Converts temperature from Fahrenheit to Celsius |
FahrenheitToCelsius(double?, double) |
Converts nullable Fahrenheit to Celsius; returns defaultValue when null |
ConvertWindSpeed(double, WindSpeedUnits?) |
Converts wind speed from km/h to specified unit |
ConvertWindSpeed(double?, WindSpeedUnits?) |
Converts nullable wind speed; returns 0 when null |
FormatTemperature(double, TemperatureUnits?, bool) |
Formats temperature with optional unit symbol |
FormatTemperature(double?, TemperatureUnits?, bool) |
Formats nullable temperature; returns empty string when null |
FormatLength(double?, DistanceUnits, bool) |
Formats length/precipitation with optional unit symbol |
FormatPressure(double?, BarometerUnits, bool) |
Formats pressure with optional unit symbol |
OpenMeteoHelper
| Method | Description |
|---|---|
BuildAirQualityPointAsync(string, string, ILogger, CancellationToken) |
Retrieves and builds air quality data for coordinates |
BuildCurrentForecastAsync(string, string, ILogger, CancellationToken) |
Retrieves and builds current weather forecast point |
BuildShortTermForecastAsync(string, string, ILogger, CancellationToken) |
Retrieves and builds 15-minute forecast points |
BuildHourlyForecastAsync(string, string, int, int, ILogger, CancellationToken) |
Retrieves and builds hourly forecast points across forecast and past-day ranges |
BuildDailyForecastAsync(string, string, int, int, ILogger, CancellationToken) |
Retrieves and builds daily forecast points across forecast and past-day ranges |
BuildYesterdayHourlyForecastAsync(string, string, string, ILogger, CancellationToken) |
Retrieves and builds yesterday's hourly forecast |
BuildYesterdayDailyForecastAsync(string, string, string, string, ILogger, CancellationToken) |
Retrieves and builds yesterday's daily forecast |
BuildHourlyAirQualityAsync(string, string, int, int, ILogger, CancellationToken) |
Retrieves and builds hourly air-quality points across forecast and past-day ranges |
GeocodioHelper
| Method | Description |
|---|---|
TestApiKeyAsync(string, ILogger) |
Tests the validity of a Geocodio API key |
BuildAddressLocationsAsync(...) |
Geocodes an address query and builds location models |
IpGeoHelper
| Method | Description |
|---|---|
TestApiKeyAsync(string, ILogger) |
Tests the validity of an IpGeolocation API key |
BuildSunMoonPointAsync(string, string, string, ILogger) |
Retrieves and builds sun/moon astronomical data |
AtmosporeHelper
| Method | Description |
|---|---|
TestApiKeyAsync(string, ILogger) |
Tests the validity of an Atmospore API key |
BuildPollenForecastAsync(string, string, string, string?, int, ILogger?) |
Retrieves and maps Atmospore pollen forecast data to a PollenInformation model |
SunriseSunsetHelper
| Method | Description |
|---|---|
BuildSunMoonPointAsync(string, string, ILogger?) |
Fetches sunrise/sunset data from SunriseSunset.io and maps it to a SunMoonPoint โ no API key required |
OpenStreetMapHelper
| Method | Description |
|---|---|
BuildAddressLocationsAsync(string, string?, string?, ILogger?) |
Geocodes an address query via OpenStreetMap Nominatim with optional language and country filtering โ no API key required |
WeatherAlertHelper
| Method | Description |
|---|---|
BuildCombinedAlertsAsync(string, string, ILogger, CancellationToken, string?, string?) |
Aggregates weather alerts from multiple global sources (Meteoalarm, NWS, GDACS, Environment Canada, BOM, EMSC, DWD) into a unified CombinedWeatherAlertInformation model. Intelligently selects services based on geographic location. Optional provinceCode for Canada and stateCode for Australia. |
BuildCombinedAlertsConsolidatedAsync(...) |
Recommended for UI display. Returns only the consolidated alerts list, removing overlapping duplicates and keeping the highest severity alert from each group. Returns an empty list if no alerts exist. Clean, simple API. |
ConsolidateAlerts(IEnumerable<WeatherAlertItem>, ILogger?) |
Consolidates a collection of alerts by removing overlapping duplicates and keeping the highest severity alert from each group. Use this for manual consolidation when you need access to the full CombinedWeatherAlertInformation object. |
WeatherObservationHelper
| Method | Description |
|---|---|
GetObservationAsync(string, string, ILogger, CancellationToken) |
Retrieves the nearest observation using string coordinates |
GetObservationAsync(double, double, ILogger, CancellationToken) |
Retrieves the nearest observation using numeric coordinates |
GetMultipleObservationsAsync(string, string, int, ILogger, CancellationToken) |
Retrieves multiple nearby observations using string coordinates |
GetMultipleObservationsAsync(double, double, int, ILogger, CancellationToken) |
Retrieves multiple nearby observations using numeric coordinates |
DetermineRegion(string, string) |
Determines the observation region from string coordinates |
DetermineRegion(double, double) |
Determines the observation region from numeric coordinates |
GetNwsObservationAsync(double, double, ILogger, CancellationToken) |
Retrieves an observation from NWS directly |
GetEcccObservationAsync(double, double, ILogger, CancellationToken) |
Retrieves an observation from ECCC directly |
GetMetarObservationAsync(double, double, ILogger, CancellationToken) |
Retrieves an observation from METAR directly |
TimeZoneHelper
| Method | Description |
|---|---|
ConvertFromTimezone(DateTime?, string?) |
Converts a nullable DateTime using the provided timezone |
ConvertFromTimezone(DateTime, string?) |
Converts a DateTime using the provided timezone |
ConvertFromTimezoneUtc(DateTime?, string?) |
Converts a nullable UTC DateTime from UTC into the provided timezone |
ConvertFromTimezoneUtc(DateTime, string?) |
Converts a UTC DateTime from UTC into the provided timezone |
WeatherRegionHelper
| Method | Description |
|---|---|
DetermineRegion(double, double) |
Determines the geographic region (US, Canada, Europe, Australia, Other) based on coordinates |
IsInGermany(double, double) |
Checks if coordinates fall within German geographic bounds |
DetermineCanadianProvince(double, double) |
Returns the two-letter Canadian province code for the given coordinates |
DetermineAustralianState(double, double) |
Returns the Australian state code for the given coordinates |
Testing
The library ships with a comprehensive xUnit test suite covering all helpers and conversion utilities.
Test Coverage
| Area | Tests | Coverage |
|---|---|---|
ConversionHelper |
Temperature, wind speed, length, and pressure conversions and formatting โ including nullable overloads, null-unit guards, near-zero normalisation, and invalid-unit exceptions | Full public API |
OpenMeteoHelper |
Air quality, current, short-term, hourly, daily, and yesterday forecasts โ including absent/empty response blocks and timezone-aware current-point assessment | Full public API |
GeocodioHelper |
Address location mapping (single and multiple results), null/empty/invalid-JSON responses, API key validation | Full public API |
IpGeoHelper |
Sun/moon point mapping, null/whitespace key guards, deserialization, and HTTP error responses | Full public API |
SunriseSunsetHelper |
Sun/moon point mapping, successful deserialization, HTTP error and invalid-JSON responses | Full public API |
OpenStreetMapHelper |
Address location mapping, town fallback, language/country filtering, empty/null/invalid-JSON/HTTP error responses |
Full public API |
AtmosporeHelper |
Pollen forecast deserialization, API key validation, null/whitespace guards, HTTP error and invalid-JSON responses | Full public API |
WeatherAlertHelper |
Combined alert aggregation, consolidation behavior, overlap resolution, countryName parameter routing, and cancellation behavior |
Full public API |
WeatherAlertService |
Meteoalarm country-lookup (all 40 supported feeds, case-insensitive, whitespace trim), non-European short-circuit, HTTP error handling | Full GetMeteoalarmAlertsAsync API |
WeatherObservationHelper |
Invalid coordinate handling, nearest observation routing, nearby observation retrieval, and string/double overload region determination | Focused public API coverage |
TimeZoneHelper |
Null handling and timezone conversion behavior across all nullable and non-nullable overloads | Full public API |
WeatherRegionHelper |
Region determination (US, Canada, Europe, Australia), Germany bounds check, Canadian province detection, Australian state detection | Full public API |
Running the Tests
dotnet test
Or via the .NET CLI targeting the test project directly:
dotnet test Xcalibur.Weather.Helpers.Tests/Xcalibur.Weather.Helpers.Tests.csproj
Best Practices
Null Handling
All conversion methods include overloads that handle nullable values:
double? temperature = null;
double result = temperature.CelsiusToFahrenheit(defaultValue: 0); // Returns 0
Logging
All service helpers accept an ILogger parameter for diagnostics and troubleshooting:
using Microsoft.Extensions.Logging;
ILogger logger = loggerFactory.CreateLogger<YourClass>();
var forecast = await OpenMeteoHelper.BuildCurrentForecastAsync(
latitude, longitude, logger, CancellationToken.None
);
HttpClient Usage
Service helpers manage HttpClient usage internally, so callers can use the helper APIs directly without constructing provider service instances.
Dependencies
This library depends on:
- Xcalibur.Weather.Services (v1.1.6) - Weather service providers and models
- Microsoft.Extensions.Hosting (v10.0.11) - Hosting abstractions
Changelog
Version 1.1.6 (Latest)
- โจ Improved: Meteoalarm feed resolution replaced runtime slug-builder with a curated
MeteoalarmFeedSlugslookup- 40 European countries and the
"Europe"aggregate feed supported - Unsupported countries short-circuit immediately with a warning โ no speculative HTTP requests
- Irregular slugs (
czechia,republic-of-north-macedonia) mapped correctly
- 40 European countries and the
- โจ Improved:
BuildCombinedAlertsAsyncaccepts optionalcountryNamefor targeted European feed selection - ๐ Updated: Dependency on Xcalibur.Weather.Services v1.1.6
- ๐ Maintained: Dependency on Microsoft.Extensions.Hosting v10.0.11
- ๐งช Testing: Added
WeatherAlertServiceTests(53 tests) covering full country lookup table, case sensitivity, HTTP error paths, and helpercountryNamerouting - ๐ฆ Packaging: Package metadata and README synchronized for v1.1.6
Version 1.1.5
- โจ Improved: Native AOT compatibility for observation deserialization
- Added explicit source-generated JSON metadata coverage for NWS observation payloads
- Added explicit source-generated JSON metadata coverage for METAR observation payloads
- Hardens serializer behavior for trimmed and ahead-of-time compiled applications
- ๐ Updated: Dependency on Xcalibur.Weather.Services v1.1.5
- ๐ Maintained: Dependency on Microsoft.Extensions.Hosting v10.0.11
- ๐งช Testing: Expanded
WeatherObservationHelperandTimeZoneHelpercoverage for additional overload and edge-case behavior - ๐ฆ Packaging: Package metadata and README synchronized for v1.1.5
Version 1.1.0
- โจ New:
WeatherObservationHelperfor nearest and nearby observation retrieval- Supports string and numeric coordinates
- Adds region detection for observation routing
- Includes direct NWS, ECCC, and METAR observation helpers
- โจ New:
TimeZoneHelperextension methods for timezone conversion - โจ New:
BuildShortTermForecastAsyncfor 15-minute OpenMeteo forecasts - ๐ Improved: OpenMeteo helpers now use timezone-aware current-day/current-hour mapping
- ๐ Improved:
OpenStreetMapHelper.BuildAddressLocationsAsyncnow accepts optionallanguageCodeandcountry - ๐งน Changed:
WeatherAlertHelperpublic API is centered on combined aggregation and consolidation methods - ๐ Updated: Dependency on Xcalibur.Weather.Services v1.1.0
- ๐ Updated: Dependency on Microsoft.Extensions.Hosting v10.0.11
- ๐งช Testing: Added tests for
WeatherObservationHelperandTimeZoneHelper, and synchronized helper tests with current signatures - ๐ฆ Packaging: Package metadata and README synchronized for v1.1.0
Version 1.0.24
- โจ New: Historic data retrieval for all OpenMeteo forecast functions
BuildDailyForecastAsyncnow acceptsforecastDaysandpastDaysparametersBuildHourlyForecastAsyncnow acceptsforecastDaysandpastDaysparameters- Consistent API pattern across all OpenMeteo forecast methods
- Enables querying both future forecasts and historical weather data
- ๐ Updated: Dependency on Xcalibur.Weather.Services v1.0.24
- ๐ Maintained: Dependency on Xcalibur.Weather.Models v1.0.21
- ๐งช Testing: Updated all forecast tests for the new method signatures
- ๐ฆ Packaging: Package references synchronized for v1.0.24
Version 1.0.22
- โจ New: Historic hourly air quality retrieval support
BuildHourlyAirQualityAsyncnow acceptsforecastDaysandpastDays- Supports retrieving historical and forecast hourly air quality data in a single flow
- Preserves current-hour detection for mapped
AirQualityPointresults
- ๐ Updated: Dependency on Xcalibur.Weather.Services v1.0.22
- ๐ Maintained: Dependency on Xcalibur.Weather.Models v1.0.21
- ๐งช Testing: Updated hourly air quality tests for the new method signature
- ๐ฆ Packaging: Package references synchronized for v1.0.22
Version 1.0.21
- โจ New: Air Quality Index (AQI) enhancements to account for US and EU metrics
- Full US AQI support with individual pollutant tracking and health recommendations
- Complete EU AQI implementation with European air quality standards
- New
BuildHourlyAirQualityAsyncmethod for hourly air quality forecasts - Automatic current hour detection in air quality data
- ๐ Updated: Dependency on Xcalibur.Weather.Services v1.0.21
- ๐ Updated: Dependency on Xcalibur.Weather.Models v1.0.21
- ๐งช Testing: Added comprehensive test coverage for hourly air quality functionality
- ๐ฆ Packaging: All dependencies synchronized to v1.0.21
Version 1.0.20
- โจ New: Enhanced air quality data support
- ๐ Updated: Dependency on Xcalibur.Weather.Services v1.0.20
- ๐ง Improved: Air quality point data structures
Version 1.0.19
- โจ New: Relative humidity support for daily forecasts
- Added relative humidity data to daily forecast models
- Enhanced daily weather models with moisture information
- Improved data completeness for agricultural and outdoor activity planning
- ๐ Updated: Dependency on Xcalibur.Weather.Services v1.0.19
- ๐ง Improved: Daily forecast models enhanced with additional meteorological parameters
- ๐ฆ Packaging: Updated dependencies for better compatibility
Version 1.0.18
- โจ New: Supplemental weather data support for hourly and daily forecasts
- Added
GetHourlyForecastSupplementalAsyncmethod for enhanced hourly data - Added
GetDailyForecastSupplementalAsyncmethod for enhanced daily data - Automatic merging of supplemental forecast parameters
- Added
- ๐ Updated: Dependency on Xcalibur.Weather.Services v1.0.18
- ๐ Updated: Dependency on Xcalibur.Weather.Models v1.0.18
- ๐ง Improved: OpenMeteoHelper refactored for better supplemental data integration
- ๐ฆ Maintenance: All test packages updated to latest versions
- โก Performance: Optimized data mapping and processing
Version 1.0.17
- ๐ Breaking Change: Weather code value retired for multi-language compatibility
- Removed
WeatherCodeValuestring property from forecast models - WMO weather code integer remains available for custom locale implementations
- Removed
- ๐ Updated: Dependency on Xcalibur.Weather.Services v1.0.17
- ๐ Fixed: Several improvements and bug fixes for model handling
- โก Performance: MVVM performance improvements and optimizations
- ๐ง Improved: Model changes for better data handling
- ๐งช Testing: Several test updates and improvements
Version 1.0.16
- ๐ Updated: Dependency on Xcalibur.Weather.Services v1.0.17
- ๐ Updated: Dependency on Microsoft.Extensions.Hosting v10.0.10
- ๐ Documentation: Enhanced README with Purpose and Use Cases sections
- ๐๏ธ Improved: Project structure and formatting consistency
- ๐ง Maintenance: Minor improvements and dependency updates
Version 1.0.15
- ๐ Updated: Dependency on Xcalibur.Weather.Services v1.0.16
- ๐ Updated: Dependency on Microsoft.Extensions.Hosting v10.0.10
- ๐ Documentation: Enhanced README with Purpose and Use Cases sections
- ๐๏ธ Improved: Project structure and formatting consistency
- ๐ง Maintenance: Minor improvements and dependency updates
Version 1.0.10
- โจ New: Added consolidated alert methods for all 7 weather alert providers
BuildCombinedAlertsConsolidatedAsync- Multi-provider consolidated alertsBuildNwsAlertsConsolidatedAsync- US National Weather ServiceBuildMeteoalarmAlertsConsolidatedAsync- European weather alertsBuildEnvironmentCanadaAlertsConsolidatedAsync- Canadian weather alertsBuildBomAlertsConsolidatedAsync- Australian Bureau of MeteorologyBuildGdacsAlertsConsolidatedAsync- Global disaster alertsBuildDwdAlertsConsolidatedAsync- German weather warningsBuildEmscAlertsConsolidatedAsync- Earthquake/seismic alerts
- ๐ Improved: Automatic consolidation of overlapping alerts by event type and severity
- ๐ฏ Optimized: Clean API design returning
IReadOnlyList<WeatherAlertItem>for easier consumption - ๐ Documentation: Comprehensive examples for all consolidated methods
- โ Testing: 23 new tests covering all consolidated alert scenarios
Version 1.0.9
- ๐ Updated README with version information
- ๐ง Minor improvements and bug fixes
Version 1.0.8
- ๐ Comprehensive weather alert support (Meteoalarm, NWS, GDACS, Environment Canada, BOM, EMSC, DWD)
- ๐ ๏ธ Helper utilities for Open-Meteo, Geocodio, IpGeolocation, Atmospore, SunriseSunset, OpenStreetMap
- ๐ Conversion helpers for temperature, wind speed, length, and pressure
- ๐ Geographic region detection and routing
License
This project is licensed under the Apache License 2.0. See the LICENSE-2.0.txt file for details.
Copyright ยฉ 2006 - 2026, Xcalibur Systems, LLC - All Rights Reserved
Related Projects
- Xcalibur.Weather.Services (v1.1.6) - HTTP client services for weather APIs and models (GitHub)
Part of the Xcalibur Weather ecosystem for comprehensive weather data integration.
Author
Joshua Arzt
Xcalibur Systems, LLC
| 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. |
-
net10.0
- Microsoft.Extensions.Hosting (>= 10.0.11)
- Xcalibur.Weather.Services (>= 1.1.6)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.1.7 | 110 | 8/16/2026 |
| 1.1.6 | 105 | 8/16/2026 |
| 1.1.4 | 100 | 8/15/2026 |
| 1.1.3 | 98 | 8/15/2026 |
| 1.1.0 | 111 | 8/13/2026 |
| 1.0.24 | 98 | 8/7/2026 |
| 1.0.23 | 96 | 8/5/2026 |
| 1.0.22 | 97 | 8/5/2026 |
| 1.0.21 | 105 | 8/4/2026 |
| 1.0.19 | 113 | 8/3/2026 |
| 1.0.18 | 105 | 7/31/2026 |
| 1.0.17 | 110 | 7/31/2026 |
| 1.0.16 | 110 | 7/28/2026 |
| 1.0.15 | 106 | 7/28/2026 |
| 1.0.13 | 167 | 7/7/2026 |
| 1.0.12 | 112 | 7/6/2026 |
| 1.0.11 | 142 | 7/3/2026 |
| 1.0.10 | 108 | 7/2/2026 |
| 1.0.9 | 127 | 7/2/2026 |
| 1.0.8 | 114 | 7/2/2026 |
Meteoalarm Country Lookup revisions.