ProjectsOld/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/Stats.cs
2017-09-26 21:44:41 +02:00

339 lines
12 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using Dashboard.Connector;
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 ADataBackend mosquitto;
public delegate void UpdateMessage(Stats sender, EventArgs e);
public event UpdateMessage UpdatedConsumption;
public Stats(ADataBackend 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/v1/load_balancing/events/.*").Success) {
this.PowerEvents(e);
} else if (Regex.Match(e.Topic, "/flex4grid/v1/households/[^/]*/device/error").Success) {
this.ErrorDeviceMessage(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>
/// Fehlermeldung eines Plugs
/// </summary>
/// <param name="e"></param>
private void ErrorDeviceMessage(MqttEventArgs e) {
// /flex4grid/v1/households/[^/]*/device/error {"errorCode": "200", "timestamp": "2017-09-26T19:21:58.561839Z", "errorMessage": "Unable_to_start_ZWave_network", "id": "1"}
}
/// <summary>
/// Raspberry Powerevents
/// </summary>
/// <param name="e"></param>
private void PowerEvents(MqttEventArgs e) {
// /flex4grid/v1/load_balancing/events/10000000 {"status": 1, "areaId": "1000000", "end": "2017-09-20T18:00:00.0000000000Z", "timestamp": "2017-09-19T08:55:52.237Z", "group_name": "ALL_2017_09_20", "start" :"2017-09-20T17:00:00.0000000000Z", "magnitude": "49", "id":"84"}
}
/// <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 Tuple<Int32, Int32> 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 new Tuple<Int32, Int32>(0, 0);
}
return new Tuple<Int32, Int32>(active, all);
}
internal Tuple<Int32, Int32, Int32> 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(-15)) {
ping++;
}
if (item.Value.Connected) {
active++;
}
}
} catch (Exception) {
return new Tuple<Int32, Int32, Int32>(0, 0, 0);
}
return new Tuple<Int32, Int32, Int32>(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 String 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 "0kWh / 0kWh";
}
return active.ToString("F1") + "kWh / " + all.ToString("F1") + "kWh";
}
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
}
}