diff --git a/Power/Service/.vscode/launch.json b/Power/Service/.vscode/launch.json index 818819d..410a4e4 100644 --- a/Power/Service/.vscode/launch.json +++ b/Power/Service/.vscode/launch.json @@ -1,30 +1,30 @@ { - // Use IntelliSense to find out which attributes exist for C# debugging - // Use hover for the description of the existing attributes - // For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0", "configurations": [ { - "name": ".NET Core Launch (remote console)", + "name": ".NET Core Launch (web)", "type": "coreclr", "request": "launch", - "preLaunchTask": "publish", - "program": "dotnet", - "args": [ - "/home/ckaczor/Power/Service/Power.Service.dll" - ], - "cwd": "/home/ckaczor/Power/Service", + "preLaunchTask": "build", + "program": "${workspaceFolder}/bin/Debug/netcoreapp3.0/ChrisKaczor.HomeMonitor.Power.Service.dll", + "args": [], + "cwd": "${workspaceFolder}", "stopAtEntry": false, - "console": "internalConsole", - "pipeTransport": { - "pipeCwd": "${workspaceFolder}", - "pipeProgram": "C:\\Program Files (x86)\\PuTTY\\PLINK.EXE", - "pipeArgs": [ - "root@172.23.10.6" - ], - "debuggerPath": "/home/ckaczor/vsdbg/vsdbg" + "env": { + "ASPNETCORE_ENVIRONMENT": "Development" }, - "internalConsoleOptions": "openOnSessionStart" + "sourceFileMap": { + "/Views": "${workspaceFolder}/Views" + } + }, + { + "name": ".NET Core Attach", + "type": "coreclr", + "request": "attach", + "processId": "${command:pickProcess}" } ] } \ No newline at end of file diff --git a/Power/Service/.vscode/tasks.json b/Power/Service/.vscode/tasks.json index e872c92..0b3548f 100644 --- a/Power/Service/.vscode/tasks.json +++ b/Power/Service/.vscode/tasks.json @@ -7,29 +7,54 @@ "type": "process", "args": [ "build", - "${workspaceFolder}/Service.csproj" + "${workspaceFolder}/Service.csproj", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary" ], - "problemMatcher": "$msCompile", - "group": { - "kind": "build", - "isDefault": true - } + "problemMatcher": "$msCompile" }, { "label": "publish", + "command": "dotnet", + "type": "process", + "args": [ + "publish", + "${workspaceFolder}/Service.csproj", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary" + ], + "problemMatcher": "$msCompile" + }, + { + "label": "watch", + "command": "dotnet", + "type": "process", + "args": [ + "watch", + "run", + "${workspaceFolder}/Service.csproj", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary" + ], + "problemMatcher": "$msCompile" + }, + { + "label": "build", + "command": "dotnet", "type": "shell", + "args": [ + "build", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary" + ], + "group": { + "kind": "build", + "isDefault": true + }, "presentation": { - "reveal": "always", - "panel": "shared" + "reveal": "silent" }, - "options": { - "cwd": "${workspaceFolder}" - }, - "windows": { - "command": "${cwd}\\publish.bat" - }, - "problemMatcher": [], - "group": "build" + "problemMatcher": "$msCompile" } ] } \ No newline at end of file diff --git a/Weather/Service/.vscode/launch.json b/Weather/Service/.vscode/launch.json index 1cfddc9..0ac52c5 100644 --- a/Weather/Service/.vscode/launch.json +++ b/Weather/Service/.vscode/launch.json @@ -1,30 +1,31 @@ { - // Use IntelliSense to find out which attributes exist for C# debugging - // Use hover for the description of the existing attributes - // For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md - "version": "0.2.0", - "configurations": [ + // Use IntelliSense to find out which attributes exist for C# debugging + // Use hover for the description of the existing attributes + // For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md + "version": "0.2.0", + "configurations": [ { - "name": ".NET Core Launch (remote console)", + "name": ".NET Core Launch (web)", "type": "coreclr", "request": "launch", - "preLaunchTask": "publish", - "program": "dotnet", - "args": [ - "/home/ckaczor/Weather/Service/Weather.Service.dll" - ], - "cwd": "/home/ckaczor/Weather/Service", + "preLaunchTask": "build", + // If you have changed target frameworks, make sure to update the program path. + "program": "${workspaceFolder}/bin/Debug/netcoreapp3.0/ChrisKaczor.HomeMonitor.Weather.Service.dll", + "args": [], + "cwd": "${workspaceFolder}", "stopAtEntry": false, - "console": "internalConsole", - "pipeTransport": { - "pipeCwd": "${workspaceFolder}", - "pipeProgram": "C:\\Program Files (x86)\\PuTTY\\PLINK.EXE", - "pipeArgs": [ - "root@172.23.10.6" - ], - "debuggerPath": "/home/ckaczor/vsdbg/vsdbg" + "env": { + "ASPNETCORE_ENVIRONMENT": "Development" }, - "internalConsoleOptions": "openOnSessionStart" + "sourceFileMap": { + "/Views": "${workspaceFolder}/Views" + } + }, + { + "name": ".NET Core Attach", + "type": "coreclr", + "request": "attach", + "processId": "${command:pickProcess}" } ] } \ No newline at end of file diff --git a/Weather/Service/.vscode/settings.json b/Weather/Service/.vscode/settings.json new file mode 100644 index 0000000..c27a8d1 --- /dev/null +++ b/Weather/Service/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "cSpell.words": [ + "Kaczor" + ] +} \ No newline at end of file diff --git a/Weather/Service/.vscode/tasks.json b/Weather/Service/.vscode/tasks.json index e872c92..0b3548f 100644 --- a/Weather/Service/.vscode/tasks.json +++ b/Weather/Service/.vscode/tasks.json @@ -7,29 +7,54 @@ "type": "process", "args": [ "build", - "${workspaceFolder}/Service.csproj" + "${workspaceFolder}/Service.csproj", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary" ], - "problemMatcher": "$msCompile", - "group": { - "kind": "build", - "isDefault": true - } + "problemMatcher": "$msCompile" }, { "label": "publish", + "command": "dotnet", + "type": "process", + "args": [ + "publish", + "${workspaceFolder}/Service.csproj", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary" + ], + "problemMatcher": "$msCompile" + }, + { + "label": "watch", + "command": "dotnet", + "type": "process", + "args": [ + "watch", + "run", + "${workspaceFolder}/Service.csproj", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary" + ], + "problemMatcher": "$msCompile" + }, + { + "label": "build", + "command": "dotnet", "type": "shell", + "args": [ + "build", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary" + ], + "group": { + "kind": "build", + "isDefault": true + }, "presentation": { - "reveal": "always", - "panel": "shared" + "reveal": "silent" }, - "options": { - "cwd": "${workspaceFolder}" - }, - "windows": { - "command": "${cwd}\\publish.bat" - }, - "problemMatcher": [], - "group": "build" + "problemMatcher": "$msCompile" } ] } \ No newline at end of file diff --git a/Weather/Service/Data/Resources/GetReadingValueHistory.sql b/Weather/Service/Data/Resources/GetReadingValueHistory.sql index b57b542..b4f2389 100644 --- a/Weather/Service/Data/Resources/GetReadingValueHistory.sql +++ b/Weather/Service/Data/Resources/GetReadingValueHistory.sql @@ -2,3 +2,4 @@ SELECT Timestamp, @Value AS Value FROM Reading WHERE Timestamp BETWEEN @Start AND @End +ORDER BY Timestamp ASC diff --git a/Weather/Service/Extensions.cs b/Weather/Service/Extensions.cs new file mode 100644 index 0000000..40b09bb --- /dev/null +++ b/Weather/Service/Extensions.cs @@ -0,0 +1,12 @@ +using System; + +namespace ChrisKaczor.HomeMonitor.Weather.Service +{ + public static class Extensions + { + public static bool IsBetween(this T item, T start, T end) where T : IComparable + { + return item.CompareTo(start) >= 0 && item.CompareTo(end) <= 0; + } + } +} diff --git a/Weather/Service/MessageHandler.cs b/Weather/Service/MessageHandler.cs index 5213671..866752a 100644 --- a/Weather/Service/MessageHandler.cs +++ b/Weather/Service/MessageHandler.cs @@ -1,5 +1,6 @@ using ChrisKaczor.HomeMonitor.Weather.Models; using ChrisKaczor.HomeMonitor.Weather.Service.Data; +using ChrisKaczor.HomeMonitor.Weather.Service.Models; using JetBrains.Annotations; using Microsoft.AspNetCore.SignalR.Client; using Microsoft.Extensions.Configuration; @@ -8,11 +9,9 @@ using Newtonsoft.Json; using RabbitMQ.Client; using RabbitMQ.Client.Events; using System; -using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; -using ChrisKaczor.HomeMonitor.Weather.Service.Models; namespace ChrisKaczor.HomeMonitor.Weather.Service { @@ -97,17 +96,19 @@ namespace ChrisKaczor.HomeMonitor.Weather.Service _database.StoreWeatherData(weatherMessage); - weatherMessage.Rain = _database.GetReadingValueSum(WeatherValueType.Rain, weatherMessage.Timestamp.AddHours(-1), weatherMessage.Timestamp).Result; - if (_hubConnection == null) return; + var weatherUpdate = new WeatherUpdate(weatherMessage, _database); + try { if (_hubConnection.State == HubConnectionState.Disconnected) _hubConnection.StartAsync().Wait(); - _hubConnection.InvokeAsync("SendLatestReading", JsonConvert.SerializeObject(weatherMessage)).Wait(); + var json = JsonConvert.SerializeObject(weatherUpdate); + + _hubConnection.InvokeAsync("SendLatestReading", json).Wait(); } catch (Exception exception) { diff --git a/Weather/Service/Models/WeatherUpdate.cs b/Weather/Service/Models/WeatherUpdate.cs new file mode 100644 index 0000000..788841c --- /dev/null +++ b/Weather/Service/Models/WeatherUpdate.cs @@ -0,0 +1,114 @@ +using System.Linq; +using ChrisKaczor.HomeMonitor.Weather.Models; +using ChrisKaczor.HomeMonitor.Weather.Service.Data; +using DecimalMath; +using JetBrains.Annotations; +using MathNet.Numerics; + +namespace ChrisKaczor.HomeMonitor.Weather.Service.Models +{ + [PublicAPI] + public class WeatherUpdate : WeatherMessage + { + private Database _database; + + public decimal? WindChill { get; set; } + + public decimal? HeatIndex { get; set; } + + public decimal DewPoint { get; set; } + + public decimal PressureTrend { get; set; } + + public WeatherUpdate(WeatherMessage weatherMessage, Database database) + { + _database = database; + + Type = weatherMessage.Type; + Message = weatherMessage.Message; + Timestamp = weatherMessage.Timestamp; + WindDirection = weatherMessage.WindDirection; + WindSpeed = weatherMessage.WindSpeed; + Humidity = weatherMessage.Humidity; + HumidityTemperature = weatherMessage.HumidityTemperature; + Rain = weatherMessage.Rain; + Pressure = weatherMessage.Pressure; + PressureTemperature = weatherMessage.PressureTemperature; + BatteryLevel = weatherMessage.BatteryLevel; + LightLevel = weatherMessage.LightLevel; + Latitude = weatherMessage.Latitude; + Longitude = weatherMessage.Longitude; + Altitude = weatherMessage.Altitude; + SatelliteCount = weatherMessage.SatelliteCount; + GpsTimestamp = weatherMessage.GpsTimestamp; + + HeatIndex = CalculateHeatIndex(); + WindChill = CalculateWindChill(); + DewPoint = CalculateDewPoint(); + PressureTrend = CalculatePressureTrend(); + + Rain = database.GetReadingValueSum(WeatherValueType.Rain, Timestamp.AddHours(-1), Timestamp).Result; + } + + private decimal CalculatePressureTrend() + { + var pressureData = _database.GetReadingValueHistory(WeatherValueType.Pressure, Timestamp.AddHours(-3), Timestamp).Result; + + 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); + + var difference = (decimal) (lineFunction(yData.Length - 1) - lineFunction(0)); + + return difference; + } + + private decimal? CalculateHeatIndex() + { + var temperature = PressureTemperature; + var humidity = Humidity; + + if (temperature.IsBetween(80, 100) && humidity.IsBetween(40, 100)) + { + var 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; + + return heatIndex; + } + + return null; + } + + private decimal? CalculateWindChill() + { + var temperatureInF = PressureTemperature; + var windSpeedInMph = WindSpeed; + + if (temperatureInF.IsBetween(-45, 45) && windSpeedInMph.IsBetween(3, 60)) + { + var windChill = 35.74m + 0.6215m * temperatureInF - 35.75m * DecimalEx.Pow(windSpeedInMph, 0.16m) + 0.4275m * temperatureInF * DecimalEx.Pow(windSpeedInMph, 0.16m); + + return windChill; + } + + return null; + } + + private decimal CalculateDewPoint() + { + var relativeHumidity = Humidity; + var temperatureInF = PressureTemperature; + + 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; + + return dewPointInC * 9.0m / 5.0m + 32.0m; + } + } +} diff --git a/Weather/Service/Service.csproj b/Weather/Service/Service.csproj index b3ee606..df80e15 100644 --- a/Weather/Service/Service.csproj +++ b/Weather/Service/Service.csproj @@ -34,6 +34,8 @@ + +