This commit is contained in:
2017-09-26 20:21:42 +02:00
parent e144bde202
commit 319ca0cbbb
194 changed files with 10149 additions and 0 deletions
+31
View File
@@ -0,0 +1,31 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.25420.1
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mqtt-SWB-Dashboard", "Mqtt-SWB-Dashboard\Mqtt-SWB-Dashboard.csproj", "{324B2308-7C6E-4F16-8764-7C2F8C342B6A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Utils", "..\Utils\Utils\Utils.csproj", "{FAC8CE64-BF13-4ECE-8097-AEB5DD060098}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{324B2308-7C6E-4F16-8764-7C2F8C342B6A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{324B2308-7C6E-4F16-8764-7C2F8C342B6A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{324B2308-7C6E-4F16-8764-7C2F8C342B6A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{324B2308-7C6E-4F16-8764-7C2F8C342B6A}.Release|Any CPU.Build.0 = Release|Any CPU
{FAC8CE64-BF13-4ECE-8097-AEB5DD060098}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FAC8CE64-BF13-4ECE-8097-AEB5DD060098}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FAC8CE64-BF13-4ECE-8097-AEB5DD060098}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FAC8CE64-BF13-4ECE-8097-AEB5DD060098}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {8640C2B5-61E7-4C20-8E37-28A9543423B7}
EndGlobalSection
EndGlobal
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
</startup>
</configuration>
@@ -0,0 +1,9 @@
<Application x:Class="Mqtt_SWB_Dashboard.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Mqtt_SWB_Dashboard"
StartupUri="MainWindow.xaml">
<Application.Resources>
</Application.Resources>
</Application>
@@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
namespace Mqtt_SWB_Dashboard {
/// <summary>
/// Interaktionslogik für "App.xaml"
/// </summary>
public partial class App : Application {
}
}
@@ -0,0 +1,56 @@
using System;
using System.Globalization;
using LitJson;
namespace Mqtt_SWB_Dashboard.Helper {
class Device {
public enum DevType {
State,
Consumption,
Production
}
public Device(JsonData data, DevType type) {
this.TimeStamp = new DateTime();
this.Power = 0;
this.Comul = 0;
this.Status = false;
this.Production = 0;
this.Type = type;
this.Update(data, type);
}
public Device(JsonData data) {
this.TimeStamp = DateTime.Parse(data["TimeStamp"].ToString(), new CultureInfo("en-US"));
this.Status = data["Status"].ToString() == "true" ? true : false;
this.Production = Double.Parse(data["Production"].ToString());
this.Type = (DevType)Int32.Parse(data["Type"].ToString());
this.Power = Double.Parse(data["Power"].ToString());
this.Comul = Double.Parse(data["Comul"].ToString());
}
public DateTime TimeStamp { get; private set; }
public Boolean Status { get; private set; }
public Double Production { get; private set; }
public DevType Type { get; private set; }
public Double Power { get; private set; }
public Double Comul { get; private set; }
internal void Update(JsonData data, DevType type) {
this.TimeStamp = DateTime.Parse(data["timestamp"].ToString());
if (type == DevType.State) {
this.Status = data["status"].ToString() == "active" ? true : false;
}
if (type == DevType.Consumption) {
this.Power = Double.Parse(data["power"].ToString());
this.Comul = Double.Parse(data["energyCumul"].ToString());
}
if (type == DevType.Production) {
this.Power = Double.Parse(data["power"].ToString());
this.Comul = Double.Parse(data["energyCumulative"].ToString());
this.Production = Double.Parse(data["productionCumulative"].ToString());
}
}
}
}
@@ -0,0 +1,105 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using LitJson;
namespace Mqtt_SWB_Dashboard.Helper {
class Household {
public SortedDictionary<String, Device> Devices { get; private set; }
public DateTime Active { get; private set; }
public Boolean Connected { get; private set; }
public Household(String did, Device device) {
this.Active = DateTime.Now;
this.Devices = new SortedDictionary<String, Device> {
{ did, device }
};
}
public Household(JsonData data) {
this.Devices = new SortedDictionary<String, Device>();
if (data.Keys.Contains("Devices")) {
foreach (KeyValuePair<String, JsonData> item in data["Devices"]) {
this.Devices.Add(item.Key, new Device(item.Value));
}
}
if(data.Keys.Contains("Connected")) {
this.Connected = Boolean.Parse(data["Connected"].ToString());
if (this.Connected) {
this.Active = DateTime.Now;
}
}
if(data.Keys.Contains("Active")) {
this.Active = DateTime.Parse(data["Active"].ToString(), new CultureInfo("en-US"));
}
}
public void PutDevice(String did, JsonData data, Device.DevType dtype) {
this.Active = DateTime.Now;
if (this.Devices.Keys.Contains(did)) {
this.Devices[did].Update(data, dtype);
} else {
this.Devices.Add(did, new Device(data, dtype));
}
}
internal Int32 GetActive() {
Int32 ret = 0;
foreach (KeyValuePair<String, Device> item in this.Devices) {
if (item.Value.TimeStamp > DateTime.Now.AddMinutes(-10)) {
ret++;
}
}
return ret;
}
internal Double GetPower() {
Double ret = 0;
foreach (KeyValuePair<String, Device> item in this.Devices) {
if (item.Value.TimeStamp > DateTime.Now.AddMinutes(-10) && item.Value.Type != Device.DevType.Production) {
ret += item.Value.Power;
}
}
return ret;
}
internal Double GetAllPower() {
Double ret = 0;
foreach (KeyValuePair<String, Device> item in this.Devices) {
if (item.Value.Type != Device.DevType.Production) {
ret += item.Value.Power;
}
}
return ret;
}
internal Double GetColum() {
Double ret = 0;
foreach (KeyValuePair<String, Device> item in this.Devices) {
if (item.Value.TimeStamp > DateTime.Now.AddMinutes(-10) && item.Value.Type != Device.DevType.Production) {
ret += item.Value.Comul;
}
}
return ret;
}
internal Double GetAllColum() {
Double ret = 0;
foreach (KeyValuePair<String, Device> item in this.Devices) {
if (item.Value.Type != Device.DevType.Production) {
ret += item.Value.Comul;
}
}
return ret;
}
internal void PutConnection(JsonData data) {
this.Connected = Boolean.Parse(data["Connected"].ToString());
if(this.Connected) {
this.Active = DateTime.Now;
}
}
}
}
@@ -0,0 +1,35 @@
using System;
using LitJson;
namespace Mqtt_SWB_Dashboard.Helper {
class Raspi {
public Raspi(JsonData data) {
PutStatus(data);
if(data.Keys.Contains("Connected")) {
this.Connected = Boolean.Parse(data["Connected"].ToString());
}
if (data.Keys.Contains("Uptime")) {
this.Uptime = Double.Parse(data["Uptime"].ToString());
}
}
public Boolean Connected { get; private set; }
public Double Uptime { get; private set; }
internal void PutStatus(JsonData data) {
if (data.Keys.Contains("message")) {
if (data["message"].Keys.Contains("status")) {
this.Connected = (data["message"]["status"].ToString() == "disconnected") ? false : true;
if (!this.Connected) {
this.Uptime = 0;
}
}
if (data["message"].Keys.Contains("uptime")) {
this.Uptime = Double.Parse(data["message"]["uptime"].ToString());
this.Connected = true;
}
}
}
}
}
@@ -0,0 +1,34 @@
<Window x:Class="Mqtt_SWB_Dashboard.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:oxy="clr-namespace:OxyPlot.Wpf;assembly=OxyPlot.Wpf"
xmlns:models="clr-namespace:Mqtt_SWB_Dashboard.Models"
xmlns:local="clr-namespace:Mqtt_SWB_Dashboard"
mc:Ignorable="d"
Title="Flex4Grid-Debugger" Height="400" Width="525" Closed="OnClosed">
<Window.DataContext>
<models:PowerChartModel />
</Window.DataContext>
<Grid>
<TextBlock HorizontalAlignment="Left" Margin="10,55,0,0" TextWrapping="Wrap" Text="Haushalte" VerticalAlignment="Top" Width="70" TextAlignment="Center"/>
<TextBlock HorizontalAlignment="Left" Margin="85,55,0,0" TextWrapping="Wrap" Text="Geräte" VerticalAlignment="Top" Width="62" TextAlignment="Center"/>
<TextBlock HorizontalAlignment="Left" Margin="10,139,0,0" TextWrapping="Wrap" Text="Power" VerticalAlignment="Top" Width="202" TextAlignment="Center"/>
<TextBlock HorizontalAlignment="Left" Margin="10,97,0,0" TextWrapping="Wrap" Text="Verbrauch" VerticalAlignment="Top" Width="202" TextAlignment="Center"/>
<TextBlock HorizontalAlignment="Left" Margin="152,55,0,0" TextWrapping="Wrap" Text="Raspis" VerticalAlignment="Top" Width="60" TextAlignment="Center"/>
<TextBlock HorizontalAlignment="Left" Margin="217,55,0,0" TextWrapping="Wrap" Text="Most Uptime" VerticalAlignment="Top" Width="195" TextAlignment="Center"/>
<TextBlock HorizontalAlignment="Left" Margin="417,55,0,0" TextWrapping="Wrap" Text="Avg Uptime" VerticalAlignment="Top" Width="90" TextAlignment="Center"/>
<TextBlock x:Name="connectedTo" HorizontalAlignment="Left" Margin="10,10,0,0" TextWrapping="Wrap" Text="Connected to: *.broker.flex4grid.eu" VerticalAlignment="Top" Width="497" TextAlignment="Center"/>
<TextBlock x:Name="countHouses" HorizontalAlignment="Left" Margin="10,76,0,0" TextWrapping="Wrap" Text="0 / 0 / 0" VerticalAlignment="Top" Width="70" TextAlignment="Center"/>
<TextBlock x:Name="countDevices" HorizontalAlignment="Left" Margin="85,76,0,0" TextWrapping="Wrap" Text="0 / 0" VerticalAlignment="Top" Width="62" TextAlignment="Center"/>
<TextBlock x:Name="countPower" HorizontalAlignment="Left" Margin="10,160,0,0" TextWrapping="Wrap" Text="0W / 0W" VerticalAlignment="Top" Width="202" TextAlignment="Center"/>
<TextBlock x:Name="countColum" HorizontalAlignment="Left" Margin="10,118,0,0" TextWrapping="Wrap" Text="0kW / 0kW" VerticalAlignment="Top" Width="202" TextAlignment="Center"/>
<TextBlock x:Name="countRaspis" HorizontalAlignment="Left" Margin="152,76,0,0" TextWrapping="Wrap" Text="0 / 0" VerticalAlignment="Top" Width="60" TextAlignment="Center"/>
<TextBlock x:Name="maxRaspi" HorizontalAlignment="Left" Margin="217,76,0,0" TextWrapping="Wrap" Text="- / 0" VerticalAlignment="Top" Width="195" TextAlignment="Center"/>
<TextBlock x:Name="avgUptime" HorizontalAlignment="Left" Margin="417,76,0,0" TextWrapping="Wrap" Text="0t 00:00:00" VerticalAlignment="Top" Width="90" TextAlignment="Center"/>
<TextBlock HorizontalAlignment="Right" Margin="0,160,10,0" TextWrapping="Wrap" Text="{Binding TotalNumberOfPoints, StringFormat='Total number of data points in Diagram: {0}'}" VerticalAlignment="Top"/>
<oxy:PlotView Margin="10,181,10,10" Model="{Binding Model}" />
</Grid>
</Window>
@@ -0,0 +1,56 @@
using BlubbFish.Utils;
using System;
using System.Globalization;
using System.Windows;
namespace Mqtt_SWB_Dashboard {
/// <summary>
/// Interaktionslogik für MainWindow.xaml
/// </summary>
public partial class MainWindow : Window {
private Stats s;
public MainWindow() {
InitializeComponent();
CultureInfo info = new CultureInfo("de-DE");
info.NumberFormat.NumberDecimalSeparator = ".";
CultureInfo.DefaultThreadCurrentCulture = info;
CultureInfo.DefaultThreadCurrentUICulture = info;
System.Threading.Thread.CurrentThread.CurrentCulture = info;
System.Threading.Thread.CurrentThread.CurrentUICulture = info;
LanguageProperty.OverrideMetadata(typeof(FrameworkElement), new FrameworkPropertyMetadata(System.Windows.Markup.XmlLanguage.GetLanguage(CultureInfo.CurrentCulture.IetfLanguageTag)));
try {
String broker = InIReader.GetInstance("settings.ini").GetValue("general", "broker");
this.Dispatcher.BeginInvoke((Action)(() => {
this.connectedTo.Text = "Connected to: " + broker;
}));
this.s = new Stats(new Mosquitto(broker));
this.s.UpdatedConsumption += this.S_UpdatedConsumption;
this.S_UpdatedConsumption(this.s, null);
} catch(Exception e) {
MessageBox.Show(e.Message+"\n"+e.StackTrace, "Some Shit goes fucking wrong!");
Application.Current.Shutdown(1);
}
}
private void S_UpdatedConsumption(Stats sender, EventArgs e) {
this.Dispatcher.BeginInvoke((Action)(() => {
this.countHouses.Text = sender.GetNumberHouseholds();
this.countDevices.Text = sender.GetNumberDevices();
this.countRaspis.Text = sender.GetNumberRaspis();
this.maxRaspi.Text = sender.GetMostRaspiUptime();
this.avgUptime.Text = sender.GetAvgRaspiUptime();
Tuple<Double, Double> power = sender.GetCurrentPower();
this.countPower.Text = power.Item1 + "W / " + power.Item2 + "W";
Tuple<Double, Double> colum = sender.GetCurrentColum();
this.countColum.Text = colum.Item1.ToString("F1") + "kW / " + colum.Item2.ToString("F1") + "kW";
((Models.PowerChartModel)this.DataContext).AddPower(power, colum);
}));
}
private void OnClosed(Object sender, EventArgs e) {
this.s.Dispose();
}
}
}
@@ -0,0 +1,79 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using OxyPlot;
using OxyPlot.Axes;
using OxyPlot.Series;
namespace Mqtt_SWB_Dashboard.Models {
public class PowerChartModel : INotifyPropertyChanged {
private Double MaximumDrawnL = 5;
private Double MaximumDrawnR = 5;
public event PropertyChangedEventHandler PropertyChanged;
public PowerChartModel() {
Instance = this;
this.Model = new PlotModel { Title = "Stromverbrauch" };
this.Model.Axes.Add(new DateTimeAxis { Position = AxisPosition.Bottom, AbsoluteMinimum = DateTimeAxis.ToDouble(DateTime.Now), AbsoluteMaximum = DateTimeAxis.ToDouble(DateTime.Now.AddMinutes(1)), IsZoomEnabled = false });
this.Model.Axes.Add(new LinearAxis { Position = AxisPosition.Left, AbsoluteMinimum = 0, Minimum = 0, AbsoluteMaximum = 1, IsZoomEnabled = false });
this.Model.Axes.Add(new LinearAxis { Position = AxisPosition.Right, AbsoluteMinimum = 0, Minimum = 0, AbsoluteMaximum = 1, IsZoomEnabled = false, Key = "Right" });
this.Model.Series.Add(new LineSeries { Title = "Active [W]", Color = OxyColor.FromRgb(0, 150, 0) });
this.Model.Series.Add(new LineSeries { Title = "Seen [W]", Color = OxyColor.FromRgb(0, 255, 0) });
this.Model.Series.Add(new LineSeries { Title = "Active [kW]", Color = OxyColor.FromRgb(0, 0, 150), YAxisKey= "Right" });
this.Model.Series.Add(new LineSeries { Title = "Seen [kW]", Color = OxyColor.FromRgb(0, 0, 255), YAxisKey = "Right" });
this.RaisePropertyChanged("Model");
}
internal void AddPower(Tuple<Double, Double> power, Tuple<Double, Double> colum) {
if((power.Item1 == 0 && power.Item2 == 0) || (colum.Item1 == 0 && colum.Item2 == 0)) {
return;
}
((LineSeries)this.Model.Series[0]).Points.Add(new DataPoint(DateTimeAxis.ToDouble(DateTime.Now), power.Item1));
((LineSeries)this.Model.Series[1]).Points.Add(new DataPoint(DateTimeAxis.ToDouble(DateTime.Now), power.Item2));
((LineSeries)this.Model.Series[2]).Points.Add(new DataPoint(DateTimeAxis.ToDouble(DateTime.Now), colum.Item1));
((LineSeries)this.Model.Series[3]).Points.Add(new DataPoint(DateTimeAxis.ToDouble(DateTime.Now), colum.Item2));
if (this.MaximumDrawnL < power.Item1) {
this.MaximumDrawnL = power.Item1;
}
if (this.MaximumDrawnL < power.Item2) {
this.MaximumDrawnL = power.Item2;
}
if (this.MaximumDrawnR < colum.Item1) {
this.MaximumDrawnR = colum.Item1;
}
if (this.MaximumDrawnR < colum.Item2) {
this.MaximumDrawnR = colum.Item2;
}
//this.Model.Axes[1].Minimum = 0;
//this.Model.Axes[2].Minimum = 0;
this.Model.Axes[1].Maximum = this.MaximumDrawnL * 1.1;
this.Model.Axes[1].AbsoluteMaximum = this.MaximumDrawnL * 1.1;
this.Model.Axes[2].Maximum = this.MaximumDrawnR * 1.05;
this.Model.Axes[2].AbsoluteMaximum = this.MaximumDrawnR * 1.05;
this.Model.Axes[0].AbsoluteMaximum = DateTimeAxis.ToDouble(DateTime.Now);
this.TotalNumberOfPoints++;
this.RaisePropertyChanged("TotalNumberOfPoints");
this.Model.InvalidatePlot(true);
}
protected void RaisePropertyChanged(String property) {
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));
}
public PlotModel Model { get; private set; }
public Int32 TotalNumberOfPoints { get; private set; }
public static PowerChartModel Instance { get; private set; }
}
}
@@ -0,0 +1,88 @@
using System;
using System.Diagnostics;
using System.Text.RegularExpressions;
namespace Mqtt_SWB_Dashboard {
class Mosquitto : IDisposable {
private Process p;
private String message;
public delegate void MqttMessage(Object sender, MqttEventArgs e);
public event MqttMessage MessageIncomming;
public Mosquitto(String broker) {
//mosquitto_sub --cafile ca.pem --cert cert.pem --key cert.key -h swb.broker.flex4grid.eu -p 8883 -t /# -v
this.message = "";
this.p = new Process();
this.p.StartInfo.FileName = "mosquitto_sub.exe";
this.p.StartInfo.Arguments = "--cafile ca.pem --cert cert.pem --key cert.key -h "+broker+" -p 8883 -t /# -v -d";
this.p.StartInfo.CreateNoWindow = true;
this.p.StartInfo.UseShellExecute = false;
this.p.StartInfo.RedirectStandardOutput = true;
this.p.StartInfo.RedirectStandardError = true;
this.p.OutputDataReceived += this.P_OutputDataReceived;
this.p.ErrorDataReceived += this.P_ErrorDataReceived;
this.p.Start();
this.p.BeginOutputReadLine();
}
private void P_ErrorDataReceived(Object sender, DataReceivedEventArgs e) {
if (e.Data != null) {
throw new NotImplementedException(e.Data);
}
}
private void P_OutputDataReceived(Object sender, DataReceivedEventArgs e) {
if (e.Data != null) {
if (e.Data.StartsWith("Client mosqsub")) {
if (this.message != "" && this.message.IndexOf(" received PUBLISH ") > 0) {
MatchCollection matches = (new Regex("^Client mosqsub\\|.*received PUBLISH \\(.*,.*,.*,.*, '(.*)'.*\\)\\)\n[^ ]* (.*)$", RegexOptions.IgnoreCase | RegexOptions.Singleline)).Matches(this.message);
String topic = matches[0].Groups[1].Value;
String message = matches[0].Groups[2].Value.Trim();
this.MessageIncomming?.Invoke(this, new MqttEventArgs(message, topic));
}
this.message = e.Data + "\n";
} else {
this.message += e.Data + "\n";
}
}
}
#region IDisposable Support
private Boolean disposedValue = false; // Dient zur Erkennung redundanter Aufrufe.
protected virtual void Dispose(Boolean disposing) {
if (!this.disposedValue) {
if (disposing) {
this.p.CancelOutputRead();
this.p.Kill();
this.p.Close();
}
this.p = null;
this.disposedValue = true;
}
}
~Mosquitto() {
Dispose(false);
}
public void Dispose() {
Dispose(true);
GC.SuppressFinalize(this);
}
#endregion
}
class MqttEventArgs : EventArgs {
public MqttEventArgs() : base() { }
public MqttEventArgs(String message, String topic) {
this.Topic = topic;
this.Message = message;
this.Date = DateTime.Now;
}
public String Topic { get; private set; }
public String Message { get; private set; }
public DateTime Date { get; private set; }
}
}
@@ -0,0 +1,122 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{324B2308-7C6E-4F16-8764-7C2F8C342B6A}</ProjectGuid>
<OutputType>WinExe</OutputType>
<RootNamespace>Mqtt_SWB_Dashboard</RootNamespace>
<AssemblyName>Mqtt-SWB-Dashboard</AssemblyName>
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<WarningLevel>4</WarningLevel>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="LitJson, Version=0.9.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\LitJson.0.9.0\lib\LitJson.dll</HintPath>
</Reference>
<Reference Include="OxyPlot, Version=1.0.0.0, Culture=neutral, PublicKeyToken=638079a8f0bd61e9, processorArchitecture=MSIL">
<HintPath>..\packages\OxyPlot.Core.1.0.0\lib\net45\OxyPlot.dll</HintPath>
</Reference>
<Reference Include="OxyPlot.Wpf, Version=1.0.0.0, Culture=neutral, PublicKeyToken=75e952ba404cdbb0, processorArchitecture=MSIL">
<HintPath>..\packages\OxyPlot.Wpf.1.0.0\lib\net45\OxyPlot.Wpf.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xaml">
<RequiredTargetFramework>4.0</RequiredTargetFramework>
</Reference>
<Reference Include="WindowsBase" />
<Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" />
</ItemGroup>
<ItemGroup>
<ApplicationDefinition Include="App.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</ApplicationDefinition>
<Compile Include="Helper\Device.cs" />
<Compile Include="Helper\Household.cs" />
<Compile Include="Helper\Raspi.cs" />
<Compile Include="Models\PowerChartModel.cs" />
<Compile Include="Stats.cs" />
<Page Include="MainWindow.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Compile Include="App.xaml.cs">
<DependentUpon>App.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Compile Include="MainWindow.xaml.cs">
<DependentUpon>MainWindow.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
</ItemGroup>
<ItemGroup>
<Compile Include="Mosquitto.cs" />
<Compile Include="Properties\AssemblyInfo.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<Compile Include="Properties\Settings.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
<None Include="packages.config" />
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<ItemGroup>
<Folder Include="Properties\DataSources\" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Utils\Utils\Utils.csproj">
<Project>{fac8ce64-bf13-4ece-8097-aeb5dd060098}</Project>
<Name>Utils</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
@@ -0,0 +1,57 @@
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Windows;
// Allgemeine Informationen über eine Assembly werden über die folgenden
// Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern,
// die einer Assembly zugeordnet sind.
[assembly: AssemblyTitle("Mqtt-SWB-Dashboard")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Mqtt-SWB-Dashboard")]
[assembly: AssemblyCopyright("Copyright © 2017")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Durch Festlegen von ComVisible auf FALSE werden die Typen in dieser Assembly
// für COM-Komponenten unsichtbar. Wenn Sie auf einen Typ in dieser Assembly von
// COM aus zugreifen müssen, sollten Sie das ComVisible-Attribut für diesen Typ auf "True" festlegen.
[assembly: ComVisible(false)]
//Um mit dem Erstellen lokalisierbarer Anwendungen zu beginnen, legen Sie
//<UICulture>ImCodeVerwendeteKultur</UICulture> in der .csproj-Datei
//in einer <PropertyGroup> fest. Wenn Sie in den Quelldateien beispielsweise Deutsch
//(Deutschland) verwenden, legen Sie <UICulture> auf \"de-DE\" fest. Heben Sie dann die Auskommentierung
//des nachstehenden NeutralResourceLanguage-Attributs auf. Aktualisieren Sie "en-US" in der nachstehenden Zeile,
//sodass es mit der UICulture-Einstellung in der Projektdatei übereinstimmt.
//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
[assembly: ThemeInfo(
ResourceDictionaryLocation.None, //Speicherort der designspezifischen Ressourcenwörterbücher
//(wird verwendet, wenn eine Ressource auf der Seite nicht gefunden wird,
// oder in den Anwendungsressourcen-Wörterbüchern nicht gefunden werden kann.)
ResourceDictionaryLocation.SourceAssembly //Speicherort des generischen Ressourcenwörterbuchs
//(wird verwendet, wenn eine Ressource auf der Seite nicht gefunden wird,
// designspezifischen Ressourcenwörterbuch nicht gefunden werden kann.)
)]
// Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten:
//
// Hauptversion
// Nebenversion
// Buildnummer
// Revision
//
// Sie können alle Werte angeben oder Standardwerte für die Build- und Revisionsnummern verwenden,
// übernehmen, indem Sie "*" eingeben:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: NeutralResourcesLanguage("")]
@@ -0,0 +1,62 @@
//------------------------------------------------------------------------------
// <auto-generated>
// Dieser Code wurde von einem Tool generiert.
// Laufzeitversion: 4.0.30319.42000
//
// Änderungen an dieser Datei können fehlerhaftes Verhalten verursachen und gehen verloren, wenn
// der Code neu generiert wird.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Mqtt_SWB_Dashboard.Properties {
/// <summary>
/// Eine stark typisierte Ressourcenklasse zum Suchen von lokalisierten Zeichenfolgen usw.
/// </summary>
// Diese Klasse wurde von der StronglyTypedResourceBuilder-Klasse
// über ein Tool wie ResGen oder Visual Studio automatisch generiert.
// Um einen Member hinzuzufügen oder zu entfernen, bearbeiten Sie die .ResX-Datei und führen dann ResGen
// mit der Option /str erneut aus, oder erstellen Sie Ihr VS-Projekt neu.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
/// <summary>
/// Gibt die zwischengespeicherte ResourceManager-Instanz zurück, die von dieser Klasse verwendet wird.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if ((resourceMan == null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Mqtt_SWB_Dashboard.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Überschreibt die CurrentUICulture-Eigenschaft des aktuellen Threads für alle
/// Ressourcenlookups, die diese stark typisierte Ressourcenklasse verwenden.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
}
}
@@ -0,0 +1,117 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>
@@ -0,0 +1,26 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Mqtt_SWB_Dashboard.Properties {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default {
get {
return defaultInstance;
}
}
}
}
@@ -0,0 +1,7 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="uri:settings" CurrentProfile="(Default)">
<Profiles>
<Profile Name="(Default)" />
</Profiles>
<Settings />
</SettingsFile>
@@ -0,0 +1,318 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using LitJson;
using Mqtt_SWB_Dashboard.Helper;
namespace Mqtt_SWB_Dashboard {
internal class Stats : IDisposable {
private SortedDictionary<String, Household> households = new SortedDictionary<String, Household>();
private SortedDictionary<String, Raspi> raspis = new SortedDictionary<String, Raspi>();
private Mosquitto mosquitto;
public delegate void UpdateMessage(Stats sender, EventArgs e);
public event UpdateMessage UpdatedConsumption;
public Stats(Mosquitto mosquitto) {
LoadSavedData();
this.mosquitto = mosquitto;
this.mosquitto.MessageIncomming += this.Mosquitto_MessageIncomming;
}
private void LoadSavedData() {
if (File.Exists("household.json")) {
try {
JsonData data = JsonMapper.ToObject(File.ReadAllText("household.json"));
foreach (KeyValuePair<String, JsonData> item in data) {
this.households.Add(item.Key, new Household(item.Value));
}
} catch (Exception) { }
}
if (File.Exists("raspi.json")) {
JsonData data = JsonMapper.ToObject(File.ReadAllText("raspi.json"));
foreach (KeyValuePair<String, JsonData> item in data) {
this.raspis.Add(item.Key, new Raspi(item.Value));
}
}
}
/*
*
*/
private void Mosquitto_MessageIncomming(Object sender, MqttEventArgs e) {
if (Regex.Match(e.Topic, "/flex4grid/VersionControl/LocalGateway/groups/.*").Success) {
this.LvcMessages(e);
} else if (Regex.Match(e.Topic, "/flex4grid/VersionControl/LocalGateway/hosts/.*/status").Success ||
e.Topic == "/flex4grid/VersionControl/LocalGateway/status") {
this.RaspiStatus(e);
} else if(Regex.Match(e.Topic, "/flex4grid/VersionControl/LocalGateway/hosts/.*/logs/gateway/plugs/gateway_plugs_1").Success) {
this.RaspiLogs(e);
} else if (Regex.Match(e.Topic, "/flex4grid/v1/households/.*/connection").Success) {
this.HouseholdStatus(e);
} else if (Regex.Match(e.Topic, "/flex4grid/v1/households/.*/consumption").Success ||
Regex.Match(e.Topic, "/flex4grid/v1/households/.*/device/consumption").Success ||
Regex.Match(e.Topic, "/flex4grid/v1/households/.*/device/state").Success) {
this.HouseholdConsumption(e);
} else if (Regex.Match(e.Topic, "/flex4grid/v1/households/.*/devices/state/request").Success ||
Regex.Match(e.Topic, "/flex4grid/v1/households/.*/devices/state/response").Success) {
this.DeviceStates(e);
} else if (Regex.Match(e.Topic, "/flex4grid/v1/households/.*/device/actuate").Success) {
this.DeviceSwitching(e);
} else {
System.Windows.MessageBox.Show(e.Topic + " " + e.Message);
}
}
#region Mqtt-Message Parser
/// <summary>
/// LogMessages eines Raspis
/// </summary>
/// <param name="e"></param>
private void RaspiLogs(MqttEventArgs e) {
// /flex4grid/VersionControl/LocalGateway/hosts/F4G-B827EB705A1F/logs/gateway/plugs/gateway_plugs_1 2017-09-17T20:31:13.081733337Z
// [main] MQTTPulbisher.onConnectionLost() lost connection to the broker: pingresp not received, disconnecting
}
/// <summary>
/// Nachrichten des LVC-Images
/// </summary>
/// <param name="e"></param>
private void LvcMessages(MqttEventArgs e) {
//"/flex4grid/VersionControl/LocalGateway/groups/BONN_1 {\n \"src\": \"fc.flex4grid.eu\",\n \"type\": \"config_update\",\n..." -> Nachricht vom Lvc Image
}
/// <summary>
/// Nachricht wenn ein gerät umgeschaltet werden soll von der App aus.
/// </summary>
/// <param name="e"></param>
private void DeviceSwitching(MqttEventArgs e) {
// "/flex4grid/v1/households/911b2e25-8ac4-4ad0-90ae-c8cff42c4224/device/actuate {"command":"OFF","deviceId":"6","timestamp":"2017-09-17T16:41:50.963000Z"}" -> App Gerät Schalten
}
/// <summary>
/// Status der Geräte von der App aus abfragen und den Schaltzustand antworten
/// </summary>
/// <param name="e"></param>
private void DeviceStates(MqttEventArgs e) {
// "/flex4grid/v1/households/911b2e25-8ac4-4ad0-90ae-c8cff42c4224/devices/state/request {"timestamp": "2017-09-17T16:40:46.456000Z"}" -> App Gerät Abfragen
// "/flex4grid/v1/households/911b2e25-8ac4-4ad0-90ae-c8cff42c4224/devices/state/response {"2": "active", "3": "active", "4": "active", "5": "active", "6": "active", "timestamp": "2017-09-17T14:43:52.536676Z"}" -> App Gerät Antworten
}
/// <summary>
/// Schaltstatus, Stromverbrauch und Produktion von PowerPlugs
/// </summary>
/// <param name="e"></param>
private void HouseholdConsumption(MqttEventArgs e) {
Match m = Regex.Match(e.Topic, "/flex4grid/v1/households/([^/]*)/(consumption|device/(consumption|state))");
String id = m.Groups[1].Value;
Device.DevType dtype = Device.DevType.Consumption;
if (m.Groups[2].Value == "consumption") {
dtype = Device.DevType.Production;
} else if (m.Groups[3].Value == "consumption") {
dtype = Device.DevType.Consumption;
} else if (m.Groups[3].Value == "state") {
dtype = Device.DevType.State;
}
try {
JsonData data = JsonMapper.ToObject(e.Message);
String did = data["id"].ToString();
if(id.Contains("911b2e25") && did == "3") {
}
if (this.households.Keys.Contains(id)) {
this.households[id].PutDevice(did, data, dtype);
} else {
this.households.Add(id, new Household(did, new Device(data, dtype)));
}
this.UpdatedConsumption?.Invoke(this, null);
} catch (Exception) {
}
}
/// <summary>
/// Nachricht ob ein Haushalt (gateway_plugs_1) verbunden ist (Vermutlich vom Master)
/// </summary>
/// <param name="e"></param>
private void HouseholdStatus(MqttEventArgs e) {
Match m = Regex.Match(e.Topic, "/flex4grid/v1/households/([^/]*)/connection");
String id = m.Groups[1].Value;
try {
JsonData data = JsonMapper.ToObject(e.Message.Replace("connected", "Connected"));
if (this.households.Keys.Contains(id)) {
this.households[id].PutConnection(data);
} else {
this.households.Add(id, new Household(data));
}
this.UpdatedConsumption?.Invoke(this, null);
} catch (Exception) {
}
}
/// <summary>
/// Nachricht ob ein Raspi Verbunden ist (liefert die lvc Werte?)
/// </summary>
/// <param name="e"></param>
private void RaspiStatus(MqttEventArgs e) {
try {
JsonData data = JsonMapper.ToObject(e.Message);
String id = data["src"].ToString();
if (this.raspis.Keys.Contains(id)) {
this.raspis[id].PutStatus(data);
} else {
this.raspis.Add(id, new Raspi(data));
}
this.UpdatedConsumption?.Invoke(this, null);
} catch (Exception) {
}
}
#endregion
#region Statistics Output
internal String GetNumberDevices() {
Int32 active = 0;
Int32 all = 0;
try {
foreach (KeyValuePair<String, Household> item in this.households) {
active += item.Value.GetActive();
all += item.Value.Devices.Count;
}
} catch(Exception) {
return "0 / 0";
}
return active.ToString() + " / " + all.ToString();
}
internal String GetNumberHouseholds() {
Int32 active = 0;
Int32 ping = 0;
Int32 all = this.households.Count;
try {
foreach (KeyValuePair<String, Household> item in this.households) {
if (item.Value.Active > DateTime.Now.AddMinutes(-10)) {
ping++;
}
if (item.Value.Connected) {
active++;
}
}
} catch (Exception) {
return "0 / 0 / 0";
}
return ping + " / " + active + " / " + all;
}
internal Tuple<Double, Double> GetCurrentPower() {
Double active = 0;
Double all = 0;
try {
foreach (KeyValuePair<String, Household> item in this.households) {
active += item.Value.GetPower();
all += item.Value.GetAllPower();
}
} catch(Exception) {
return new Tuple<Double, Double>(0d, 0d);
}
return new Tuple<Double, Double>(active, all);
}
internal Tuple<Double, Double> GetCurrentColum() {
Double active = 0;
Double all = 0;
try {
foreach (KeyValuePair<String, Household> item in this.households) {
active += item.Value.GetColum();
all += item.Value.GetAllColum();
}
} catch(Exception) {
return new Tuple<Double, Double>(0d, 0d);
}
return new Tuple<Double, Double>(active, all);
}
internal String GetNumberRaspis() {
Int32 active = 0;
Int32 all = this.raspis.Count;
try {
foreach (KeyValuePair<String, Raspi> item in this.raspis) {
if(item.Value.Connected) {
active++;
}
}
} catch (Exception) {
return "0 / 0";
}
return active.ToString() + " / " + all.ToString();
}
internal String GetAvgRaspiUptime() {
Double values = 0;
Int32 count = 0;
try {
foreach (KeyValuePair<String, Raspi> item in this.raspis) {
if (item.Value.Connected) {
values += item.Value.Uptime;
count++;
}
}
} catch (Exception) {
return "0t 00:00:00";
}
return new TimeSpan((Int64)((values/count) * 10000000d)).ToString("%d't 'hh':'mm':'ss");
}
internal String GetMostRaspiUptime() {
Double max = 0;
String name="";
try {
foreach (KeyValuePair<String, Raspi> item in this.raspis) {
if (item.Value.Connected && max < item.Value.Uptime) {
max = item.Value.Uptime;
name = item.Key;
}
}
} catch (Exception) {
return "- / 0";
}
return name + " / " + new TimeSpan((Int64)(max * 10000000d)).ToString("%d't 'hh':'mm':'ss");
}
#endregion
#region IDisposable Support
private Boolean disposedValue = false; // Dient zur Erkennung redundanter Aufrufe.
protected virtual void Dispose(Boolean disposing) {
if (!this.disposedValue) {
if (disposing) {
this.mosquitto.MessageIncomming -= this.Mosquitto_MessageIncomming;
JsonWriter writer = new JsonWriter {
PrettyPrint = true
};
JsonMapper.ToJson(this.households, writer);
File.WriteAllText("household.json", writer.ToString());
writer.Reset();
JsonMapper.ToJson(this.raspis, writer);
File.WriteAllText("raspi.json", writer.ToString());
this.mosquitto.Dispose();
}
this.mosquitto = null;
this.disposedValue = true;
}
}
~Stats() {
Dispose(false);
}
public void Dispose() {
Dispose(true);
GC.SuppressFinalize(this);
}
#endregion
}
}
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="LitJson" version="0.9.0" targetFramework="net461" />
<package id="OxyPlot.Core" version="1.0.0" targetFramework="net461" />
<package id="OxyPlot.Wpf" version="1.0.0" targetFramework="net461" />
</packages>