mirror of
https://github.com/ckaczor/HomeMonitor.git
synced 2026-01-30 17:24:21 -05:00
Update Weather to .NET 8 and add telemetry
This commit is contained in:
@@ -1,25 +1,17 @@
|
||||
using ChrisKaczor.HomeMonitor.Weather.Models;
|
||||
using JetBrains.Annotations;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using ChrisKaczor.HomeMonitor.Weather.Models;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace ChrisKaczor.HomeMonitor.Weather.Service.Models
|
||||
namespace ChrisKaczor.HomeMonitor.Weather.Service.Models;
|
||||
|
||||
[PublicAPI]
|
||||
public class ReadingAggregate(IEnumerable<WeatherReading> readings, Func<WeatherReading, decimal> selector, int decimalPlaces)
|
||||
{
|
||||
[PublicAPI]
|
||||
public class ReadingAggregate
|
||||
{
|
||||
public decimal Min { get; set; }
|
||||
public decimal Min { get; set; } = readings.Min(selector);
|
||||
|
||||
public decimal Max { get; set; }
|
||||
public decimal Max { get; set; } = readings.Max(selector);
|
||||
|
||||
public decimal Average { get; set; }
|
||||
|
||||
public ReadingAggregate(IEnumerable<WeatherReading> readings, Func<WeatherReading, decimal> selector, int decimalPlaces)
|
||||
{
|
||||
Min = readings.Min(selector);
|
||||
Max = readings.Max(selector);
|
||||
Average = readings.Average(selector).Truncate(decimalPlaces);
|
||||
}
|
||||
}
|
||||
public decimal Average { get; set; } = readings.Average(selector).Truncate(decimalPlaces);
|
||||
}
|
||||
@@ -1,49 +1,48 @@
|
||||
using ChrisKaczor.HomeMonitor.Weather.Models;
|
||||
using JetBrains.Annotations;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using ChrisKaczor.HomeMonitor.Weather.Models;
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace ChrisKaczor.HomeMonitor.Weather.Service.Models
|
||||
namespace ChrisKaczor.HomeMonitor.Weather.Service.Models;
|
||||
|
||||
[PublicAPI]
|
||||
public class WeatherAggregate
|
||||
{
|
||||
[PublicAPI]
|
||||
public class WeatherAggregate
|
||||
public ReadingAggregate Humidity { get; set; }
|
||||
|
||||
public ReadingAggregate Temperature { get; set; }
|
||||
|
||||
public ReadingAggregate Pressure { get; set; }
|
||||
|
||||
public ReadingAggregate Light { get; set; }
|
||||
|
||||
public ReadingAggregate WindSpeed { get; set; }
|
||||
|
||||
public WindDirection WindDirectionAverage { get; set; }
|
||||
|
||||
public decimal RainTotal { get; set; }
|
||||
|
||||
private static readonly List<int> WindDirectionValues = ((WindDirection[])Enum.GetValues(typeof(WindDirection))).Select(e => (int)e).ToList();
|
||||
|
||||
public WeatherAggregate(List<WeatherReading> readings)
|
||||
{
|
||||
public ReadingAggregate Humidity { get; set; }
|
||||
if (!readings.Any())
|
||||
return;
|
||||
|
||||
public ReadingAggregate Temperature { get; set; }
|
||||
Humidity = new ReadingAggregate(readings, r => r.Humidity, 1);
|
||||
|
||||
public ReadingAggregate Pressure { get; set; }
|
||||
Temperature = new ReadingAggregate(readings, r => r.HumidityTemperature, 1);
|
||||
|
||||
public ReadingAggregate Light { get; set; }
|
||||
Pressure = new ReadingAggregate(readings, r => r.Pressure, 2);
|
||||
|
||||
public ReadingAggregate WindSpeed { get; set; }
|
||||
Light = new ReadingAggregate(readings, r => r.LightLevel, 2);
|
||||
|
||||
public WindDirection WindDirectionAverage { get; set; }
|
||||
WindSpeed = new ReadingAggregate(readings, r => r.WindSpeed, 1);
|
||||
|
||||
public decimal RainTotal { get; set; }
|
||||
var windDirectionAverage = readings.Average(r => (decimal)r.WindDirection);
|
||||
WindDirectionAverage = (WindDirection)WindDirectionValues.Aggregate((x, y) => Math.Abs(x - windDirectionAverage) < Math.Abs(y - windDirectionAverage) ? x : y);
|
||||
|
||||
private static readonly List<int> WindDirectionValues = ((WindDirection[])Enum.GetValues(typeof(WindDirection))).Select(e => (int)e).ToList();
|
||||
|
||||
public WeatherAggregate(List<WeatherReading> readings)
|
||||
{
|
||||
if (!readings.Any())
|
||||
return;
|
||||
|
||||
Humidity = new ReadingAggregate(readings, r => r.Humidity, 1);
|
||||
|
||||
Temperature = new ReadingAggregate(readings, r => r.HumidityTemperature, 1);
|
||||
|
||||
Pressure = new ReadingAggregate(readings, r => r.Pressure, 2);
|
||||
|
||||
Light = new ReadingAggregate(readings, r => r.LightLevel, 2);
|
||||
|
||||
WindSpeed = new ReadingAggregate(readings, r => r.WindSpeed, 1);
|
||||
|
||||
var windDirectionAverage = readings.Average(r => (decimal)r.WindDirection);
|
||||
WindDirectionAverage = (WindDirection)WindDirectionValues.Aggregate((x, y) => Math.Abs(x - windDirectionAverage) < Math.Abs(y - windDirectionAverage) ? x : y);
|
||||
|
||||
RainTotal = readings.Sum(r => r.Rain);
|
||||
}
|
||||
RainTotal = readings.Sum(r => r.Rain);
|
||||
}
|
||||
}
|
||||
@@ -1,21 +1,20 @@
|
||||
using JetBrains.Annotations;
|
||||
using System;
|
||||
|
||||
namespace ChrisKaczor.HomeMonitor.Weather.Service.Models
|
||||
namespace ChrisKaczor.HomeMonitor.Weather.Service.Models;
|
||||
|
||||
[PublicAPI]
|
||||
public class WeatherReadingGrouped
|
||||
{
|
||||
[PublicAPI]
|
||||
public class WeatherReadingGrouped
|
||||
{
|
||||
public DateTimeOffset Bucket { get; set; }
|
||||
public DateTimeOffset Bucket { get; set; }
|
||||
|
||||
public decimal AverageHumidity { get; set; }
|
||||
public decimal AverageHumidity { get; set; }
|
||||
|
||||
public decimal AverageTemperature { get; set; }
|
||||
public decimal AverageTemperature { get; set; }
|
||||
|
||||
public decimal AveragePressure { get; set; }
|
||||
public decimal AveragePressure { get; set; }
|
||||
|
||||
public decimal AverageLightLevel { get; set; }
|
||||
public decimal AverageLightLevel { get; set; }
|
||||
|
||||
public decimal RainTotal { get; set; }
|
||||
}
|
||||
public decimal RainTotal { get; set; }
|
||||
}
|
||||
@@ -5,97 +5,96 @@ using JetBrains.Annotations;
|
||||
using MathNet.Numerics;
|
||||
using System.Linq;
|
||||
|
||||
namespace ChrisKaczor.HomeMonitor.Weather.Service.Models
|
||||
namespace ChrisKaczor.HomeMonitor.Weather.Service.Models;
|
||||
|
||||
[PublicAPI]
|
||||
public class WeatherUpdate : WeatherUpdateBase
|
||||
{
|
||||
[PublicAPI]
|
||||
public class WeatherUpdate : WeatherUpdateBase
|
||||
private readonly Database _database;
|
||||
|
||||
public WeatherUpdate(WeatherMessage weatherMessage, Database database)
|
||||
{
|
||||
private readonly Database _database;
|
||||
_database = database;
|
||||
|
||||
public WeatherUpdate(WeatherMessage weatherMessage, Database database)
|
||||
Type = weatherMessage.Type;
|
||||
Message = weatherMessage.Message;
|
||||
Timestamp = weatherMessage.Timestamp;
|
||||
WindDirection = weatherMessage.WindDirection;
|
||||
WindSpeed = weatherMessage.WindSpeed;
|
||||
Humidity = weatherMessage.Humidity;
|
||||
Rain = weatherMessage.Rain;
|
||||
Pressure = weatherMessage.Pressure;
|
||||
Temperature = weatherMessage.HumidityTemperature;
|
||||
LightLevel = weatherMessage.LightLevel;
|
||||
Latitude = weatherMessage.Latitude;
|
||||
Longitude = weatherMessage.Longitude;
|
||||
Altitude = weatherMessage.Altitude;
|
||||
SatelliteCount = weatherMessage.SatelliteCount;
|
||||
GpsTimestamp = weatherMessage.GpsTimestamp;
|
||||
|
||||
CalculateHeatIndex();
|
||||
CalculateWindChill();
|
||||
CalculateDewPoint();
|
||||
CalculatePressureTrend();
|
||||
CalculateRainLastHour();
|
||||
}
|
||||
|
||||
private void CalculateRainLastHour()
|
||||
{
|
||||
RainLastHour = _database.GetReadingValueSum(WeatherValueType.Rain, Timestamp.AddHours(-1), Timestamp).Result;
|
||||
}
|
||||
|
||||
private void CalculateWindChill()
|
||||
{
|
||||
var temperatureInF = Temperature;
|
||||
var windSpeedInMph = WindSpeed;
|
||||
|
||||
if (temperatureInF.IsBetween(-45, 45) && windSpeedInMph.IsBetween(3, 60))
|
||||
{
|
||||
_database = database;
|
||||
|
||||
Type = weatherMessage.Type;
|
||||
Message = weatherMessage.Message;
|
||||
Timestamp = weatherMessage.Timestamp;
|
||||
WindDirection = weatherMessage.WindDirection;
|
||||
WindSpeed = weatherMessage.WindSpeed;
|
||||
Humidity = weatherMessage.Humidity;
|
||||
Rain = weatherMessage.Rain;
|
||||
Pressure = weatherMessage.Pressure;
|
||||
Temperature = weatherMessage.HumidityTemperature;
|
||||
LightLevel = weatherMessage.LightLevel;
|
||||
Latitude = weatherMessage.Latitude;
|
||||
Longitude = weatherMessage.Longitude;
|
||||
Altitude = weatherMessage.Altitude;
|
||||
SatelliteCount = weatherMessage.SatelliteCount;
|
||||
GpsTimestamp = weatherMessage.GpsTimestamp;
|
||||
|
||||
CalculateHeatIndex();
|
||||
CalculateWindChill();
|
||||
CalculateDewPoint();
|
||||
CalculatePressureTrend();
|
||||
CalculateRainLastHour();
|
||||
}
|
||||
|
||||
private void CalculateRainLastHour()
|
||||
{
|
||||
RainLastHour = _database.GetReadingValueSum(WeatherValueType.Rain, Timestamp.AddHours(-1), Timestamp).Result;
|
||||
}
|
||||
|
||||
private void CalculateWindChill()
|
||||
{
|
||||
var temperatureInF = Temperature;
|
||||
var windSpeedInMph = WindSpeed;
|
||||
|
||||
if (temperatureInF.IsBetween(-45, 45) && windSpeedInMph.IsBetween(3, 60))
|
||||
{
|
||||
WindChill = 35.74m + 0.6215m * temperatureInF - 35.75m * DecimalEx.Pow(windSpeedInMph, 0.16m) + 0.4275m * temperatureInF * DecimalEx.Pow(windSpeedInMph, 0.16m);
|
||||
}
|
||||
}
|
||||
|
||||
private void CalculateDewPoint()
|
||||
{
|
||||
var relativeHumidity = Humidity;
|
||||
var temperatureInF = Temperature;
|
||||
|
||||
var temperatureInC = (temperatureInF - 32.0m) * 5.0m / 9.0m;
|
||||
|
||||
var vaporPressure = relativeHumidity * 0.01m * 6.112m * DecimalEx.Exp(17.62m * temperatureInC / (temperatureInC + 243.12m));
|
||||
var numerator = 243.12m * DecimalEx.Log(vaporPressure) - 440.1m;
|
||||
var denominator = 19.43m - DecimalEx.Log(vaporPressure);
|
||||
var dewPointInC = numerator / denominator;
|
||||
|
||||
DewPoint = dewPointInC * 9.0m / 5.0m + 32.0m;
|
||||
}
|
||||
|
||||
private void CalculatePressureTrend()
|
||||
{
|
||||
var pressureData = _database
|
||||
.GetReadingValueHistory(WeatherValueType.Pressure, Timestamp.AddHours(-3), Timestamp).Result.ToList();
|
||||
|
||||
var xData = pressureData.Select(p => (double)p.Timestamp.ToUnixTimeSeconds()).ToArray();
|
||||
var yData = pressureData.Select(p => (double)p.Value / 100.0).ToArray();
|
||||
|
||||
var lineFunction = Fit.LineFunc(xData, yData);
|
||||
|
||||
PressureDifferenceThreeHour = (decimal)(lineFunction(xData.Last()) - lineFunction(xData[0]));
|
||||
}
|
||||
|
||||
private void CalculateHeatIndex()
|
||||
{
|
||||
var temperature = Temperature;
|
||||
var humidity = Humidity;
|
||||
|
||||
if (temperature.IsBetween(80, 100) && humidity.IsBetween(40, 100))
|
||||
{
|
||||
HeatIndex = -42.379m + 2.04901523m * temperature + 10.14333127m * humidity -
|
||||
.22475541m * temperature * humidity - .00683783m * temperature * temperature -
|
||||
.05481717m * humidity * humidity + .00122874m * temperature * temperature * humidity +
|
||||
.00085282m * temperature * humidity * humidity -
|
||||
.00000199m * temperature * temperature * humidity * humidity;
|
||||
}
|
||||
WindChill = 35.74m + 0.6215m * temperatureInF - 35.75m * DecimalEx.Pow(windSpeedInMph, 0.16m) + 0.4275m * temperatureInF * DecimalEx.Pow(windSpeedInMph, 0.16m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void CalculateDewPoint()
|
||||
{
|
||||
var relativeHumidity = Humidity;
|
||||
var temperatureInF = Temperature;
|
||||
|
||||
var temperatureInC = (temperatureInF - 32.0m) * 5.0m / 9.0m;
|
||||
|
||||
var vaporPressure = relativeHumidity * 0.01m * 6.112m * DecimalEx.Exp(17.62m * temperatureInC / (temperatureInC + 243.12m));
|
||||
var numerator = 243.12m * DecimalEx.Log(vaporPressure) - 440.1m;
|
||||
var denominator = 19.43m - DecimalEx.Log(vaporPressure);
|
||||
var dewPointInC = numerator / denominator;
|
||||
|
||||
DewPoint = dewPointInC * 9.0m / 5.0m + 32.0m;
|
||||
}
|
||||
|
||||
private void CalculatePressureTrend()
|
||||
{
|
||||
var pressureData = _database
|
||||
.GetReadingValueHistory(WeatherValueType.Pressure, Timestamp.AddHours(-3), Timestamp).Result.ToList();
|
||||
|
||||
var xData = pressureData.Select(p => (double)p.Timestamp.ToUnixTimeSeconds()).ToArray();
|
||||
var yData = pressureData.Select(p => (double)p.Value / 100.0).ToArray();
|
||||
|
||||
var lineFunction = Fit.LineFunc(xData, yData);
|
||||
|
||||
PressureDifferenceThreeHour = (decimal)(lineFunction(xData.Last()) - lineFunction(xData[0]));
|
||||
}
|
||||
|
||||
private void CalculateHeatIndex()
|
||||
{
|
||||
var temperature = Temperature;
|
||||
var humidity = Humidity;
|
||||
|
||||
if (temperature.IsBetween(80, 100) && humidity.IsBetween(40, 100))
|
||||
{
|
||||
HeatIndex = -42.379m + 2.04901523m * temperature + 10.14333127m * humidity -
|
||||
.22475541m * temperature * humidity - .00683783m * temperature * temperature -
|
||||
.05481717m * humidity * humidity + .00122874m * temperature * temperature * humidity +
|
||||
.00085282m * temperature * humidity * humidity -
|
||||
.00000199m * temperature * temperature * humidity * humidity;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,12 @@
|
||||
using JetBrains.Annotations;
|
||||
using System;
|
||||
|
||||
namespace ChrisKaczor.HomeMonitor.Weather.Service.Models
|
||||
{
|
||||
[PublicAPI]
|
||||
public class WeatherValue
|
||||
{
|
||||
public DateTimeOffset Timestamp { get; set; }
|
||||
namespace ChrisKaczor.HomeMonitor.Weather.Service.Models;
|
||||
|
||||
public decimal Value { get; set; }
|
||||
}
|
||||
}
|
||||
[PublicAPI]
|
||||
public class WeatherValue
|
||||
{
|
||||
public DateTimeOffset Timestamp { get; set; }
|
||||
|
||||
public decimal Value { get; set; }
|
||||
}
|
||||
@@ -1,13 +1,12 @@
|
||||
using JetBrains.Annotations;
|
||||
using System;
|
||||
|
||||
namespace ChrisKaczor.HomeMonitor.Weather.Service.Models
|
||||
{
|
||||
[PublicAPI]
|
||||
public class WeatherValueGrouped
|
||||
{
|
||||
public DateTimeOffset Bucket { get; set; }
|
||||
namespace ChrisKaczor.HomeMonitor.Weather.Service.Models;
|
||||
|
||||
public decimal AverageValue { get; set; }
|
||||
}
|
||||
[PublicAPI]
|
||||
public class WeatherValueGrouped
|
||||
{
|
||||
public DateTimeOffset Bucket { get; set; }
|
||||
|
||||
public decimal AverageValue { get; set; }
|
||||
}
|
||||
@@ -1,18 +1,17 @@
|
||||
using JetBrains.Annotations;
|
||||
|
||||
namespace ChrisKaczor.HomeMonitor.Weather.Service.Models
|
||||
namespace ChrisKaczor.HomeMonitor.Weather.Service.Models;
|
||||
|
||||
[PublicAPI]
|
||||
public enum WeatherValueType
|
||||
{
|
||||
[PublicAPI]
|
||||
public enum WeatherValueType
|
||||
{
|
||||
WindSpeed,
|
||||
Humidity,
|
||||
HumidityTemperature,
|
||||
Rain,
|
||||
Pressure,
|
||||
PressureTemperature,
|
||||
LightLevel,
|
||||
Altitude,
|
||||
SatelliteCount
|
||||
}
|
||||
}
|
||||
WindSpeed,
|
||||
Humidity,
|
||||
HumidityTemperature,
|
||||
Rain,
|
||||
Pressure,
|
||||
PressureTemperature,
|
||||
LightLevel,
|
||||
Altitude,
|
||||
SatelliteCount
|
||||
}
|
||||
@@ -1,19 +1,18 @@
|
||||
using JetBrains.Annotations;
|
||||
using System;
|
||||
|
||||
namespace ChrisKaczor.HomeMonitor.Weather.Service.Models
|
||||
namespace ChrisKaczor.HomeMonitor.Weather.Service.Models;
|
||||
|
||||
[PublicAPI]
|
||||
public class WindHistoryGrouped
|
||||
{
|
||||
[PublicAPI]
|
||||
public class WindHistoryGrouped
|
||||
{
|
||||
public DateTimeOffset Bucket { get; set; }
|
||||
public DateTimeOffset Bucket { get; set; }
|
||||
|
||||
public decimal MinimumSpeed { get; set; }
|
||||
public decimal MinimumSpeed { get; set; }
|
||||
|
||||
public decimal AverageSpeed { get; set; }
|
||||
public decimal AverageSpeed { get; set; }
|
||||
|
||||
public decimal MaximumSpeed { get; set; }
|
||||
public decimal MaximumSpeed { get; set; }
|
||||
|
||||
public decimal AverageDirection { get; set; }
|
||||
}
|
||||
public decimal AverageDirection { get; set; }
|
||||
}
|
||||
Reference in New Issue
Block a user