diff --git a/.gitignore b/.gitignore index e2c0f04..2070ce8 100644 --- a/.gitignore +++ b/.gitignore @@ -79,3 +79,6 @@ /TimeKeeper/Arduino/Zeit/Zeit-V2/Debug /TimeKeeper/Arduino/Zeit/Zeit-V2/__vm /TimeKeeper/lib/System.Data.SQLite.xml +/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/Connector/.svn +/MqttToTelegram/MqttToTelegram/Connector/.svn +/MqttToTelegram/MqttToTelegram/Sensor/.svn diff --git a/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/Connector/ADataBackend.cs b/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/Connector/ADataBackend.cs new file mode 100644 index 0000000..33a0301 --- /dev/null +++ b/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/Connector/ADataBackend.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; + +namespace Dashboard.Connector { + public abstract class ADataBackend { + + public abstract event MqttMessage MessageIncomming; + public abstract event MqttMessage MessageSending; + public delegate void MqttMessage(Object sender, MqttEventArgs e); + + public static ADataBackend GetInstance(Dictionary dictionary) { + String object_sensor = "Dashboard.Connector." + Char.ToUpper(dictionary["type"][0]) + dictionary["type"].Substring(1).ToLower(); + Type t = null; + try { + t = Type.GetType(object_sensor, true); + } catch (TypeLoadException) { + throw new ArgumentException("settings.ini: " + dictionary["type"] + " is not a Connector"); + } + return (ADataBackend)t.GetConstructor(new Type[] { typeof(Dictionary) }).Invoke(new Object[] { dictionary }); + } + + public abstract void Send(String topic, String data); + + public abstract void Dispose(); + } + public 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; } + } +} diff --git a/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/Connector/Mosquitto.cs b/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/Connector/Mosquitto.cs new file mode 100644 index 0000000..cf88022 --- /dev/null +++ b/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/Connector/Mosquitto.cs @@ -0,0 +1,121 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Text.RegularExpressions; + +namespace Dashboard.Connector { + class Mosquitto : ADataBackend, IDisposable { + private Process p; + private String message; + + public override event MqttMessage MessageIncomming; + public override event MqttMessage MessageSending; + + public Mosquitto(Dictionary mqtt_settings) { + this.settings = mqtt_settings; + //mosquitto_sub --cafile ca.pem --cert cert.pem --key cert.key -h swb.broker.flex4grid.eu -p 8883 -t "#" -v -d + this.message = ""; + this.p = new Process(); + this.p.StartInfo.FileName = "mosquitto_sub"; + String args = "-h " + this.settings["server"]+" "; + if(this.settings.ContainsKey("port")) { + args += "-p "+ this.settings["port"]+" "; + } + if (this.settings.ContainsKey("cafile")) { + args += "--cafile " + this.settings["cafile"] + " "; + } + if (this.settings.ContainsKey("cert")) { + args += "--cert " + this.settings["cert"] + " "; + } + if (this.settings.ContainsKey("key")) { + args += "--key " + this.settings["key"] + " "; + } + this.p.StartInfo.Arguments = args+"-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(); + + } + + public override void Send(String topic, String data) { + Process send = new Process(); + send.StartInfo.FileName = "mosquitto_pub"; + String args = "-h " + this.settings["server"] + " "; + if (this.settings.ContainsKey("port")) { + args += "-p " + this.settings["port"] + " "; + } + if (this.settings.ContainsKey("cafile")) { + args += "--cafile " + this.settings["cafile"] + " "; + } + if (this.settings.ContainsKey("cert")) { + args += "--cert " + this.settings["cert"] + " "; + } + if (this.settings.ContainsKey("key")) { + args += "--key " + this.settings["key"] + " "; + } + send.StartInfo.Arguments = args + "-m \""+data.Replace("\"","\\\"")+"\" -t \""+topic+"\" -d"; + send.StartInfo.CreateNoWindow = true; + send.StartInfo.UseShellExecute = false; + send.StartInfo.RedirectStandardOutput = true; + send.StartInfo.RedirectStandardError = true; + send.Start(); + send.WaitForExit(); + MessageSending?.Invoke(this, new MqttEventArgs(data, topic)); + } + + 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. + private readonly Dictionary settings; + + protected virtual void Dispose(Boolean disposing) { + if (!this.disposedValue) { + if (disposing) { + this.p.CancelOutputRead(); + if (!this.p.HasExited) { + this.p.Kill(); + } + this.p.Close(); + } + this.p = null; + this.disposedValue = true; + } + } + + ~Mosquitto() { + Dispose(false); + } + + public override void Dispose() { + Dispose(true); + GC.SuppressFinalize(this); + } + #endregion + } +} diff --git a/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/Connector/Mqtt.cs b/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/Connector/Mqtt.cs new file mode 100644 index 0000000..36d21a4 --- /dev/null +++ b/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/Connector/Mqtt.cs @@ -0,0 +1,66 @@ +using System; +using System.Collections.Generic; +using System.Text; +using BlubbFish.Utils; +using uPLibrary.Networking.M2Mqtt; +using uPLibrary.Networking.M2Mqtt.Messages; + +namespace Dashboard.Connector { + class Mqtt : ADataBackend, IDisposable { + private MqttClient client; + + public override event MqttMessage MessageIncomming; + public override event MqttMessage MessageSending; + + public Mqtt(Dictionary settings) { + if(settings.ContainsKey("port")) { + this.client = new MqttClient(settings["server"], Int32.Parse(settings["port"]), false, null, null, MqttSslProtocols.None); + } else { + this.client = new MqttClient(settings["server"]); + } + Connect(); + } + + private void Connect() { + this.client.MqttMsgPublishReceived += this.Client_MqttMsgPublishReceived; + this.client.Connect(Guid.NewGuid().ToString()); + this.client.Subscribe(new String[] { "#" }, new Byte[] { MqttMsgBase.QOS_LEVEL_AT_LEAST_ONCE }); + } + + private void Client_MqttMsgPublishReceived(Object sender, MqttMsgPublishEventArgs e) { + this.MessageIncomming?.Invoke(this, new MqttEventArgs(Encoding.UTF8.GetString(e.Message), e.Topic)); + } + + public override void Send(String topic, String data) { + this.client.Publish(topic, Encoding.UTF8.GetBytes(data)); + this.MessageSending?.Invoke(this, new MqttEventArgs(data, topic)); + } + + #region IDisposable Support + private Boolean disposedValue = false; + + + + protected virtual void Dispose(Boolean disposing) { + if(!this.disposedValue) { + if(disposing) { + this.client.MqttMsgPublishReceived -= this.Client_MqttMsgPublishReceived; + this.client.Unsubscribe(new String[] { "#" }); + this.client.Disconnect(); + } + + this.client = null; + + this.disposedValue = true; + } + } + ~Mqtt() { + Dispose(false); + } + public override void Dispose() { + Dispose(true); + GC.SuppressFinalize(this); + } + #endregion + } +} diff --git a/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/Connector/Telegram.cs b/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/Connector/Telegram.cs new file mode 100644 index 0000000..4ec1ded --- /dev/null +++ b/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/Connector/Telegram.cs @@ -0,0 +1,54 @@ +using BlubbFish.Utils; +using System; +using Telegram.Bot; +using Telegram.Bot.Args; +using Telegram.Bot.Exceptions; +using Telegram.Bot.Types; + +namespace MqttToTelegram { + class Telegram { + private static Telegram instance; + private TelegramBotClient bot; + private ChatId chat; + + public delegate void TelegramMessage(Object sender, Message e); + + public event TelegramMessage MessageIncomming; + public event TelegramMessage MessageSending; + + private Telegram() { + bot = new TelegramBotClient(InIReader.GetInstance("settings.ini").GetValue("general", "telegram-key")); + bot.OnMessage += Bot_OnMessage; + this.Connect(); + } + + private void Bot_OnMessage(Object sender, MessageEventArgs e) { + this.MessageIncomming?.Invoke(this, e.Message); + } + + public static Telegram Instance { + get { + if(instance == null) { + instance = new Telegram(); + } + return instance; + } + } + + private void Connect() { + bot.StartReceiving(); + this.chat = new ChatId(InIReader.GetInstance("settings.ini").GetValue("general", "chatid")); + } + + public async void Send(String text) { + try { + Message x = await this.bot.SendTextMessageAsync(this.chat, text); + this.MessageSending?.Invoke(this, x); + } catch(ApiRequestException e) { + Console.ForegroundColor = ConsoleColor.Red; + Console.WriteLine(e.Message+" "+e.ErrorCode+" "+e.Parameters); + Console.ForegroundColor = ConsoleColor.White; + } + } + } +} diff --git a/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/Helper/Household.cs b/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/Helper/Household.cs index 47e301d..a328130 100644 --- a/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/Helper/Household.cs +++ b/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/Helper/Household.cs @@ -48,7 +48,7 @@ namespace Mqtt_SWB_Dashboard.Helper { internal Int32 GetActive() { Int32 ret = 0; foreach (KeyValuePair item in this.Devices) { - if (item.Value.TimeStamp > DateTime.Now.AddMinutes(-10)) { + if (item.Value.TimeStamp > DateTime.Now.AddMinutes(-15)) { ret++; } } @@ -58,7 +58,7 @@ namespace Mqtt_SWB_Dashboard.Helper { internal Double GetPower() { Double ret = 0; foreach (KeyValuePair item in this.Devices) { - if (item.Value.TimeStamp > DateTime.Now.AddMinutes(-10) && item.Value.Type != Device.DevType.Production) { + if (item.Value.TimeStamp > DateTime.Now.AddMinutes(-15) && item.Value.Type != Device.DevType.Production) { ret += item.Value.Power; } } @@ -78,7 +78,7 @@ namespace Mqtt_SWB_Dashboard.Helper { internal Double GetColum() { Double ret = 0; foreach (KeyValuePair item in this.Devices) { - if (item.Value.TimeStamp > DateTime.Now.AddMinutes(-10) && item.Value.Type != Device.DevType.Production) { + if (item.Value.TimeStamp > DateTime.Now.AddMinutes(-15) && item.Value.Type != Device.DevType.Production) { ret += item.Value.Comul; } } diff --git a/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/MainWindow.xaml.cs b/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/MainWindow.xaml.cs index 19c04f9..0eaa4be 100644 --- a/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/MainWindow.xaml.cs +++ b/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/MainWindow.xaml.cs @@ -2,6 +2,7 @@ using System; using System.Globalization; using System.Windows; +using Dashboard.Connector; namespace Mqtt_SWB_Dashboard { /// @@ -21,11 +22,11 @@ namespace Mqtt_SWB_Dashboard { LanguageProperty.OverrideMetadata(typeof(FrameworkElement), new FrameworkPropertyMetadata(System.Windows.Markup.XmlLanguage.GetLanguage(CultureInfo.CurrentCulture.IetfLanguageTag))); try { - String broker = InIReader.GetInstance("settings.ini").GetValue("general", "broker"); + String broker = InIReader.GetInstance("settings.ini").GetValue("mqtt", "server"); this.Dispatcher.BeginInvoke((Action)(() => { this.connectedTo.Text = "Connected to: " + broker; })); - this.s = new Stats(new Mosquitto(broker)); + this.s = new Stats(ADataBackend.GetInstance(InIReader.GetInstance("settings.ini").GetSection("mqtt"))); this.s.UpdatedConsumption += this.S_UpdatedConsumption; this.S_UpdatedConsumption(this.s, null); } catch(Exception e) { @@ -36,16 +37,17 @@ namespace Mqtt_SWB_Dashboard { 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(); + this.countColum.Text = sender.GetCurrentColum(); + Tuple devices = sender.GetNumberDevices(); + this.countDevices.Text = devices.Item1 + " / " + devices.Item2; + Tuple houses = sender.GetNumberHouseholds(); + this.countHouses.Text = houses.Item1 + " / " + houses.Item2 + " / " + houses.Item3; Tuple power = sender.GetCurrentPower(); this.countPower.Text = power.Item1 + "W / " + power.Item2 + "W"; - Tuple colum = sender.GetCurrentColum(); - this.countColum.Text = colum.Item1.ToString("F1") + "kW / " + colum.Item2.ToString("F1") + "kW"; - ((Models.PowerChartModel)this.DataContext).AddPower(power, colum); + ((Models.PowerChartModel)this.DataContext).AddPower(power, houses, devices); })); } diff --git a/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/Models/PowerChartModel.cs b/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/Models/PowerChartModel.cs index 0621698..c00e095 100644 --- a/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/Models/PowerChartModel.cs +++ b/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/Models/PowerChartModel.cs @@ -12,7 +12,7 @@ using OxyPlot.Series; namespace Mqtt_SWB_Dashboard.Models { public class PowerChartModel : INotifyPropertyChanged { private Double MaximumDrawnL = 5; - private Double MaximumDrawnR = 5; + private Int32 MaximumDrawnR = 5; public event PropertyChangedEventHandler PropertyChanged; @@ -23,33 +23,28 @@ namespace Mqtt_SWB_Dashboard.Models { 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.Model.Series.Add(new LineSeries { Title = "Power [W]", Color = OxyColor.FromRgb(0, 150, 0) }); + this.Model.Series.Add(new LineSeries { Title = "Houses", Color = OxyColor.FromRgb(0, 0, 255), YAxisKey= "Right" }); + this.Model.Series.Add(new LineSeries { Title = "Devices", Color = OxyColor.FromRgb(255, 0, 0), YAxisKey = "Right" }); this.RaisePropertyChanged("Model"); } - internal void AddPower(Tuple power, Tuple colum) { - if((power.Item1 == 0 && power.Item2 == 0) || (colum.Item1 == 0 && colum.Item2 == 0)) { + internal void AddPower(Tuple power, Tuple houses, Tuple devices) { + if((power.Item1 == 0 && power.Item2 == 0) || (houses.Item1 == 0 && houses.Item2 == 0 && houses.Item3 == 0) || (devices.Item1 == 0 && devices.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)); + ((LineSeries)this.Model.Series[1]).Points.Add(new DataPoint(DateTimeAxis.ToDouble(DateTime.Now), houses.Item1)); + ((LineSeries)this.Model.Series[2]).Points.Add(new DataPoint(DateTimeAxis.ToDouble(DateTime.Now), devices.Item1)); if (this.MaximumDrawnL < power.Item1) { this.MaximumDrawnL = power.Item1; } - if (this.MaximumDrawnL < power.Item2) { - this.MaximumDrawnL = power.Item2; + if (this.MaximumDrawnR < houses.Item1) { + this.MaximumDrawnR = houses.Item1; } - if (this.MaximumDrawnR < colum.Item1) { - this.MaximumDrawnR = colum.Item1; - } - if (this.MaximumDrawnR < colum.Item2) { - this.MaximumDrawnR = colum.Item2; + if (this.MaximumDrawnR < devices.Item1) { + this.MaximumDrawnR = devices.Item1; } //this.Model.Axes[1].Minimum = 0; //this.Model.Axes[2].Minimum = 0; diff --git a/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/Mosquitto.cs b/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/Mosquitto.cs deleted file mode 100644 index 597b5f5..0000000 --- a/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/Mosquitto.cs +++ /dev/null @@ -1,88 +0,0 @@ -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; } - } -} diff --git a/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard.csproj b/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard.csproj index 7037cb8..837ea42 100644 --- a/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard.csproj +++ b/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard.csproj @@ -63,6 +63,8 @@ MSBuild:Compile Designer + + @@ -82,7 +84,6 @@ - Code @@ -105,6 +106,7 @@ SettingsSingleFileGenerator Settings.Designer.cs + diff --git a/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/Stats.cs b/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/Stats.cs index 5d707d3..2d8a587 100644 --- a/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/Stats.cs +++ b/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/Stats.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Text.RegularExpressions; +using Dashboard.Connector; using LitJson; using Mqtt_SWB_Dashboard.Helper; @@ -10,12 +11,12 @@ namespace Mqtt_SWB_Dashboard { internal class Stats : IDisposable { private SortedDictionary households = new SortedDictionary(); private SortedDictionary raspis = new SortedDictionary(); - private Mosquitto mosquitto; + private ADataBackend mosquitto; public delegate void UpdateMessage(Stats sender, EventArgs e); public event UpdateMessage UpdatedConsumption; - public Stats(Mosquitto mosquitto) { + public Stats(ADataBackend mosquitto) { LoadSavedData(); this.mosquitto = mosquitto; this.mosquitto.MessageIncomming += this.Mosquitto_MessageIncomming; @@ -44,6 +45,10 @@ namespace Mqtt_SWB_Dashboard { 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); @@ -67,6 +72,22 @@ namespace Mqtt_SWB_Dashboard { #region Mqtt-Message Parser + /// + /// Fehlermeldung eines Plugs + /// + /// + 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"} + } + + /// + /// Raspberry Powerevents + /// + /// + 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"} + } + /// /// LogMessages eines Raspis /// @@ -173,7 +194,7 @@ namespace Mqtt_SWB_Dashboard { #region Statistics Output - internal String GetNumberDevices() { + internal Tuple GetNumberDevices() { Int32 active = 0; Int32 all = 0; try { @@ -182,18 +203,18 @@ namespace Mqtt_SWB_Dashboard { all += item.Value.Devices.Count; } } catch(Exception) { - return "0 / 0"; + return new Tuple(0, 0); } - return active.ToString() + " / " + all.ToString(); + return new Tuple(active, all); } - internal String GetNumberHouseholds() { + internal Tuple GetNumberHouseholds() { Int32 active = 0; Int32 ping = 0; Int32 all = this.households.Count; try { foreach (KeyValuePair item in this.households) { - if (item.Value.Active > DateTime.Now.AddMinutes(-10)) { + if (item.Value.Active > DateTime.Now.AddMinutes(-15)) { ping++; } if (item.Value.Connected) { @@ -201,9 +222,9 @@ namespace Mqtt_SWB_Dashboard { } } } catch (Exception) { - return "0 / 0 / 0"; + return new Tuple(0, 0, 0); } - return ping + " / " + active + " / " + all; + return new Tuple(ping, active, all); } internal Tuple GetCurrentPower() { @@ -220,7 +241,7 @@ namespace Mqtt_SWB_Dashboard { return new Tuple(active, all); } - internal Tuple GetCurrentColum() { + internal String GetCurrentColum() { Double active = 0; Double all = 0; try { @@ -229,9 +250,9 @@ namespace Mqtt_SWB_Dashboard { all += item.Value.GetAllColum(); } } catch(Exception) { - return new Tuple(0d, 0d); + return "0kWh / 0kWh"; } - return new Tuple(active, all); + return active.ToString("F1") + "kWh / " + all.ToString("F1") + "kWh"; } internal String GetNumberRaspis() { diff --git a/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/bin/Release/Mqtt-SWB-Dashboard.exe b/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/bin/Release/Mqtt-SWB-Dashboard.exe index b775cc4..a9d9abc 100644 Binary files a/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/bin/Release/Mqtt-SWB-Dashboard.exe and b/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/bin/Release/Mqtt-SWB-Dashboard.exe differ diff --git a/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/bin/Release/Utils.dll b/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/bin/Release/Utils.dll index 7edc0ad..dfb96ce 100644 Binary files a/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/bin/Release/Utils.dll and b/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/bin/Release/Utils.dll differ diff --git a/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/settings.ini.example b/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/settings.ini.example new file mode 100644 index 0000000..0ed4f13 --- /dev/null +++ b/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/settings.ini.example @@ -0,0 +1,8 @@ +[mqtt] +type=mosquitto +; server=localhost +server=swb.broker.flex4grid.eu +port=8883 +cafile=ca.pem +cert=cert.pem +key=cert.key \ No newline at end of file diff --git a/MqttToTelegram/MqttToTelegram/Condition/ACondition.cs b/MqttToTelegram/MqttToTelegram/Condition/ACondition.cs new file mode 100644 index 0000000..c0357d1 --- /dev/null +++ b/MqttToTelegram/MqttToTelegram/Condition/ACondition.cs @@ -0,0 +1,32 @@ +using Dashboard.Sensor; +using System; +using System.Collections.Generic; + +namespace MqttToTelegram.Condition { + abstract class ACondition { + protected ASensor sensor; + protected Dictionary settings; + + public ACondition(Dictionary settings) { + this.settings = settings; + Dictionary l = new Dictionary(); + l.Add("topic", this.settings["sensor_topic"]); + l.Add("polling", this.settings["sensor_polling"]); + this.sensor = ASensor.GetInstance(this.settings["sensor"],l); + this.sensor.Update += Sensor_Update; + } + + protected abstract void Sensor_Update(Object sender, EventArgs e); + + public static ACondition GetInstance(String v, Dictionary dictionary) { + string object_condition = "MqttToTelegram.Condition." + char.ToUpper(v[0]) + v.Substring(1).ToLower(); + Type t = null; + try { + t = Type.GetType(object_condition, true); + } catch(TypeLoadException) { + throw new ArgumentException("condition.ini: " + v + " is not a Sensor"); + } + return (ACondition)t.GetConstructor(new Type[] { typeof(Dictionary) }).Invoke(new object[] { dictionary }); + } + } +} \ No newline at end of file diff --git a/MqttToTelegram/MqttToTelegram/Condition/ConditionWorker.cs b/MqttToTelegram/MqttToTelegram/Condition/ConditionWorker.cs new file mode 100644 index 0000000..b4d2f5a --- /dev/null +++ b/MqttToTelegram/MqttToTelegram/Condition/ConditionWorker.cs @@ -0,0 +1,35 @@ +using BlubbFish.Utils; +using System; +using System.Collections.Generic; +using Dashboard.Connector; + +namespace MqttToTelegram.Condition { + class ConditionWorker { + private InIReader ini; + private static ConditionWorker instance; + private List conditions; + private Telegram telegram; + + public static ConditionWorker Instance { + get { + if(instance == null) { + instance = new ConditionWorker(); + } + return instance; + } + } + + internal void Run(Telegram telegram) { + this.telegram = telegram; + } + + private ConditionWorker() { + this.ini = InIReader.GetInstance("condition.ini"); + this.conditions = new List(); + List sections = this.ini.GetSections(); + foreach(String section in sections) { + this.conditions.Add(ACondition.GetInstance(this.ini.GetValue(section,"type"), this.ini.GetSection(section))); + } + } + } +} diff --git a/MqttToTelegram/MqttToTelegram/Condition/Edge.cs b/MqttToTelegram/MqttToTelegram/Condition/Edge.cs new file mode 100644 index 0000000..ee52876 --- /dev/null +++ b/MqttToTelegram/MqttToTelegram/Condition/Edge.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MqttToTelegram.Condition { + class Edge : ACondition { + private Boolean histBool; + + public Edge(Dictionary settings) : base(settings) { + + } + + protected override void Sensor_Update(Object sender, EventArgs e) { + if(this.sensor.Datatypes == Dashboard.Sensor.ASensor.Types.Bool) { + if(this.sensor.GetBool == Boolean.Parse(this.settings["sensor_value"]) && this.histBool != this.sensor.GetBool) { + this.histBool = this.sensor.GetBool; + Telegram.Instance.Send("Jemand ist DA!"); + } else { + this.histBool = this.sensor.GetBool; + } + } + } + } +} diff --git a/MqttToTelegram/MqttToTelegram/Connector/ADataBackend.cs b/MqttToTelegram/MqttToTelegram/Connector/ADataBackend.cs new file mode 100644 index 0000000..33a0301 --- /dev/null +++ b/MqttToTelegram/MqttToTelegram/Connector/ADataBackend.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; + +namespace Dashboard.Connector { + public abstract class ADataBackend { + + public abstract event MqttMessage MessageIncomming; + public abstract event MqttMessage MessageSending; + public delegate void MqttMessage(Object sender, MqttEventArgs e); + + public static ADataBackend GetInstance(Dictionary dictionary) { + String object_sensor = "Dashboard.Connector." + Char.ToUpper(dictionary["type"][0]) + dictionary["type"].Substring(1).ToLower(); + Type t = null; + try { + t = Type.GetType(object_sensor, true); + } catch (TypeLoadException) { + throw new ArgumentException("settings.ini: " + dictionary["type"] + " is not a Connector"); + } + return (ADataBackend)t.GetConstructor(new Type[] { typeof(Dictionary) }).Invoke(new Object[] { dictionary }); + } + + public abstract void Send(String topic, String data); + + public abstract void Dispose(); + } + public 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; } + } +} diff --git a/MqttToTelegram/MqttToTelegram/Connector/Mosquitto.cs b/MqttToTelegram/MqttToTelegram/Connector/Mosquitto.cs new file mode 100644 index 0000000..cf88022 --- /dev/null +++ b/MqttToTelegram/MqttToTelegram/Connector/Mosquitto.cs @@ -0,0 +1,121 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Text.RegularExpressions; + +namespace Dashboard.Connector { + class Mosquitto : ADataBackend, IDisposable { + private Process p; + private String message; + + public override event MqttMessage MessageIncomming; + public override event MqttMessage MessageSending; + + public Mosquitto(Dictionary mqtt_settings) { + this.settings = mqtt_settings; + //mosquitto_sub --cafile ca.pem --cert cert.pem --key cert.key -h swb.broker.flex4grid.eu -p 8883 -t "#" -v -d + this.message = ""; + this.p = new Process(); + this.p.StartInfo.FileName = "mosquitto_sub"; + String args = "-h " + this.settings["server"]+" "; + if(this.settings.ContainsKey("port")) { + args += "-p "+ this.settings["port"]+" "; + } + if (this.settings.ContainsKey("cafile")) { + args += "--cafile " + this.settings["cafile"] + " "; + } + if (this.settings.ContainsKey("cert")) { + args += "--cert " + this.settings["cert"] + " "; + } + if (this.settings.ContainsKey("key")) { + args += "--key " + this.settings["key"] + " "; + } + this.p.StartInfo.Arguments = args+"-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(); + + } + + public override void Send(String topic, String data) { + Process send = new Process(); + send.StartInfo.FileName = "mosquitto_pub"; + String args = "-h " + this.settings["server"] + " "; + if (this.settings.ContainsKey("port")) { + args += "-p " + this.settings["port"] + " "; + } + if (this.settings.ContainsKey("cafile")) { + args += "--cafile " + this.settings["cafile"] + " "; + } + if (this.settings.ContainsKey("cert")) { + args += "--cert " + this.settings["cert"] + " "; + } + if (this.settings.ContainsKey("key")) { + args += "--key " + this.settings["key"] + " "; + } + send.StartInfo.Arguments = args + "-m \""+data.Replace("\"","\\\"")+"\" -t \""+topic+"\" -d"; + send.StartInfo.CreateNoWindow = true; + send.StartInfo.UseShellExecute = false; + send.StartInfo.RedirectStandardOutput = true; + send.StartInfo.RedirectStandardError = true; + send.Start(); + send.WaitForExit(); + MessageSending?.Invoke(this, new MqttEventArgs(data, topic)); + } + + 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. + private readonly Dictionary settings; + + protected virtual void Dispose(Boolean disposing) { + if (!this.disposedValue) { + if (disposing) { + this.p.CancelOutputRead(); + if (!this.p.HasExited) { + this.p.Kill(); + } + this.p.Close(); + } + this.p = null; + this.disposedValue = true; + } + } + + ~Mosquitto() { + Dispose(false); + } + + public override void Dispose() { + Dispose(true); + GC.SuppressFinalize(this); + } + #endregion + } +} diff --git a/MqttToTelegram/MqttToTelegram/Connector/Mqtt.cs b/MqttToTelegram/MqttToTelegram/Connector/Mqtt.cs new file mode 100644 index 0000000..36d21a4 --- /dev/null +++ b/MqttToTelegram/MqttToTelegram/Connector/Mqtt.cs @@ -0,0 +1,66 @@ +using System; +using System.Collections.Generic; +using System.Text; +using BlubbFish.Utils; +using uPLibrary.Networking.M2Mqtt; +using uPLibrary.Networking.M2Mqtt.Messages; + +namespace Dashboard.Connector { + class Mqtt : ADataBackend, IDisposable { + private MqttClient client; + + public override event MqttMessage MessageIncomming; + public override event MqttMessage MessageSending; + + public Mqtt(Dictionary settings) { + if(settings.ContainsKey("port")) { + this.client = new MqttClient(settings["server"], Int32.Parse(settings["port"]), false, null, null, MqttSslProtocols.None); + } else { + this.client = new MqttClient(settings["server"]); + } + Connect(); + } + + private void Connect() { + this.client.MqttMsgPublishReceived += this.Client_MqttMsgPublishReceived; + this.client.Connect(Guid.NewGuid().ToString()); + this.client.Subscribe(new String[] { "#" }, new Byte[] { MqttMsgBase.QOS_LEVEL_AT_LEAST_ONCE }); + } + + private void Client_MqttMsgPublishReceived(Object sender, MqttMsgPublishEventArgs e) { + this.MessageIncomming?.Invoke(this, new MqttEventArgs(Encoding.UTF8.GetString(e.Message), e.Topic)); + } + + public override void Send(String topic, String data) { + this.client.Publish(topic, Encoding.UTF8.GetBytes(data)); + this.MessageSending?.Invoke(this, new MqttEventArgs(data, topic)); + } + + #region IDisposable Support + private Boolean disposedValue = false; + + + + protected virtual void Dispose(Boolean disposing) { + if(!this.disposedValue) { + if(disposing) { + this.client.MqttMsgPublishReceived -= this.Client_MqttMsgPublishReceived; + this.client.Unsubscribe(new String[] { "#" }); + this.client.Disconnect(); + } + + this.client = null; + + this.disposedValue = true; + } + } + ~Mqtt() { + Dispose(false); + } + public override void Dispose() { + Dispose(true); + GC.SuppressFinalize(this); + } + #endregion + } +} diff --git a/MqttToTelegram/MqttToTelegram/Connector/Telegram.cs b/MqttToTelegram/MqttToTelegram/Connector/Telegram.cs new file mode 100644 index 0000000..4ec1ded --- /dev/null +++ b/MqttToTelegram/MqttToTelegram/Connector/Telegram.cs @@ -0,0 +1,54 @@ +using BlubbFish.Utils; +using System; +using Telegram.Bot; +using Telegram.Bot.Args; +using Telegram.Bot.Exceptions; +using Telegram.Bot.Types; + +namespace MqttToTelegram { + class Telegram { + private static Telegram instance; + private TelegramBotClient bot; + private ChatId chat; + + public delegate void TelegramMessage(Object sender, Message e); + + public event TelegramMessage MessageIncomming; + public event TelegramMessage MessageSending; + + private Telegram() { + bot = new TelegramBotClient(InIReader.GetInstance("settings.ini").GetValue("general", "telegram-key")); + bot.OnMessage += Bot_OnMessage; + this.Connect(); + } + + private void Bot_OnMessage(Object sender, MessageEventArgs e) { + this.MessageIncomming?.Invoke(this, e.Message); + } + + public static Telegram Instance { + get { + if(instance == null) { + instance = new Telegram(); + } + return instance; + } + } + + private void Connect() { + bot.StartReceiving(); + this.chat = new ChatId(InIReader.GetInstance("settings.ini").GetValue("general", "chatid")); + } + + public async void Send(String text) { + try { + Message x = await this.bot.SendTextMessageAsync(this.chat, text); + this.MessageSending?.Invoke(this, x); + } catch(ApiRequestException e) { + Console.ForegroundColor = ConsoleColor.Red; + Console.WriteLine(e.Message+" "+e.ErrorCode+" "+e.Parameters); + Console.ForegroundColor = ConsoleColor.White; + } + } + } +} diff --git a/MqttToTelegram/MqttToTelegram/Mqtt.cs b/MqttToTelegram/MqttToTelegram/Mqtt.cs deleted file mode 100644 index e0ccfa0..0000000 --- a/MqttToTelegram/MqttToTelegram/Mqtt.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System; -using System.Text; -using uPLibrary.Networking.M2Mqtt; -using uPLibrary.Networking.M2Mqtt.Messages; - -namespace MqttToTelegram { - class Mqtt { - private static Mqtt instance; - private MqttClient client; - - private Mqtt() { - client = new MqttClient("129.26.160.65"); - byte code = client.Connect(System.Guid.NewGuid().ToString()); - client.MqttMsgPublishReceived += MessageResieved; - } - - private void MessageResieved(System.Object sender, MqttMsgPublishEventArgs e) { - Console.WriteLine("Received = " + Encoding.UTF8.GetString(e.Message) + " on Topic " + e.Topic); - } - - public static Mqtt Instance { - get { - if(instance == null) { - instance = new Mqtt(); - } - return instance; - } - } - public void Subscripe(string[] topics) { - byte[] qos = new byte[topics.Length]; - for(int i=0;i - + + + + - + + + + + + + + + + + {fac8ce64-bf13-4ece-8097-aeb5dd060098} + Utils + + +