From abddf2521ea1b0c50e674d1653ffe96aeb0de401 Mon Sep 17 00:00:00 2001 From: Colin Noakes Date: Mon, 11 Mar 2024 18:47:51 -0700 Subject: [PATCH 01/23] feat: Add ECMWF 0.25 IFS and AIFS models --- OpenMeteo/WeatherModelOptions.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/OpenMeteo/WeatherModelOptions.cs b/OpenMeteo/WeatherModelOptions.cs index cb955e8..0d69688 100644 --- a/OpenMeteo/WeatherModelOptions.cs +++ b/OpenMeteo/WeatherModelOptions.cs @@ -104,6 +104,8 @@ public enum WeatherModelOptionsParameter { best_match, ecmwf_ifs04, + ecmwf_ifs025, + ecmwf_aifs025, metno_nordic, gfs_seamless, gfs_global, From c5a963659e1889988dc8c6d96462e9fa574895a0 Mon Sep 17 00:00:00 2001 From: Colin Noakes Date: Mon, 11 Mar 2024 19:56:48 -0700 Subject: [PATCH 02/23] feat: Add Hourly units for ECMWF 0.25 models --- OpenMeteo/Hourly.cs | 112 +++++++++++++++++++++++++++++++++++++++ OpenMeteo/HourlyUnits.cs | 112 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 224 insertions(+) diff --git a/OpenMeteo/Hourly.cs b/OpenMeteo/Hourly.cs index 95fe2b7..d25879e 100644 --- a/OpenMeteo/Hourly.cs +++ b/OpenMeteo/Hourly.cs @@ -437,6 +437,118 @@ public class Hourly public float?[]? Geopotential_height_250hPa_ecmwf_ifs04 { get; set; } public float?[]? Geopotential_height_200hPa_ecmwf_ifs04 { get; set; } public float?[]? Geopotential_height_50hPa_ecmwf_ifs04 { get; set; } + public float?[]? Temperature_2m_ecmwf_ifs025 { get; set; } + public float?[]? Precipitation_ecmwf_ifs025 { get; set; } + public float?[]? Snowfall_ecmwf_ifs025 { get; set; } + public int?[]? Weathercode_ecmwf_ifs025 { get; set; } + public float?[]? Pressure_msl_ecmwf_ifs025 { get; set; } + public int?[]? Cloudcover_ecmwf_ifs025 { get; set; } + public int?[]? Cloudcover_low_ecmwf_ifs025 { get; set; } + public int?[]? Cloudcover_mid_ecmwf_ifs025 { get; set; } + public int?[]? Cloudcover_high_ecmwf_ifs025 { get; set; } + public float?[]? Windspeed_10m_ecmwf_ifs025 { get; set; } + public int?[]? Winddirection_10m_ecmwf_ifs025 { get; set; } + public float?[]? Temperature_1000hPa_ecmwf_ifs025 { get; set; } + public float?[]? Temperature_925hPa_ecmwf_ifs025 { get; set; } + public float?[]? Temperature_850hPa_ecmwf_ifs025 { get; set; } + public float?[]? Temperature_700hPa_ecmwf_ifs025 { get; set; } + public float?[]? Temperature_500hPa_ecmwf_ifs025 { get; set; } + public float?[]? Temperature_300hPa_ecmwf_ifs025 { get; set; } + public float?[]? Temperature_250hPa_ecmwf_ifs025 { get; set; } + public float?[]? Temperature_200hPa_ecmwf_ifs025 { get; set; } + public float?[]? Temperature_50hPa_ecmwf_ifs025 { get; set; } + public int?[]? Cloudcover_1000hPa_ecmwf_ifs025 { get; set; } + public int?[]? Cloudcover_925hPa_ecmwf_ifs025 { get; set; } + public int?[]? Cloudcover_850hPa_ecmwf_ifs025 { get; set; } + public int?[]? Cloudcover_700hPa_ecmwf_ifs025 { get; set; } + public int?[]? Cloudcover_500hPa_ecmwf_ifs025 { get; set; } + public int?[]? Cloudcover_300hPa_ecmwf_ifs025 { get; set; } + public int?[]? Cloudcover_250hPa_ecmwf_ifs025 { get; set; } + public int?[]? Cloudcover_200hPa_ecmwf_ifs025 { get; set; } + public int?[]? Cloudcover_50hPa_ecmwf_ifs025 { get; set; } + public float?[]? Windspeed_1000hPa_ecmwf_ifs025 { get; set; } + public float?[]? Windspeed_925hPa_ecmwf_ifs025 { get; set; } + public float?[]? Windspeed_850hPa_ecmwf_ifs025 { get; set; } + public float?[]? Windspeed_700hPa_ecmwf_ifs025 { get; set; } + public float?[]? Windspeed_500hPa_ecmwf_ifs025 { get; set; } + public float?[]? Windspeed_300hPa_ecmwf_ifs025 { get; set; } + public float?[]? Windspeed_250hPa_ecmwf_ifs025 { get; set; } + public float?[]? Windspeed_200hPa_ecmwf_ifs025 { get; set; } + public float?[]? Windspeed_50hPa_ecmwf_ifs025 { get; set; } + public int?[]? Winddirection_1000hPa_ecmwf_ifs025 { get; set; } + public int?[]? Winddirection_925hPa_ecmwf_ifs025 { get; set; } + public int?[]? Winddirection_850hPa_ecmwf_ifs025 { get; set; } + public int?[]? Winddirection_700hPa_ecmwf_ifs025 { get; set; } + public int?[]? Winddirection_500hPa_ecmwf_ifs025 { get; set; } + public int?[]? Winddirection_300hPa_ecmwf_ifs025 { get; set; } + public int?[]? Winddirection_250hPa_ecmwf_ifs025 { get; set; } + public int?[]? Winddirection_200hPa_ecmwf_ifs025 { get; set; } + public int?[]? Winddirection_50hPa_ecmwf_ifs025 { get; set; } + public float?[]? Geopotential_height_1000hPa_ecmwf_ifs025 { get; set; } + public float?[]? Geopotential_height_925hPa_ecmwf_ifs025 { get; set; } + public float?[]? Geopotential_height_850hPa_ecmwf_ifs025 { get; set; } + public float?[]? Geopotential_height_700hPa_ecmwf_ifs025 { get; set; } + public float?[]? Geopotential_height_500hPa_ecmwf_ifs025 { get; set; } + public float?[]? Geopotential_height_300hPa_ecmwf_ifs025 { get; set; } + public float?[]? Geopotential_height_250hPa_ecmwf_ifs025 { get; set; } + public float?[]? Geopotential_height_200hPa_ecmwf_ifs025 { get; set; } + public float?[]? Geopotential_height_50hPa_ecmwf_ifs025 { get; set; } + public float?[]? Temperature_2m_ecmwf_aifs025 { get; set; } + public float?[]? Precipitation_ecmwf_aifs025 { get; set; } + public float?[]? Snowfall_ecmwf_aifs025 { get; set; } + public int?[]? Weathercode_ecmwf_aifs025 { get; set; } + public float?[]? Pressure_msl_ecmwf_aifs025 { get; set; } + public int?[]? Cloudcover_ecmwf_aifs025 { get; set; } + public int?[]? Cloudcover_low_ecmwf_aifs025 { get; set; } + public int?[]? Cloudcover_mid_ecmwf_aifs025 { get; set; } + public int?[]? Cloudcover_high_ecmwf_aifs025 { get; set; } + public float?[]? Windspeed_10m_ecmwf_aifs025 { get; set; } + public int?[]? Winddirection_10m_ecmwf_aifs025 { get; set; } + public float?[]? Temperature_1000hPa_ecmwf_aifs025 { get; set; } + public float?[]? Temperature_925hPa_ecmwf_aifs025 { get; set; } + public float?[]? Temperature_850hPa_ecmwf_aifs025 { get; set; } + public float?[]? Temperature_700hPa_ecmwf_aifs025 { get; set; } + public float?[]? Temperature_500hPa_ecmwf_aifs025 { get; set; } + public float?[]? Temperature_300hPa_ecmwf_aifs025 { get; set; } + public float?[]? Temperature_250hPa_ecmwf_aifs025 { get; set; } + public float?[]? Temperature_200hPa_ecmwf_aifs025 { get; set; } + public float?[]? Temperature_50hPa_ecmwf_aifs025 { get; set; } + public int?[]? Cloudcover_1000hPa_ecmwf_aifs025 { get; set; } + public int?[]? Cloudcover_925hPa_ecmwf_aifs025 { get; set; } + public int?[]? Cloudcover_850hPa_ecmwf_aifs025 { get; set; } + public int?[]? Cloudcover_700hPa_ecmwf_aifs025 { get; set; } + public int?[]? Cloudcover_500hPa_ecmwf_aifs025 { get; set; } + public int?[]? Cloudcover_300hPa_ecmwf_aifs025 { get; set; } + public int?[]? Cloudcover_250hPa_ecmwf_aifs025 { get; set; } + public int?[]? Cloudcover_200hPa_ecmwf_aifs025 { get; set; } + public int?[]? Cloudcover_50hPa_ecmwf_aifs025 { get; set; } + public float?[]? Windspeed_1000hPa_ecmwf_aifs025 { get; set; } + public float?[]? Windspeed_925hPa_ecmwf_aifs025 { get; set; } + public float?[]? Windspeed_850hPa_ecmwf_aifs025 { get; set; } + public float?[]? Windspeed_700hPa_ecmwf_aifs025 { get; set; } + public float?[]? Windspeed_500hPa_ecmwf_aifs025 { get; set; } + public float?[]? Windspeed_300hPa_ecmwf_aifs025 { get; set; } + public float?[]? Windspeed_250hPa_ecmwf_aifs025 { get; set; } + public float?[]? Windspeed_200hPa_ecmwf_aifs025 { get; set; } + public float?[]? Windspeed_50hPa_ecmwf_aifs025 { get; set; } + public int?[]? Winddirection_1000hPa_ecmwf_aifs025 { get; set; } + public int?[]? Winddirection_925hPa_ecmwf_aifs025 { get; set; } + public int?[]? Winddirection_850hPa_ecmwf_aifs025 { get; set; } + public int?[]? Winddirection_700hPa_ecmwf_aifs025 { get; set; } + public int?[]? Winddirection_500hPa_ecmwf_aifs025 { get; set; } + public int?[]? Winddirection_300hPa_ecmwf_aifs025 { get; set; } + public int?[]? Winddirection_250hPa_ecmwf_aifs025 { get; set; } + public int?[]? Winddirection_200hPa_ecmwf_aifs025 { get; set; } + public int?[]? Winddirection_50hPa_ecmwf_aifs025 { get; set; } + public float?[]? Geopotential_height_1000hPa_ecmwf_aifs025 { get; set; } + public float?[]? Geopotential_height_925hPa_ecmwf_aifs025 { get; set; } + public float?[]? Geopotential_height_850hPa_ecmwf_aifs025 { get; set; } + public float?[]? Geopotential_height_700hPa_ecmwf_aifs025 { get; set; } + public float?[]? Geopotential_height_500hPa_ecmwf_aifs025 { get; set; } + public float?[]? Geopotential_height_300hPa_ecmwf_aifs025 { get; set; } + public float?[]? Geopotential_height_250hPa_ecmwf_aifs025 { get; set; } + public float?[]? Geopotential_height_200hPa_ecmwf_aifs025 { get; set; } + public float?[]? Geopotential_height_50hPa_ecmwf_aifs025 { get; set; } public float?[]? Temperature_2m_gfs_seamless { get; set; } public int?[]? Relativehumidity_2m_gfs_seamless { get; set; } public float?[]? Dewpoint_2m_gfs_seamless { get; set; } diff --git a/OpenMeteo/HourlyUnits.cs b/OpenMeteo/HourlyUnits.cs index 929cb6b..55f18b1 100644 --- a/OpenMeteo/HourlyUnits.cs +++ b/OpenMeteo/HourlyUnits.cs @@ -437,6 +437,118 @@ public class HourlyUnits public string? Geopotential_height_250hPa_ecmwf_ifs04 { get; set; } public string? Geopotential_height_200hPa_ecmwf_ifs04 { get; set; } public string? Geopotential_height_50hPa_ecmwf_ifs04 { get; set; } + public string? Temperature_2m_ecmwf_ifs025 { get; set; } + public string? Precipitation_ecmwf_ifs025 { get; set; } + public string? Snowfall_ecmwf_ifs025 { get; set; } + public string? Weathercode_ecmwf_ifs025 { get; set; } + public string? Pressure_msl_ecmwf_ifs025 { get; set; } + public string? Cloudcover_ecmwf_ifs025 { get; set; } + public string? Cloudcover_low_ecmwf_ifs025 { get; set; } + public string? Cloudcover_mid_ecmwf_ifs025 { get; set; } + public string? Cloudcover_high_ecmwf_ifs025 { get; set; } + public string? Windspeed_10m_ecmwf_ifs025 { get; set; } + public string? Winddirection_10m_ecmwf_ifs025 { get; set; } + public string? Temperature_1000hPa_ecmwf_ifs025 { get; set; } + public string? Temperature_925hPa_ecmwf_ifs025 { get; set; } + public string? Temperature_850hPa_ecmwf_ifs025 { get; set; } + public string? Temperature_700hPa_ecmwf_ifs025 { get; set; } + public string? Temperature_500hPa_ecmwf_ifs025 { get; set; } + public string? Temperature_300hPa_ecmwf_ifs025 { get; set; } + public string? Temperature_250hPa_ecmwf_ifs025 { get; set; } + public string? Temperature_200hPa_ecmwf_ifs025 { get; set; } + public string? Temperature_50hPa_ecmwf_ifs025 { get; set; } + public string? Cloudcover_1000hPa_ecmwf_ifs025 { get; set; } + public string? Cloudcover_925hPa_ecmwf_ifs025 { get; set; } + public string? Cloudcover_850hPa_ecmwf_ifs025 { get; set; } + public string? Cloudcover_700hPa_ecmwf_ifs025 { get; set; } + public string? Cloudcover_500hPa_ecmwf_ifs025 { get; set; } + public string? Cloudcover_300hPa_ecmwf_ifs025 { get; set; } + public string? Cloudcover_250hPa_ecmwf_ifs025 { get; set; } + public string? Cloudcover_200hPa_ecmwf_ifs025 { get; set; } + public string? Cloudcover_50hPa_ecmwf_ifs025 { get; set; } + public string? Windspeed_1000hPa_ecmwf_ifs025 { get; set; } + public string? Windspeed_925hPa_ecmwf_ifs025 { get; set; } + public string? Windspeed_850hPa_ecmwf_ifs025 { get; set; } + public string? Windspeed_700hPa_ecmwf_ifs025 { get; set; } + public string? Windspeed_500hPa_ecmwf_ifs025 { get; set; } + public string? Windspeed_300hPa_ecmwf_ifs025 { get; set; } + public string? Windspeed_250hPa_ecmwf_ifs025 { get; set; } + public string? Windspeed_200hPa_ecmwf_ifs025 { get; set; } + public string? Windspeed_50hPa_ecmwf_ifs025 { get; set; } + public string? Winddirection_1000hPa_ecmwf_ifs025 { get; set; } + public string? Winddirection_925hPa_ecmwf_ifs025 { get; set; } + public string? Winddirection_850hPa_ecmwf_ifs025 { get; set; } + public string? Winddirection_700hPa_ecmwf_ifs025 { get; set; } + public string? Winddirection_500hPa_ecmwf_ifs025 { get; set; } + public string? Winddirection_300hPa_ecmwf_ifs025 { get; set; } + public string? Winddirection_250hPa_ecmwf_ifs025 { get; set; } + public string? Winddirection_200hPa_ecmwf_ifs025 { get; set; } + public string? Winddirection_50hPa_ecmwf_ifs025 { get; set; } + public string? Geopotential_height_1000hPa_ecmwf_ifs025 { get; set; } + public string? Geopotential_height_925hPa_ecmwf_ifs025 { get; set; } + public string? Geopotential_height_850hPa_ecmwf_ifs025 { get; set; } + public string? Geopotential_height_700hPa_ecmwf_ifs025 { get; set; } + public string? Geopotential_height_500hPa_ecmwf_ifs025 { get; set; } + public string? Geopotential_height_300hPa_ecmwf_ifs025 { get; set; } + public string? Geopotential_height_250hPa_ecmwf_ifs025 { get; set; } + public string? Geopotential_height_200hPa_ecmwf_ifs025 { get; set; } + public string? Geopotential_height_50hPa_ecmwf_ifs025 { get; set; } + public string? Temperature_2m_ecmwf_aifs025 { get; set; } + public string? Precipitation_ecmwf_aifs025 { get; set; } + public string? Snowfall_ecmwf_aifs025 { get; set; } + public string? Weathercode_ecmwf_aifs025 { get; set; } + public string? Pressure_msl_ecmwf_aifs025 { get; set; } + public string? Cloudcover_ecmwf_aifs025 { get; set; } + public string? Cloudcover_low_ecmwf_aifs025 { get; set; } + public string? Cloudcover_mid_ecmwf_aifs025 { get; set; } + public string? Cloudcover_high_ecmwf_aifs025 { get; set; } + public string? Windspeed_10m_ecmwf_aifs025 { get; set; } + public string? Winddirection_10m_ecmwf_aifs025 { get; set; } + public string? Temperature_1000hPa_ecmwf_aifs025 { get; set; } + public string? Temperature_925hPa_ecmwf_aifs025 { get; set; } + public string? Temperature_850hPa_ecmwf_aifs025 { get; set; } + public string? Temperature_700hPa_ecmwf_aifs025 { get; set; } + public string? Temperature_500hPa_ecmwf_aifs025 { get; set; } + public string? Temperature_300hPa_ecmwf_aifs025 { get; set; } + public string? Temperature_250hPa_ecmwf_aifs025 { get; set; } + public string? Temperature_200hPa_ecmwf_aifs025 { get; set; } + public string? Temperature_50hPa_ecmwf_aifs025 { get; set; } + public string? Cloudcover_1000hPa_ecmwf_aifs025 { get; set; } + public string? Cloudcover_925hPa_ecmwf_aifs025 { get; set; } + public string? Cloudcover_850hPa_ecmwf_aifs025 { get; set; } + public string? Cloudcover_700hPa_ecmwf_aifs025 { get; set; } + public string? Cloudcover_500hPa_ecmwf_aifs025 { get; set; } + public string? Cloudcover_300hPa_ecmwf_aifs025 { get; set; } + public string? Cloudcover_250hPa_ecmwf_aifs025 { get; set; } + public string? Cloudcover_200hPa_ecmwf_aifs025 { get; set; } + public string? Cloudcover_50hPa_ecmwf_aifs025 { get; set; } + public string? Windspeed_1000hPa_ecmwf_aifs025 { get; set; } + public string? Windspeed_925hPa_ecmwf_aifs025 { get; set; } + public string? Windspeed_850hPa_ecmwf_aifs025 { get; set; } + public string? Windspeed_700hPa_ecmwf_aifs025 { get; set; } + public string? Windspeed_500hPa_ecmwf_aifs025 { get; set; } + public string? Windspeed_300hPa_ecmwf_aifs025 { get; set; } + public string? Windspeed_250hPa_ecmwf_aifs025 { get; set; } + public string? Windspeed_200hPa_ecmwf_aifs025 { get; set; } + public string? Windspeed_50hPa_ecmwf_aifs025 { get; set; } + public string? Winddirection_1000hPa_ecmwf_aifs025 { get; set; } + public string? Winddirection_925hPa_ecmwf_aifs025 { get; set; } + public string? Winddirection_850hPa_ecmwf_aifs025 { get; set; } + public string? Winddirection_700hPa_ecmwf_aifs025 { get; set; } + public string? Winddirection_500hPa_ecmwf_aifs025 { get; set; } + public string? Winddirection_300hPa_ecmwf_aifs025 { get; set; } + public string? Winddirection_250hPa_ecmwf_aifs025 { get; set; } + public string? Winddirection_200hPa_ecmwf_aifs025 { get; set; } + public string? Winddirection_50hPa_ecmwf_aifs025 { get; set; } + public string? Geopotential_height_1000hPa_ecmwf_aifs025 { get; set; } + public string? Geopotential_height_925hPa_ecmwf_aifs025 { get; set; } + public string? Geopotential_height_850hPa_ecmwf_aifs025 { get; set; } + public string? Geopotential_height_700hPa_ecmwf_aifs025 { get; set; } + public string? Geopotential_height_500hPa_ecmwf_aifs025 { get; set; } + public string? Geopotential_height_300hPa_ecmwf_aifs025 { get; set; } + public string? Geopotential_height_250hPa_ecmwf_aifs025 { get; set; } + public string? Geopotential_height_200hPa_ecmwf_aifs025 { get; set; } + public string? Geopotential_height_50hPa_ecmwf_aifs025 { get; set; } public string? Temperature_2m_gfs_seamless { get; set; } public string? Relativehumidity_2m_gfs_seamless { get; set; } public string? Dewpoint_2m_gfs_seamless { get; set; } From cbd5d2cd7a5b5ebf4fbb927c3182d39f99997022 Mon Sep 17 00:00:00 2001 From: Colin Noakes Date: Wed, 13 Mar 2024 08:36:18 -0700 Subject: [PATCH 03/23] fix: Reduce number of calls made to the open-meteo API in the tests - as we are hitting a limit imposed by them --- OpenMeteoTests/WeatherForecastTests.cs | 42 +++++--------------------- 1 file changed, 7 insertions(+), 35 deletions(-) diff --git a/OpenMeteoTests/WeatherForecastTests.cs b/OpenMeteoTests/WeatherForecastTests.cs index 54e8abe..70f47af 100644 --- a/OpenMeteoTests/WeatherForecastTests.cs +++ b/OpenMeteoTests/WeatherForecastTests.cs @@ -1,4 +1,5 @@ using System.Globalization; +using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -107,9 +108,8 @@ public async Task WeatherForecast_With_String_And_Options_Test() } [TestMethod] - public async Task WeatherForecast_With_All_Options_Test() + public void WeatherForecast_With_All_Options_Test() { - OpenMeteoClient client = new(); WeatherForecastOptions options = new() { Hourly = HourlyOptions.All, @@ -119,39 +119,11 @@ public async Task WeatherForecast_With_All_Options_Test() Minutely15 = Minutely15Options.All }; - var res = await client.QueryAsync(options); - - Assert.IsNotNull(res); - Assert.IsNotNull(res.Hourly); - Assert.IsNotNull(res.HourlyUnits); - Assert.IsNotNull(res.Daily); - Assert.IsNotNull(res.DailyUnits); - Assert.IsNotNull(res.Hourly.Cloudcover_1000hPa_best_match); - Assert.IsNotNull(res.Current); - Assert.IsNotNull(res.Minutely15); - } - - [TestMethod] - public void WeatherForecast_With_All_Options_Sync_Test() - { - OpenMeteoClient client = new(); - WeatherForecastOptions options = new() - { - Hourly = HourlyOptions.All, - Daily = DailyOptions.All, - Current = CurrentOptions.All, - Minutely15 = Minutely15Options.All, - }; - - var res = client.Query(options); - - Assert.IsNotNull(res); - Assert.IsNotNull(res.Hourly); - Assert.IsNotNull(res.HourlyUnits); - Assert.IsNotNull(res.Daily); - Assert.IsNotNull(res.DailyUnits); - Assert.IsNotNull(res.Current); - Assert.IsNotNull(res.Minutely15); + Assert.IsTrue(HourlyOptions.All.Parameter.All(p => options.Hourly.Parameter.Contains(p))); + Assert.IsTrue(DailyOptions.All.Parameter.All(p => options.Daily.Parameter.Contains(p))); + Assert.IsTrue(WeatherModelOptions.All.Parameter.All(p => options.Models.Parameter.Contains(p))); + Assert.IsTrue(CurrentOptions.All.Parameter.All(p => options.Current.Parameter.Contains(p))); + Assert.IsTrue(Minutely15Options.All.Parameter.All(p => options.Minutely15.Parameter.Contains(p))); } } } From 748665f9a84dfde8b61eff90b5801a8308a628e2 Mon Sep 17 00:00:00 2001 From: Colin Noakes Date: Wed, 13 Mar 2024 09:08:28 -0700 Subject: [PATCH 04/23] feat: Add elevation API & tests --- OpenMeteo/ElevationApiResponse.cs | 12 ++++++++ OpenMeteo/ElevationOptions.cs | 21 +++++++++++++ OpenMeteo/OpenMeteoClient.cs | 50 +++++++++++++++++++++++++++++++ OpenMeteoTests/ElevationTests.cs | 33 ++++++++++++++++++++ 4 files changed, 116 insertions(+) create mode 100644 OpenMeteo/ElevationApiResponse.cs create mode 100644 OpenMeteo/ElevationOptions.cs create mode 100644 OpenMeteoTests/ElevationTests.cs diff --git a/OpenMeteo/ElevationApiResponse.cs b/OpenMeteo/ElevationApiResponse.cs new file mode 100644 index 0000000..97ae763 --- /dev/null +++ b/OpenMeteo/ElevationApiResponse.cs @@ -0,0 +1,12 @@ +namespace OpenMeteo +{ + /// + /// Elevation API response + /// + public class ElevationApiResponse + { + /// + /// Elevation array in meters - this library currently only supports 1 elevation so this ill always be a single value array + public float[]? Elevation { get; set; } + } +} diff --git a/OpenMeteo/ElevationOptions.cs b/OpenMeteo/ElevationOptions.cs new file mode 100644 index 0000000..70459f8 --- /dev/null +++ b/OpenMeteo/ElevationOptions.cs @@ -0,0 +1,21 @@ +namespace OpenMeteo +{ + internal class ElevationOptions + { + public ElevationOptions(float latitude, float longitude) + { + Latitude = latitude; + Longitude = longitude; + } + + /// + /// Geographical WGS84 coordinate of the location + /// + public float Latitude { get; set; } + + /// + /// Geographical WGS84 coordinate of the location + /// + public float Longitude { get; set; } + } +} diff --git a/OpenMeteo/OpenMeteoClient.cs b/OpenMeteo/OpenMeteoClient.cs index 5d4123f..a470854 100644 --- a/OpenMeteo/OpenMeteoClient.cs +++ b/OpenMeteo/OpenMeteoClient.cs @@ -14,6 +14,7 @@ public class OpenMeteoClient private readonly string _weatherApiUrl = "https://api.open-meteo.com/v1/forecast"; private readonly string _geocodeApiUrl = "https://geocoding-api.open-meteo.com/v1/search"; private readonly string _airQualityApiUrl = "https://air-quality-api.open-meteo.com/v1/air-quality"; + private readonly string _elevationApiUrl = "https://api.open-meteo.com/v1/elevation"; private readonly HttpController httpController; /// @@ -164,6 +165,19 @@ public OpenMeteoClient() return (response.Locations[0].Latitude, response.Locations[0].Longitude); } + /// + /// Performs one GET-Request to Open-Meteo Elevation API + /// + /// Latitude + /// Longitude + /// + public async Task QueryElevationAsync(float latitude, float longitude) + { + ElevationOptions elevationOptions = new ElevationOptions(latitude, longitude); + + return await GetElevationAsync(elevationOptions); + } + public WeatherForecast? Query(WeatherForecastOptions options) { return QueryAsync(options).GetAwaiter().GetResult(); @@ -194,6 +208,11 @@ public OpenMeteoClient() return QueryAsync(options).GetAwaiter().GetResult(); } + public ElevationApiResponse? QueryElevation(float latitude, float longitude) + { + return QueryElevationAsync(latitude, longitude).GetAwaiter().GetResult(); + } + private async Task GetAirQualityAsync(AirQualityOptions options) { try @@ -320,6 +339,25 @@ public string WeathercodeToString(int weathercode) } } + private async Task GetElevationAsync(ElevationOptions options) + { + try + { + HttpResponseMessage response = await httpController.Client.GetAsync(MergeUrlWithOptions(_elevationApiUrl, options)); + response.EnsureSuccessStatusCode(); + + ElevationApiResponse? elevationData = await JsonSerializer.DeserializeAsync(await response.Content.ReadAsStreamAsync(), new JsonSerializerOptions() { PropertyNameCaseInsensitive = true }); + + return elevationData; + } + catch (HttpRequestException e) + { + Console.WriteLine($"Can't find elevation for latitude {options.Latitude} & longitude {options.Longitude}. Please make sure that they are valid."); + Console.WriteLine(e.Message); + return null; + } + } + private string MergeUrlWithOptions(string url, WeatherForecastOptions? options) { if (options == null) return url; @@ -563,6 +601,18 @@ private string MergeUrlWithOptions(string url, AirQualityOptions options) return uri.ToString(); } + + private string MergeUrlWithOptions(string url, ElevationOptions options) + { + if (options == null) return url; + + UriBuilder uri = new UriBuilder(url) + { + Query = $"?latitude={options.Latitude.ToString(CultureInfo.InvariantCulture)}&longitude={options.Longitude.ToString(CultureInfo.InvariantCulture)}" + }; + + return uri.ToString(); + } } } diff --git a/OpenMeteoTests/ElevationTests.cs b/OpenMeteoTests/ElevationTests.cs new file mode 100644 index 0000000..1658731 --- /dev/null +++ b/OpenMeteoTests/ElevationTests.cs @@ -0,0 +1,33 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using OpenMeteo; +using System.Threading.Tasks; + +namespace OpenMeteoTests +{ + [TestClass] + public class ElevationTests + { + private static readonly float Latitude = 52.5235f; + private static readonly float Longitude = 13.4115f; + + [TestMethod] + public async Task Elevation_Async_Test() + { + OpenMeteoClient client = new(); + var res = await client.QueryElevationAsync(Latitude, Longitude); + + Assert.IsNotNull(res); + Assert.AreEqual(res.Elevation.Length, 1); + } + + [TestMethod] + public void Elevation_Sync_Test() + { + OpenMeteoClient client = new(); + var res = client.QueryElevation(Latitude, Longitude); + + Assert.IsNotNull(res); + Assert.AreEqual(res.Elevation.Length, 1); + } + } +} From 6973bfbb46abdb66aa11143225c87ee4ec52739f Mon Sep 17 00:00:00 2001 From: Colin Noakes Date: Wed, 13 Mar 2024 09:16:27 -0700 Subject: [PATCH 05/23] fix: comment typos --- OpenMeteo/ElevationApiResponse.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenMeteo/ElevationApiResponse.cs b/OpenMeteo/ElevationApiResponse.cs index 97ae763..91fee0d 100644 --- a/OpenMeteo/ElevationApiResponse.cs +++ b/OpenMeteo/ElevationApiResponse.cs @@ -6,7 +6,7 @@ public class ElevationApiResponse { /// - /// Elevation array in meters - this library currently only supports 1 elevation so this ill always be a single value array + /// Elevation array in meters - this library currently only supports 1 input elevation so this will always be a single value array public float[]? Elevation { get; set; } } } From a56afca1beb7749e8062a085072be6deb2db3947 Mon Sep 17 00:00:00 2001 From: Colin Noakes Date: Thu, 21 Mar 2024 19:44:21 -0700 Subject: [PATCH 06/23] Update package-and-deploy.yml --- .github/workflows/package-and-deploy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/package-and-deploy.yml b/.github/workflows/package-and-deploy.yml index 445631e..b12b0cb 100644 --- a/.github/workflows/package-and-deploy.yml +++ b/.github/workflows/package-and-deploy.yml @@ -52,4 +52,4 @@ jobs: run: dotnet pack ./OpenMeteo/OpenMeteo.csproj --configuration release -o:package /p:PackageVersion=${{ steps.gitversion.outputs.AssemblySemVer }} - name: Push generated package to NuGet.org - run: dotnet nuget push ./package/*.nupkg --api-key ${{ secrets.API_KEY }} --source https://api.nuget.org/v3/index.json --skip-duplicate + run: dotnet nuget push ./package/*.nupkg --api-key ${{ secrets.GITHUB_TOKEN }} --source https://nuget.pkg.github.com/colinnuk/index.json --skip-duplicate From 47aa2358fb40f3841c87c7934e0a0c8f8423fd8f Mon Sep 17 00:00:00 2001 From: Colin Noakes Date: Thu, 21 Mar 2024 19:45:09 -0700 Subject: [PATCH 07/23] Delete .github/workflows/test-dev-build.yml --- .github/workflows/test-dev-build.yml | 49 ---------------------------- 1 file changed, 49 deletions(-) delete mode 100644 .github/workflows/test-dev-build.yml diff --git a/.github/workflows/test-dev-build.yml b/.github/workflows/test-dev-build.yml deleted file mode 100644 index a40ef54..0000000 --- a/.github/workflows/test-dev-build.yml +++ /dev/null @@ -1,49 +0,0 @@ -name: Test Development Build - -on: - push: - branches-ignore: - - 'master' - paths: - - '**/*.cs' - - '**/*.csproj' - pull_request: - branches-ignore: - - 'master' - paths: - - '**/*.cs' - - '**/*.csproj' - - -env: - DOTNET_VERSION: '6.x.x' # The .NET SDK version to use - -jobs: - test: - - name: test-ubuntu - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v3 - - name: Setup .NET Core - uses: actions/setup-dotnet@v2 - with: - dotnet-version: ${{ env.DOTNET_VERSION }} - - - name: Caching dependencies - uses: actions/cache@v3 - with: - path: ~/.nuget/packages - key: ${{ runner.os }}-nuget-${{ hashFiles('**/packages.lock.json') }} - restore-keys: | - ${{ runner.os }}-nuget - - - name: Install dependencies - run: dotnet restore - - - name: Build - run: dotnet build --configuration Release --no-restore - - - name: Test - run: dotnet test --no-restore --verbosity normal From 0eb818b40394d41c2bb5162dfb2b31f6022cf022 Mon Sep 17 00:00:00 2001 From: Colin Noakes Date: Thu, 21 Mar 2024 19:57:59 -0700 Subject: [PATCH 08/23] Update build-and-test.yml Only need one OS --- .github/workflows/build-and-test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index e46d5cc..6ca34f2 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -22,7 +22,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-latest, windows-latest, macOS-latest] + os: [ubuntu-latest] steps: - name: Checkout Code From a8d10e6132f9729f04ba29a1994feebfb1ce3ffe Mon Sep 17 00:00:00 2001 From: Colin Noakes Date: Thu, 21 Mar 2024 19:58:21 -0700 Subject: [PATCH 09/23] Update package-and-deploy.yml --- .github/workflows/package-and-deploy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/package-and-deploy.yml b/.github/workflows/package-and-deploy.yml index b12b0cb..89874ef 100644 --- a/.github/workflows/package-and-deploy.yml +++ b/.github/workflows/package-and-deploy.yml @@ -51,5 +51,5 @@ jobs: - name: Package nuget run: dotnet pack ./OpenMeteo/OpenMeteo.csproj --configuration release -o:package /p:PackageVersion=${{ steps.gitversion.outputs.AssemblySemVer }} - - name: Push generated package to NuGet.org + - name: Push generated package to Github Packages run: dotnet nuget push ./package/*.nupkg --api-key ${{ secrets.GITHUB_TOKEN }} --source https://nuget.pkg.github.com/colinnuk/index.json --skip-duplicate From e94bb0ae532974b293b8b77337d41912536d2bee Mon Sep 17 00:00:00 2001 From: Colin Noakes Date: Thu, 21 Mar 2024 19:59:34 -0700 Subject: [PATCH 10/23] Update build-and-test.yml --- .github/workflows/build-and-test.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 6ca34f2..8886509 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -11,6 +11,7 @@ on: paths: - '**/*.cs' - '**/*.csproj' + workflow_dispatch: env: DOTNET_VERSION: '6.x.x' # The .NET SDK version to use From b00e7790edd459b1832176a67b90550bb3e806f1 Mon Sep 17 00:00:00 2001 From: Colin Noakes Date: Thu, 21 Mar 2024 20:18:41 -0700 Subject: [PATCH 11/23] Update OpenMeteo.csproj --- OpenMeteo/OpenMeteo.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenMeteo/OpenMeteo.csproj b/OpenMeteo/OpenMeteo.csproj index f56b1ee..c37b69c 100644 --- a/OpenMeteo/OpenMeteo.csproj +++ b/OpenMeteo/OpenMeteo.csproj @@ -3,7 +3,7 @@ netstandard2.1 enable - $(AssemblyName).dotnet + $(AssemblyName).colinnuk.dotnet Open Meteo Dotnet Library 0.0.3 AlienDwarf From 19dace5ac56cbadfe1f1fe151792d891c1b7cc20 Mon Sep 17 00:00:00 2001 From: Colin Noakes Date: Thu, 21 Mar 2024 21:33:55 -0700 Subject: [PATCH 12/23] Handle the OpenMeteo error responses more accurately --- OpenMeteo/ErrorResponse.cs | 13 +++++ OpenMeteo/IOpenMeteoLogger.cs | 16 ++++++ OpenMeteo/OpenMeteoClient.cs | 70 +++++++++++++++++--------- OpenMeteo/OpenMeteoClientException.cs | 15 ++++++ OpenMeteoTests/WeatherForecastTests.cs | 18 +++++++ 5 files changed, 109 insertions(+), 23 deletions(-) create mode 100644 OpenMeteo/ErrorResponse.cs create mode 100644 OpenMeteo/IOpenMeteoLogger.cs create mode 100644 OpenMeteo/OpenMeteoClientException.cs diff --git a/OpenMeteo/ErrorResponse.cs b/OpenMeteo/ErrorResponse.cs new file mode 100644 index 0000000..4de35a5 --- /dev/null +++ b/OpenMeteo/ErrorResponse.cs @@ -0,0 +1,13 @@ +using System.Text.Json.Serialization; + +namespace OpenMeteo +{ + internal class ErrorResponse + { + [JsonPropertyName("reason")] + public string? Reason { get; set; } + + [JsonPropertyName("error")] + public bool Error { get; set; } + } +} diff --git a/OpenMeteo/IOpenMeteoLogger.cs b/OpenMeteo/IOpenMeteoLogger.cs new file mode 100644 index 0000000..b260c73 --- /dev/null +++ b/OpenMeteo/IOpenMeteoLogger.cs @@ -0,0 +1,16 @@ +namespace OpenMeteo +{ + /// + /// Specifies a simple interface for a logger. + /// Usage of this interface is optional. + /// To use this, create your own implementation of this interface which you can easily setup + /// to call your own logging framework. + /// + public interface IOpenMeteoLogger + { + void Information(string message); + void Warning(string message); + void Error(string message); + void Debug(string message); + } +} \ No newline at end of file diff --git a/OpenMeteo/OpenMeteoClient.cs b/OpenMeteo/OpenMeteoClient.cs index a470854..d316b34 100644 --- a/OpenMeteo/OpenMeteoClient.cs +++ b/OpenMeteo/OpenMeteoClient.cs @@ -17,6 +17,9 @@ public class OpenMeteoClient private readonly string _elevationApiUrl = "https://api.open-meteo.com/v1/elevation"; private readonly HttpController httpController; + private readonly IOpenMeteoLogger? _logger = default!; + private readonly bool _rethrowExceptions = false; + /// /// Creates a new object and sets the neccessary variables (httpController, CultureInfo) /// @@ -25,6 +28,16 @@ public OpenMeteoClient() httpController = new HttpController(); } + /// + /// Creates a new object and sets the neccessary variables (httpController, CultureInfo) + /// + public OpenMeteoClient(bool rethrowExceptions, IOpenMeteoLogger? logger = null) + { + httpController = new HttpController(); + _logger = logger; + _rethrowExceptions = rethrowExceptions; + } + /// /// Performs two GET-Requests (first geocoding api for latitude,longitude, then weather forecast) /// @@ -80,14 +93,7 @@ public OpenMeteoClient() /// Awaitable Task containing WeatherForecast or NULL public async Task QueryAsync(WeatherForecastOptions options) { - try - { - return await GetWeatherForecastAsync(options); - } - catch (Exception) - { - return null; - } + return await GetWeatherForecastAsync(options); } /// @@ -217,7 +223,9 @@ public OpenMeteoClient() { try { - HttpResponseMessage response = await httpController.Client.GetAsync(MergeUrlWithOptions(_airQualityApiUrl, options)); + var url = MergeUrlWithOptions(_airQualityApiUrl, options); + _logger?.Debug($"{nameof(OpenMeteoClient)}.GetAirQualityAsync(). URL: {url}"); + HttpResponseMessage response = await httpController.Client.GetAsync(url); response.EnsureSuccessStatusCode(); AirQuality? airQuality = await JsonSerializer.DeserializeAsync(await response.Content.ReadAsStreamAsync(), new JsonSerializerOptions() { PropertyNameCaseInsensitive = true }); @@ -225,8 +233,9 @@ public OpenMeteoClient() } catch (HttpRequestException e) { - Console.WriteLine(e.Message); - Console.WriteLine(e.StackTrace); + _logger?.Error($"Error in {nameof(OpenMeteoClient)}.GetAirQualityAsync(). Message: {e.Message} StackTrace: {e.StackTrace}"); + if (_rethrowExceptions) + throw; return null; } } @@ -305,16 +314,23 @@ public string WeathercodeToString(int weathercode) { try { - HttpResponseMessage response = await httpController.Client.GetAsync(MergeUrlWithOptions(_weatherApiUrl, options)); - response.EnsureSuccessStatusCode(); + var url = MergeUrlWithOptions(_weatherApiUrl, options); + _logger?.Debug($"{nameof(OpenMeteoClient)}.GetElevationAsync(). URL: {url}"); + HttpResponseMessage response = await httpController.Client.GetAsync(url); + if(response.IsSuccessStatusCode) + { + WeatherForecast? weatherForecast = await JsonSerializer.DeserializeAsync(await response.Content.ReadAsStreamAsync(), new JsonSerializerOptions() { PropertyNameCaseInsensitive = true }); + return weatherForecast; + } - WeatherForecast? weatherForecast = await JsonSerializer.DeserializeAsync(await response.Content.ReadAsStreamAsync(), new JsonSerializerOptions() { PropertyNameCaseInsensitive = true }); - return weatherForecast; + var error = await JsonSerializer.DeserializeAsync(await response.Content.ReadAsStreamAsync(), new JsonSerializerOptions() { PropertyNameCaseInsensitive = true }); + throw new OpenMeteoClientException(error?.Reason ?? "Exception in OpenMeteoClient", response.StatusCode); } catch (HttpRequestException e) { - Console.WriteLine(e.Message); - Console.WriteLine(e.StackTrace); + _logger?.Error($"Error in {nameof(OpenMeteoClient)}.GetWeatherForecastAsync(). Message: {e.Message} StackTrace: {e.StackTrace}"); + if (_rethrowExceptions) + throw; return null; } @@ -324,7 +340,10 @@ public string WeathercodeToString(int weathercode) { try { - HttpResponseMessage response = await httpController.Client.GetAsync(MergeUrlWithOptions(_geocodeApiUrl, options)); + + var url = MergeUrlWithOptions(_geocodeApiUrl, options); + _logger?.Debug($"{nameof(OpenMeteoClient)}.GetGeocodingDataAsync(). URL: {url}"); + HttpResponseMessage response = await httpController.Client.GetAsync(url); response.EnsureSuccessStatusCode(); GeocodingApiResponse? geocodingData = await JsonSerializer.DeserializeAsync(await response.Content.ReadAsStreamAsync(), new JsonSerializerOptions() { PropertyNameCaseInsensitive = true }); @@ -333,8 +352,9 @@ public string WeathercodeToString(int weathercode) } catch (HttpRequestException e) { - Console.WriteLine("Can't find " + options.Name + ". Please make sure that the name is valid."); - Console.WriteLine(e.Message); + _logger?.Error($"Error in {nameof(OpenMeteoClient)}.GetGeocodingDataAsync(). Message: {e.Message} StackTrace: {e.StackTrace}"); + if (_rethrowExceptions) + throw; return null; } } @@ -343,7 +363,9 @@ public string WeathercodeToString(int weathercode) { try { - HttpResponseMessage response = await httpController.Client.GetAsync(MergeUrlWithOptions(_elevationApiUrl, options)); + var url = MergeUrlWithOptions(_elevationApiUrl, options); + _logger?.Debug($"{nameof(OpenMeteoClient)}.GetElevationAsync(). URL: {url}"); + HttpResponseMessage response = await httpController.Client.GetAsync(url); response.EnsureSuccessStatusCode(); ElevationApiResponse? elevationData = await JsonSerializer.DeserializeAsync(await response.Content.ReadAsStreamAsync(), new JsonSerializerOptions() { PropertyNameCaseInsensitive = true }); @@ -352,8 +374,10 @@ public string WeathercodeToString(int weathercode) } catch (HttpRequestException e) { - Console.WriteLine($"Can't find elevation for latitude {options.Latitude} & longitude {options.Longitude}. Please make sure that they are valid."); - Console.WriteLine(e.Message); + _logger?.Warning($"Can't find elevation for latitude {options.Latitude} & longitude {options.Longitude}. Please make sure that they are valid."); + _logger?.Error($"Error in {nameof(OpenMeteoClient)}.GetElevationAsync(). Message: {e.Message} StackTrace: {e.StackTrace}"); + if (_rethrowExceptions) + throw; return null; } } diff --git a/OpenMeteo/OpenMeteoClientException.cs b/OpenMeteo/OpenMeteoClientException.cs new file mode 100644 index 0000000..6c70617 --- /dev/null +++ b/OpenMeteo/OpenMeteoClientException.cs @@ -0,0 +1,15 @@ +using System.Net; +using System.Net.Http; + +namespace OpenMeteo +{ + public class OpenMeteoClientException : HttpRequestException + { + public HttpStatusCode StatusCode { get; } + + public OpenMeteoClientException(string message, HttpStatusCode httpStatusCode) : base(message) + { + StatusCode = httpStatusCode; + } + } +} diff --git a/OpenMeteoTests/WeatherForecastTests.cs b/OpenMeteoTests/WeatherForecastTests.cs index 70f47af..0e3301a 100644 --- a/OpenMeteoTests/WeatherForecastTests.cs +++ b/OpenMeteoTests/WeatherForecastTests.cs @@ -1,5 +1,6 @@ using System.Globalization; using System.Linq; +using System.Net.Http; using System.Threading; using System.Threading.Tasks; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -125,5 +126,22 @@ public void WeatherForecast_With_All_Options_Test() Assert.IsTrue(CurrentOptions.All.Parameter.All(p => options.Current.Parameter.Contains(p))); Assert.IsTrue(Minutely15Options.All.Parameter.All(p => options.Minutely15.Parameter.Contains(p))); } + + [TestMethod] + public async Task Latitude_Longitude_No_Data_For_Selected_Forecast_Rethrows_Test() + { + OpenMeteoClient client = new(true); + + WeatherForecastOptions options = new WeatherForecastOptions + { + Latitude = 1, + Longitude = 1, + Models = new WeatherModelOptions(WeatherModelOptionsParameter.gfs_hrrr), + }; + + var ex = await Assert.ThrowsExceptionAsync(async () => await client.QueryAsync(options)); + Assert.AreEqual(System.Net.HttpStatusCode.BadRequest, ex.StatusCode); + Assert.AreEqual("No data is available for this location", ex.Message); + } } } From 0cee91b7d187f74af2abbb63c274446035727e0b Mon Sep 17 00:00:00 2001 From: Colin Noakes Date: Thu, 21 Mar 2024 21:40:38 -0700 Subject: [PATCH 13/23] Add models --- OpenMeteo/WeatherModelOptions.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/OpenMeteo/WeatherModelOptions.cs b/OpenMeteo/WeatherModelOptions.cs index 0d69688..0748120 100644 --- a/OpenMeteo/WeatherModelOptions.cs +++ b/OpenMeteo/WeatherModelOptions.cs @@ -125,6 +125,10 @@ public enum WeatherModelOptionsParameter meteofrance_arpege_world, meteofrance_arpege_europe, meteofrance_arome_france, - meteofrance_arome_france_hd + meteofrance_arome_france_hd, + bom_access_global, + arpae_cosmo_2i, + arpae_cosmo_2i_ruc, + arpae_cosmo_5m } } From 111b33ee140b043658705df3551b3a95421961ab Mon Sep 17 00:00:00 2001 From: Colin Noakes Date: Fri, 22 Mar 2024 06:14:56 -0700 Subject: [PATCH 14/23] Small tweak to error handling --- OpenMeteo/OpenMeteoClient.cs | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/OpenMeteo/OpenMeteoClient.cs b/OpenMeteo/OpenMeteoClient.cs index d316b34..15f85d5 100644 --- a/OpenMeteo/OpenMeteoClient.cs +++ b/OpenMeteo/OpenMeteoClient.cs @@ -233,7 +233,7 @@ public OpenMeteoClient(bool rethrowExceptions, IOpenMeteoLogger? logger = null) } catch (HttpRequestException e) { - _logger?.Error($"Error in {nameof(OpenMeteoClient)}.GetAirQualityAsync(). Message: {e.Message} StackTrace: {e.StackTrace}"); + _logger?.Error($"{nameof(OpenMeteoClient)}.GetAirQualityAsync(). Message: {e.Message} StackTrace: {e.StackTrace}"); if (_rethrowExceptions) throw; return null; @@ -323,12 +323,24 @@ public string WeathercodeToString(int weathercode) return weatherForecast; } - var error = await JsonSerializer.DeserializeAsync(await response.Content.ReadAsStreamAsync(), new JsonSerializerOptions() { PropertyNameCaseInsensitive = true }); + ErrorResponse? error = null; + if((int)response.StatusCode >= 400 && (int)response.StatusCode < 500) + { + try + { + error = await JsonSerializer.DeserializeAsync(await response.Content.ReadAsStreamAsync(), new JsonSerializerOptions() { PropertyNameCaseInsensitive = true }); + } + catch (Exception e) + { + _logger?.Error($"{nameof(OpenMeteoClient)}.GetWeatherForecastAsync(). Unable to deserialise error response. This exception will be thrown. Message: {e.Message} StackTrace: {e.StackTrace}"); + } + } + throw new OpenMeteoClientException(error?.Reason ?? "Exception in OpenMeteoClient", response.StatusCode); } - catch (HttpRequestException e) + catch (Exception e) { - _logger?.Error($"Error in {nameof(OpenMeteoClient)}.GetWeatherForecastAsync(). Message: {e.Message} StackTrace: {e.StackTrace}"); + _logger?.Error($"{nameof(OpenMeteoClient)}.GetWeatherForecastAsync(). Message: {e.Message} StackTrace: {e.StackTrace}"); if (_rethrowExceptions) throw; return null; @@ -352,7 +364,7 @@ public string WeathercodeToString(int weathercode) } catch (HttpRequestException e) { - _logger?.Error($"Error in {nameof(OpenMeteoClient)}.GetGeocodingDataAsync(). Message: {e.Message} StackTrace: {e.StackTrace}"); + _logger?.Error($"{nameof(OpenMeteoClient)}.GetGeocodingDataAsync(). Message: {e.Message} StackTrace: {e.StackTrace}"); if (_rethrowExceptions) throw; return null; From 2fd56d233b2e18162bd0d83817e215f9cb00fc3d Mon Sep 17 00:00:00 2001 From: Colin Noakes Date: Fri, 5 Apr 2024 14:12:55 -0700 Subject: [PATCH 15/23] Add gfs_graphcast025 --- OpenMeteo/WeatherModelOptions.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/OpenMeteo/WeatherModelOptions.cs b/OpenMeteo/WeatherModelOptions.cs index 0748120..0d9d94b 100644 --- a/OpenMeteo/WeatherModelOptions.cs +++ b/OpenMeteo/WeatherModelOptions.cs @@ -110,6 +110,7 @@ public enum WeatherModelOptionsParameter gfs_seamless, gfs_global, gfs_hrrr, + gfs_graphcast025, jma_seamless, jma_msm, jma_gsm, From 4ada501717c0a3a38a716e3af1c012f1c3a4e064 Mon Sep 17 00:00:00 2001 From: Colin Noakes Date: Tue, 9 Apr 2024 13:16:24 -0700 Subject: [PATCH 16/23] Change to only log errors if we have set to rethrow exceptions --- OpenMeteo/OpenMeteoClient.cs | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/OpenMeteo/OpenMeteoClient.cs b/OpenMeteo/OpenMeteoClient.cs index 15f85d5..c3b2a63 100644 --- a/OpenMeteo/OpenMeteoClient.cs +++ b/OpenMeteo/OpenMeteoClient.cs @@ -232,10 +232,13 @@ public OpenMeteoClient(bool rethrowExceptions, IOpenMeteoLogger? logger = null) return airQuality; } catch (HttpRequestException e) - { - _logger?.Error($"{nameof(OpenMeteoClient)}.GetAirQualityAsync(). Message: {e.Message} StackTrace: {e.StackTrace}"); + { if (_rethrowExceptions) + { + _logger?.Error($"{nameof(OpenMeteoClient)}.GetAirQualityAsync(). Message: {e.Message} StackTrace: {e.StackTrace}"); throw; + } + _logger?.Warning($"{nameof(OpenMeteoClient)}.GetAirQualityAsync(). Message: {e.Message} StackTrace: {e.StackTrace}"); return null; } } @@ -340,9 +343,13 @@ public string WeathercodeToString(int weathercode) } catch (Exception e) { - _logger?.Error($"{nameof(OpenMeteoClient)}.GetWeatherForecastAsync(). Message: {e.Message} StackTrace: {e.StackTrace}"); + if (_rethrowExceptions) + { + _logger?.Error($"{nameof(OpenMeteoClient)}.GetWeatherForecastAsync(). Message: {e.Message} StackTrace: {e.StackTrace}"); throw; + } + _logger?.Warning($"{nameof(OpenMeteoClient)}.GetWeatherForecastAsync(). Message: {e.Message} StackTrace: {e.StackTrace}"); return null; } @@ -364,9 +371,12 @@ public string WeathercodeToString(int weathercode) } catch (HttpRequestException e) { - _logger?.Error($"{nameof(OpenMeteoClient)}.GetGeocodingDataAsync(). Message: {e.Message} StackTrace: {e.StackTrace}"); if (_rethrowExceptions) + { + _logger?.Error($"{nameof(OpenMeteoClient)}.GetGeocodingDataAsync(). Message: {e.Message} StackTrace: {e.StackTrace}"); throw; + } + _logger?.Warning($"{nameof(OpenMeteoClient)}.GetGeocodingDataAsync(). Message: {e.Message} StackTrace: {e.StackTrace}"); return null; } } @@ -387,9 +397,12 @@ public string WeathercodeToString(int weathercode) catch (HttpRequestException e) { _logger?.Warning($"Can't find elevation for latitude {options.Latitude} & longitude {options.Longitude}. Please make sure that they are valid."); - _logger?.Error($"Error in {nameof(OpenMeteoClient)}.GetElevationAsync(). Message: {e.Message} StackTrace: {e.StackTrace}"); if (_rethrowExceptions) + { + _logger?.Error($"Error in {nameof(OpenMeteoClient)}.GetElevationAsync(). Message: {e.Message} StackTrace: {e.StackTrace}"); throw; + } + _logger?.Warning($"Error in {nameof(OpenMeteoClient)}.GetElevationAsync(). Message: {e.Message} StackTrace: {e.StackTrace}"); return null; } } From 8ad1b3fa51356de5d45b13990ae2a2e333c7d02f Mon Sep 17 00:00:00 2001 From: Colin Noakes Date: Tue, 9 Apr 2024 16:18:34 -0700 Subject: [PATCH 17/23] Revert "Change to only log errors if we have set to rethrow exceptions" This reverts commit 4ada501717c0a3a38a716e3af1c012f1c3a4e064. --- OpenMeteo/OpenMeteoClient.cs | 23 +++++------------------ 1 file changed, 5 insertions(+), 18 deletions(-) diff --git a/OpenMeteo/OpenMeteoClient.cs b/OpenMeteo/OpenMeteoClient.cs index c3b2a63..15f85d5 100644 --- a/OpenMeteo/OpenMeteoClient.cs +++ b/OpenMeteo/OpenMeteoClient.cs @@ -232,13 +232,10 @@ public OpenMeteoClient(bool rethrowExceptions, IOpenMeteoLogger? logger = null) return airQuality; } catch (HttpRequestException e) - { + { + _logger?.Error($"{nameof(OpenMeteoClient)}.GetAirQualityAsync(). Message: {e.Message} StackTrace: {e.StackTrace}"); if (_rethrowExceptions) - { - _logger?.Error($"{nameof(OpenMeteoClient)}.GetAirQualityAsync(). Message: {e.Message} StackTrace: {e.StackTrace}"); throw; - } - _logger?.Warning($"{nameof(OpenMeteoClient)}.GetAirQualityAsync(). Message: {e.Message} StackTrace: {e.StackTrace}"); return null; } } @@ -343,13 +340,9 @@ public string WeathercodeToString(int weathercode) } catch (Exception e) { - + _logger?.Error($"{nameof(OpenMeteoClient)}.GetWeatherForecastAsync(). Message: {e.Message} StackTrace: {e.StackTrace}"); if (_rethrowExceptions) - { - _logger?.Error($"{nameof(OpenMeteoClient)}.GetWeatherForecastAsync(). Message: {e.Message} StackTrace: {e.StackTrace}"); throw; - } - _logger?.Warning($"{nameof(OpenMeteoClient)}.GetWeatherForecastAsync(). Message: {e.Message} StackTrace: {e.StackTrace}"); return null; } @@ -371,12 +364,9 @@ public string WeathercodeToString(int weathercode) } catch (HttpRequestException e) { + _logger?.Error($"{nameof(OpenMeteoClient)}.GetGeocodingDataAsync(). Message: {e.Message} StackTrace: {e.StackTrace}"); if (_rethrowExceptions) - { - _logger?.Error($"{nameof(OpenMeteoClient)}.GetGeocodingDataAsync(). Message: {e.Message} StackTrace: {e.StackTrace}"); throw; - } - _logger?.Warning($"{nameof(OpenMeteoClient)}.GetGeocodingDataAsync(). Message: {e.Message} StackTrace: {e.StackTrace}"); return null; } } @@ -397,12 +387,9 @@ public string WeathercodeToString(int weathercode) catch (HttpRequestException e) { _logger?.Warning($"Can't find elevation for latitude {options.Latitude} & longitude {options.Longitude}. Please make sure that they are valid."); + _logger?.Error($"Error in {nameof(OpenMeteoClient)}.GetElevationAsync(). Message: {e.Message} StackTrace: {e.StackTrace}"); if (_rethrowExceptions) - { - _logger?.Error($"Error in {nameof(OpenMeteoClient)}.GetElevationAsync(). Message: {e.Message} StackTrace: {e.StackTrace}"); throw; - } - _logger?.Warning($"Error in {nameof(OpenMeteoClient)}.GetElevationAsync(). Message: {e.Message} StackTrace: {e.StackTrace}"); return null; } } From 0f46876681fd55cbeba1c8da56562502b47b981b Mon Sep 17 00:00:00 2001 From: Colin Noakes Date: Tue, 9 Apr 2024 16:19:45 -0700 Subject: [PATCH 18/23] Change errors to warnings - client code will have to log this if it needs to --- OpenMeteo/OpenMeteoClient.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/OpenMeteo/OpenMeteoClient.cs b/OpenMeteo/OpenMeteoClient.cs index 15f85d5..cb8d057 100644 --- a/OpenMeteo/OpenMeteoClient.cs +++ b/OpenMeteo/OpenMeteoClient.cs @@ -233,7 +233,7 @@ public OpenMeteoClient(bool rethrowExceptions, IOpenMeteoLogger? logger = null) } catch (HttpRequestException e) { - _logger?.Error($"{nameof(OpenMeteoClient)}.GetAirQualityAsync(). Message: {e.Message} StackTrace: {e.StackTrace}"); + _logger?.Warning($"{nameof(OpenMeteoClient)}.GetAirQualityAsync(). Message: {e.Message} StackTrace: {e.StackTrace}"); if (_rethrowExceptions) throw; return null; @@ -340,7 +340,7 @@ public string WeathercodeToString(int weathercode) } catch (Exception e) { - _logger?.Error($"{nameof(OpenMeteoClient)}.GetWeatherForecastAsync(). Message: {e.Message} StackTrace: {e.StackTrace}"); + _logger?.Warning($"{nameof(OpenMeteoClient)}.GetWeatherForecastAsync(). Message: {e.Message} StackTrace: {e.StackTrace}"); if (_rethrowExceptions) throw; return null; @@ -364,7 +364,7 @@ public string WeathercodeToString(int weathercode) } catch (HttpRequestException e) { - _logger?.Error($"{nameof(OpenMeteoClient)}.GetGeocodingDataAsync(). Message: {e.Message} StackTrace: {e.StackTrace}"); + _logger?.Warning($"{nameof(OpenMeteoClient)}.GetGeocodingDataAsync(). Message: {e.Message} StackTrace: {e.StackTrace}"); if (_rethrowExceptions) throw; return null; @@ -387,7 +387,7 @@ public string WeathercodeToString(int weathercode) catch (HttpRequestException e) { _logger?.Warning($"Can't find elevation for latitude {options.Latitude} & longitude {options.Longitude}. Please make sure that they are valid."); - _logger?.Error($"Error in {nameof(OpenMeteoClient)}.GetElevationAsync(). Message: {e.Message} StackTrace: {e.StackTrace}"); + _logger?.Warning($"Error in {nameof(OpenMeteoClient)}.GetElevationAsync(). Message: {e.Message} StackTrace: {e.StackTrace}"); if (_rethrowExceptions) throw; return null; From 3b47c1a8fcd0793877ba55cdfc90dfb5f2e30a56 Mon Sep 17 00:00:00 2001 From: Colin Noakes Date: Tue, 30 Apr 2024 15:43:14 -0700 Subject: [PATCH 19/23] Upgrade lib to dotnet 8 --- .github/workflows/build-and-test.yml | 2 +- OpenMeteo/HttpController.cs | 9 ++++++--- OpenMeteo/OpenMeteo.csproj | 6 +++--- OpenMeteoTests/OpenMeteoTests.csproj | 2 +- 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 8886509..60b5de3 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -14,7 +14,7 @@ on: workflow_dispatch: env: - DOTNET_VERSION: '6.x.x' # The .NET SDK version to use + DOTNET_VERSION: '8.x.x' # The .NET SDK version to use jobs: build-and-test: diff --git a/OpenMeteo/HttpController.cs b/OpenMeteo/HttpController.cs index d563ead..cd48cd9 100644 --- a/OpenMeteo/HttpController.cs +++ b/OpenMeteo/HttpController.cs @@ -1,6 +1,4 @@ using System; -using System.Collections.Generic; -using System.Text; using System.Net.Http; namespace OpenMeteo @@ -15,7 +13,12 @@ internal class HttpController public HttpController() { - _httpClient = new HttpClient(); + var socketHttpHandler = new SocketsHttpHandler() + { + PooledConnectionLifetime = TimeSpan.FromMinutes(4), + }; + _httpClient = new HttpClient(socketHttpHandler); + _httpClient.DefaultRequestHeaders.Accept.Clear(); _httpClient.DefaultRequestHeaders.Accept.Add( new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json") diff --git a/OpenMeteo/OpenMeteo.csproj b/OpenMeteo/OpenMeteo.csproj index c37b69c..e4900f0 100644 --- a/OpenMeteo/OpenMeteo.csproj +++ b/OpenMeteo/OpenMeteo.csproj @@ -1,10 +1,10 @@ - netstandard2.1 + net8.0 enable $(AssemblyName).colinnuk.dotnet - Open Meteo Dotnet Library + Open Meteo Dotnet 8 Library 0.0.3 AlienDwarf @@ -17,7 +17,7 @@ 0.0.1 0.0.1 LICENSE - A .Net Standard 2.1 library for the Open-Meteo.com API. + A DotNet 8 library for the Open-Meteo.com API. True snupkg False diff --git a/OpenMeteoTests/OpenMeteoTests.csproj b/OpenMeteoTests/OpenMeteoTests.csproj index 17432e8..15a682d 100644 --- a/OpenMeteoTests/OpenMeteoTests.csproj +++ b/OpenMeteoTests/OpenMeteoTests.csproj @@ -1,7 +1,7 @@  - net6.0 + net8.0 false From 4dc5c111e5bb8e7571d7098aa950f318e10bb0e9 Mon Sep 17 00:00:00 2001 From: Colin Noakes Date: Tue, 30 Apr 2024 16:03:35 -0700 Subject: [PATCH 20/23] Add pressure height params --- OpenMeteo/HourlyOptions.cs | 98 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) diff --git a/OpenMeteo/HourlyOptions.cs b/OpenMeteo/HourlyOptions.cs index 7d25e3b..d23e707 100644 --- a/OpenMeteo/HourlyOptions.cs +++ b/OpenMeteo/HourlyOptions.cs @@ -158,11 +158,25 @@ public enum HourlyOptionsParameter temperature_950hPa, temperature_925hPa, temperature_900hPa, + temperature_875hPa, temperature_850hPa, + temperature_825hPa, temperature_800hPa, + temperature_775hPa, + temperature_750hPa, + temperature_725hPa, temperature_700hPa, + temperature_675hPa, + temperature_650hPa, + temperature_625hPa, temperature_600hPa, + temperature_575hPa, + temperature_550hPa, + temperature_525hPa, temperature_500hPa, + temperature_475hPa, + temperature_450hPa, + temperature_425hPa, temperature_400hPa, temperature_300hPa, temperature_250hPa, @@ -177,11 +191,25 @@ public enum HourlyOptionsParameter dewpoint_950hPa, dewpoint_925hPa, dewpoint_900hPa, + dewpoint_875hPa, dewpoint_850hPa, + dewpoint_825hPa, dewpoint_800hPa, + dewpoint_775hPa, + dewpoint_750hPa, + dewpoint_725hPa, dewpoint_700hPa, + dewpoint_675hPa, + dewpoint_650hPa, + dewpoint_625hPa, dewpoint_600hPa, + dewpoint_575hPa, + dewpoint_550hPa, + dewpoint_525hPa, dewpoint_500hPa, + dewpoint_475hPa, + dewpoint_450hPa, + dewpoint_425hPa, dewpoint_400hPa, dewpoint_300hPa, dewpoint_250hPa, @@ -196,11 +224,25 @@ public enum HourlyOptionsParameter relativehumidity_950hPa, relativehumidity_925hPa, relativehumidity_900hPa, + relativehumidity_875hPa, relativehumidity_850hPa, + relativehumidity_825hPa, relativehumidity_800hPa, + relativehumidity_775hPa, + relativehumidity_750hPa, + relativehumidity_725hPa, relativehumidity_700hPa, + relativehumidity_675hPa, + relativehumidity_650hPa, + relativehumidity_625hPa, relativehumidity_600hPa, + relativehumidity_575hPa, + relativehumidity_550hPa, + relativehumidity_525hPa, relativehumidity_500hPa, + relativehumidity_475hPa, + relativehumidity_450hPa, + relativehumidity_425hPa, relativehumidity_400hPa, relativehumidity_300hPa, relativehumidity_250hPa, @@ -215,11 +257,25 @@ public enum HourlyOptionsParameter cloudcover_950hPa, cloudcover_925hPa, cloudcover_900hPa, + cloudcover_875hPa, cloudcover_850hPa, + cloudcover_825hPa, cloudcover_800hPa, + cloudcover_775hPa, + cloudcover_750hPa, + cloudcover_725hPa, cloudcover_700hPa, + cloudcover_675hPa, + cloudcover_650hPa, + cloudcover_625hPa, cloudcover_600hPa, + cloudcover_575hPa, + cloudcover_550hPa, + cloudcover_525hPa, cloudcover_500hPa, + cloudcover_475hPa, + cloudcover_450hPa, + cloudcover_425hPa, cloudcover_400hPa, cloudcover_300hPa, cloudcover_250hPa, @@ -234,11 +290,25 @@ public enum HourlyOptionsParameter windspeed_950hPa, windspeed_925hPa, windspeed_900hPa, + windspeed_875hPa, windspeed_850hPa, + windspeed_825hPa, windspeed_800hPa, + windspeed_775hPa, + windspeed_750hPa, + windspeed_725hPa, windspeed_700hPa, + windspeed_675hPa, + windspeed_650hPa, + windspeed_625hPa, windspeed_600hPa, + windspeed_575hPa, + windspeed_550hPa, + windspeed_525hPa, windspeed_500hPa, + windspeed_475hPa, + windspeed_450hPa, + windspeed_425hPa, windspeed_400hPa, windspeed_300hPa, windspeed_250hPa, @@ -253,11 +323,25 @@ public enum HourlyOptionsParameter winddirection_950hPa, winddirection_925hPa, winddirection_900hPa, + winddirection_875hPa, winddirection_850hPa, + winddirection_825hPa, winddirection_800hPa, + winddirection_775hPa, + winddirection_750hPa, + winddirection_725hPa, winddirection_700hPa, + winddirection_675hPa, + winddirection_650hPa, + winddirection_625hPa, winddirection_600hPa, + winddirection_575hPa, + winddirection_550hPa, + winddirection_525hPa, winddirection_500hPa, + winddirection_475hPa, + winddirection_450hPa, + winddirection_425hPa, winddirection_400hPa, winddirection_300hPa, winddirection_250hPa, @@ -272,11 +356,25 @@ public enum HourlyOptionsParameter geopotential_height_950hPa, geopotential_height_925hPa, geopotential_height_900hPa, + geopotential_height_875hPa, geopotential_height_850hPa, + geopotential_height_825hPa, geopotential_height_800hPa, + geopotential_height_775hPa, + geopotential_height_750hPa, + geopotential_height_725hPa, geopotential_height_700hPa, + geopotential_height_675hPa, + geopotential_height_650hPa, + geopotential_height_625hPa, geopotential_height_600hPa, + geopotential_height_575hPa, + geopotential_height_550hPa, + geopotential_height_525hPa, geopotential_height_500hPa, + geopotential_height_475hPa, + geopotential_height_450hPa, + geopotential_height_425hPa, geopotential_height_400hPa, geopotential_height_300hPa, geopotential_height_250hPa, From 91f9d4fdb6af0c08f1120e1f8d7353232c0a93d4 Mon Sep 17 00:00:00 2001 From: Colin Noakes Date: Tue, 30 Apr 2024 17:45:26 -0700 Subject: [PATCH 21/23] Add new pressure level options --- OpenMeteo/Hourly.cs | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/OpenMeteo/Hourly.cs b/OpenMeteo/Hourly.cs index d25879e..321f6b9 100644 --- a/OpenMeteo/Hourly.cs +++ b/OpenMeteo/Hourly.cs @@ -67,10 +67,21 @@ public class Hourly public float?[]? Temperature_950hPa { get; set; } public float?[]? Temperature_925hPa { get; set; } public float?[]? Temperature_900hPa { get; set; } + public float?[]? Temperature_875hPa { get; set; } public float?[]? Temperature_850hPa { get; set; } + public float?[]? Temperature_825hPa { get; set; } public float?[]? Temperature_800hPa { get; set; } + public float?[]? Temperature_775hPa { get; set; } + public float?[]? Temperature_750hPa { get; set; } + public float?[]? Temperature_725hPa { get; set; } public float?[]? Temperature_700hPa { get; set; } + public float?[]? Temperature_675hPa { get; set; } + public float?[]? Temperature_650hPa { get; set; } + public float?[]? Temperature_625hPa { get; set; } public float?[]? Temperature_600hPa { get; set; } + public float?[]? Temperature_575hPa { get; set; } + public float?[]? Temperature_550hPa { get; set; } + public float?[]? Temperature_525hPa { get; set; } public float?[]? Temperature_500hPa { get; set; } public float?[]? Temperature_400hPa { get; set; } public float?[]? Temperature_300hPa { get; set; } @@ -105,10 +116,21 @@ public class Hourly public int?[]? Relativehumidity_950hPa { get; set; } public int?[]? Relativehumidity_925hPa { get; set; } public int?[]? Relativehumidity_900hPa { get; set; } + public int?[]? Relativehumidity_875hPa { get; set; } public int?[]? Relativehumidity_850hPa { get; set; } + public int?[]? Relativehumidity_825hPa { get; set; } public int?[]? Relativehumidity_800hPa { get; set; } + public int?[]? Relativehumidity_775hPa { get; set; } + public int?[]? Relativehumidity_750hPa { get; set; } + public int?[]? Relativehumidity_725hPa { get; set; } public int?[]? Relativehumidity_700hPa { get; set; } + public int?[]? Relativehumidity_675hPa { get; set; } + public int?[]? Relativehumidity_650hPa { get; set; } + public int?[]? Relativehumidity_625hPa { get; set; } public int?[]? Relativehumidity_600hPa { get; set; } + public int?[]? Relativehumidity_575hPa { get; set; } + public int?[]? Relativehumidity_550hPa { get; set; } + public int?[]? Relativehumidity_525hPa { get; set; } public int?[]? Relativehumidity_500hPa { get; set; } public int?[]? Relativehumidity_400hPa { get; set; } public int?[]? Relativehumidity_300hPa { get; set; } @@ -124,10 +146,21 @@ public class Hourly public int?[]? Cloudcover_950hPa { get; set; } public int?[]? Cloudcover_925hPa { get; set; } public int?[]? Cloudcover_900hPa { get; set; } + public int?[]? Cloudcover_875hPa { get; set; } public int?[]? Cloudcover_850hPa { get; set; } + public int?[]? Cloudcover_825hPa { get; set; } public int?[]? Cloudcover_800hPa { get; set; } + public int?[]? Cloudcover_775hPa { get; set; } + public int?[]? Cloudcover_750hPa { get; set; } + public int?[]? Cloudcover_725hPa { get; set; } public int?[]? Cloudcover_700hPa { get; set; } + public int?[]? Cloudcover_675hPa { get; set; } + public int?[]? Cloudcover_650hPa { get; set; } + public int?[]? Cloudcover_625hPa { get; set; } public int?[]? Cloudcover_600hPa { get; set; } + public int?[]? Cloudcover_575hPa { get; set; } + public int?[]? Cloudcover_550hPa { get; set; } + public int?[]? Cloudcover_525hPa { get; set; } public int?[]? Cloudcover_500hPa { get; set; } public int?[]? Cloudcover_400hPa { get; set; } public int?[]? Cloudcover_300hPa { get; set; } @@ -181,10 +214,21 @@ public class Hourly public float?[]? Geopotential_height_950hPa { get; set; } public float?[]? Geopotential_height_925hPa { get; set; } public float?[]? Geopotential_height_900hPa { get; set; } + public float?[]? Geopotential_height_875hPa { get; set; } public float?[]? Geopotential_height_850hPa { get; set; } + public float?[]? Geopotential_height_825hPa { get; set; } public float?[]? Geopotential_height_800hPa { get; set; } + public float?[]? Geopotential_height_775hPa { get; set; } + public float?[]? Geopotential_height_750hPa { get; set; } + public float?[]? Geopotential_height_725hPa { get; set; } public float?[]? Geopotential_height_700hPa { get; set; } + public float?[]? Geopotential_height_675hPa { get; set; } + public float?[]? Geopotential_height_650hPa { get; set; } + public float?[]? Geopotential_height_625hPa { get; set; } public float?[]? Geopotential_height_600hPa { get; set; } + public float?[]? Geopotential_height_575hPa { get; set; } + public float?[]? Geopotential_height_550hPa { get; set; } + public float?[]? Geopotential_height_525hPa { get; set; } public float?[]? Geopotential_height_500hPa { get; set; } public float?[]? Geopotential_height_400hPa { get; set; } public float?[]? Geopotential_height_300hPa { get; set; } From cffdca273af961979a9b99cd343c584db600a7b3 Mon Sep 17 00:00:00 2001 From: Colin Noakes Date: Tue, 30 Apr 2024 17:49:52 -0700 Subject: [PATCH 22/23] Fix warning --- OpenMeteo/OpenMeteoClientException.cs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/OpenMeteo/OpenMeteoClientException.cs b/OpenMeteo/OpenMeteoClientException.cs index 6c70617..e6cc822 100644 --- a/OpenMeteo/OpenMeteoClientException.cs +++ b/OpenMeteo/OpenMeteoClientException.cs @@ -3,13 +3,7 @@ namespace OpenMeteo { - public class OpenMeteoClientException : HttpRequestException + public class OpenMeteoClientException(string message, HttpStatusCode httpStatusCode) : HttpRequestException(message, null, httpStatusCode) { - public HttpStatusCode StatusCode { get; } - - public OpenMeteoClientException(string message, HttpStatusCode httpStatusCode) : base(message) - { - StatusCode = httpStatusCode; - } } } From 6b91bdef0c62efa0d220144aae036d865e6dd442 Mon Sep 17 00:00:00 2001 From: colinnuk Date: Mon, 26 Aug 2024 18:11:46 -0700 Subject: [PATCH 23/23] Add UK Met Office models --- OpenMeteo/WeatherModelOptions.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/OpenMeteo/WeatherModelOptions.cs b/OpenMeteo/WeatherModelOptions.cs index 0d9d94b..604dd92 100644 --- a/OpenMeteo/WeatherModelOptions.cs +++ b/OpenMeteo/WeatherModelOptions.cs @@ -130,6 +130,8 @@ public enum WeatherModelOptionsParameter bom_access_global, arpae_cosmo_2i, arpae_cosmo_2i_ruc, - arpae_cosmo_5m + arpae_cosmo_5m, + ukmo_global_deterministic_10km, + ukmo_global_deterministic_2km, } }