Skip to content

Commit

Permalink
Merge pull request #1 from colinnuk/feature/elevation_api
Browse files Browse the repository at this point in the history
Feature/elevation api
  • Loading branch information
colinnuk authored Mar 22, 2024
2 parents 47aa235 + 6973bfb commit 4feb257
Show file tree
Hide file tree
Showing 5 changed files with 123 additions and 35 deletions.
12 changes: 12 additions & 0 deletions OpenMeteo/ElevationApiResponse.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
namespace OpenMeteo
{
/// <summary>
/// Elevation API response
/// </summary>
public class ElevationApiResponse
{
/// <summary>
/// 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; }
}
}
21 changes: 21 additions & 0 deletions OpenMeteo/ElevationOptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
namespace OpenMeteo
{
internal class ElevationOptions
{
public ElevationOptions(float latitude, float longitude)
{
Latitude = latitude;
Longitude = longitude;
}

/// <summary>
/// Geographical WGS84 coordinate of the location
/// </summary>
public float Latitude { get; set; }

/// <summary>
/// Geographical WGS84 coordinate of the location
/// </summary>
public float Longitude { get; set; }
}
}
50 changes: 50 additions & 0 deletions OpenMeteo/OpenMeteoClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

/// <summary>
Expand Down Expand Up @@ -164,6 +165,19 @@ public OpenMeteoClient()
return (response.Locations[0].Latitude, response.Locations[0].Longitude);
}

/// <summary>
/// Performs one GET-Request to Open-Meteo Elevation API
/// </summary>
/// <param name="latitude">Latitude</param>
/// <param name="longitude">Longitude</param>
/// <returns></returns>
public async Task<ElevationApiResponse?> 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();
Expand Down Expand Up @@ -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<AirQuality?> GetAirQualityAsync(AirQualityOptions options)
{
try
Expand Down Expand Up @@ -320,6 +339,25 @@ public string WeathercodeToString(int weathercode)
}
}

private async Task<ElevationApiResponse?> GetElevationAsync(ElevationOptions options)
{
try
{
HttpResponseMessage response = await httpController.Client.GetAsync(MergeUrlWithOptions(_elevationApiUrl, options));
response.EnsureSuccessStatusCode();

ElevationApiResponse? elevationData = await JsonSerializer.DeserializeAsync<ElevationApiResponse>(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;
Expand Down Expand Up @@ -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();
}
}
}

33 changes: 33 additions & 0 deletions OpenMeteoTests/ElevationTests.cs
Original file line number Diff line number Diff line change
@@ -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);
}
}
}
42 changes: 7 additions & 35 deletions OpenMeteoTests/WeatherForecastTests.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Globalization;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
Expand Down Expand Up @@ -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,
Expand 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)));
}
}
}

0 comments on commit 4feb257

Please sign in to comment.