306 lines
11 KiB
C#
306 lines
11 KiB
C#
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 Dictionary<String, Household> households = new Dictionary<String, Household>();
|
|
private Dictionary<String, Raspi> raspis = new Dictionary<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 (e.Topic == "/flex4grid/VersionControl/LocalGateway/groups/BONN_1") {
|
|
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);
|
|
}
|
|
}
|
|
|
|
/// <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 Gerät 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) {
|
|
}
|
|
}
|
|
|
|
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) {
|
|
}
|
|
}
|
|
|
|
#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;
|
|
String households = JsonMapper.ToJson(this.households);
|
|
File.WriteAllText("household.json", households);
|
|
String raspis = JsonMapper.ToJson(this.raspis);
|
|
File.WriteAllText("raspi.json", raspis);
|
|
this.mosquitto.Dispose();
|
|
}
|
|
this.mosquitto = null;
|
|
this.disposedValue = true;
|
|
}
|
|
}
|
|
|
|
~Stats() {
|
|
Dispose(false);
|
|
}
|
|
|
|
public void Dispose() {
|
|
Dispose(true);
|
|
GC.SuppressFinalize(this);
|
|
}
|
|
#endregion
|
|
}
|
|
} |