diff --git a/DKSRDomain/WeatherResponse.cs b/DKSRDomain/WeatherResponse.cs new file mode 100644 index 0000000..9b827a9 --- /dev/null +++ b/DKSRDomain/WeatherResponse.cs @@ -0,0 +1,88 @@ +using Newtonsoft.Json; + +namespace DKSRDomain; + +public class WeatherResponse +{ + public List SensorData { get; set; } +} + +// { +// "rain": 0, +// "weather_id": 800, +// "temp": 299.37, +// "sunrise": "2024-07-19T03:24:11.000Z", +// "visibility": 10000, +// "city": "Weißdorf", +// "countrycode": "DE", +// "lon": 11.85, +// "clouds": 0, +// "pressure": 1018, +// "weather_icon": "01d", +// "feels_like": 299.37, +// "temp_max": 299.37, +// "SID": "fbc81ae8-87a2-49e7-948e-aeef30e66f71", +// "wind_deg": 190, +// "temp_min": 299.26, +// "grnd_level": 949, +// "sunset": "2024-07-19T19:13:15.000Z", +// "humidity": 53, +// "wind_speed": 2.06, +// "sea_level": 1018, +// "lat": 50.1833, +// "timestamp": "2024-07-19T15:43:50.730Z", +// "_headers": { +// "eventType": "OpenWeatherMapHofV1EventType" +// } +// } + +public class WeatherSensorData +{ + [JsonProperty("rain")] public int Rain { get; set; } + + [JsonProperty("weather_id")] public int WeatherId { get; set; } + + [JsonProperty("temp")] public double Temp { get; set; } + + [JsonProperty("sunrise")] public DateTime Sunrise { get; set; } + + [JsonProperty("visibility")] public int Visibility { get; set; } + + [JsonProperty("city")] public string City { get; set; } + + [JsonProperty("countrycode")] public string CountryCode { get; set; } + + [JsonProperty("lon")] public double Lon { get; set; } + + [JsonProperty("clouds")] public int Clouds { get; set; } + + [JsonProperty("pressure")] public int Pressure { get; set; } + + [JsonProperty("weather_icon")] public string WeatherIcon { get; set; } + + [JsonProperty("feels_like")] public double FeelsLike { get; set; } + + [JsonProperty("temp_max")] public double TempMax { get; set; } + + [JsonProperty("SID")] public string SID { get; set; } + + [JsonProperty("wind_deg")] public int WindDeg { get; set; } + + [JsonProperty("temp_min")] public double TempMin { get; set; } + + [JsonProperty("grnd_level")] public int GrndLevel { get; set; } + + [JsonProperty("sunset")] public DateTime Sunset { get; set; } + + [JsonProperty("humidity")] public int Humidity { get; set; } + + [JsonProperty("wind_speed")] public double WindSpeed { get; set; } + + [JsonProperty("sea_level")] public int SeaLevel { get; set; } + + [JsonProperty("lat")] public double Lat { get; set; } + + [JsonProperty("timestamp")] public DateTime Timestamp { get; set; } + + [JsonProperty("_headers")] public Dictionary Headers { get; set; } +} \ No newline at end of file diff --git a/Importer/Constants/Endpoints.cs b/Importer/Constants/Endpoints.cs index 1a93122..63108b1 100644 --- a/Importer/Constants/Endpoints.cs +++ b/Importer/Constants/Endpoints.cs @@ -4,12 +4,17 @@ public static class Endpoints { private const string Prefix = "https://"; private const string Url = "mainz-staging.dksr.city"; + + private const string DKSRUrl = "oup.hoferland-digital.de"; public const string TreesenseEndpoint = "/UrbanPulseData/historic/sensordata?eventtype=fac3edb2-53fa-4319-a897-e3e3c02102cc"; public const string ParkingSpaceEndpoint = "/UrbanPulseData/historic/sensordata?eventtype=2a4ce3e9-92db-455e-bece-0176c62fafba"; + + public const string WeatherEndpoint = + "/UrbanPulseData/historic/sensordata?SID=fbc81ae8-87a2-49e7-948e-aeef30e66f71"; public static string GetAuthenticatedEndpointUrl(string? username, string? password, string socket) { @@ -19,9 +24,23 @@ public static string GetAuthenticatedEndpointUrl(string? username, string? passw return $"{Prefix}{username}:{password}@{Url}{socket}"; } + + public static string GetAuthenticatedDKSREndpointUrl(string? username, string? password, string socket) + { + // if username or password is null, return the unauthenticated endpoint + if (username == null || password == null) + throw new ArgumentException("username or password undefined"); + + return $"{Prefix}{username}:{password}@{DKSRUrl}{socket}"; + } public static string GetEndpointUrl(string socket) { return $"{Prefix}{Url}{socket}"; } + + public static string GetDKSREndpointUrl(string socket) + { + return $"{Prefix}{DKSRUrl}{socket}"; + } } \ No newline at end of file diff --git a/Importer/Importer.csproj b/Importer/Importer.csproj index c7adb6c..6347e96 100644 --- a/Importer/Importer.csproj +++ b/Importer/Importer.csproj @@ -6,6 +6,7 @@ enable enable Linux + e176392a-7a30-4b16-b02d-30acfefd587a diff --git a/Importer/Importers/Importer.cs b/Importer/Importers/Importer.cs index 1690c3f..81ceb73 100644 --- a/Importer/Importers/Importer.cs +++ b/Importer/Importers/Importer.cs @@ -24,10 +24,21 @@ public abstract class Importer protected Importer(ILogger logger, string dataType, string dataStreamName) { - _frostApi = new FrostApi.FrostApi(Environment.GetEnvironmentVariable("FROST_SERVER_BASE_URL") ?? - throw new Exception("FROST_SERVER_BASE_URL not set")); - Username = Environment.GetEnvironmentVariable("DKSR_HISTORIC_USERNAME") ?? throw new Exception("DKSR_HISTORIC_USERNAME not set"); - Password = Environment.GetEnvironmentVariable("DKSR_HISTORIC_PASSWORD") ?? throw new Exception("DKSR_HISTORIC_PASSWORD not set"); + // _frostApi = new FrostApi.FrostApi(Environment.GetEnvironmentVariable("FROST_SERVER_BASE_URL") ?? + // throw new Exception("FROST_SERVER_BASE_URL not set")); + // + // Username = Environment.GetEnvironmentVariable("DKSR_HISTORIC_USERNAME") ?? throw new Exception("DKSR_HISTORIC_USERNAME not set"); + // Password = Environment.GetEnvironmentVariable("DKSR_HISTORIC_PASSWORD") ?? throw new Exception("DKSR_HISTORIC_PASSWORD not set"); + // Client = SetupHttpClient(); + // Logger = logger; + // DataType = dataType; + // _dataStreamName = dataStreamName; + + _frostApi = new FrostApi.FrostApi(Environment.GetEnvironmentVariable("FROST_SERVER_BASE_URL_WEATHER") ?? + throw new Exception("FROST_SERVER_BASE_URL_WEATHER not set")); + + Username = Environment.GetEnvironmentVariable("DKSR_HISTORIC_USERNAME_WEATHER") ?? throw new Exception("DKSR_HISTORIC_USERNAME_WEATHER not set"); + Password = Environment.GetEnvironmentVariable("DKSR_HISTORIC_PASSWORD_WEATHER") ?? throw new Exception("DKSR_HISTORIC_PASSWORD_WEATHER not set"); Client = SetupHttpClient(); Logger = logger; DataType = dataType; diff --git a/Importer/Importers/WeatherImporter.cs b/Importer/Importers/WeatherImporter.cs new file mode 100644 index 0000000..3aaf97d --- /dev/null +++ b/Importer/Importers/WeatherImporter.cs @@ -0,0 +1,70 @@ +using DKSRDomain; +using FrostApi.Models.Thing; +using Importer.Constants; +using Microsoft.Extensions.Logging; + +namespace Importer.Importers; + +public class WeatherImporter : Importer +{ + private Timer _importerTimer; + + public WeatherImporter(ILogger logger) : base(logger, "Weather", "weather") + { + _importerTimer = new Timer(Import, null, 0, 60 * 1000 * 60); // every hour + } + + protected override async void Import(object? _) + { + try + { + Logger.LogInformation($"{DateTime.Now} - Updating {DataType} Data..."); + var data = await GetDksrData(); + foreach (var weather in data.SensorData) + try + { + Thing thing; + var frostThing = await GetFrostThingData(weather.SID); + if (frostThing.Value.Count == 0) + { + thing = Mappers.MapDksrResponse(weather, DataType); + await CreateNewThing(thing); + frostThing = await GetFrostThingData(weather.SID); + } + + if (frostThing.Value.Count < 1) + throw new Exception($"Creating new thing with id {weather.SID} seems to have failed..."); + + thing = Mappers.MapDksrResponse(weather, DataType); + thing.Id = frostThing.Value.First().Id; + await Update(thing); + } + catch (Exception e) + { + Logger.LogError($"{DateTime.Now} - {e}"); + } + } + catch (Exception e) + { + Logger.LogError($"{DateTime.Now} - {e}"); + } + } + + + private async Task GetDksrData() + { + try + { + var response = + await Client.GetAsync( + Endpoints.GetAuthenticatedDKSREndpointUrl(Username, Password, Endpoints.WeatherEndpoint)); + var result = await response.Content.ReadAsAsync(); + return result; + } + catch (Exception e) + { + Logger.LogError("Getting data from DKSR failed, returning empty response"); + throw new Exception($"{DateTime.Now} - {e}"); + } + } +} \ No newline at end of file diff --git a/Importer/Mappers.cs b/Importer/Mappers.cs index 3199a8e..f064b67 100644 --- a/Importer/Mappers.cs +++ b/Importer/Mappers.cs @@ -30,6 +30,26 @@ public static Thing MapDksrResponse(ParkingSpaceSensorData parkingSpace, string return Thing.Create($"{dataType}-{parkingSpace.Sid}", dataType, properties, parkingSpace.Lat, parkingSpace.Lon, observation); } + + public static Thing MapDksrResponse(WeatherSensorData weather, string dataType) + { + var properties = new Dictionary + { + { "Id", weather.SID }, + { "Temperature", weather.Temp.ToString() }, + { "Max temperature", weather.TempMax.ToString() }, + { "Min temperature", weather.TempMin.ToString() }, + { "Pressure", weather.Pressure.ToString() }, + { "Humidity", weather.Humidity.ToString() }, + { "Wind speed", weather.WindSpeed.ToString() }, + { "Wind direction", weather.WindDeg.ToString() }, + { "Cloudiness", weather.Clouds.ToString() } + }; + + var observation = new Observation { Result = weather.Temp, PhenomenonTime = weather.Timestamp }; + + return Thing.Create($"{dataType}-{weather.SID}", dataType, properties, weather.Lat, weather.Lon, observation); + } public static DataStream MapFrostResponseToDataStream(DataStreamResponse? response) { diff --git a/Importer/Program.cs b/Importer/Program.cs index 71da986..e7fc58a 100644 --- a/Importer/Program.cs +++ b/Importer/Program.cs @@ -16,8 +16,9 @@ private static void Main(string[] args) IServiceProvider serviceProvider = services.BuildServiceProvider(); _logger = serviceProvider.GetRequiredService>(); - var treeImporter = new TreeImporter(_logger); - var parkingSpaceImporter = new ParkingSpaceImporter(_logger); + // var treeImporter = new TreeImporter(_logger); + // var parkingSpaceImporter = new ParkingSpaceImporter(_logger); + var weatherImporter = new WeatherImporter(_logger); Process.GetCurrentProcess().WaitForExit(); }