Ejemplo n.º 1
0
        public static StationDayStatisticsDto ToStationDayStatisticsDto(this StationDayStatistics stationDayStatistics)
        {
            StationDayStatisticsDto dto = new StationDayStatisticsDto();

            dto.Id                     = stationDayStatistics.Id;
            dto.Date                   = stationDayStatistics.Date;
            dto.DewpointHighC          = stationDayStatistics.DewpointHighC;
            dto.DewpointHighTime       = stationDayStatistics.DewpointHighTime;
            dto.DewpointLowC           = stationDayStatistics.DewpointLowC;
            dto.DewpointLowTime        = stationDayStatistics.DewpointLowTime;
            dto.HeatIndexHighC         = stationDayStatistics.HeatIndexHighC;
            dto.HeatIndexHighTime      = stationDayStatistics.HeatIndexHighTime;
            dto.PressureHighMbar       = stationDayStatistics.PressureHighMbar;
            dto.PressureHighTime       = stationDayStatistics.PressureHighTime;
            dto.PressureLowMbar        = stationDayStatistics.PressureLowMbar;
            dto.PressureLowTime        = stationDayStatistics.PressureLowTime;
            dto.RainRateHighCmPerHour  = stationDayStatistics.RainRateHighCmPerHour;
            dto.RelativeHumidityHigh   = stationDayStatistics.RelativeHumidityHigh;
            dto.RelativeHumidityLow    = stationDayStatistics.RelativeHumidityLow;
            dto.RelativeHumidyHighTime = stationDayStatistics.RelativeHumidyHighTime;
            dto.RelativeHumidyLowTime  = stationDayStatistics.RelativeHumidyLowTime;
            dto.TempHighC              = stationDayStatistics.TempHighC;
            dto.TempHighTime           = stationDayStatistics.TempHighTime;
            dto.TempLowC               = stationDayStatistics.TempLowC;
            dto.TempLowTime            = stationDayStatistics.TempLowTime;
            dto.TotalRainCm            = stationDayStatistics.TotalRainCm;
            dto.WindChillLowC          = stationDayStatistics.WindChillLowC;
            dto.WindChillLowTime       = stationDayStatistics.WindChillLowTime;
            dto.WindHighMph            = stationDayStatistics.WindHighMph;
            dto.WindHighTime           = stationDayStatistics.WindHighTime;

            return(dto);
        }
        public async Task Run(
            [QueueTrigger("davis-station-collections")] string queueItem)
        {
            // Queue item format is seperated by pipes: "[weather station ID]|[report epoch]|[collection attempt number]"
            string[] queueItemParts = queueItem.Split('|');

            if (!Guid.TryParse(queueItemParts[0], out Guid weatherStationId))
            {
                _logger.LogError($"Could not parse weather station id from queue item: '{queueItem}'.");
                return;
            }

            if (!DateTime.TryParse(queueItemParts[1], out DateTime reportEpoch))
            {
                _logger.LogError($"Could not parse report epoch from queue item: '{queueItem}'.");
                return;
            }

            if (!int.TryParse(queueItemParts[2], out int collectionAttemptNumber))
            {
                _logger.LogError($"Could not parse collection attempt number from queue item: '{queueItem}'.");
                return;
            }

            _logger.LogInformation($"Processing data collection for weather station: {weatherStationId}, report epoch: {reportEpoch:u}, collection attempt: {collectionAttemptNumber}");

            HttpResponseMessage httpResponse;

            WeatherStation weatherStation = await _weatherStationRepository.GetByIdAsync(weatherStationId);

            if (weatherStation == null)
            {
                _logger.LogError($"Could not find the weather station with id: {weatherStationId}.");
                return;
            }

            var userSetting         = weatherStation.FetcherSettings.SingleOrDefault(x => x.Key == "User");
            var passwordSetting     = weatherStation.FetcherSettings.SingleOrDefault(x => x.Key == "Password");
            var apiTokenSetting     = weatherStation.FetcherSettings.SingleOrDefault(x => x.Key == "ApiToken");
            var pickupPeriodSetting = weatherStation.FetcherSettings.SingleOrDefault(x => x.Key == "PickupPeriod");
            var timeZoneIdSetting   = weatherStation.FetcherSettings.SingleOrDefault(x => x.Key == "TimeZoneId");

            if (userSetting == null)
            {
                _logger.LogError($"Weather station with the Id: {weatherStation.Id} does not provide a value for 'User'.");
                return;
            }

            if (passwordSetting == null)
            {
                _logger.LogError($"Weather station with the Id: {weatherStation.Id} does not provide a value for 'Password'.");
                return;
            }

            if (apiTokenSetting == null)
            {
                _logger.LogError($"Weather station with the Id: {weatherStation.Id} does not provide a value for 'ApiKey'.");
                return;
            }

            if (pickupPeriodSetting == null)
            {
                _logger.LogError($"Weather station with the Id: {weatherStation.Id} does not provide a value for 'PickupPeriod'.");
                return;
            }

            if (timeZoneIdSetting == null)
            {
                _logger.LogError($"Weather station with the Id: {weatherStation.Id} does not provide a value for 'TimeZoneId'.");
                return;
            }

            var timeZone = TimeZoneInfo.FindSystemTimeZoneById(timeZoneIdSetting.Value);

            if (timeZone == null)
            {
                _logger.LogError($"'TimeZoneId' for weather station with Id: {weatherStationId} could not be parsed. For the UK use 'GMT Standard Time'");
            }

            try
            {
                HttpClient client     = _httpClientFactory.CreateClient();
                var        requestUrl = $"https://api.weatherlink.com/v1/NoaaExt.json?user={userSetting.Value}&pass={passwordSetting.Value}&apiToken={apiTokenSetting.Value}";
                httpResponse = await client.GetAsync(requestUrl);

                if (!httpResponse.IsSuccessStatusCode)
                {
                    _logger.LogError($"Could not query weather API for station with id: {weatherStationId}. Response code was {httpResponse.StatusCode}");
                    return;
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, $"Exception trying to receive weather information from API for weather station: {weatherStationId}");
                return;
            }

            string responseBody = await httpResponse.Content.ReadAsStringAsync();

            var weatherStationInfo = JsonSerializer.Deserialize <NoaaExtResult>(responseBody);

            // Station Reading
            StationReading receivedReading = weatherStationInfo.ToStationReading(weatherStation);

            _logger.LogInformation($"Parsed reading for station: {weatherStationId} reading date: {receivedReading.When:u}.");

            // This is not the report we were looking for! Maybe queue another attempt?
            if (receivedReading.When != reportEpoch)
            {
                if (collectionAttemptNumber < 3)
                {
                    QueueClient queueClient = new (
                        _storageQueueSettings.StorageConnectionString,
                        "davis-station-collections",
                        new QueueClientOptions {
                        MessageEncoding = QueueMessageEncoding.Base64
                    });

                    int      nextCollectionNumber = collectionAttemptNumber + 1;
                    DateTime nextAttemptEpoch     = reportEpoch.AddMinutes(nextCollectionNumber);
                    TimeSpan nextAttemptDelay     = DateTime.UtcNow - nextAttemptEpoch;

                    // 1 here denotes the collection attempt number for this report epoch
                    await queueClient.SendMessageAsync($"{weatherStation.Id:D}|{reportEpoch:u}|{nextCollectionNumber}", nextAttemptDelay);

                    _logger.LogWarning($"Attempt to receive report: {reportEpoch:u} but recieved: {receivedReading.When:u} for attempt {collectionAttemptNumber} @ {DateTime.UtcNow:u}. Enqueed another attempt at: {nextAttemptEpoch:u}.");
                }
                else
                {
                    _logger.LogError($"Attempt to receive report: {reportEpoch:u} but recieved: {receivedReading.When:u} for attempt {collectionAttemptNumber} @ {DateTime.UtcNow:u}. Not enqueuing another attempt.");
                }

                return;
            }

            var stationUpdateHub = new HubConnectionBuilder()
                                   .WithUrl(_signalRSettings.HubUri, connectionOptions =>
            {
                connectionOptions.Headers.Add("Authorization", $"SharedKey {_signalRSettings.SharedKey}");
            })
                                   .Build();

            try
            {
                await stationUpdateHub.StartAsync(CancellationToken.None);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, $"Error connecting to Signal R server. This will effect the real time updating of information in the widget.");
            }

            StationReading latestReading = await _stationReadingRepository.FetchLatestReadingAsync(weatherStationId);

            if (latestReading == null || latestReading.When != receivedReading.When)
            {
                _stationReadingRepository.Create(receivedReading);

                if (stationUpdateHub.State == HubConnectionState.Connected)
                {
                    await stationUpdateHub.SendAsync("NewStationReading", weatherStationId, receivedReading.ToStationReadingDto(weatherStation.AltitudeM));
                }
            }

            // Station Day Statistics
            DateTime             statisticsDate      = TimeZoneInfo.ConvertTimeFromUtc(receivedReading.When, timeZone).Date;
            StationDayStatistics latestDayStatistics = await _stationDayStatisticsRepository.FetchForDateAsync(weatherStationId, statisticsDate);

            StationDayStatistics receivedStats = weatherStationInfo.CurrentObservation.ToStationDayStatistics(weatherStation, statisticsDate);

            _logger.LogInformation($"Parsed daily stats for station: {weatherStationId} reading date: {statisticsDate}.");

            if (latestDayStatistics == null)
            {
                _stationDayStatisticsRepository.Create(receivedStats);
                _logger.LogInformation($"Creating new stats for: {weatherStationId} reading date: {statisticsDate}.");
            }
            else
            {
                latestDayStatistics.DewpointHighC          = receivedStats.DewpointHighC;
                latestDayStatistics.DewpointHighTime       = receivedStats.DewpointHighTime;
                latestDayStatistics.DewpointLowC           = receivedStats.DewpointLowC;
                latestDayStatistics.DewpointLowTime        = receivedStats.DewpointLowTime;
                latestDayStatistics.HeatIndexHighC         = receivedStats.HeatIndexHighC;
                latestDayStatistics.HeatIndexHighTime      = receivedStats.HeatIndexHighTime;
                latestDayStatistics.PressureHighMbar       = receivedStats.PressureHighMbar;
                latestDayStatistics.PressureHighTime       = receivedStats.PressureHighTime;
                latestDayStatistics.PressureLowMbar        = receivedStats.PressureLowMbar;
                latestDayStatistics.PressureLowTime        = receivedStats.PressureLowTime;
                latestDayStatistics.RainRateHighCmPerHour  = receivedStats.RainRateHighCmPerHour;
                latestDayStatistics.RelativeHumidityHigh   = receivedStats.RelativeHumidityHigh;
                latestDayStatistics.RelativeHumidityLow    = receivedStats.RelativeHumidityLow;
                latestDayStatistics.RelativeHumidyHighTime = receivedStats.RelativeHumidyHighTime;
                latestDayStatistics.RelativeHumidyLowTime  = receivedStats.RelativeHumidyLowTime;
                latestDayStatistics.TempHighC        = receivedStats.TempHighC;
                latestDayStatistics.TempHighTime     = receivedStats.TempHighTime;
                latestDayStatistics.TempLowC         = receivedStats.TempLowC;
                latestDayStatistics.TempLowTime      = receivedStats.TempLowTime;
                latestDayStatistics.TotalRainCm      = receivedStats.TotalRainCm;
                latestDayStatistics.WindChillLowC    = receivedStats.WindChillLowC;
                latestDayStatistics.WindChillLowTime = receivedStats.WindChillLowTime;
                latestDayStatistics.WindHighMph      = receivedStats.WindHighMph;
                latestDayStatistics.WindHighTime     = receivedStats.WindHighTime;
                _stationDayStatisticsRepository.Update(latestDayStatistics);
                _logger.LogInformation($"Updating stats for: {weatherStationId} reading date: {statisticsDate}.");
            }

            await _dbContext.SaveChangesAsync(CancellationToken.None);

            DateTime?lastRain = await _stationReadingRepository.FetchLastRainDateAsync(weatherStationId);

            StationStatisticsDto statisticsDto = new StationStatisticsDto
            {
                DayStatistics = latestDayStatistics.ToStationDayStatisticsDto(),
                LastRain      = lastRain,
            };

            if (stationUpdateHub.State == HubConnectionState.Connected)
            {
                await stationUpdateHub.SendAsync("UpdatedStationStatistics", weatherStationId, statisticsDto);
            }

            await stationUpdateHub.StopAsync();

            await stationUpdateHub.DisposeAsync();

            _logger.LogInformation($"Processed data collection for weather station: {weatherStationId}");
        }
        public static StationDayStatistics ToStationDayStatistics(this DavisCurrentObservation currentObservation, WeatherStation station, DateTime date)
        {
            StationDayStatistics stationDayStatistics = new StationDayStatistics();

            stationDayStatistics.Date    = date;
            stationDayStatistics.Station = station;

            float dewpointHighF;

            if (float.TryParse(currentObservation.DewpointDayHighF, out dewpointHighF))
            {
                stationDayStatistics.DewpointHighC = dewpointHighF.ToCelsiusFromFahrenheit();
            }

            DateTime dewpointHighTime;

            if (DateTime.TryParse(currentObservation.DewpointDayHighTime, out dewpointHighTime))
            {
                stationDayStatistics.DewpointHighTime = dewpointHighTime.TimeOfDay;
            }

            float dewpointLowF;

            if (float.TryParse(currentObservation.DewpointDayLowF, out dewpointLowF))
            {
                stationDayStatistics.DewpointLowC = dewpointLowF.ToCelsiusFromFahrenheit();
            }

            DateTime dewpointLowTime;

            if (DateTime.TryParse(currentObservation.DewpointDayLowTime, out dewpointLowTime))
            {
                stationDayStatistics.DewpointLowTime = dewpointLowTime.TimeOfDay;
            }

            float heatIndexHighF;

            if (float.TryParse(currentObservation.HeatIndexDayHighF, out heatIndexHighF))
            {
                stationDayStatistics.HeatIndexHighC = heatIndexHighF.ToCelsiusFromFahrenheit();
            }

            DateTime heatIndexHighTime;

            if (DateTime.TryParse(currentObservation.HeatIndexDayHighTime, out heatIndexHighTime))
            {
                stationDayStatistics.HeatIndexHighTime = heatIndexHighTime.TimeOfDay;
            }

            float pressureDayHighIn;

            if (float.TryParse(currentObservation.PressureDayHighIn, out pressureDayHighIn))
            {
                stationDayStatistics.PressureHighMbar = pressureDayHighIn.ToMbarFromInHG();
            }

            DateTime pressureDayHighTime;

            if (DateTime.TryParse(currentObservation.PressureDayHighTime, out pressureDayHighTime))
            {
                stationDayStatistics.PressureHighTime = pressureDayHighTime.TimeOfDay;
            }

            float pressureDayLowIn;

            if (float.TryParse(currentObservation.PressureDayLowIn, out pressureDayLowIn))
            {
                stationDayStatistics.PressureLowMbar = pressureDayLowIn.ToMbarFromInHG();
            }

            DateTime pressureDayLowTime;

            if (DateTime.TryParse(currentObservation.PressureDayLowTime, out pressureDayLowTime))
            {
                stationDayStatistics.PressureLowTime = pressureDayLowTime.TimeOfDay;
            }

            float rainRateDayHighInPerHour;

            if (float.TryParse(currentObservation.RainRateDayHighInPerHour, out rainRateDayHighInPerHour))
            {
                stationDayStatistics.RainRateHighCmPerHour = rainRateDayHighInPerHour.ToCmFromInches();
            }

            float rainDayIn;

            if (float.TryParse(currentObservation.RainDayIn, out rainDayIn))
            {
                stationDayStatistics.TotalRainCm = rainDayIn.ToCmFromInches();
            }

            float relativeHumidityDayHigh;

            if (float.TryParse(currentObservation.RelativeHumidityDayHigh, out relativeHumidityDayHigh))
            {
                stationDayStatistics.RelativeHumidityHigh = relativeHumidityDayHigh;
            }

            DateTime relativeHumidityDayHighTime;

            if (DateTime.TryParse(currentObservation.RelativeHumidityDayHighTime, out relativeHumidityDayHighTime))
            {
                stationDayStatistics.RelativeHumidyHighTime = relativeHumidityDayHighTime.TimeOfDay;
            }

            float relativeHumidityDayLow;

            if (float.TryParse(currentObservation.RelativeHumidityDayLow, out relativeHumidityDayLow))
            {
                stationDayStatistics.RelativeHumidityLow = relativeHumidityDayLow;
            }

            DateTime relativeHumidityDayLowTime;

            if (DateTime.TryParse(currentObservation.RelativeHumidityDayLowTime, out relativeHumidityDayLowTime))
            {
                stationDayStatistics.RelativeHumidyLowTime = relativeHumidityDayLowTime.TimeOfDay;
            }

            float tempDayHighF;

            if (float.TryParse(currentObservation.TempDayHighF, out tempDayHighF))
            {
                stationDayStatistics.TempHighC = tempDayHighF.ToCelsiusFromFahrenheit();
            }

            DateTime tempDayHighTime;

            if (DateTime.TryParse(currentObservation.TempDayHighTime, out tempDayHighTime))
            {
                stationDayStatistics.TempHighTime = tempDayHighTime.TimeOfDay;
            }

            float tempDayLowF;

            if (float.TryParse(currentObservation.TempDayLowF, out tempDayLowF))
            {
                stationDayStatistics.TempLowC = tempDayLowF.ToCelsiusFromFahrenheit();
            }

            DateTime tempDayLowTime;

            if (DateTime.TryParse(currentObservation.TempDayLowTime, out tempDayLowTime))
            {
                stationDayStatistics.TempLowTime = tempDayLowTime.TimeOfDay;
            }

            float windChillDayLowF;

            if (float.TryParse(currentObservation.WindChillDayLowF, out windChillDayLowF))
            {
                stationDayStatistics.WindChillLowC = windChillDayLowF.ToCelsiusFromFahrenheit();
            }

            DateTime windChillDayLowTime;

            if (DateTime.TryParse(currentObservation.WindChillDayLowTime, out windChillDayLowTime))
            {
                stationDayStatistics.WindChillLowTime = windChillDayLowTime.TimeOfDay;
            }

            float windDayHigh;

            if (float.TryParse(currentObservation.WindDayHighMph, out windDayHigh))
            {
                stationDayStatistics.WindHighMph = windDayHigh;
            }

            DateTime windDayHighTime;

            if (DateTime.TryParse(currentObservation.WindDayHighTime, out windDayHighTime))
            {
                stationDayStatistics.WindHighTime = windDayHighTime.TimeOfDay;
            }

            return(stationDayStatistics);
        }