124 lines
4.4 KiB
C#
124 lines
4.4 KiB
C#
using Portfolio.Domain.Features.TemperatureDay;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Text.Json;
|
|
using System.Text.Json.Serialization;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace Portfolio.Application.Services.NWSWeatherService
|
|
{
|
|
public class NWSWeatherService : INWSWeatherService
|
|
{
|
|
private readonly HttpClient _httpClient;
|
|
|
|
public NWSWeatherService(HttpClient httpClient)
|
|
{
|
|
_httpClient = httpClient;
|
|
_httpClient.DefaultRequestHeaders.Add("User-Agent", "kira.jiroux@gmail.com"); // Replace with your email ideally
|
|
}
|
|
|
|
public async Task<string> GetNearestStationAsync(double latitude, double longitude)
|
|
{
|
|
var url = $"https://api.weather.gov/points/{latitude},{longitude}";
|
|
var response = await _httpClient.GetAsync(url);
|
|
response.EnsureSuccessStatusCode();
|
|
|
|
using var stream = await response.Content.ReadAsStreamAsync();
|
|
var json = await JsonDocument.ParseAsync(stream);
|
|
|
|
var stationUrl = json.RootElement
|
|
.GetProperty("properties")
|
|
.GetProperty("observationStations")
|
|
.GetString();
|
|
|
|
if (string.IsNullOrEmpty(stationUrl))
|
|
throw new Exception("Could not find station info.");
|
|
|
|
var stationListResponse = await _httpClient.GetAsync(stationUrl);
|
|
stationListResponse.EnsureSuccessStatusCode();
|
|
|
|
using var stationStream = await stationListResponse.Content.ReadAsStreamAsync();
|
|
var stationJson = await JsonDocument.ParseAsync(stationStream);
|
|
|
|
var firstStation = stationJson.RootElement
|
|
.GetProperty("features")[0]
|
|
.GetProperty("properties")
|
|
.GetProperty("stationIdentifier")
|
|
.GetString();
|
|
|
|
return firstStation;
|
|
}
|
|
|
|
public async Task<double?> GetDailyAverageTempAsync(string stationId, DateTime date)
|
|
{
|
|
var start = date.ToString("yyyy-MM-dd") + "T00:00:00Z";
|
|
var end = date.ToString("yyyy-MM-dd") + "T23:59:59Z";
|
|
|
|
var url = $"https://api.weather.gov/stations/{stationId}/observations?start={start}&end={end}";
|
|
var response = await _httpClient.GetAsync(url);
|
|
response.EnsureSuccessStatusCode();
|
|
|
|
using var stream = await response.Content.ReadAsStreamAsync();
|
|
var json = await JsonDocument.ParseAsync(stream);
|
|
|
|
var temps = new List<double>();
|
|
|
|
foreach (var feature in json.RootElement.GetProperty("features").EnumerateArray())
|
|
{
|
|
if (feature.TryGetProperty("properties", out var props) &&
|
|
props.TryGetProperty("temperature", out var tempObj) &&
|
|
tempObj.TryGetProperty("value", out var valueProp) &&
|
|
valueProp.ValueKind == JsonValueKind.Number)
|
|
{
|
|
var celsius = valueProp.GetDouble();
|
|
if (!double.IsNaN(celsius))
|
|
{
|
|
var fahrenheit = (celsius * 9.0 / 5.0) + 32.0;
|
|
temps.Add(fahrenheit);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (temps.Count == 0)
|
|
return null;
|
|
|
|
return temps.Average();
|
|
}
|
|
|
|
public async Task<List<TemperatureDay>> GetTemperatureDataAsync(double latitude, double longitude, int year)
|
|
{
|
|
var stationId = await GetNearestStationAsync(latitude, longitude);
|
|
|
|
var result = new List<TemperatureDay>();
|
|
|
|
var startDate = new DateTime(year, 1, 1);
|
|
var endDate = new DateTime(year, 12, 31);
|
|
|
|
for (var date = startDate; date <= endDate; date = date.AddDays(1))
|
|
{
|
|
Console.WriteLine($"Fetching {date:yyyy-MM-dd}...");
|
|
var avgTemp = await GetDailyAverageTempAsync(stationId, date);
|
|
|
|
if (avgTemp.HasValue)
|
|
{
|
|
result.Add(new TemperatureDay
|
|
{
|
|
Date = date,
|
|
AvgTemp = Math.Round(avgTemp.Value, 1)
|
|
});
|
|
}
|
|
else
|
|
{
|
|
Console.WriteLine($"No data for {date:yyyy-MM-dd}");
|
|
}
|
|
|
|
await Task.Delay(600); // small delay to be nice to NWS
|
|
}
|
|
|
|
return result;
|
|
}
|
|
}
|
|
}
|