diff --git a/.gitignore b/.gitignore index bb1bfcb..e2c0f04 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,79 @@ ################################################################################ /.svn +/.vs +/CorrelationsAttacker +/flight hands +/Utils/Utils/obj +/Utils/Utils/bin/Debug +/Utils/Utils/bin/Release/Utils.pdb +/TT-Crawler +/TestUsb +/Testconsole +/testapp +/tconv +/SWP +/svnsync +/svgb +/Spielfeld +/SmallptGPU-v1.6 +/Rollmorad +/Rock_C +/RailWorks_Joystick_API +/PowerSwitcher +/Plot +/PicoSopeReader +/OpenCLNet +/OpenCLImageFilter +/OpenCLFilter +/OpenCL +/netmonitor +/mwPS +/miranda +/Matomat +/MateBeweis +/MailServer +/LFSInsim +/Joystik-Test +/helloworld +/gspylogin +/GPSViewer +/GPGPU +/GoproControl +/Gcc-Proxy +/ebbits/.vs/ebbits/v15 +/ebbits/AdvancedServo-simple/obj/Debug +/Mqtt-Dashboard/.vs/Dashboard/v15 +/Mqtt-Dashboard/Mqtt-Dashboard/obj +/Mqtt-Dashboard/Mqtt-Dashboard/bin/Debug +/Mqtt-Dashboard/Mqtt-Dashboard/bin/Release/ca.pem +/Mqtt-Dashboard/Mqtt-Dashboard/bin/Release/cert.key +/Mqtt-Dashboard/Mqtt-Dashboard/bin/Release/cert.pem +/Mqtt-Dashboard/Mqtt-Dashboard/bin/Release/Dashboard.exe.config +/Mqtt-Dashboard/Mqtt-Dashboard/bin/Release/Dashboard.pdb +/Mqtt-Dashboard/Mqtt-Dashboard/bin/Release/M2Mqtt.Net.pdb +/Mqtt-Dashboard/Mqtt-Dashboard/bin/Release/OxyPlot.pdb +/Mqtt-Dashboard/Mqtt-Dashboard/bin/Release/OxyPlot.WindowsForms.pdb +/Mqtt-Dashboard/Mqtt-Dashboard/bin/Release/OxyPlot.WindowsForms.xml +/Mqtt-Dashboard/Mqtt-Dashboard/bin/Release/OxyPlot.xml +/Mqtt-Dashboard/Mqtt-Dashboard/bin/Release/sensor.ini +/Mqtt-Dashboard/Mqtt-Dashboard/bin/Release/settings.ini +/Mqtt-Dashboard/Mqtt-Dashboard/bin/Release/tracings.ini +/Mqtt-Dashboard/Mqtt-Dashboard/bin/Release/Utils.pdb +/Mqtt-Dashboard/packages +/Mqtt-SWB-Dashboard/.vs +/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/bin/Debug +/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/bin/ELE +/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/bin/SWB +/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/bin/Release/Mqtt-SWB-Dashboard.exe.config +/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/bin/Release/Mqtt-SWB-Dashboard.pdb +/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/bin/Release/OxyPlot.xml +/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/bin/Release/OxyPlot.Wpf.xml +/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/bin/Release/OxyPlot.Wpf.pdb +/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/bin/Release/OxyPlot.pdb +/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/bin/Release/Utils.pdb +/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/obj +/Mqtt-SWB-Dashboard/packages +/TimeKeeper/Arduino/Zeit/Zeit-V2/Debug +/TimeKeeper/Arduino/Zeit/Zeit-V2/__vm +/TimeKeeper/lib/System.Data.SQLite.xml diff --git a/Kinect/Demo1/Demo1.sln b/Kinect/Demo1/Demo1.sln new file mode 100644 index 0000000..5ea3b88 --- /dev/null +++ b/Kinect/Demo1/Demo1.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Demo1", "Demo1\Demo1.csproj", "{1D0066B4-E5EE-4F76-97E4-0372F1EFAE1E}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x86 = Debug|x86 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {1D0066B4-E5EE-4F76-97E4-0372F1EFAE1E}.Debug|x86.ActiveCfg = Debug|x86 + {1D0066B4-E5EE-4F76-97E4-0372F1EFAE1E}.Debug|x86.Build.0 = Debug|x86 + {1D0066B4-E5EE-4F76-97E4-0372F1EFAE1E}.Release|x86.ActiveCfg = Release|x86 + {1D0066B4-E5EE-4F76-97E4-0372F1EFAE1E}.Release|x86.Build.0 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Kinect/Demo1/Demo1/App.xaml b/Kinect/Demo1/Demo1/App.xaml new file mode 100644 index 0000000..dcbb72a --- /dev/null +++ b/Kinect/Demo1/Demo1/App.xaml @@ -0,0 +1,8 @@ + + + + + diff --git a/Kinect/Demo1/Demo1/App.xaml.cs b/Kinect/Demo1/Demo1/App.xaml.cs new file mode 100644 index 0000000..42a2e84 --- /dev/null +++ b/Kinect/Demo1/Demo1/App.xaml.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Configuration; +using System.Data; +using System.Linq; +using System.Windows; + +namespace Demo1 +{ + /// + /// Interaktionslogik für "App.xaml" + /// + public partial class App : Application + { + } +} diff --git a/Kinect/Demo1/Demo1/Demo1.csproj b/Kinect/Demo1/Demo1/Demo1.csproj new file mode 100644 index 0000000..d7fd1d9 --- /dev/null +++ b/Kinect/Demo1/Demo1/Demo1.csproj @@ -0,0 +1,110 @@ + + + + Debug + x86 + 8.0.30703 + 2.0 + {1D0066B4-E5EE-4F76-97E4-0372F1EFAE1E} + WinExe + Properties + Demo1 + Demo1 + v4.0 + Client + 512 + {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 4 + + + x86 + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + x86 + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + False + C:\Program Files\Microsoft SDKs\Kinect\v1.7\Assemblies\Microsoft.Kinect.dll + + + + + + + + + + + 4.0 + + + + + + + + MSBuild:Compile + Designer + + + + MSBuild:Compile + Designer + + + App.xaml + Code + + + + MainWindow.xaml + Code + + + + + Code + + + True + True + Resources.resx + + + True + Settings.settings + True + + + ResXFileCodeGenerator + Resources.Designer.cs + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + + + + \ No newline at end of file diff --git a/Kinect/Demo1/Demo1/DepthFrameConverter.cs b/Kinect/Demo1/Demo1/DepthFrameConverter.cs new file mode 100644 index 0000000..fd0a4ea --- /dev/null +++ b/Kinect/Demo1/Demo1/DepthFrameConverter.cs @@ -0,0 +1,137 @@ +using Microsoft.Kinect; +using System.Drawing; + +namespace KinectWorkshop +{ + /*public class DepthFrameConverter + { + const int RED_IDX = 2; + const int GREEN_IDX = 1; + const int BLUE_IDX = 0; + byte[] depthFrame32 = new byte[320 * 240 * 4]; + + // Converts a 16-bit grayscale depth frame which includes player indexes into a 32-bit frame + // that displays different players in different colors + public byte[] ConvertDepthFrameWithUser(DepthImagePixel[] depthFrame, int width, int height) + { + Color c = Color.Empty; + byte[] ret = new byte[width * height * 4]; + for (int x = 1; x < width; x++) + { + for (int y = 0; y < height; y++) + { + int i = ((y * width) + x) * 4; + short depth = (depthFrame[x + y * width]).Depth; + c = Color.Empty; + if(depth > 0 && depth <= 4000) + { + int depthdist = (int)((depth / 4090f) * 255f); + c = System.Drawing.Color.FromArgb((int)(depthdist / 2f), depthdist, (int)(depthdist * 0.7f)); + } + ret[i] = c.B; + ret[i] = c.G; + ret[i] = c.R; + ret[i] = 255; + } + + } + + /* for (int i16 = 0, i32 = 0; i16 < depthFrame16.Length && i32 < depthFrame32.Length; i16 += 2, i32 += 4) + { + int player = depthFrame16[i16] & 0x07; + //if ((y - 1) * 320 + x * 4 == i16) + //{ + // player = 8; + //} + int realDepth = (depthFrame16[i16 + 1] << 5) | (depthFrame16[i16] >> 3); + // transform 13-bit depth information into an 8-bit intensity appropriate + // for display (we disregard information in most significant bit) + byte intensity = (byte)(255 - (255 * realDepth / 0x0fff)); + + depthFrame32[i32 + RED_IDX] = 0; + depthFrame32[i32 + GREEN_IDX] = 0; + depthFrame32[i32 + BLUE_IDX] = 0; + + // choose different display colors based on player + switch (player) + { + case 0: + depthFrame32[i32 + RED_IDX] = (byte)(intensity / 2); + depthFrame32[i32 + GREEN_IDX] = (byte)(intensity / 2); + depthFrame32[i32 + BLUE_IDX] = (byte)(intensity / 2); + break; + case 1: + depthFrame32[i32 + RED_IDX] = intensity; + break; + case 2: + depthFrame32[i32 + GREEN_IDX] = intensity; + break; + case 3: + depthFrame32[i32 + RED_IDX] = (byte)(intensity / 4); + depthFrame32[i32 + GREEN_IDX] = (byte)(intensity); + depthFrame32[i32 + BLUE_IDX] = (byte)(intensity); + break; + case 4: + depthFrame32[i32 + RED_IDX] = (byte)(intensity); + depthFrame32[i32 + GREEN_IDX] = (byte)(intensity); + depthFrame32[i32 + BLUE_IDX] = (byte)(intensity / 4); + break; + case 5: + depthFrame32[i32 + RED_IDX] = (byte)(intensity); + depthFrame32[i32 + GREEN_IDX] = (byte)(intensity / 4); + depthFrame32[i32 + BLUE_IDX] = (byte)(intensity); + break; + case 6: + depthFrame32[i32 + RED_IDX] = (byte)(intensity / 2); + depthFrame32[i32 + GREEN_IDX] = (byte)(intensity / 2); + depthFrame32[i32 + BLUE_IDX] = (byte)(intensity); + break; + case 7: + depthFrame32[i32 + RED_IDX] = (byte)(255 - intensity); + depthFrame32[i32 + GREEN_IDX] = (byte)(255 - intensity); + depthFrame32[i32 + BLUE_IDX] = (byte)(255 - intensity); + break; + case 8: + depthFrame32[i32 + RED_IDX] = 255; + depthFrame32[i32 + GREEN_IDX] = 0; + depthFrame32[i32 + BLUE_IDX] = 0; + break; + } + } + return depthFrame32;* + return ret; + } + + internal byte[] ConvertDepthFrame(byte[] depthFrame16) + { + for (int i16 = 0, i32 = 0; i16 < depthFrame16.Length && i32 < depthFrame32.Length; i16 += 2, i32 += 4) + { + int realDepth = (depthFrame16[i16+1] << 8)|(depthFrame16[i16]); + //byte r = (byte)(realDepth >> 8); + //byte b = (byte)realDepth; + byte intensity = (byte)(255 - (255 * realDepth / 0x0fff)); + depthFrame32[i32 + RED_IDX] = (byte)((intensity * -1) + 255);// (byte)(intensity / 2); + depthFrame32[i32 + GREEN_IDX] = (byte)((intensity * -1) + 255);// (byte)(intensity / 2); + depthFrame32[i32 + BLUE_IDX] = (byte)((intensity * -1) + 255);// (byte)(intensity / 2); + + } + return depthFrame32; + } + + internal byte[] ConvertDepthFrameHiddenPlayer(byte[] depthFrame16) + { + for (int i16 = 0, i32 = 0; i16 < depthFrame16.Length && i32 < depthFrame32.Length; i16 += 2, i32 += 4) + { + int realDepth = (depthFrame16[i16 + 1] << 5) | (depthFrame16[i16] >> 3); + //byte r = (byte)(realDepth >> 8); + //byte b = (byte)realDepth; + byte intensity = (byte)(255 - (255 * realDepth / 0x0fff)); + depthFrame32[i32 + RED_IDX] = (byte)((intensity * -1) + 255);// (byte)(intensity / 2); + depthFrame32[i32 + GREEN_IDX] = (byte)((intensity * -1) + 255);// (byte)(intensity / 2); + depthFrame32[i32 + BLUE_IDX] = (byte)((intensity * -1) + 255);// (byte)(intensity / 2); + + } + return depthFrame32; + } + }*/ +} diff --git a/Kinect/Demo1/Demo1/MainWindow.xaml b/Kinect/Demo1/Demo1/MainWindow.xaml new file mode 100644 index 0000000..ef57fc8 --- /dev/null +++ b/Kinect/Demo1/Demo1/MainWindow.xaml @@ -0,0 +1,14 @@ + + + + + + + + diff --git a/Kinect/Demo1/Demo1/MainWindow.xaml.cs b/Kinect/Demo1/Demo1/MainWindow.xaml.cs new file mode 100644 index 0000000..6f88874 --- /dev/null +++ b/Kinect/Demo1/Demo1/MainWindow.xaml.cs @@ -0,0 +1,257 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; +using Microsoft.Kinect; + +namespace Demo1 +{ + /// + /// Interaktionslogik für MainWindow.xaml + /// + public partial class MainWindow : Window + { + private KinectWorkshop.DepthFrameConverter cv = new KinectWorkshop.DepthFrameConverter(); + private KinectSensor r; + //private DepthImagePixel[] depthPixels; + //private byte[] colorPixels; + //private DepthImageFormat DepthFormat = DepthImageFormat.Resolution320x240Fps30; + //private ColorImageFormat ColorFormat = ColorImageFormat.RgbResolution640x480Fps30; + //private ColorImagePoint[] colorCoordinates; + //private bool init = false; + + public MainWindow() + { + InitializeComponent(); + } + + private void Window_Loaded(object sender, RoutedEventArgs e) + { + if (KinectSensor.KinectSensors.Count == 0) + { + MessageBox.Show("Keine Kinect"); + return; + } + try + { + r = KinectSensor.KinectSensors[0]; + r.Start(); + //r.Initialize(RuntimeOptions.UseSkeletalTracking | RuntimeOptions.UseDepthAndPlayerIndex); + + //r.VideoFrameReady += new EventHandler(r_VideoFrameReady); + //r.VideoStream.Open(ImageStreamType.Video, 2, ImageResolution.Resolution640x480, ImageType.Color); + //r.DepthFrameReady += r_DepthFrameReady; + //r.DepthStream.Enable(); + //r.DepthStream.Open(ImageStreamType.Depth, 2, ImageResolution.Resolution320x240, ImageType.DepthAndPlayerIndex); + //r.SkeletonFrameReady += r_SkeletonFrameReady; + r.SkeletonStream.Enable(new TransformSmoothParameters() { Smoothing = 0.1f }); + //r.SkeletonEngine.TransformSmooth = true; + //r.SkeletonFrameReady += new EventHandler(r_SkeletonFrameReady); + //_cam = r.NuiCamera; + //r.AllFramesReady += R_AllFramesReady; + r.SkeletonFrameReady += this.r_SkeletonFrameReady; + } + catch (Exception ex) + { + MessageBox.Show(ex.ToString()); + } + } + + /*private void R_AllFramesReady(object sender, AllFramesReadyEventArgs e) + { + if(r == null) + { + return; + } + bool depthReceived = false; + bool colorReceived = false; + + using (DepthImageFrame depthFrame = e.OpenDepthImageFrame()) + { + if (null != depthFrame) + { + // Copy the pixel data from the image to a temporary array + depthFrame.CopyDepthImagePixelDataTo(this.depthPixels); + + depthReceived = true; + if(!init) { + this.colorCoordinates = new ColorImagePoint[r.DepthStream.FramePixelDataLength]; + init = true; + } + } + } + + using (ColorImageFrame colorFrame = e.OpenColorImageFrame()) + { + if (null != colorFrame) + { + // Copy the pixel data from the image to a temporary array + colorFrame.CopyPixelDataTo(this.colorPixels); + + colorReceived = true; + } + } + + if (true == depthReceived) + { + r.CoordinateMapper.MapDepthFrameToColorFrame( + DepthFormat, + this.depthPixels, + ColorFormat, + this.colorCoordinates); + + // ... + + int depthIndex = x + (y * this.depthWidth); + DepthImagePixel depthPixel = this.depthPixels[depthIndex]; + + // scale color coordinates to depth resolution + int X = colorImagePoint.X / this.colorToDepthDivisor; + int Y = colorImagePoint.Y / this.colorToDepthDivisor; + + // depthPixel is the depth for the (X,Y) pixel in the color frame + } + + }*/ + + void r_SkeletonFrameReady(object sender, SkeletonFrameReadyEventArgs e) + { + SkeletonFrame skf = e.OpenSkeletonFrame(); + if(skf == null) + { + return; + } + Skeleton[] sks = new Skeleton[skf.SkeletonArrayLength]; + skf.CopySkeletonDataTo(sks); + this.MainCanvas.Children.Clear(); + foreach (Skeleton sk in sks) + { + if (sk.TrackingState == SkeletonTrackingState.Tracked) + { + this.drawPlayer(sk); + + } + } + } + + private void drawPlayer(Skeleton sk) + { + this.SetPoints(sk); + this.SetLines(sk); + } + + private void SetLines(Skeleton sk) + { + JointType[,] id = { + { JointType.Head, JointType.ShoulderCenter }, + { JointType.ShoulderCenter, JointType.ShoulderLeft }, + { JointType.ShoulderCenter, JointType.ShoulderRight }, + { JointType.ShoulderLeft, JointType.ElbowLeft }, + { JointType.ShoulderRight, JointType.ElbowRight }, + { JointType.ElbowLeft, JointType.WristLeft }, + { JointType.ElbowRight, JointType.WristRight }, + { JointType.WristLeft, JointType.HandLeft }, + { JointType.WristRight, JointType.HandRight }, + { JointType.ShoulderCenter, JointType.Spine }, + { JointType.Spine, JointType.HipCenter }, + { JointType.HipCenter, JointType.HipLeft }, + { JointType.HipCenter, JointType.HipRight }, + { JointType.HipLeft, JointType.KneeLeft }, + { JointType.HipRight, JointType.KneeRight }, + { JointType.KneeLeft, JointType.AnkleLeft }, + { JointType.KneeRight, JointType.AnkleRight }, + { JointType.AnkleLeft, JointType.FootLeft }, + { JointType.AnkleRight, JointType.FootRight } + }; + for (int i = 0; i < id.Length / 2; i++) + { + Joint r1 = sk.Joints[id[i, 0]].ScaleTo(640, 480); + Joint r2 = sk.Joints[id[i, 1]].ScaleTo(640, 480); + + /**** */ + Line l = new Line(); + l.Stroke = Brushes.Blue; + l.StrokeThickness = 5.0; + l.Y1 = r1.Position.Y; + l.X1 = r1.Position.X; + l.Y2 = r2.Position.Y; + l.X2 = r2.Position.X; + /**** */ + + this.MainCanvas.Children.Add(l); + } + } + + private void SetPoints(Skeleton sk) + { + foreach (Joint joint in sk.Joints) + { + Joint p = joint.ScaleTo(640, 480); + Ellipse e = new Ellipse(); + e.Fill = Brushes.Red; + e.Stroke = Brushes.Black; + e.Height = 10; + e.Width = 10; + Canvas.SetLeft(e, p.Position.X - e.Width / 2); + Canvas.SetTop(e, p.Position.Y - e.Height / 2); + this.MainCanvas.Children.Add(e); + } + } + + /*void r_DepthFrameReady(object sender, DepthImageFrameReadyEventArgs e) + { + //PlanarImage img = e.ImageFrame.Image; + DepthImageFrame img = e.OpenDepthImageFrame(); + if(img == null) + { + return; + } + DepthImagePixel[] bs = new DepthImagePixel[img.PixelDataLength]; + img.CopyDepthImagePixelDataTo(bs); + byte[] bh = cv.ConvertDepthFrameWithUser(bs, img.Width, img.Height); + imgDepth.Source = BitmapSource.Create(img.Width, img.Height, 96, 96, PixelFormats.Bgr32, null, bh, img.Width * 4); + //bh = cv.ConvertDepthFrameHiddenPlayer(img.Bits); + //byte[] bh = cv.ConvertDepthFrame(img.Bits); + //imgDepthPlayer.Source = BitmapSource.Create(img.Width, img.Height, + // 96, 96, PixelFormats.Bgr32, null, + // bh, img.Width * 4); + }*/ + + private void Window_KeyUp(object sender, KeyEventArgs e) + { + try + { + if (e.Key == Key.Up) + { + int k = r.ElevationAngle; + k++; + r.ElevationAngle = k; + } + if (e.Key == Key.Down) + r.ElevationAngle -= 1; + } + catch (ArgumentOutOfRangeException outOfRangeException) + { + MessageBox.Show(outOfRangeException.Message); + } + catch (Exception) { } + } + + /*void r_VideoFrameReady(object sender, ImageFrameReadyEventArgs e) + { + PlanarImage img = e.ImageFrame.Image; + imgRgb.Source = BitmapSource.Create(img.Width, img.Height, + 96, 96, PixelFormats.Bgr32, null, + img.Bits, img.Width * img.BytesPerPixel); + }*/ + } +} diff --git a/Kinect/Demo1/Demo1/Properties/AssemblyInfo.cs b/Kinect/Demo1/Demo1/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..b85ddc9 --- /dev/null +++ b/Kinect/Demo1/Demo1/Properties/AssemblyInfo.cs @@ -0,0 +1,55 @@ +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 mit einer Assembly verknüpft sind. +[assembly: AssemblyTitle("Demo1")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Demo1")] +[assembly: AssemblyCopyright("Copyright © 2011")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Durch Festlegen von ComVisible auf "false" werden die Typen in dieser Assembly unsichtbar +// für COM-Komponenten. Wenn Sie auf einen Typ in dieser Assembly von +// COM zugreifen müssen, legen Sie das ComVisible-Attribut für diesen Typ auf "true" fest. +[assembly: ComVisible(false)] + +//Um mit dem Erstellen lokalisierbarer Anwendungen zu beginnen, legen Sie +//ImCodeVerwendeteKultur in der .csproj-Datei +//in einer fest. Wenn Sie in den Quelldateien beispielsweise Deutsch +//(Deutschland) verwenden, legen Sie 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 + // 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, in der Anwendung oder einem + // 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 die standardmäßigen Build- und Revisionsnummern +// übernehmen, indem Sie "*" eingeben: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Kinect/Demo1/Demo1/Properties/Resources.Designer.cs b/Kinect/Demo1/Demo1/Properties/Resources.Designer.cs new file mode 100644 index 0000000..527f4a9 --- /dev/null +++ b/Kinect/Demo1/Demo1/Properties/Resources.Designer.cs @@ -0,0 +1,71 @@ +//------------------------------------------------------------------------------ +// +// Dieser Code wurde von einem Tool generiert. +// Laufzeitversion:4.0.30319.239 +// +// Änderungen an dieser Datei können fehlerhaftes Verhalten verursachen und gehen verloren, wenn +// der Code neu generiert wird. +// +//------------------------------------------------------------------------------ + +namespace Demo1.Properties +{ + + + /// + /// Eine stark typisierte Ressourcenklasse zum Suchen von lokalisierten Zeichenfolgen usw. + /// + // 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() + { + } + + /// + /// Gibt die zwischengespeicherte ResourceManager-Instanz zurück, die von dieser Klasse verwendet wird. + /// + [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("Demo1.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Überschreibt die CurrentUICulture-Eigenschaft des aktuellen Threads für alle + /// Ressourcenlookups, die diese stark typisierte Ressourcenklasse verwenden. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture + { + get + { + return resourceCulture; + } + set + { + resourceCulture = value; + } + } + } +} diff --git a/Kinect/Demo1/Demo1/Properties/Resources.resx b/Kinect/Demo1/Demo1/Properties/Resources.resx new file mode 100644 index 0000000..af7dbeb --- /dev/null +++ b/Kinect/Demo1/Demo1/Properties/Resources.resx @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Kinect/Demo1/Demo1/Properties/Settings.Designer.cs b/Kinect/Demo1/Demo1/Properties/Settings.Designer.cs new file mode 100644 index 0000000..8bffaa1 --- /dev/null +++ b/Kinect/Demo1/Demo1/Properties/Settings.Designer.cs @@ -0,0 +1,30 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.239 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Demo1.Properties +{ + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "10.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; + } + } + } +} diff --git a/Kinect/Demo1/Demo1/Properties/Settings.settings b/Kinect/Demo1/Demo1/Properties/Settings.settings new file mode 100644 index 0000000..033d7a5 --- /dev/null +++ b/Kinect/Demo1/Demo1/Properties/Settings.settings @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/Kinect/Demo1/Demo1/SkeletalCommonExtensions.cs b/Kinect/Demo1/Demo1/SkeletalCommonExtensions.cs new file mode 100644 index 0000000..a13c436 --- /dev/null +++ b/Kinect/Demo1/Demo1/SkeletalCommonExtensions.cs @@ -0,0 +1,41 @@ +using Microsoft.Kinect; +using System.Windows; + +namespace Demo1 +{ + internal static class SkeletalCommonExtensions + { + public static Joint ScaleTo(this Joint joint, int width, int height, float skeletonMaxX, float skeletonMaxY) + { + SkeletonPoint pos = new SkeletonPoint() + { + X = Scale(width, skeletonMaxX, joint.Position.X), + Y = Scale(height, skeletonMaxY, -joint.Position.Y), + Z = joint.Position.Z + }; + + Joint j = new Joint() + { + TrackingState = joint.TrackingState, + Position = pos + }; + + return j; + } + + public static Joint ScaleTo(this Joint joint, int width, int height) + { + return ScaleTo(joint, width, height, 1.0f, 1.0f); + } + + private static float Scale(int maxPixel, float maxSkeleton, float position) + { + float value = ((((maxPixel / maxSkeleton) / 2) * position) + (maxPixel / 2)); + if (value > maxPixel) + return maxPixel; + if (value < 0) + return 0; + return value; + } + } +} diff --git a/Kinect/Demo2/Demo2.sln b/Kinect/Demo2/Demo2.sln new file mode 100644 index 0000000..e38c107 --- /dev/null +++ b/Kinect/Demo2/Demo2.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Demo2", "Demo2\Demo2.csproj", "{12018BA3-A02D-488C-83F6-1799D344C1C3}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x86 = Debug|x86 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {12018BA3-A02D-488C-83F6-1799D344C1C3}.Debug|x86.ActiveCfg = Debug|x86 + {12018BA3-A02D-488C-83F6-1799D344C1C3}.Debug|x86.Build.0 = Debug|x86 + {12018BA3-A02D-488C-83F6-1799D344C1C3}.Release|x86.ActiveCfg = Release|x86 + {12018BA3-A02D-488C-83F6-1799D344C1C3}.Release|x86.Build.0 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Kinect/Demo2/Demo2/Demo2.csproj b/Kinect/Demo2/Demo2/Demo2.csproj new file mode 100644 index 0000000..1f2ac6b --- /dev/null +++ b/Kinect/Demo2/Demo2/Demo2.csproj @@ -0,0 +1,58 @@ + + + + Debug + x86 + 8.0.30703 + 2.0 + {12018BA3-A02D-488C-83F6-1799D344C1C3} + Exe + Properties + Demo2 + Demo2 + v4.0 + Client + 512 + + + x86 + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + x86 + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Kinect/Demo2/Demo2/Program.cs b/Kinect/Demo2/Demo2/Program.cs new file mode 100644 index 0000000..1b3dbd7 --- /dev/null +++ b/Kinect/Demo2/Demo2/Program.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Microsoft.Research.Kinect.Nui; + +namespace Demo2 +{ + class Program + { + static void Main(string[] args) + { + if (Runtime.Kinects.Count == 0) + { + Console.WriteLine("KEine Kinect"); + return; + } + Runtime r = Runtime.Kinects[0]; + r.Initialize(RuntimeOptions.UseSkeletalTracking); + r.SkeletonFrameReady += new EventHandler(r_SkeletonFrameReady); + r.SkeletonEngine.TransformSmooth = true; + + Console.ReadLine(); + r.Uninitialize(); + } + + static void r_SkeletonFrameReady(object sender, SkeletonFrameReadyEventArgs e) + { + foreach (SkeletonData sk in e.SkeletonFrame.Skeletons) + { + if (sk.TrackingState == SkeletonTrackingState.Tracked) + { + Joint l = sk.Joints[JointID.HandLeft]; + Joint r = sk.Joints[JointID.HandRight]; + Console.WriteLine("Left Hand: X:{0}, Y:{1}, Z:{2}", l.Position.X, l.Position.Y, l.Position.Z); + Console.WriteLine("Right Hand: X:{0}, Y:{1}, Z:{2}", r.Position.X, r.Position.Y, r.Position.Z); + } + } + Console.WriteLine(); + } + } +} diff --git a/Kinect/Demo2/Demo2/Properties/AssemblyInfo.cs b/Kinect/Demo2/Demo2/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..0a95656 --- /dev/null +++ b/Kinect/Demo2/Demo2/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// Allgemeine Informationen über eine Assembly werden über die folgenden +// Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern, +// die mit einer Assembly verknüpft sind. +[assembly: AssemblyTitle("Demo2")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Demo2")] +[assembly: AssemblyCopyright("Copyright © 2011")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Durch Festlegen von ComVisible auf "false" werden die Typen in dieser Assembly unsichtbar +// für COM-Komponenten. Wenn Sie auf einen Typ in dieser Assembly von +// COM zugreifen müssen, legen Sie das ComVisible-Attribut für diesen Typ auf "true" fest. +[assembly: ComVisible(false)] + +// Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird +[assembly: Guid("c0c8b6f9-5275-4f3b-a622-0a78d2a3a3dd")] + +// Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten: +// +// Hauptversion +// Nebenversion +// Buildnummer +// Revision +// +// Sie können alle Werte angeben oder die standardmäßigen Build- und Revisionsnummern +// übernehmen, indem Sie "*" eingeben: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Kinect/Demo3/Demo3.sln b/Kinect/Demo3/Demo3.sln new file mode 100644 index 0000000..a061036 --- /dev/null +++ b/Kinect/Demo3/Demo3.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Demo3", "Demo3\Demo3.csproj", "{33D30437-2141-4BEE-B4DE-FBF5B01F7A8C}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x86 = Debug|x86 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {33D30437-2141-4BEE-B4DE-FBF5B01F7A8C}.Debug|x86.ActiveCfg = Debug|x86 + {33D30437-2141-4BEE-B4DE-FBF5B01F7A8C}.Debug|x86.Build.0 = Debug|x86 + {33D30437-2141-4BEE-B4DE-FBF5B01F7A8C}.Release|x86.ActiveCfg = Release|x86 + {33D30437-2141-4BEE-B4DE-FBF5B01F7A8C}.Release|x86.Build.0 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Kinect/Demo3/Demo3/Demo3.csproj b/Kinect/Demo3/Demo3/Demo3.csproj new file mode 100644 index 0000000..d0604f1 --- /dev/null +++ b/Kinect/Demo3/Demo3/Demo3.csproj @@ -0,0 +1,63 @@ + + + + Debug + x86 + 8.0.30703 + 2.0 + {33D30437-2141-4BEE-B4DE-FBF5B01F7A8C} + Exe + Properties + Demo3 + Demo3 + v4.0 + Client + 512 + + + x86 + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + x86 + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + False + C:\Program Files\Microsoft Speech Platform SDK\Assembly\Microsoft.Speech.dll + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Kinect/Demo3/Demo3/Program.cs b/Kinect/Demo3/Demo3/Program.cs new file mode 100644 index 0000000..4832dfe --- /dev/null +++ b/Kinect/Demo3/Demo3/Program.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Demo3 +{ + class Program + { + static void Main(string[] args) + { + KinectWorkshop.SpeechToText stt = new KinectWorkshop.SpeechToText(); + stt.TextRecognized += new EventHandler(stt_TextRecognized); + stt.Start(); + Console.ReadLine(); + stt.Stop(); + } + + static void stt_TextRecognized(object sender, KinectWorkshop.SpeechToText.TextRecognizedArgs e) + { + Console.WriteLine(e.Verb); + switch (e.Verb) + { + case KinectWorkshop.SpeechToText.Verbs.None: + break; + case KinectWorkshop.SpeechToText.Verbs.PreviousSlide: + break; + case KinectWorkshop.SpeechToText.Verbs.NextSlide: + break; + default: + break; + } + } + } +} diff --git a/Kinect/Demo3/Demo3/Properties/AssemblyInfo.cs b/Kinect/Demo3/Demo3/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..20cc130 --- /dev/null +++ b/Kinect/Demo3/Demo3/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// Allgemeine Informationen über eine Assembly werden über die folgenden +// Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern, +// die mit einer Assembly verknüpft sind. +[assembly: AssemblyTitle("Demo3")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Demo3")] +[assembly: AssemblyCopyright("Copyright © 2011")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Durch Festlegen von ComVisible auf "false" werden die Typen in dieser Assembly unsichtbar +// für COM-Komponenten. Wenn Sie auf einen Typ in dieser Assembly von +// COM zugreifen müssen, legen Sie das ComVisible-Attribut für diesen Typ auf "true" fest. +[assembly: ComVisible(false)] + +// Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird +[assembly: Guid("1fd608c9-3dd2-4d4b-b7a0-c368ff56a377")] + +// Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten: +// +// Hauptversion +// Nebenversion +// Buildnummer +// Revision +// +// Sie können alle Werte angeben oder die standardmäßigen Build- und Revisionsnummern +// übernehmen, indem Sie "*" eingeben: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Kinect/Demo3/Demo3/SpeechToText.cs b/Kinect/Demo3/Demo3/SpeechToText.cs new file mode 100644 index 0000000..5dc8780 --- /dev/null +++ b/Kinect/Demo3/Demo3/SpeechToText.cs @@ -0,0 +1,136 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Threading; +using Microsoft.Research.Kinect.Audio; +using Microsoft.Speech.AudioFormat; +using Microsoft.Speech.Recognition; + +namespace KinectWorkshop +{ + public class SpeechToText + { + public enum Verbs + { + None = 0, + PreviousSlide, + NextSlide + }; + + Dictionary SinglePhrases = new Dictionary() + { + {"previous slide", Verbs.PreviousSlide}, + {"next slide", Verbs.NextSlide} + }; + + public class TextRecognizedArgs : EventArgs + { + public Verbs Verb { get; set; } + public string Phrase { get; set; } + public string Matched {get; set; } + } + + public event EventHandler TextRecognized; + + private KinectAudioSource kinectSource; + private SpeechRecognitionEngine sre; + private const string RecognizerId = "SR_MS_en-US_Kinect_10.0"; + + public SpeechToText() + { + RecognizerInfo ri = SpeechRecognitionEngine.InstalledRecognizers().Where(r => r.Id == RecognizerId).FirstOrDefault(); + if (ri == null) + return; + + sre = new SpeechRecognitionEngine(ri.Id); + var singlePhrases = new Choices(); + foreach (var phrase in SinglePhrases) + singlePhrases.Add(phrase.Key); + + var g = new Grammar(new GrammarBuilder(singlePhrases)); + sre.LoadGrammar(g); + sre.SpeechRecognized += sre_SpeechRecognized; + sre.SpeechRecognitionRejected += new EventHandler(sre_SpeechRecognitionRejected); + } + + private void StartSST() + { + kinectSource = new KinectAudioSource(); + kinectSource.SystemMode = SystemMode.OptibeamArrayOnly; + kinectSource.FeatureMode = true; + kinectSource.AutomaticGainControl = false; + kinectSource.MicArrayMode = MicArrayMode.MicArrayAdaptiveBeam; + var kinectStream = kinectSource.Start(); + sre.SetInputToAudioStream(kinectStream, new SpeechAudioFormatInfo( + EncodingFormat.Pcm, 16000, 16, 1, + 32000, 2, null)); + sre.RecognizeAsync(RecognizeMode.Multiple); + + //const double alpha = 0.35; + //double angle = 0.0; + //while (true) + //{ + // if (kinectSource.SoundSourcePositionConfidence > 0.5) + // { + // double a = alpha*kinectSource.SoundSourcePositionConfidence; + // angle = (1 - a) * angle + a * kinectSource.SoundSourcePosition; + // Console.WriteLine(angle + ":" + kinectSource.MicArrayBeamAngle); + // } + // System.Threading.Thread.Sleep(50); + //} + } + + public void Start() + { + var t = new Thread(StartSST); + t.Start(); + } + + public void Stop() + { + if (sre != null) + { + sre.RecognizeAsyncCancel(); + sre.RecognizeAsyncStop(); + kinectSource.Dispose(); + } + } + + void sre_SpeechRecognitionRejected(object sender, SpeechRecognitionRejectedEventArgs e) + { + var said = new TextRecognizedArgs(); + said.Verb = Verbs.None; + said.Matched = "?"; + TextRecognized(new object(), said); + Console.WriteLine("\nSpeech Rejected"); + } + + void sre_SpeechRecognized(object sender, SpeechRecognizedEventArgs e) + { + if (TextRecognized == null) + return; + + var said = new TextRecognizedArgs(); + said.Verb = Verbs.None; + said.Phrase = e.Result.Text; + + bool found = false; + foreach (var phrase in SinglePhrases) + { + if (e.Result.Text.Contains(phrase.Key)) + { + said.Verb = phrase.Value; + found = true; + break; + } + } + + if (!found) + return; + + TextRecognized(new object(), said); + } + } +} \ No newline at end of file diff --git a/Kinect/Demo4/Demo4.sln b/Kinect/Demo4/Demo4.sln new file mode 100644 index 0000000..fc5a88e --- /dev/null +++ b/Kinect/Demo4/Demo4.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Demo4", "Demo4\Demo4.csproj", "{FBF0FD4F-54D6-4077-AE63-F98C1FD10FBC}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x86 = Debug|x86 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {FBF0FD4F-54D6-4077-AE63-F98C1FD10FBC}.Debug|x86.ActiveCfg = Debug|x86 + {FBF0FD4F-54D6-4077-AE63-F98C1FD10FBC}.Debug|x86.Build.0 = Debug|x86 + {FBF0FD4F-54D6-4077-AE63-F98C1FD10FBC}.Release|x86.ActiveCfg = Release|x86 + {FBF0FD4F-54D6-4077-AE63-F98C1FD10FBC}.Release|x86.Build.0 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Kinect/Demo4/Demo4/Demo4.csproj b/Kinect/Demo4/Demo4/Demo4.csproj new file mode 100644 index 0000000..8bbd77e --- /dev/null +++ b/Kinect/Demo4/Demo4/Demo4.csproj @@ -0,0 +1,60 @@ + + + + Debug + x86 + 8.0.30703 + 2.0 + {FBF0FD4F-54D6-4077-AE63-F98C1FD10FBC} + Exe + Properties + Demo4 + Demo4 + v4.0 + Client + 512 + + + x86 + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + x86 + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Kinect/Demo4/Demo4/KeySender.cs b/Kinect/Demo4/Demo4/KeySender.cs new file mode 100644 index 0000000..90fa244 --- /dev/null +++ b/Kinect/Demo4/Demo4/KeySender.cs @@ -0,0 +1,114 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Runtime.InteropServices; + +namespace KinectWorkshop +{ + public enum VirtualKey : ushort + { + SHIFT = 0x10, + CONTROL = 0x11, + MENU = 0x12, + ESCAPE = 0x1B, + BACK = 0x08, + TAB = 0x09, + RETURN = 0x0D, + PRIOR = 0x21, + NEXT = 0x22, + END = 0x23, + HOME = 0x24, + LEFT = 0x25, + UP = 0x26, + RIGHT = 0x27, + DOWN = 0x28, + SELECT = 0x29, + PRINT = 0x2A, + EXECUTE = 0x2B, + SNAPSHOT = 0x2C, + INSERT = 0x2D, + DELETE = 0x2E, + HELP = 0x2F, + NUMPAD0 = 0x60, + NUMPAD1 = 0x61, + NUMPAD2 = 0x62, + NUMPAD3 = 0x63, + NUMPAD4 = 0x64, + NUMPAD5 = 0x65, + NUMPAD6 = 0x66, + NUMPAD7 = 0x67, + NUMPAD8 = 0x68, + NUMPAD9 = 0x69, + MULTIPLY = 0x6A, + ADD = 0x6B, + SEPARATOR = 0x6C, + SUBTRACT = 0x6D, + DECIMAL = 0x6E, + DIVIDE = 0x6F, + F1 = 0x70, + F2 = 0x71, + F3 = 0x72, + F4 = 0x73, + F5 = 0x74, + F6 = 0x75, + F7 = 0x76, + F8 = 0x77, + F9 = 0x78, + F10 = 0x79, + F11 = 0x7A, + F12 = 0x7B, + OEM_1 = 0xBA, // ',:' for US + OEM_PLUS = 0xBB, // '+' any country + OEM_COMMA = 0xBC, // ',' any country + OEM_MINUS = 0xBD, // '-' any country + OEM_PERIOD = 0xBE, // '.' any country + OEM_2 = 0xBF, // '/?' for US + OEM_3 = 0xC0, // '`~' for US + MEDIA_NEXT_TRACK = 0xB0, + MEDIA_PREV_TRACK = 0xB1, + MEDIA_STOP = 0xB2, + MEDIA_PLAY_PAUSE = 0xB3, + LWIN =0x5B, + RWIN =0x5C + } + + class KeySender + { + [DllImport("user32.dll", SetLastError = true)] + static extern uint SendInput(uint nInputs, ref INPUT pInputs, int cbSize); + + public struct KEYBDINPUT + { + public ushort wVk; + public ushort wScan; + public uint dwFlags; + public long time; + public uint dwExtraInfo; + } + + [StructLayout(LayoutKind.Explicit, Size = 28)] + public struct INPUT + { + [FieldOffset(0)] + public uint type; + [FieldOffset(4)] + public KEYBDINPUT ki; + } + + public enum Win32Consts : int + { + INPUT_MOUSE = 0, + INPUT_KEYBOARD = 1, + INPUT_HARDWARE = 2, + } + + public static void Send(VirtualKey key) + { + INPUT structInput = new INPUT(); + structInput.type = (uint)Win32Consts.INPUT_KEYBOARD; + structInput.ki.wVk = (ushort)key; + SendInput(1, ref structInput, Marshal.SizeOf(structInput)); + } + } +} diff --git a/Kinect/Demo4/Demo4/Program.cs b/Kinect/Demo4/Demo4/Program.cs new file mode 100644 index 0000000..3e447c1 --- /dev/null +++ b/Kinect/Demo4/Demo4/Program.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Microsoft.Research.Kinect.Nui; + +namespace Demo4 +{ + class Program + { + private static DateTime lastTimeHit; + static void Main(string[] args) + { + if (Runtime.Kinects.Count == 0) + { + Console.WriteLine("Keine Kinect"); + return; + } + Runtime r = Runtime.Kinects[0]; + r.Initialize(RuntimeOptions.UseSkeletalTracking); + r.SkeletonEngine.TransformSmooth = true; + + r.SkeletonFrameReady += new EventHandler(r_SkeletonFrameReady); + + Console.ReadLine(); + r.Uninitialize(); + } + + static void r_SkeletonFrameReady(object sender, SkeletonFrameReadyEventArgs e) + { + if ((DateTime.Now - lastTimeHit).Seconds < 5) + { + return; + } + foreach (SkeletonData s in e.SkeletonFrame.Skeletons) + { + if (s.TrackingState == SkeletonTrackingState.Tracked) + { + Joint rh = s.Joints[JointID.HandRight]; + Joint h = s.Joints[JointID.Head]; + + if (rh.Position.Y > h.Position.Y) + { + lastTimeHit = DateTime.Now; + Console.WriteLine("Hand über kopf"); + IntPtr hwnd = KinectWorkshop.WindowFinder.StartingWith("Unbenannt"); + KinectWorkshop.WindowFinder.SetFocusOn(hwnd); + KinectWorkshop.KeySender.Send(KinectWorkshop.VirtualKey.NEXT); + } + } + } + } + } +} diff --git a/Kinect/Demo4/Demo4/Properties/AssemblyInfo.cs b/Kinect/Demo4/Demo4/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..54bfbd3 --- /dev/null +++ b/Kinect/Demo4/Demo4/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// Allgemeine Informationen über eine Assembly werden über die folgenden +// Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern, +// die mit einer Assembly verknüpft sind. +[assembly: AssemblyTitle("Demo4")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Demo4")] +[assembly: AssemblyCopyright("Copyright © 2011")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Durch Festlegen von ComVisible auf "false" werden die Typen in dieser Assembly unsichtbar +// für COM-Komponenten. Wenn Sie auf einen Typ in dieser Assembly von +// COM zugreifen müssen, legen Sie das ComVisible-Attribut für diesen Typ auf "true" fest. +[assembly: ComVisible(false)] + +// Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird +[assembly: Guid("aa436451-b12f-49c9-aa04-728a278274ee")] + +// Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten: +// +// Hauptversion +// Nebenversion +// Buildnummer +// Revision +// +// Sie können alle Werte angeben oder die standardmäßigen Build- und Revisionsnummern +// übernehmen, indem Sie "*" eingeben: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Kinect/Demo4/Demo4/WindowFinder.cs b/Kinect/Demo4/Demo4/WindowFinder.cs new file mode 100644 index 0000000..2b73d1f --- /dev/null +++ b/Kinect/Demo4/Demo4/WindowFinder.cs @@ -0,0 +1,55 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Runtime.InteropServices; + +namespace KinectWorkshop +{ + class WindowFinder + { + [DllImport("user32.dll", SetLastError = true)] + static extern IntPtr FindWindow(string lpClassName, string lpWindowName); + + [DllImport("user32.Dll")] + [return: MarshalAs(UnmanagedType.Bool)] + static extern bool EnumWindows(EnumWindowsProc lpEnumFunc, [MarshalAsAttribute(UnmanagedType.Struct)] ref SearchData data); + private delegate bool EnumWindowsProc(IntPtr hWnd, ref SearchData data); + + [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] + public static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount); + + [DllImport("user32.dll")] + static extern IntPtr SetFocus(IntPtr hWnd); + + struct SearchData + { + public string TitlePrefix; + public IntPtr hWnd; + } + + static bool EnumProc(IntPtr hWnd, ref SearchData data) + { + StringBuilder sb = new StringBuilder(1024); + GetWindowText(hWnd, sb, sb.Capacity); + if (sb.ToString().StartsWith(data.TitlePrefix)) + { + data.hWnd = hWnd; + return false; + } + return true; + } + + public static IntPtr StartingWith(string prefix) + { + SearchData sd = new SearchData { TitlePrefix = prefix }; + EnumWindows(new EnumWindowsProc(EnumProc), ref sd); + return sd.hWnd; + } + + public static void SetFocusOn(IntPtr hwnd) + { + SetFocus(hwnd); + } + } +} diff --git a/Kinect/Demo5/Demo5.sln b/Kinect/Demo5/Demo5.sln new file mode 100644 index 0000000..075f0ab --- /dev/null +++ b/Kinect/Demo5/Demo5.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Demo5", "Demo5\Demo5.csproj", "{CF078AB1-B658-48F7-89C1-45610E317B3D}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {CF078AB1-B658-48F7-89C1-45610E317B3D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CF078AB1-B658-48F7-89C1-45610E317B3D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CF078AB1-B658-48F7-89C1-45610E317B3D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CF078AB1-B658-48F7-89C1-45610E317B3D}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Kinect/Demo5/Demo5/Class1.cs b/Kinect/Demo5/Demo5/Class1.cs new file mode 100644 index 0000000..e88091f --- /dev/null +++ b/Kinect/Demo5/Demo5/Class1.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Demo5 +{ + public class Class1 + { + } +} diff --git a/Kinect/Demo5/Demo5/Demo5.csproj b/Kinect/Demo5/Demo5/Demo5.csproj new file mode 100644 index 0000000..7b9b769 --- /dev/null +++ b/Kinect/Demo5/Demo5/Demo5.csproj @@ -0,0 +1,81 @@ + + + + Debug + AnyCPU + 8.0.30703 + 2.0 + {CF078AB1-B658-48F7-89C1-45610E317B3D} + Library + Properties + Demo5 + Demo5 + v4.0 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + true + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + true + + + KinectDemo5.snk + + + + + + + + + + + + + + + + + + UserControl + + + KinectControl.cs + + + + + KinectControl.cs + + + + + + + + + + + \ No newline at end of file diff --git a/Kinect/Demo5/Demo5/KinectControl.Designer.cs b/Kinect/Demo5/Demo5/KinectControl.Designer.cs new file mode 100644 index 0000000..e8b735c --- /dev/null +++ b/Kinect/Demo5/Demo5/KinectControl.Designer.cs @@ -0,0 +1,72 @@ +namespace Demo5 +{ + partial class KinectControl + { + /// + /// Erforderliche Designervariable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Verwendete Ressourcen bereinigen. + /// + /// True, wenn verwaltete Ressourcen gelöscht werden sollen; andernfalls False. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Vom Komponenten-Designer generierter Code + + /// + /// Erforderliche Methode für die Designerunterstützung. + /// Der Inhalt der Methode darf nicht mit dem Code-Editor geändert werden. + /// + private void InitializeComponent() + { + this.lbHandLeft = new System.Windows.Forms.Label(); + this.lbHandRight = new System.Windows.Forms.Label(); + this.SuspendLayout(); + // + // lbHandLeft + // + this.lbHandLeft.AutoSize = true; + this.lbHandLeft.Location = new System.Drawing.Point(3, 15); + this.lbHandLeft.Name = "lbHandLeft"; + this.lbHandLeft.Size = new System.Drawing.Size(59, 13); + this.lbHandLeft.TabIndex = 0; + this.lbHandLeft.Text = "lbHandLeft"; + // + // lbHandRight + // + this.lbHandRight.AutoSize = true; + this.lbHandRight.Location = new System.Drawing.Point(84, 15); + this.lbHandRight.Name = "lbHandRight"; + this.lbHandRight.Size = new System.Drawing.Size(66, 13); + this.lbHandRight.TabIndex = 1; + this.lbHandRight.Text = "lbHandRight"; + // + // KinectControl + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.lbHandRight); + this.Controls.Add(this.lbHandLeft); + this.Name = "KinectControl"; + this.Size = new System.Drawing.Size(150, 46); + this.Load += new System.EventHandler(this.KinectControl_Load); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Label lbHandLeft; + private System.Windows.Forms.Label lbHandRight; + } +} diff --git a/Kinect/Demo5/Demo5/KinectControl.cs b/Kinect/Demo5/Demo5/KinectControl.cs new file mode 100644 index 0000000..30ff5c3 --- /dev/null +++ b/Kinect/Demo5/Demo5/KinectControl.cs @@ -0,0 +1,90 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Drawing; +using System.Data; +using System.Linq; +using System.Text; +using System.Windows.Forms; +using System.Runtime.InteropServices; +using Microsoft.Win32; +using System.Reflection; +using Microsoft.Research.Kinect.Nui; + + +namespace Demo5 +{ + [ProgId("Demo5.KinectControl")] + [Guid("577410DD-1FC4-4B28-A0FE-9D0F78CEEDB5")] + [ClassInterface(ClassInterfaceType.AutoDual)] + [ComVisible(true)] + public partial class KinectControl : UserControl + { + private string text; + [ComRegisterFunction()] + public static void RegisterClass(string key) + { + StringBuilder sb = new StringBuilder(key); + sb.Replace(@"HKEY_CLASSES_ROOT\", ""); + + RegistryKey k = Registry.ClassesRoot.OpenSubKey(sb.ToString(), true); + RegistryKey ctrl = k.CreateSubKey("Control"); + ctrl.Close(); + + RegistryKey inprocServer32 = k.OpenSubKey("InprocServer32", true); + inprocServer32.SetValue("CodeBase", Assembly.GetExecutingAssembly().CodeBase); + inprocServer32.Close(); + + k.Close(); + } + + [ComUnregisterFunction()] + public static void UnregisterClass(string key) + { + StringBuilder sb = new StringBuilder(key); + sb.Replace(@"HKEY_CLASSES_ROOT\", ""); + + RegistryKey k = Registry.ClassesRoot.OpenSubKey(sb.ToString(), true); + k.DeleteSubKey("Control", false); + RegistryKey inprocServer32 = k.OpenSubKey("InprocServer32", true); + inprocServer32.DeleteSubKey("CodeBase", false); + inprocServer32.Close(); + k.Close(); + } + + + + public KinectControl() + { + InitializeComponent(); + } + + private void KinectControl_Load(object sender, EventArgs e) + { + Runtime r = Runtime.Kinects[0]; + r.Initialize(RuntimeOptions.UseSkeletalTracking); + r.SkeletonEngine.TransformSmooth = true; + r.SkeletonFrameReady += new EventHandler(r_SkeletonFrameReady); + } + + void r_SkeletonFrameReady(object sender, SkeletonFrameReadyEventArgs e) + { + foreach (SkeletonData s in e.SkeletonFrame.Skeletons) + { + if (s.TrackingState == SkeletonTrackingState.Tracked) + { + Joint lh = s.Joints[JointID.HandLeft]; + this.text = String.Format("X: {0}, Y: {1}", lh.Position.X, lh.Position.Y); + this.Invoke(new CallMe(SetText)); + } + } + } + + void SetText() + { + lbHandLeft.Text = this.text; + } + + delegate void CallMe(); + } +} diff --git a/Kinect/Demo5/Demo5/KinectControl.resx b/Kinect/Demo5/Demo5/KinectControl.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/Kinect/Demo5/Demo5/KinectControl.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Kinect/Demo5/Demo5/KinectDemo5.snk b/Kinect/Demo5/Demo5/KinectDemo5.snk new file mode 100644 index 0000000..eb5081d Binary files /dev/null and b/Kinect/Demo5/Demo5/KinectDemo5.snk differ diff --git a/Kinect/Demo5/Demo5/Properties/AssemblyInfo.cs b/Kinect/Demo5/Demo5/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..961bc36 --- /dev/null +++ b/Kinect/Demo5/Demo5/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// Allgemeine Informationen über eine Assembly werden über die folgenden +// Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern, +// die mit einer Assembly verknüpft sind. +[assembly: AssemblyTitle("Demo5")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Demo5")] +[assembly: AssemblyCopyright("Copyright © 2011")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Durch Festlegen von ComVisible auf "false" werden die Typen in dieser Assembly unsichtbar +// für COM-Komponenten. Wenn Sie auf einen Typ in dieser Assembly von +// COM zugreifen müssen, legen Sie das ComVisible-Attribut für diesen Typ auf "true" fest. +[assembly: ComVisible(false)] + +// Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird +[assembly: Guid("75922dfb-1c32-4750-9af7-48d92b2c969d")] + +// Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten: +// +// Hauptversion +// Nebenversion +// Buildnummer +// Revision +// +// Sie können alle Werte angeben oder die standardmäßigen Build- und Revisionsnummern +// übernehmen, indem Sie "*" eingeben: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Kinect/Demo5/Demo5/TextFile1.txt b/Kinect/Demo5/Demo5/TextFile1.txt new file mode 100644 index 0000000..030ffae --- /dev/null +++ b/Kinect/Demo5/Demo5/TextFile1.txt @@ -0,0 +1,2 @@ +regasm demo.dll +regasm /u demo.dll \ No newline at end of file diff --git a/Kinect/Demo6/Demo6.sln b/Kinect/Demo6/Demo6.sln new file mode 100644 index 0000000..bfa7e06 --- /dev/null +++ b/Kinect/Demo6/Demo6.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Demo6", "Demo6\Demo6.csproj", "{9775B675-99C5-4DAD-8F6E-757002AE51D4}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x86 = Debug|x86 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {9775B675-99C5-4DAD-8F6E-757002AE51D4}.Debug|x86.ActiveCfg = Debug|x86 + {9775B675-99C5-4DAD-8F6E-757002AE51D4}.Debug|x86.Build.0 = Debug|x86 + {9775B675-99C5-4DAD-8F6E-757002AE51D4}.Release|x86.ActiveCfg = Release|x86 + {9775B675-99C5-4DAD-8F6E-757002AE51D4}.Release|x86.Build.0 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Kinect/Demo6/Demo6/App.xaml b/Kinect/Demo6/Demo6/App.xaml new file mode 100644 index 0000000..f742932 --- /dev/null +++ b/Kinect/Demo6/Demo6/App.xaml @@ -0,0 +1,8 @@ + + + + + diff --git a/Kinect/Demo6/Demo6/App.xaml.cs b/Kinect/Demo6/Demo6/App.xaml.cs new file mode 100644 index 0000000..63a8aa8 --- /dev/null +++ b/Kinect/Demo6/Demo6/App.xaml.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Configuration; +using System.Data; +using System.Linq; +using System.Windows; + +namespace Demo6 +{ + /// + /// Interaktionslogik für "App.xaml" + /// + public partial class App : Application + { + } +} diff --git a/Kinect/Demo6/Demo6/Demo6.csproj b/Kinect/Demo6/Demo6/Demo6.csproj new file mode 100644 index 0000000..ef8b88e --- /dev/null +++ b/Kinect/Demo6/Demo6/Demo6.csproj @@ -0,0 +1,104 @@ + + + + Debug + x86 + 8.0.30703 + 2.0 + {9775B675-99C5-4DAD-8F6E-757002AE51D4} + WinExe + Properties + Demo6 + Demo6 + v4.0 + Client + 512 + {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 4 + + + x86 + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + x86 + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + 4.0 + + + + + + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + App.xaml + Code + + + MainWindow.xaml + Code + + + + + Code + + + True + True + Resources.resx + + + True + Settings.settings + True + + + ResXFileCodeGenerator + Resources.Designer.cs + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + + + + \ No newline at end of file diff --git a/Kinect/Demo6/Demo6/MainWindow.xaml b/Kinect/Demo6/Demo6/MainWindow.xaml new file mode 100644 index 0000000..e10986c --- /dev/null +++ b/Kinect/Demo6/Demo6/MainWindow.xaml @@ -0,0 +1,8 @@ + + + + + diff --git a/Kinect/Demo6/Demo6/MainWindow.xaml.cs b/Kinect/Demo6/Demo6/MainWindow.xaml.cs new file mode 100644 index 0000000..3f2772b --- /dev/null +++ b/Kinect/Demo6/Demo6/MainWindow.xaml.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; +using Microsoft.Research.Kinect.Nui; + +namespace Demo6 +{ + /// + /// Interaktionslogik für MainWindow.xaml + /// + public partial class MainWindow : Window + { + public MainWindow() + { + InitializeComponent(); + } + + private void Window_Loaded(object sender, RoutedEventArgs e) + { + if (Runtime.Kinects.Count == 0) + { + MessageBox.Show("Keine Kinect"); + return; + } + Runtime r = Runtime.Kinects[0]; + r.Initialize(RuntimeOptions.UseDepth); + r.DepthStream.Open(ImageStreamType.Depth, 2, ImageResolution.Resolution320x240, ImageType.Depth); + r.DepthFrameReady += new EventHandler(r_DepthFrameReady); + } + + void r_DepthFrameReady(object sender, ImageFrameReadyEventArgs e) + { + PlanarImage img = e.ImageFrame.Image; + //byte[] b = cv.ConvertDepthFrame(img.Bits); + imgDepth.Source = BitmapSource.Create(img.Width, img.Height, + 96, 96, PixelFormats.Bgr32, null, + b, img.Width * img.BytesPerPixel); + } + } +} diff --git a/Kinect/Demo6/Demo6/Properties/AssemblyInfo.cs b/Kinect/Demo6/Demo6/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..7884b85 --- /dev/null +++ b/Kinect/Demo6/Demo6/Properties/AssemblyInfo.cs @@ -0,0 +1,55 @@ +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 mit einer Assembly verknüpft sind. +[assembly: AssemblyTitle("Demo6")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Demo6")] +[assembly: AssemblyCopyright("Copyright © 2011")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Durch Festlegen von ComVisible auf "false" werden die Typen in dieser Assembly unsichtbar +// für COM-Komponenten. Wenn Sie auf einen Typ in dieser Assembly von +// COM zugreifen müssen, legen Sie das ComVisible-Attribut für diesen Typ auf "true" fest. +[assembly: ComVisible(false)] + +//Um mit dem Erstellen lokalisierbarer Anwendungen zu beginnen, legen Sie +//ImCodeVerwendeteKultur in der .csproj-Datei +//in einer fest. Wenn Sie in den Quelldateien beispielsweise Deutsch +//(Deutschland) verwenden, legen Sie 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 + // 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, in der Anwendung oder einem + // 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 die standardmäßigen Build- und Revisionsnummern +// übernehmen, indem Sie "*" eingeben: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Kinect/Demo6/Demo6/Properties/Resources.Designer.cs b/Kinect/Demo6/Demo6/Properties/Resources.Designer.cs new file mode 100644 index 0000000..8fb4bab --- /dev/null +++ b/Kinect/Demo6/Demo6/Properties/Resources.Designer.cs @@ -0,0 +1,71 @@ +//------------------------------------------------------------------------------ +// +// Dieser Code wurde von einem Tool generiert. +// Laufzeitversion:4.0.30319.239 +// +// Änderungen an dieser Datei können fehlerhaftes Verhalten verursachen und gehen verloren, wenn +// der Code neu generiert wird. +// +//------------------------------------------------------------------------------ + +namespace Demo6.Properties +{ + + + /// + /// Eine stark typisierte Ressourcenklasse zum Suchen von lokalisierten Zeichenfolgen usw. + /// + // 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() + { + } + + /// + /// Gibt die zwischengespeicherte ResourceManager-Instanz zurück, die von dieser Klasse verwendet wird. + /// + [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("Demo6.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Überschreibt die CurrentUICulture-Eigenschaft des aktuellen Threads für alle + /// Ressourcenlookups, die diese stark typisierte Ressourcenklasse verwenden. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture + { + get + { + return resourceCulture; + } + set + { + resourceCulture = value; + } + } + } +} diff --git a/Kinect/Demo6/Demo6/Properties/Resources.resx b/Kinect/Demo6/Demo6/Properties/Resources.resx new file mode 100644 index 0000000..af7dbeb --- /dev/null +++ b/Kinect/Demo6/Demo6/Properties/Resources.resx @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Kinect/Demo6/Demo6/Properties/Settings.Designer.cs b/Kinect/Demo6/Demo6/Properties/Settings.Designer.cs new file mode 100644 index 0000000..9f82a6f --- /dev/null +++ b/Kinect/Demo6/Demo6/Properties/Settings.Designer.cs @@ -0,0 +1,30 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.239 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Demo6.Properties +{ + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "10.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; + } + } + } +} diff --git a/Kinect/Demo6/Demo6/Properties/Settings.settings b/Kinect/Demo6/Demo6/Properties/Settings.settings new file mode 100644 index 0000000..033d7a5 --- /dev/null +++ b/Kinect/Demo6/Demo6/Properties/Settings.settings @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/Mqtt-Dashboard/Dashboard.sln b/Mqtt-Dashboard/Dashboard.sln new file mode 100644 index 0000000..0789cb8 --- /dev/null +++ b/Mqtt-Dashboard/Dashboard.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.26403.7 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dashboard", "Mqtt-Dashboard\Dashboard.csproj", "{16AC0F61-0B60-4A1D-A827-B3BFDBA9AAC7}" +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 + {16AC0F61-0B60-4A1D-A827-B3BFDBA9AAC7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {16AC0F61-0B60-4A1D-A827-B3BFDBA9AAC7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {16AC0F61-0B60-4A1D-A827-B3BFDBA9AAC7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {16AC0F61-0B60-4A1D-A827-B3BFDBA9AAC7}.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 +EndGlobal diff --git a/Mqtt-Dashboard/Mqtt-Dashboard/App.config b/Mqtt-Dashboard/Mqtt-Dashboard/App.config new file mode 100644 index 0000000..88fa402 --- /dev/null +++ b/Mqtt-Dashboard/Mqtt-Dashboard/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Mqtt-Dashboard/Mqtt-Dashboard/Connector/ADataBackend.cs b/Mqtt-Dashboard/Mqtt-Dashboard/Connector/ADataBackend.cs new file mode 100644 index 0000000..33a0301 --- /dev/null +++ b/Mqtt-Dashboard/Mqtt-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-Dashboard/Mqtt-Dashboard/Connector/Mosquitto.cs b/Mqtt-Dashboard/Mqtt-Dashboard/Connector/Mosquitto.cs new file mode 100644 index 0000000..cf88022 --- /dev/null +++ b/Mqtt-Dashboard/Mqtt-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-Dashboard/Mqtt-Dashboard/Connector/Mqtt.cs b/Mqtt-Dashboard/Mqtt-Dashboard/Connector/Mqtt.cs new file mode 100644 index 0000000..36d21a4 --- /dev/null +++ b/Mqtt-Dashboard/Mqtt-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-Dashboard/Mqtt-Dashboard/Connector/Telegram.cs b/Mqtt-Dashboard/Mqtt-Dashboard/Connector/Telegram.cs new file mode 100644 index 0000000..4ec1ded --- /dev/null +++ b/Mqtt-Dashboard/Mqtt-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-Dashboard/Mqtt-Dashboard/Dashboard.csproj b/Mqtt-Dashboard/Mqtt-Dashboard/Dashboard.csproj new file mode 100644 index 0000000..6780600 --- /dev/null +++ b/Mqtt-Dashboard/Mqtt-Dashboard/Dashboard.csproj @@ -0,0 +1,149 @@ + + + + + Debug + AnyCPU + {16AC0F61-0B60-4A1D-A827-B3BFDBA9AAC7} + WinExe + Dashboard + Dashboard + v4.5.2 + 512 + true + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + DEBUG + prompt + 4 + + + + + + + ..\packages\LitJson.0.9.0\lib\LitJson.dll + + + ..\packages\M2Mqtt.4.3.0.0\lib\net45\M2Mqtt.Net.dll + + + ..\packages\OxyPlot.Core.1.0.0\lib\net45\OxyPlot.dll + + + ..\packages\OxyPlot.WindowsForms.1.0.0\lib\net45\OxyPlot.WindowsForms.dll + + + + + + + + + + + + + + + + + + + + Form + + + Form1.cs + + + + + + + + + + + + + + + Form1.cs + + + ResXFileCodeGenerator + Resources.Designer.cs + Designer + + + True + Resources.resx + True + + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + True + Settings.settings + True + + + + + + + + + + + {fac8ce64-bf13-4ece-8097-aeb5dd060098} + Utils + + + + + False + Microsoft .NET Framework 4.5.2 %28x86 und x64%29 + true + + + False + .NET Framework 3.5 SP1 + false + + + + \ No newline at end of file diff --git a/Mqtt-Dashboard/Mqtt-Dashboard/Dashboard.csproj.user b/Mqtt-Dashboard/Mqtt-Dashboard/Dashboard.csproj.user new file mode 100644 index 0000000..67fe57a --- /dev/null +++ b/Mqtt-Dashboard/Mqtt-Dashboard/Dashboard.csproj.user @@ -0,0 +1,19 @@ + + + + -debug + + + -debug + + + + + + + + + de-DE + false + + \ No newline at end of file diff --git a/Mqtt-Dashboard/Mqtt-Dashboard/Form1.Designer.cs b/Mqtt-Dashboard/Mqtt-Dashboard/Form1.Designer.cs new file mode 100644 index 0000000..65a1049 --- /dev/null +++ b/Mqtt-Dashboard/Mqtt-Dashboard/Form1.Designer.cs @@ -0,0 +1,65 @@ +namespace Dashboard { + partial class Dashboard { + /// + /// Erforderliche Designervariable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Verwendete Ressourcen bereinigen. + /// + /// True, wenn verwaltete Ressourcen gelöscht werden sollen; andernfalls False. + protected override void Dispose(bool disposing) { + if (disposing && (components != null)) { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Vom Windows Form-Designer generierter Code + + /// + /// Erforderliche Methode für die Designerunterstützung. + /// Der Inhalt der Methode darf nicht mit dem Code-Editor geändert werden. + /// + private void InitializeComponent() { + this.statusStrip1 = new System.Windows.Forms.StatusStrip(); + this.flowLayoutPanel2 = new System.Windows.Forms.FlowLayoutPanel(); + this.SuspendLayout(); + // + // statusStrip1 + // + this.statusStrip1.Location = new System.Drawing.Point(0, 490); + this.statusStrip1.Name = "statusStrip1"; + this.statusStrip1.Size = new System.Drawing.Size(1247, 22); + this.statusStrip1.TabIndex = 0; + this.statusStrip1.Text = "statusStrip1"; + // + // flowLayoutPanel2 + // + this.flowLayoutPanel2.Location = new System.Drawing.Point(12, 12); + this.flowLayoutPanel2.Name = "flowLayoutPanel2"; + this.flowLayoutPanel2.Size = new System.Drawing.Size(1223, 475); + this.flowLayoutPanel2.TabIndex = 3; + // + // Dashboard + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(1247, 512); + this.Controls.Add(this.flowLayoutPanel2); + this.Controls.Add(this.statusStrip1); + this.Name = "Dashboard"; + this.Text = "Dashboard"; + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.StatusStrip statusStrip1; + private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel2; + } +} + diff --git a/Mqtt-Dashboard/Mqtt-Dashboard/Form1.cs b/Mqtt-Dashboard/Mqtt-Dashboard/Form1.cs new file mode 100644 index 0000000..a05edce --- /dev/null +++ b/Mqtt-Dashboard/Mqtt-Dashboard/Form1.cs @@ -0,0 +1,72 @@ +using System; +using System.Collections.Generic; +using System.Windows.Forms; +using BlubbFish.Utils; +using Dashboard.Connector; +using Dashboard.Sensor; +using Dashboard.Tracings; + +namespace Dashboard { + public partial class Dashboard : Form { + private Dictionary sensors = new Dictionary(); + private ADataBackend mqtt; + + public Dashboard(Boolean debug) { + InitializeComponent(); + this.mqtt = ADataBackend.GetInstance(InIReader.GetInstance("settings.ini").GetSection("mqtt")); + + this.GenerateSensors(); + this.GenerateForms(); + + this.FormClosed += this.Dashboard_FormClosed; + this.SizeChanged += this.Dashboard_SizeChanged; + + if (debug) { + this.mqtt.MessageIncomming += this.Instance_MessageIncomming; + this.mqtt.MessageSending += this.Instance_MessageSending; + } + } + + private void Dashboard_SizeChanged(Object sender, EventArgs e) { + this.flowLayoutPanel2.Size = new System.Drawing.Size(this.Size.Width - 40, this.Size.Width - 76); + } + + private void GenerateSensors() { + InIReader ini = InIReader.GetInstance("sensor.ini"); + List sensorini = ini.GetSections(false); + foreach(String sensor in sensorini) { + this.sensors.Add(sensor.ToLower(), ASensor.GetInstance(this.mqtt, ini.GetSection(sensor), sensor)); + } + } + + private void GenerateForms() { + InIReader ini = InIReader.GetInstance("tracings.ini"); + List tracingini = ini.GetSections(); + foreach(String tracing in tracingini) { + this.flowLayoutPanel2.Controls.Add(ATracings.GetInstance(ini.GetValue(tracing, "type").ToLower(), this.sensors, ini.GetSection(tracing)).GetPanel()); + } + } + + private void Dashboard_FormClosed(Object sender, FormClosedEventArgs e) { + this.Dispose(); + } + private new void Dispose() { + foreach (KeyValuePair item in this.sensors) { + item.Value.Dispose(); + } + this.sensors.Clear(); + this.mqtt.MessageIncomming -= this.Instance_MessageIncomming; + this.mqtt.MessageSending -= this.Instance_MessageSending; + this.mqtt.Dispose(); + this.Dispose(true); + } + + private void Instance_MessageIncomming(Object sender, MqttEventArgs e) { + Console.WriteLine("Received = " + e.Message + " on topic " + e.Topic+" at "+DateTime.Now.ToUniversalTime()); + } + + private void Instance_MessageSending(Object sender, MqttEventArgs e) { + Console.WriteLine("Sended = " + e.Message + " on topic " + e.Topic + " at " + DateTime.Now.ToUniversalTime()); + } + } +} diff --git a/Mqtt-Dashboard/Mqtt-Dashboard/Form1.resx b/Mqtt-Dashboard/Mqtt-Dashboard/Form1.resx new file mode 100644 index 0000000..174ebc7 --- /dev/null +++ b/Mqtt-Dashboard/Mqtt-Dashboard/Form1.resx @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + \ No newline at end of file diff --git a/Mqtt-Dashboard/Mqtt-Dashboard/Program.cs b/Mqtt-Dashboard/Mqtt-Dashboard/Program.cs new file mode 100644 index 0000000..16afd1f --- /dev/null +++ b/Mqtt-Dashboard/Mqtt-Dashboard/Program.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Windows.Forms; +using BlubbFish.Utils; + +namespace Dashboard { + static class Program { + /// + /// Der Haupteinstiegspunkt für die Anwendung. + /// + [STAThread] + static void Main(String[] args) { + CmdArgs.Instance.SetArguments(new Dictionary { + { "-debug", new CmdArgs.VaildArguments(CmdArgs.ArgLength.Single) } + }, args); + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + Boolean debug = false; + if(CmdArgs.Instance.HasArgumentType("-debug")) { + debug = true; + } + Application.Run(new Dashboard(debug)); + } + } +} diff --git a/Mqtt-Dashboard/Mqtt-Dashboard/Properties/AssemblyInfo.cs b/Mqtt-Dashboard/Mqtt-Dashboard/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..ace93fe --- /dev/null +++ b/Mqtt-Dashboard/Mqtt-Dashboard/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// 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-Dashboard")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Mqtt-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)] + +// Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird +[assembly: Guid("16ac0f61-0b60-4a1d-a827-b3bfdba9aac7")] + +// 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")] diff --git a/Mqtt-Dashboard/Mqtt-Dashboard/Properties/Resources.Designer.cs b/Mqtt-Dashboard/Mqtt-Dashboard/Properties/Resources.Designer.cs new file mode 100644 index 0000000..3c03f1c --- /dev/null +++ b/Mqtt-Dashboard/Mqtt-Dashboard/Properties/Resources.Designer.cs @@ -0,0 +1,63 @@ +//------------------------------------------------------------------------------ +// +// Dieser Code wurde von einem Tool generiert. +// Laufzeitversion:4.0.30319.42000 +// +// Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn +// der Code erneut generiert wird. +// +//------------------------------------------------------------------------------ + +namespace Dashboard.Properties { + using System; + + + /// + /// Eine stark typisierte Ressourcenklasse zum Suchen von lokalisierten Zeichenfolgen usw. + /// + // Diese Klasse wurde von der StronglyTypedResourceBuilder automatisch generiert + // -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 /str-Option erneut aus, oder Sie erstellen 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() { + } + + /// + /// Gibt die zwischengespeicherte ResourceManager-Instanz zurück, die von dieser Klasse verwendet wird. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Dashboard.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Überschreibt die CurrentUICulture-Eigenschaft des aktuellen Threads für alle + /// Ressourcenzuordnungen, die diese stark typisierte Ressourcenklasse verwenden. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + } +} diff --git a/Mqtt-Dashboard/Mqtt-Dashboard/Properties/Resources.resx b/Mqtt-Dashboard/Mqtt-Dashboard/Properties/Resources.resx new file mode 100644 index 0000000..af7dbeb --- /dev/null +++ b/Mqtt-Dashboard/Mqtt-Dashboard/Properties/Resources.resx @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Mqtt-Dashboard/Mqtt-Dashboard/Properties/Settings.Designer.cs b/Mqtt-Dashboard/Mqtt-Dashboard/Properties/Settings.Designer.cs new file mode 100644 index 0000000..073a096 --- /dev/null +++ b/Mqtt-Dashboard/Mqtt-Dashboard/Properties/Settings.Designer.cs @@ -0,0 +1,26 @@ +//------------------------------------------------------------------------------ +// +// Dieser Code wurde von einem Tool generiert. +// Laufzeitversion:4.0.30319.42000 +// +// Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn +// der Code erneut generiert wird. +// +//------------------------------------------------------------------------------ + +namespace Dashboard.Properties { + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.1.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; + } + } + } +} diff --git a/Mqtt-Dashboard/Mqtt-Dashboard/Properties/Settings.settings b/Mqtt-Dashboard/Mqtt-Dashboard/Properties/Settings.settings new file mode 100644 index 0000000..3964565 --- /dev/null +++ b/Mqtt-Dashboard/Mqtt-Dashboard/Properties/Settings.settings @@ -0,0 +1,7 @@ + + + + + + + diff --git a/Mqtt-Dashboard/Mqtt-Dashboard/Sensor/ASensor.cs b/Mqtt-Dashboard/Mqtt-Dashboard/Sensor/ASensor.cs new file mode 100644 index 0000000..ccbd6b7 --- /dev/null +++ b/Mqtt-Dashboard/Mqtt-Dashboard/Sensor/ASensor.cs @@ -0,0 +1,121 @@ +using Dashboard.Connector; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Text.RegularExpressions; + +namespace Dashboard.Sensor { + public abstract class ASensor : IDisposable { + protected String topic; + protected Int32 pollcount; + private Dictionary settings; + protected ADataBackend backend; + private Thread updateThread; + private Boolean pollEnabled = false; + + public ASensor(Dictionary settings, String name, ADataBackend backend) { + this.GetBool = true; + this.GetFloat = 0.0f; + this.GetInt = 0; + this.topic = (settings.Keys.Contains("topic")) ? settings["topic"] : ""; + this.settings = settings; + this.Title = (settings.Keys.Contains("title")) ? settings["title"] : ""; + this.Name = name; + this.backend = backend; + this.backend.MessageIncomming += this.IncommingMqttMessage; + if (settings.Keys.Contains("polling")) { + this.pollEnabled = true; + this.Polling = Int32.Parse(settings["polling"]); + this.pollcount = this.Polling; + this.updateThread = new Thread(this.SensorPolling); + this.updateThread.Start(); + } + } + + private void SensorPolling() { + while(this.pollEnabled) { + Thread.Sleep(1000); + this.Poll(); + } + } + + private void IncommingMqttMessage(Object sender, MqttEventArgs e) { + if(Regex.Match(e.Topic, this.topic).Success) { + if (this.UpdateValue(e)) { + this.Timestamp = DateTime.Now; + this.Update?.Invoke(this, e); + } + } + } + + internal static ASensor GetInstance(ADataBackend backend, Dictionary dictionary, String name) { + String object_sensor = "Dashboard.Sensor." + 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("sensor.ini: " + dictionary["type"] + " is not a Sensor"); + } + return (ASensor)t.GetConstructor(new Type[] { typeof(Dictionary), typeof(String), typeof(ADataBackend) }).Invoke(new Object[] { dictionary, name, backend }); + } + + protected virtual void Poll() { + if(this.pollcount++ >= this.Polling) { + this.pollcount = 1; + this.backend.Send(this.topic + "/status",""); + } + } + + internal virtual void SetBool(Boolean v) { + this.backend.Send(this.topic + "/set", v ? "on" : "off"); + } + + protected abstract Boolean UpdateValue(MqttEventArgs e); + + public Single GetFloat { get; protected set; } + public Boolean GetBool { get; protected set; } + public Int32 GetInt { get; protected set; } + public Types Datatypes { get; protected set; } + public DateTime Timestamp { get; protected set; } + public Int32 Polling { get; private set; } + public String Title { get; protected set; } + public String Name { get; internal set; } + + public enum Types { + Bool, + Int, + Float + } + public delegate void UpdatedValue(ASensor sender, EventArgs e); + public event UpdatedValue Update; + + #region IDisposable Support + private Boolean disposedValue = false; + + + protected virtual void Dispose(Boolean disposing) { + if(!this.disposedValue) { + if(disposing) { + this.pollEnabled = false; + if (this.updateThread != null && this.updateThread.ThreadState == ThreadState.Running) { + this.updateThread.Abort(); + while (this.updateThread.ThreadState != ThreadState.Aborted) { } + } + this.backend.MessageIncomming -= this.IncommingMqttMessage; + } + this.settings = null; + this.updateThread = null; + this.disposedValue = true; + } + } + ~ASensor() { + Dispose(false); + } + public void Dispose() { + Dispose(true); + GC.SuppressFinalize(this); + } + #endregion + } +} \ No newline at end of file diff --git a/Mqtt-Dashboard/Mqtt-Dashboard/Sensor/Flex4GridSwitch.cs b/Mqtt-Dashboard/Mqtt-Dashboard/Sensor/Flex4GridSwitch.cs new file mode 100644 index 0000000..20deb4d --- /dev/null +++ b/Mqtt-Dashboard/Mqtt-Dashboard/Sensor/Flex4GridSwitch.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Text.RegularExpressions; +using Dashboard.Connector; +using LitJson; + +namespace Dashboard.Sensor { + class Flex4gridswitch : ASensor { + private String id; + + public Flex4gridswitch(Dictionary settings, String name, ADataBackend backend) : base(settings, name, backend) { + this.Datatypes = Types.Bool; + this.id = settings["id"]; + } + + protected override Boolean UpdateValue(MqttEventArgs e) { + 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; + try { + JsonData data = JsonMapper.ToObject(e.Message); + if (data.Keys.Contains("id") && data["id"].ToString() == this.id) { + this.GetBool = data["status"].ToString() == "active" ? true : false; + return true; + } + if(data.Keys.Contains(this.id)) { + this.GetBool = data[this.id].ToString() == "active" ? true : false; + return true; + } + } catch (Exception) { + } + return false; + } + + protected override void Poll() { + if (this.pollcount++ >= this.Polling) { + this.pollcount = 1; + String hid = Regex.Match(this.topic, "/flex4grid/v1/households/([^/]*)/device/state").Groups[1].Value; + this.backend.Send("/flex4grid/v1/households/" + hid + "/devices/state/request", "{\"timestamp\": \"" + DateTime.Now.ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'ffffff'Z'") + "\"}"); + } + } + + internal override void SetBool(Boolean v) { + String hid = Regex.Match(this.topic, "/flex4grid/v1/households/([^/]*)/device/state").Groups[1].Value; + this.backend.Send("/flex4grid/v1/households/" + hid + "/device/actuate", "{\"command\":\""+(v ? "ON" : "OFF") + "\",\"deviceId\":\""+ this.id + "\",\"timestamp\":\"" + DateTime.Now.ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'ffffff'Z'") + "\"}"); + } + } +} \ No newline at end of file diff --git a/Mqtt-Dashboard/Mqtt-Dashboard/Sensor/Flex4gridPower.cs b/Mqtt-Dashboard/Mqtt-Dashboard/Sensor/Flex4gridPower.cs new file mode 100644 index 0000000..db95d9a --- /dev/null +++ b/Mqtt-Dashboard/Mqtt-Dashboard/Sensor/Flex4gridPower.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using Dashboard.Connector; +using LitJson; + +namespace Dashboard.Sensor { + class Flex4gridpower : ASensor { + private String id; + + public Flex4gridpower(Dictionary settings, String name, ADataBackend backend) : base(settings, name, backend) { + this.Datatypes = Types.Float; + this.id = settings["id"]; + } + + protected override Boolean UpdateValue(MqttEventArgs e) { + 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; + try { + JsonData data = JsonMapper.ToObject(e.Message); + if(data["id"].ToString() == this.id) { + this.GetFloat = Single.Parse(data["power"].ToString()); + return true; + } + } catch (Exception) { + } + return false; + } + } +} diff --git a/Mqtt-Dashboard/Mqtt-Dashboard/Sensor/Luminanz.cs b/Mqtt-Dashboard/Mqtt-Dashboard/Sensor/Luminanz.cs new file mode 100644 index 0000000..1e5eb9f --- /dev/null +++ b/Mqtt-Dashboard/Mqtt-Dashboard/Sensor/Luminanz.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Text; +using uPLibrary.Networking.M2Mqtt.Messages; + +namespace Dashboard.Sensor { + class Luminanz : ASensor { + public Luminanz(Dictionary settings) : base(settings) { + this.GetBool = true; + this.GetFloat = 0.0f; + this.GetInt = 0; + this.Datatypes = Types.Int; + } + + protected override void UpdateValue(MqttMsgPublishEventArgs e) { + this.GetInt = Int32.Parse(Encoding.UTF8.GetString(e.Message), new CultureInfo("en-US")); + } + } +} diff --git a/Mqtt-Dashboard/Mqtt-Dashboard/Sensor/Pir.cs b/Mqtt-Dashboard/Mqtt-Dashboard/Sensor/Pir.cs new file mode 100644 index 0000000..79f8d8f --- /dev/null +++ b/Mqtt-Dashboard/Mqtt-Dashboard/Sensor/Pir.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Text; +using uPLibrary.Networking.M2Mqtt.Messages; + +namespace Dashboard.Sensor { + class Pir : ASensor { + public Pir(Dictionary settings) : base(settings) { + this.Datatypes = Types.Bool; + } + + protected override void UpdateValue(MqttMsgPublishEventArgs e) { + this.GetBool = (Encoding.UTF8.GetString(e.Message).ToLower() == "on") ? true : false; + } + } +} \ No newline at end of file diff --git a/Mqtt-Dashboard/Mqtt-Dashboard/Sensor/Power.cs b/Mqtt-Dashboard/Mqtt-Dashboard/Sensor/Power.cs new file mode 100644 index 0000000..d796e1b --- /dev/null +++ b/Mqtt-Dashboard/Mqtt-Dashboard/Sensor/Power.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using Dashboard.Connector; + +namespace Dashboard.Sensor { + class Power : ASensor { + public Power(Dictionary settings, String name, ADataBackend backend) : base(settings, name, backend) { + this.GetBool = true; + this.GetFloat = 0.0f; + this.GetInt = 0; + this.Datatypes = Types.Float; + } + + protected override Boolean UpdateValue(MqttEventArgs e) { + this.GetFloat = Single.Parse(e.Message, new CultureInfo("en-US")); + return true; + } + } +} diff --git a/Mqtt-Dashboard/Mqtt-Dashboard/Sensor/Switch.cs b/Mqtt-Dashboard/Mqtt-Dashboard/Sensor/Switch.cs new file mode 100644 index 0000000..7537208 --- /dev/null +++ b/Mqtt-Dashboard/Mqtt-Dashboard/Sensor/Switch.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using Dashboard.Connector; + +namespace Dashboard.Sensor { + class Switch : ASensor { + public Switch(Dictionary settings, String name, ADataBackend backend) : base(settings, name, backend) { + this.Datatypes = Types.Bool; + } + + protected override Boolean UpdateValue(MqttEventArgs e) { + this.GetBool = (e.Message.ToLower() == "on") ? true : false; + return true; + } + } +} \ No newline at end of file diff --git a/Mqtt-Dashboard/Mqtt-Dashboard/Sensor/Temperatur.cs b/Mqtt-Dashboard/Mqtt-Dashboard/Sensor/Temperatur.cs new file mode 100644 index 0000000..702b871 --- /dev/null +++ b/Mqtt-Dashboard/Mqtt-Dashboard/Sensor/Temperatur.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Text; +using uPLibrary.Networking.M2Mqtt.Messages; + +namespace Dashboard.Sensor { + class Temperatur : ASensor { + public Temperatur(Dictionary settings) : base(settings) { + this.GetBool = true; + this.GetFloat = 0.0f; + this.GetInt = 0; + this.Datatypes = Types.Float; + } + + protected override void UpdateValue(MqttMsgPublishEventArgs e) { + this.GetFloat = Single.Parse(Encoding.UTF8.GetString(e.Message), new CultureInfo("en-US")); + } + } +} \ No newline at end of file diff --git a/Mqtt-Dashboard/Mqtt-Dashboard/Tracings/ATracings.cs b/Mqtt-Dashboard/Mqtt-Dashboard/Tracings/ATracings.cs new file mode 100644 index 0000000..e400472 --- /dev/null +++ b/Mqtt-Dashboard/Mqtt-Dashboard/Tracings/ATracings.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using System.Windows.Forms; +using Dashboard.Sensor; + +namespace Dashboard.Tracings { + public abstract class ATracings { + protected ASensor sensor; + protected Dictionary settings; + protected Dictionary sensors; + + public ATracings(ASensor sensor, Dictionary settings) { + this.sensor = sensor; + this.sensor.Update += this.SensorUpdate; + this.settings = settings; + } + public ATracings(Dictionary sensors, Dictionary settings) { + this.sensors = sensors; + foreach(KeyValuePair sensor in this.sensors) { + sensor.Value.Update += this.SensorsUpdate; + } + this.settings = settings; + } + + protected abstract void SensorsUpdate(ASensor sender, EventArgs e); + protected abstract void SensorUpdate(ASensor sender, EventArgs e); + public abstract Panel GetPanel(); + internal static ATracings GetInstance(String v, Dictionary sensorList, Dictionary dictionary) { + String object_sensor = "Dashboard.Tracings." + Char.ToUpper(v[0]) + v.Substring(1); + Type t = null; + try { + t = Type.GetType(object_sensor, true); + } catch (TypeLoadException) { + throw new ArgumentException("tracings.ini: " + v + " is not a Tracing"); + } + if (dictionary["sensor"].Contains(",")) { + Dictionary sensors = new Dictionary(); + String[] sensors_name = dictionary["sensor"].Split(','); + foreach (String item in sensors_name) { + sensors.Add(item, sensorList[item.ToLower()]); + } + return (ATracings)t.GetConstructor(new Type[] { typeof(Dictionary), typeof(Dictionary) }).Invoke(new Object[] { sensors, dictionary }); + } else { + return (ATracings)t.GetConstructor(new Type[] { typeof(ASensor), typeof(Dictionary) }).Invoke(new Object[] { sensorList[dictionary["sensor"].ToLower()], dictionary }); + } + } + } +} \ No newline at end of file diff --git a/Mqtt-Dashboard/Mqtt-Dashboard/Tracings/Graph.cs b/Mqtt-Dashboard/Mqtt-Dashboard/Tracings/Graph.cs new file mode 100644 index 0000000..7bb1d2e --- /dev/null +++ b/Mqtt-Dashboard/Mqtt-Dashboard/Tracings/Graph.cs @@ -0,0 +1,156 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Windows.Forms; +using Dashboard.Sensor; +using OxyPlot; +using OxyPlot.Axes; +using OxyPlot.Series; +using OxyPlot.WindowsForms; + +namespace Dashboard.Tracings { + class Graph : ATracings, IDisposable { + private Queue> hist = new Queue>(); + private Dictionary>> hists = new Dictionary>>(); + private Dictionary hists_last = new Dictionary(); + private Int32 Chart_Items; + private PlotView plot = new PlotView { BackColor = System.Drawing.Color.White }; + private PlotModel Model = new PlotModel(); + private Boolean multi; + private Single MaximumDrawn = 1; + + private String[] colors = { "255,255,0,0","255,230,230,0", "255,0,128,0", "255,0,0,255", "255,255,0,255", "255,255,128,0", "255,0,255,255", "255,158,255,128", "255,0,128,255", "255,0,0,0" }; + + public Graph(ASensor sensor, Dictionary settings) : base(sensor, settings) { + this.Chart_Items = (settings.Keys.Contains("items")) ? Int32.Parse(settings["items"]) : 1000; + this.multi = false; + } + + public Graph(Dictionary sensors, Dictionary settings) : base(sensors, settings) { + this.Chart_Items = (settings.Keys.Contains("items")) ? Int32.Parse(settings["items"]) : 1000; + this.multi = true; + } + + public override Panel GetPanel() { + Panel panel = new Panel { BorderStyle = BorderStyle.FixedSingle }; + + 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 }); + if (this.multi) { + Int32 i = 0; + foreach (KeyValuePair item in this.sensors) { + LineSeries l = new LineSeries { Color = OxyColor.Parse(this.colors[i++ % this.colors.Length]), TrackerKey = item.Value.Name }; + if (item.Value.Title != "") { + l.Title = item.Value.Title; + } + this.Model.Series.Add(l); + } + } else { + LineSeries l = new LineSeries { Color = OxyColor.FromRgb(0, 0, 255) }; + l.CanTrackerInterpolatePoints = true; + if (this.sensor.Title != "") { + l.Title = this.sensor.Title; + } + this.Model.Series.Add(l); + } + + Int32 fieldWidth = 200; + if(this.multi) { + fieldWidth = (this.sensors.Count * 200) + (this.sensors.Count-1)*6; + } + + this.plot.Location = new System.Drawing.Point(0, 0); + this.plot.Size = new System.Drawing.Size(fieldWidth, 200); + this.plot.Dock = DockStyle.Fill; + this.plot.Model = this.Model; + panel.Controls.Add(this.plot); + + panel.Size = new System.Drawing.Size(fieldWidth, 200); + return panel; + } + protected override void SensorUpdate(ASensor sender, EventArgs e) { + Single v = 0; + switch (sender.Datatypes) { + case ASensor.Types.Bool: v = sender.GetBool ? 1 : 0; break; + case ASensor.Types.Int: v = sender.GetInt; break; + case ASensor.Types.Float: v = sender.GetFloat; break; + } + this.hist.Enqueue(new Tuple(sender.Timestamp, v)); + if (this.MaximumDrawn < v) { + this.MaximumDrawn = v; + } + if (this.hist.Count > this.Chart_Items) { + this.hist.Dequeue(); + } + if (this.Model.Series.Count != 0) { + this.plot.BeginInvoke((MethodInvoker)delegate { + this.Model.Axes[1].Maximum = this.MaximumDrawn * 1.1; + this.Model.Axes[1].AbsoluteMaximum = this.MaximumDrawn * 1.1; + this.Model.Axes[0].AbsoluteMaximum = DateTimeAxis.ToDouble(sender.Timestamp); + ((LineSeries)this.Model.Series[0]).Points.Clear(); + try { + foreach(Tuple temp in this.hist) { + ((LineSeries)this.Model.Series[0]).Points.Add(new DataPoint(DateTimeAxis.ToDouble(temp.Item1),temp.Item2)); + } + this.Model.InvalidatePlot(true); + } catch(Exception) { }; + }); + } + } + + protected override void SensorsUpdate(ASensor sender, EventArgs e) { + Single v = 0; + if (!this.hists.ContainsKey(sender.Name)) { + this.hists.Add(sender.Name, new Queue>()); + this.hists_last.Add(sender.Name, 0); + } + switch (sender.Datatypes) { + case ASensor.Types.Bool: + v = sender.GetBool ? 1 : 0; + break; + case ASensor.Types.Int: + v = sender.GetInt; + break; + case ASensor.Types.Float: + v = sender.GetFloat; + break; + } + this.hists_last[sender.Name] = v; + foreach (KeyValuePair>> item in this.hists) { + item.Value.Enqueue(new Tuple(sender.Timestamp, this.hists_last[item.Key])); + if (this.MaximumDrawn < this.hists_last[item.Key]) { + this.MaximumDrawn = this.hists_last[item.Key]; + } + if (item.Value.Count > this.Chart_Items) { + item.Value.Dequeue(); + } + } + foreach (Series item in this.Model.Series) { + if (this.hists.ContainsKey(item.TrackerKey)) { + this.plot.BeginInvoke((MethodInvoker)delegate { + try { + this.Model.Axes[1].Maximum = this.MaximumDrawn * 1.1; + this.Model.Axes[1].AbsoluteMaximum = this.MaximumDrawn * 1.1; + this.Model.Axes[0].AbsoluteMaximum = DateTimeAxis.ToDouble(sender.Timestamp); + ((LineSeries)item).Points.Clear(); + foreach (Tuple temp in this.hists[item.TrackerKey]) { + ((LineSeries)item).Points.Add(new DataPoint(DateTimeAxis.ToDouble(temp.Item1), temp.Item2)); + } + this.Model.InvalidatePlot(true); + } catch (Exception) { }; + }); + } + } + } + + public void Dispose() { + ((LineSeries)this.Model.Series[0]).Points.Clear(); + this.Model = null; + this.hist.Clear(); + this.hist = null; + this.plot.Dispose(); + } + + + } +} diff --git a/Mqtt-Dashboard/Mqtt-Dashboard/Tracings/Meter.cs b/Mqtt-Dashboard/Mqtt-Dashboard/Tracings/Meter.cs new file mode 100644 index 0000000..928f9aa --- /dev/null +++ b/Mqtt-Dashboard/Mqtt-Dashboard/Tracings/Meter.cs @@ -0,0 +1,71 @@ +using System.Collections.Generic; +using Dashboard.Sensor; +using System; +using System.Windows.Forms; +using System.Linq; +using System.Globalization; + +namespace Dashboard.Tracings { + class Meter : ATracings { + protected Int32 DisplayItems; + protected Queue DisplayAverage = new Queue(); + protected Label label1; + protected Label label2; + + public Meter(ASensor sensor, Dictionary settings) : base(sensor, settings) { + this.DisplayItems = (settings.Keys.Contains("items")) ? Int32.Parse(settings["items"]) : 1000; + + this.label1 = new Label(); + this.label2 = new Label(); + } + public override Panel GetPanel() { + Panel panel = new Panel() { + BorderStyle = BorderStyle.FixedSingle, + Size = new System.Drawing.Size(200, 100) + }; + + this.label1 = new Label() { + Font = new System.Drawing.Font("Lucida Sans Typewriter", 27.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((Byte)(0))), + Location = new System.Drawing.Point(0, 0), + Size = new System.Drawing.Size(200, 43), + Text = "", + TextAlign = System.Drawing.ContentAlignment.TopCenter + }; + panel.Controls.Add(this.label1); + + this.label2 = new Label() { + AutoSize = true, + Location = new System.Drawing.Point(0, 50), + Size = new System.Drawing.Size(96, 13), + Text = "" + }; + panel.Controls.Add(this.label2); + + + return panel; + } + + protected override void SensorsUpdate(ASensor sender, EventArgs e) { + throw new NotImplementedException(); + } + + protected override void SensorUpdate(ASensor sender, EventArgs e) { + String value = ""; + switch(sender.Datatypes) { + case ASensor.Types.Bool: this.DisplayAverage.Enqueue((sender.GetBool) ? 1 : 0); value = sender.GetBool.ToString(new CultureInfo("de-DE")); break; + case ASensor.Types.Int: this.DisplayAverage.Enqueue(sender.GetInt); value = sender.GetInt.ToString(); break; + case ASensor.Types.Float: this.DisplayAverage.Enqueue(sender.GetFloat); value = sender.GetFloat.ToString(new CultureInfo("de-DE")); break; + } + if(this.DisplayAverage.Count > this.DisplayItems) { + this.DisplayAverage.Dequeue(); + } + Single average = this.DisplayAverage.Sum() / this.DisplayAverage.Count(); + this.label1.BeginInvoke((MethodInvoker)delegate { + this.label1.Text = value; + }); + this.label2.BeginInvoke((MethodInvoker)delegate { + this.label2.Text = "Durchschnitt: " + Math.Round(average, 2); + }); + } + } +} \ No newline at end of file diff --git a/Mqtt-Dashboard/Mqtt-Dashboard/Tracings/PowerMeter.cs b/Mqtt-Dashboard/Mqtt-Dashboard/Tracings/PowerMeter.cs new file mode 100644 index 0000000..3a4b3ca --- /dev/null +++ b/Mqtt-Dashboard/Mqtt-Dashboard/Tracings/PowerMeter.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Windows.Forms; +using Dashboard.Sensor; + +namespace Dashboard.Tracings { + class Powermeter : Meter { + public Powermeter(ASensor sensor, Dictionary settings) : base(sensor, settings) { + } + protected override void SensorUpdate(ASensor sender, EventArgs e) { + String value = ""; + switch (sender.Datatypes) { + case ASensor.Types.Bool: + this.DisplayAverage.Enqueue((sender.GetBool) ? 1 : 0); + value = sender.GetBool.ToString(new CultureInfo("de-DE")); + break; + case ASensor.Types.Int: + this.DisplayAverage.Enqueue(sender.GetInt); + value = sender.GetInt.ToString(); + break; + case ASensor.Types.Float: + this.DisplayAverage.Enqueue(sender.GetFloat); + value = sender.GetFloat.ToString(new CultureInfo("de-DE")); + break; + } + if (this.DisplayAverage.Count > this.DisplayItems) { + this.DisplayAverage.Dequeue(); + } + Single average = this.DisplayAverage.Sum() / this.DisplayAverage.Count(); + try { + this.label1.BeginInvoke((MethodInvoker)delegate { + this.label1.Text = value + " W"; + }); + this.label2.BeginInvoke((MethodInvoker)delegate { + this.label2.Text = "Durchschnitt: " + Math.Round(average, 2) + " W"; + }); + } catch (Exception) { } + } + } +} diff --git a/Mqtt-Dashboard/Mqtt-Dashboard/Tracings/Switcher.cs b/Mqtt-Dashboard/Mqtt-Dashboard/Tracings/Switcher.cs new file mode 100644 index 0000000..83679f4 --- /dev/null +++ b/Mqtt-Dashboard/Mqtt-Dashboard/Tracings/Switcher.cs @@ -0,0 +1,84 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Windows.Forms; +using Dashboard.Connector; +using Dashboard.Sensor; + +namespace Dashboard.Tracings { + class Switcher : ATracings { + private Label label; + private Button button1; + private Button button2; + + public Switcher(ASensor sensor, Dictionary settings) : base(sensor, settings) { + this.label = new Label(); + this.button1 = new Button(); + this.button2 = new Button(); + } + + public override Panel GetPanel() { + Panel panel = new Panel() { + BorderStyle = BorderStyle.FixedSingle, + Size = new System.Drawing.Size(200, 100) + }; + + this.label = new Label() { + AutoSize = true, + Location = new System.Drawing.Point(69, 16), + Size = new System.Drawing.Size(35, 13), + Text = "" + }; + panel.Controls.Add(this.label); + + this.button1 = new Button() { + BackColor = System.Drawing.Color.FromArgb(0, 192, 0), + Location = new System.Drawing.Point(94, 67), + Name = "on", + Size = new System.Drawing.Size(45, 23), + Text = "ON", + UseVisualStyleBackColor = false + }; + this.button1.Click += this.ButtonClicker; + panel.Controls.Add(this.button1); + + this.button2 = new Button() { + BackColor = System.Drawing.Color.Red, + Location = new System.Drawing.Point(145, 67), + Name = "off", + Size = new System.Drawing.Size(45, 23), + Text = "OFF", + UseVisualStyleBackColor = false + }; + this.button2.Click += this.ButtonClicker; + panel.Controls.Add(this.button2); + + return panel; + } + + private void ButtonClicker(Object sender, EventArgs e) { + Button b = (Button)sender; + if (b.Name == "on") { + this.sensor.SetBool(true); + } else if(b.Name == "off") { + this.sensor.SetBool(false); + } + } + + protected override void SensorUpdate(ASensor sender, EventArgs e) { + this.label.BeginInvoke((MethodInvoker)delegate { + this.label.Text = sender.GetBool?"Eingeschaltet":"Ausgeschaltet"; + }); + this.button1.BeginInvoke((MethodInvoker)delegate { + this.button1.Enabled = !sender.GetBool; + }); + this.button2.BeginInvoke((MethodInvoker)delegate { + this.button2.Enabled = sender.GetBool; + }); + } + + protected override void SensorsUpdate(ASensor sender, EventArgs e) { + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/Mqtt-Dashboard/Mqtt-Dashboard/bin/Release/Dashboard.exe b/Mqtt-Dashboard/Mqtt-Dashboard/bin/Release/Dashboard.exe new file mode 100644 index 0000000..e190e87 Binary files /dev/null and b/Mqtt-Dashboard/Mqtt-Dashboard/bin/Release/Dashboard.exe differ diff --git a/Mqtt-Dashboard/Mqtt-Dashboard/bin/Release/LitJson.dll b/Mqtt-Dashboard/Mqtt-Dashboard/bin/Release/LitJson.dll new file mode 100644 index 0000000..f00f11f Binary files /dev/null and b/Mqtt-Dashboard/Mqtt-Dashboard/bin/Release/LitJson.dll differ diff --git a/Mqtt-Dashboard/Mqtt-Dashboard/bin/Release/M2Mqtt.Net.dll b/Mqtt-Dashboard/Mqtt-Dashboard/bin/Release/M2Mqtt.Net.dll new file mode 100644 index 0000000..154580d Binary files /dev/null and b/Mqtt-Dashboard/Mqtt-Dashboard/bin/Release/M2Mqtt.Net.dll differ diff --git a/Mqtt-Dashboard/Mqtt-Dashboard/bin/Release/OxyPlot.WindowsForms.dll b/Mqtt-Dashboard/Mqtt-Dashboard/bin/Release/OxyPlot.WindowsForms.dll new file mode 100644 index 0000000..4bde2bd Binary files /dev/null and b/Mqtt-Dashboard/Mqtt-Dashboard/bin/Release/OxyPlot.WindowsForms.dll differ diff --git a/Mqtt-Dashboard/Mqtt-Dashboard/bin/Release/OxyPlot.dll b/Mqtt-Dashboard/Mqtt-Dashboard/bin/Release/OxyPlot.dll new file mode 100644 index 0000000..388e1dc Binary files /dev/null and b/Mqtt-Dashboard/Mqtt-Dashboard/bin/Release/OxyPlot.dll differ diff --git a/Mqtt-Dashboard/Mqtt-Dashboard/bin/Release/Utils.dll b/Mqtt-Dashboard/Mqtt-Dashboard/bin/Release/Utils.dll new file mode 100644 index 0000000..28f5d3d Binary files /dev/null and b/Mqtt-Dashboard/Mqtt-Dashboard/bin/Release/Utils.dll differ diff --git a/Mqtt-Dashboard/Mqtt-Dashboard/packages.config b/Mqtt-Dashboard/Mqtt-Dashboard/packages.config new file mode 100644 index 0000000..ee578a6 --- /dev/null +++ b/Mqtt-Dashboard/Mqtt-Dashboard/packages.config @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/Mqtt-Dashboard/Mqtt-Dashboard/sensor.ini.example b/Mqtt-Dashboard/Mqtt-Dashboard/sensor.ini.example new file mode 100644 index 0000000..bb9c314 --- /dev/null +++ b/Mqtt-Dashboard/Mqtt-Dashboard/sensor.ini.example @@ -0,0 +1,24 @@ +[Thinkpad] +topic=zway/wohnzimmer/thinkpad/power +type=Power +polling=10 + +[Tv] +topic=zway/wohnzimmer/tV/power +type=Power +polling=10 + +[Kühlschrank] +topic=zway/küche/kuehlschrank/power +type=Power +polling=10 + +[TvSW] +topic=zway/wohnzimmer/tV/switch +type=switch +polling=10 + +;[Ventilator] +;topic=zway/power/test/wVentilator +;type=Power +;polling=10 \ No newline at end of file diff --git a/Mqtt-Dashboard/Mqtt-Dashboard/settings.ini.example b/Mqtt-Dashboard/Mqtt-Dashboard/settings.ini.example new file mode 100644 index 0000000..ed05fa8 --- /dev/null +++ b/Mqtt-Dashboard/Mqtt-Dashboard/settings.ini.example @@ -0,0 +1,3 @@ +[mqtt] +type=mqtt +server=localhost \ No newline at end of file diff --git a/Mqtt-Dashboard/Mqtt-Dashboard/tracings.ini.example b/Mqtt-Dashboard/Mqtt-Dashboard/tracings.ini.example new file mode 100644 index 0000000..d0ad8f0 --- /dev/null +++ b/Mqtt-Dashboard/Mqtt-Dashboard/tracings.ini.example @@ -0,0 +1,45 @@ +[ThinkpadMeter] +sensor=Thinkpad +type=PowerMeter +items=100 + +[TvMeter] +sensor=Tv +type=PowerMeter +items=100 + +[KühlschrankrMeter] +sensor=Kühlschrank +type=PowerMeter +items=100 + +[ThinkpadGraph] +sensor=Thinkpad +type=Graph +items=100 + +[TvGraph] +sensor=Tv +type=Graph +items=100 + +[KühlschrankGraph] +sensor=Kühlschrank +type=Graph +items=100 + +[TvSWMeter] +sensor=TvSW +type=Switcher +items=100 + +;[VentilatorGraph] +;sensor=Ventilator +;type=Graph +;items=100 + +;[VentilatorMeter] +;sensor=Ventilator +;type=Meter +;unit=W +;items=100 \ No newline at end of file diff --git a/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard.sln b/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard.sln new file mode 100644 index 0000000..8ea20d1 --- /dev/null +++ b/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard.sln @@ -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 diff --git a/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/App.config b/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/App.config new file mode 100644 index 0000000..731f6de --- /dev/null +++ b/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/App.xaml b/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/App.xaml new file mode 100644 index 0000000..e67d8be --- /dev/null +++ b/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/App.xaml @@ -0,0 +1,9 @@ + + + + + diff --git a/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/App.xaml.cs b/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/App.xaml.cs new file mode 100644 index 0000000..c7d79b2 --- /dev/null +++ b/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/App.xaml.cs @@ -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 { + /// + /// Interaktionslogik für "App.xaml" + /// + public partial class App : Application { + } +} diff --git a/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/Helper/Device.cs b/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/Helper/Device.cs new file mode 100644 index 0000000..95074df --- /dev/null +++ b/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/Helper/Device.cs @@ -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()); + } + } + } +} diff --git a/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/Helper/Household.cs b/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/Helper/Household.cs new file mode 100644 index 0000000..47e301d --- /dev/null +++ b/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/Helper/Household.cs @@ -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 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 { + { did, device } + }; + } + + public Household(JsonData data) { + this.Devices = new SortedDictionary(); + if (data.Keys.Contains("Devices")) { + foreach (KeyValuePair 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 item in this.Devices) { + if (item.Value.TimeStamp > DateTime.Now.AddMinutes(-10)) { + ret++; + } + } + return ret; + } + + 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) { + ret += item.Value.Power; + } + } + return ret; + } + + internal Double GetAllPower() { + Double ret = 0; + foreach (KeyValuePair 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 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 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; + } + } + } +} diff --git a/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/Helper/Raspi.cs b/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/Helper/Raspi.cs new file mode 100644 index 0000000..3445a39 --- /dev/null +++ b/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/Helper/Raspi.cs @@ -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; + } + } + } + } +} \ No newline at end of file diff --git a/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/MainWindow.xaml b/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/MainWindow.xaml new file mode 100644 index 0000000..4b53fbf --- /dev/null +++ b/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/MainWindow.xaml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/MainWindow.xaml.cs b/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/MainWindow.xaml.cs new file mode 100644 index 0000000..19c04f9 --- /dev/null +++ b/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/MainWindow.xaml.cs @@ -0,0 +1,56 @@ +using BlubbFish.Utils; +using System; +using System.Globalization; +using System.Windows; + +namespace Mqtt_SWB_Dashboard { + /// + /// Interaktionslogik für MainWindow.xaml + /// + 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 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); + })); + } + + private void OnClosed(Object sender, EventArgs e) { + this.s.Dispose(); + } + } +} diff --git a/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/Models/PowerChartModel.cs b/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/Models/PowerChartModel.cs new file mode 100644 index 0000000..0621698 --- /dev/null +++ b/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/Models/PowerChartModel.cs @@ -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 power, Tuple 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; } + + + } +} diff --git a/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/Mosquitto.cs b/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/Mosquitto.cs new file mode 100644 index 0000000..597b5f5 --- /dev/null +++ b/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/Mosquitto.cs @@ -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; } + } +} diff --git a/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard.csproj b/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard.csproj new file mode 100644 index 0000000..7037cb8 --- /dev/null +++ b/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard.csproj @@ -0,0 +1,122 @@ + + + + + Debug + AnyCPU + {324B2308-7C6E-4F16-8764-7C2F8C342B6A} + WinExe + Mqtt_SWB_Dashboard + Mqtt-SWB-Dashboard + v4.6.1 + 512 + {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 4 + true + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\packages\LitJson.0.9.0\lib\LitJson.dll + + + ..\packages\OxyPlot.Core.1.0.0\lib\net45\OxyPlot.dll + + + ..\packages\OxyPlot.Wpf.1.0.0\lib\net45\OxyPlot.Wpf.dll + + + + + + + + + + + 4.0 + + + + + + + + MSBuild:Compile + Designer + + + + + + + + MSBuild:Compile + Designer + + + App.xaml + Code + + + MainWindow.xaml + Code + + + + + + Code + + + True + True + Resources.resx + + + True + Settings.settings + True + + + ResXFileCodeGenerator + Resources.Designer.cs + + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + + + + + + + + + {fac8ce64-bf13-4ece-8097-aeb5dd060098} + Utils + + + + \ No newline at end of file diff --git a/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/Properties/AssemblyInfo.cs b/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..1746479 --- /dev/null +++ b/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/Properties/AssemblyInfo.cs @@ -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 +//ImCodeVerwendeteKultur in der .csproj-Datei +//in einer fest. Wenn Sie in den Quelldateien beispielsweise Deutsch +//(Deutschland) verwenden, legen Sie 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("")] + diff --git a/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/Properties/Resources.Designer.cs b/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/Properties/Resources.Designer.cs new file mode 100644 index 0000000..ffb2064 --- /dev/null +++ b/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/Properties/Resources.Designer.cs @@ -0,0 +1,62 @@ +//------------------------------------------------------------------------------ +// +// 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. +// +//------------------------------------------------------------------------------ + +namespace Mqtt_SWB_Dashboard.Properties { + + + /// + /// Eine stark typisierte Ressourcenklasse zum Suchen von lokalisierten Zeichenfolgen usw. + /// + // 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() { + } + + /// + /// Gibt die zwischengespeicherte ResourceManager-Instanz zurück, die von dieser Klasse verwendet wird. + /// + [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; + } + } + + /// + /// Überschreibt die CurrentUICulture-Eigenschaft des aktuellen Threads für alle + /// Ressourcenlookups, die diese stark typisierte Ressourcenklasse verwenden. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + } +} diff --git a/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/Properties/Resources.resx b/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/Properties/Resources.resx new file mode 100644 index 0000000..af7dbeb --- /dev/null +++ b/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/Properties/Resources.resx @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/Properties/Settings.Designer.cs b/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/Properties/Settings.Designer.cs new file mode 100644 index 0000000..d9f1ade --- /dev/null +++ b/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/Properties/Settings.Designer.cs @@ -0,0 +1,26 @@ +//------------------------------------------------------------------------------ +// +// 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. +// +//------------------------------------------------------------------------------ + +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; + } + } + } +} diff --git a/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/Properties/Settings.settings b/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/Properties/Settings.settings new file mode 100644 index 0000000..033d7a5 --- /dev/null +++ b/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/Properties/Settings.settings @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/Stats.cs b/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/Stats.cs new file mode 100644 index 0000000..5d707d3 --- /dev/null +++ b/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/Stats.cs @@ -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 households = new SortedDictionary(); + private SortedDictionary raspis = new SortedDictionary(); + 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 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 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 + + /// + /// LogMessages eines Raspis + /// + /// + 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 + } + + /// + /// Nachrichten des LVC-Images + /// + /// + 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 + } + + /// + /// Nachricht wenn ein gerät umgeschaltet werden soll von der App aus. + /// + /// + 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 + } + + /// + /// Status der Geräte von der App aus abfragen und den Schaltzustand antworten + /// + /// + 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 + } + + /// + /// Schaltstatus, Stromverbrauch und Produktion von PowerPlugs + /// + /// + 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) { + } + } + + /// + /// Nachricht ob ein Haushalt (gateway_plugs_1) verbunden ist (Vermutlich vom Master) + /// + /// + 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) { + } + } + + /// + /// Nachricht ob ein Raspi Verbunden ist (liefert die lvc Werte?) + /// + /// + 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 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 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 GetCurrentPower() { + Double active = 0; + Double all = 0; + try { + foreach (KeyValuePair item in this.households) { + active += item.Value.GetPower(); + all += item.Value.GetAllPower(); + } + } catch(Exception) { + return new Tuple(0d, 0d); + } + return new Tuple(active, all); + } + + internal Tuple GetCurrentColum() { + Double active = 0; + Double all = 0; + try { + foreach (KeyValuePair item in this.households) { + active += item.Value.GetColum(); + all += item.Value.GetAllColum(); + } + } catch(Exception) { + return new Tuple(0d, 0d); + } + return new Tuple(active, all); + } + + internal String GetNumberRaspis() { + Int32 active = 0; + Int32 all = this.raspis.Count; + try { + foreach (KeyValuePair 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 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 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 + } +} \ No newline at end of file diff --git a/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/bin/Release/LitJson.dll b/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/bin/Release/LitJson.dll new file mode 100644 index 0000000..f00f11f Binary files /dev/null and b/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/bin/Release/LitJson.dll differ 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 new file mode 100644 index 0000000..b775cc4 Binary files /dev/null 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/OxyPlot.Wpf.dll b/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/bin/Release/OxyPlot.Wpf.dll new file mode 100644 index 0000000..04d8c34 Binary files /dev/null and b/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/bin/Release/OxyPlot.Wpf.dll differ diff --git a/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/bin/Release/OxyPlot.dll b/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/bin/Release/OxyPlot.dll new file mode 100644 index 0000000..388e1dc Binary files /dev/null and b/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/bin/Release/OxyPlot.dll 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 new file mode 100644 index 0000000..7edc0ad Binary files /dev/null and b/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/bin/Release/Utils.dll differ diff --git a/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/packages.config b/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/packages.config new file mode 100644 index 0000000..d70f7b9 --- /dev/null +++ b/Mqtt-SWB-Dashboard/Mqtt-SWB-Dashboard/packages.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/MqttToTelegram/MqttToTelegram.sln b/MqttToTelegram/MqttToTelegram.sln new file mode 100644 index 0000000..fc19be2 --- /dev/null +++ b/MqttToTelegram/MqttToTelegram.sln @@ -0,0 +1,22 @@ + +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}") = "MqttToTelegram", "MqttToTelegram\MqttToTelegram.csproj", "{89077643-B472-419F-8EAB-56B9E2D13ABC}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {89077643-B472-419F-8EAB-56B9E2D13ABC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {89077643-B472-419F-8EAB-56B9E2D13ABC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {89077643-B472-419F-8EAB-56B9E2D13ABC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {89077643-B472-419F-8EAB-56B9E2D13ABC}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/MqttToTelegram/MqttToTelegram/App.config b/MqttToTelegram/MqttToTelegram/App.config new file mode 100644 index 0000000..88fa402 --- /dev/null +++ b/MqttToTelegram/MqttToTelegram/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/MqttToTelegram/MqttToTelegram/Mqtt.cs b/MqttToTelegram/MqttToTelegram/Mqtt.cs new file mode 100644 index 0000000..e0ccfa0 --- /dev/null +++ b/MqttToTelegram/MqttToTelegram/Mqtt.cs @@ -0,0 +1,37 @@ +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 + + + + Debug + AnyCPU + {89077643-B472-419F-8EAB-56B9E2D13ABC} + Exe + Properties + MqttToTelegram + MqttToTelegram + v4.5.2 + 512 + true + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\packages\M2Mqtt.4.3.0.0\lib\net45\M2Mqtt.Net.dll + True + + + ..\packages\Newtonsoft.Json.10.0.3\lib\net45\Newtonsoft.Json.dll + True + + + + + + + + ..\packages\System.Runtime.InteropServices.RuntimeInformation.4.3.0\lib\net45\System.Runtime.InteropServices.RuntimeInformation.dll + True + + + + + + + + + ..\packages\Telegram.Bot.13.1.0\lib\netstandard1.1\Telegram.Bot.dll + True + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/MqttToTelegram/MqttToTelegram/Program.cs b/MqttToTelegram/MqttToTelegram/Program.cs new file mode 100644 index 0000000..799b7d0 --- /dev/null +++ b/MqttToTelegram/MqttToTelegram/Program.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MqttToTelegram { + class Program { + static void Main(string[] args) { + Mqtt.Instance.Subscripe(new string[]{ "#"}); + Messenger.Instance.bla(); + while(true) { + System.Threading.Thread.Sleep(100); + } + } + } +} diff --git a/MqttToTelegram/MqttToTelegram/Properties/AssemblyInfo.cs b/MqttToTelegram/MqttToTelegram/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..2574141 --- /dev/null +++ b/MqttToTelegram/MqttToTelegram/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// 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("MqttToTelegram")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("MqttToTelegram")] +[assembly: AssemblyCopyright("Copyright © 2017")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Durch Festlegen von ComVisible auf "false" werden die Typen in dieser Assembly unsichtbar +// für COM-Komponenten. 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)] + +// Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird +[assembly: Guid("89077643-b472-419f-8eab-56b9e2d13abc")] + +// Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten: +// +// Hauptversion +// Nebenversion +// Buildnummer +// Revision +// +// Sie können alle Werte angeben oder die standardmäßigen Build- und Revisionsnummern +// übernehmen, indem Sie "*" eingeben: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/MqttToTelegram/MqttToTelegram/Telegram.cs b/MqttToTelegram/MqttToTelegram/Telegram.cs new file mode 100644 index 0000000..b18422e --- /dev/null +++ b/MqttToTelegram/MqttToTelegram/Telegram.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Telegram.Bot; + +namespace MqttToTelegram { + class Messenger { + private static Messenger instance; + private TelegramBotClient bot; + + private Messenger() { + bot = new TelegramBotClient(""); + bot.OnMessage += Bot_OnMessage; + } + + private void Bot_OnMessage(Object sender, Telegram.Bot.Args.MessageEventArgs e) { + Console.WriteLine("Telegram: " + e.Message.Text); + } + + public static Messenger Instance { + get { + if(instance == null) { + instance = new Messenger(); + } + return instance; + } + } + + public void bla() { + bot.StartReceiving(); + } + } +} diff --git a/MqttToTelegram/MqttToTelegram/packages.config b/MqttToTelegram/MqttToTelegram/packages.config new file mode 100644 index 0000000..709db32 --- /dev/null +++ b/MqttToTelegram/MqttToTelegram/packages.config @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/TimeKeeper/Arduino/Display/Display.ino b/TimeKeeper/Arduino/Display/Display.ino new file mode 100644 index 0000000..92a426f --- /dev/null +++ b/TimeKeeper/Arduino/Display/Display.ino @@ -0,0 +1,85 @@ +#include + +#define MAX_STORE_DATA 8 + +void setup() { + Serial.begin(9600); + Serial.println("Init...."); + Rb.init(); + Serial.println("Init finished!"); +} + +String store[MAX_STORE_DATA]; +int count = 0; + +String msg; +char c; +void loop() { + if (Serial.available()) { + c = Serial.read(); + if (c == '\n') { + parse(msg); + msg = ""; + } else { + msg += c; + } + } +} + +void parse(String text) { + text.trim(); + String action = ""; + String value = ""; + if (text.indexOf("=") != -1) { + action = text.substring(0, text.indexOf("=")); + value = text.substring(text.indexOf("=") + 1); + doJob(action, value); + } +} +int job = -1; +int online = -1; +void doJob(String task, String value) { + if (task == "job") { + char b = '!'; + uint32_t co = 0; + if(value.toInt() == 1) { + b = 'F'; //Fraunhofer + co = 0x00FF22; //Fraunhofer Color + } else if(value.toInt() == 2) { + b = 'R'; //Rwth Aachen + co = 0x00539F; //Rwth Color + } + job = value.toInt(); + Rb.fillRectangle(1, 2, 7, 6, 0x000000); + Rb.drawChar(b, 1, 1, co); + } else if(task == "online") { + Rb.setPixelXY(0,7,value.toInt()==0?0xFF0000:0x00FF00); + online = value.toInt(); + } else if(task == "getJob") { + Serial.println("setJob="+String(job)); + } else if(task == "getOnline") { + Serial.println("setOnline="+String(online)); + } else if(task == "tag") { + Rb.fillRectangle(0, 0, 8, 1, 0x000000); + if(count < MAX_STORE_DATA) { + count++; + store[count-1] = String("tag="+value); + //Serial.println("d: "+ store[count-1]); + //Serial.println("d: "+ String(count)); + } + Rb.fillRectangle(7-(count-1), 0, 8, 1, 0xFFFF00); + } else if(task == "getStoreCount") { + Serial.println("hasCount="+String(count)); + } else if(task == "getStoreData") { + if(count > 0) { + Serial.print("dataStore="); + for(int i=0; i < count-1; i++) { + Serial.print(store[i]+"|"); + } + Serial.println(store[count-1]); + count = 0; + Rb.fillRectangle(0, 0, 8, 1, 0x000000); + } + } +} + diff --git a/TimeKeeper/Arduino/Zeit/Zeit-V2.sln b/TimeKeeper/Arduino/Zeit/Zeit-V2.sln new file mode 100644 index 0000000..b115c5e --- /dev/null +++ b/TimeKeeper/Arduino/Zeit/Zeit-V2.sln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.25123.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Zeit-V2", "Zeit-V2\Zeit-V2.vcxproj", "{C5F80730-F44F-4478-BDAE-6634EFC2CA88}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x86 = Debug|x86 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {C5F80730-F44F-4478-BDAE-6634EFC2CA88}.Debug|x86.ActiveCfg = Debug|Win32 + {C5F80730-F44F-4478-BDAE-6634EFC2CA88}.Debug|x86.Build.0 = Debug|Win32 + {C5F80730-F44F-4478-BDAE-6634EFC2CA88}.Release|x86.ActiveCfg = Release|Win32 + {C5F80730-F44F-4478-BDAE-6634EFC2CA88}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/TimeKeeper/Arduino/Zeit/Zeit-V2/Zeit-V2.ino b/TimeKeeper/Arduino/Zeit/Zeit-V2/Zeit-V2.ino new file mode 100644 index 0000000..5817b2d --- /dev/null +++ b/TimeKeeper/Arduino/Zeit/Zeit-V2/Zeit-V2.ino @@ -0,0 +1,20 @@ +#define DEBUG_FLAG true + +#include "programm.h" +ProgClass* p; + +void setup() { + Serial.begin(9600); + p = new ProgClass(&Serial); + #if defined(DEBUG_FLAG) && DEBUG_FLAG + Serial.println("Init loading!"); + #endif + p->loadFromDisplay(); + #if defined(DEBUG_FLAG) && DEBUG_FLAG + Serial.println("Init finished!"); + #endif +} + +void loop() { + p->loop(); +} diff --git a/TimeKeeper/Arduino/Zeit/Zeit-V2/Zeit-V2.vcxproj b/TimeKeeper/Arduino/Zeit/Zeit-V2/Zeit-V2.vcxproj new file mode 100644 index 0000000..3ba3a93 --- /dev/null +++ b/TimeKeeper/Arduino/Zeit/Zeit-V2/Zeit-V2.vcxproj @@ -0,0 +1,92 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + + {C5F80730-F44F-4478-BDAE-6634EFC2CA88} + Zeit_V2 + Zeit-V2 + + + + Application + true + + + MultiByte + + + Application + false + + + true + MultiByte + + + + + + + + + + + + + C:\Users\schell\Documents\Arduino\libraries\Ethernet2\src;D:\Programme\Arduino\hardware\arduino\avr\libraries\SoftwareSerial;C:\Users\schell\Documents\Arduino\libraries\Time;D:\Programme\Arduino\hardware\arduino\avr\libraries\SPI;$(IncludePath) + + + + Level3 + Disabled + true + D:\Programme\Arduino\libraries;C:\Users\schell\AppData\Local\arduino15\packages\arduino\hardware\avr\1.6.11\libraries;D:\Programme\Visual Studio\Common7\IDE\Extensions\hunc4op4.xpd\Micro Platforms\default\debuggers;C:\Users\schell\Documents\Arduino\libraries;C:\Users\schell\AppData\Local\arduino15\packages\arduino\hardware\avr\1.6.11\cores\arduino;C:\Users\schell\AppData\Local\arduino15\packages\arduino\hardware\avr\1.6.11\variants\standard;C:\Users\schell\Documents\Arduino\Zeit-V2\Zeit-V2;D:\Programme\Arduino\hardware\tools\avr/avr/include/;D:\Programme\Arduino\hardware\tools\avr//avr/include/avr/;D:\Programme\Arduino\hardware\tools\avr/lib\gcc\avr\4.8.1\include;%(AdditionalIncludeDirectories) + C:\Users\schell\Documents\Arduino\Zeit-V2\Zeit-V2\__vm\.Zeit-V2.vsarduino.h;%(ForcedIncludeFiles) + false + __AVR_ATmega328p__;__AVR_ATmega328P__;F_CPU=16000000L;ARDUINO=10607;ARDUINO_AVR_UNO;ARDUINO_ARCH_AVR;__cplusplus=201103L;%(PreprocessorDefinitions) + + + true + + + + + Level3 + MaxSpeed + true + true + true + + + true + true + true + + + + + CppCode + true + + + + + + + + + + + + + + \ No newline at end of file diff --git a/TimeKeeper/Arduino/Zeit/Zeit-V2/Zeit-V2.vcxproj.filters b/TimeKeeper/Arduino/Zeit/Zeit-V2/Zeit-V2.vcxproj.filters new file mode 100644 index 0000000..500d044 --- /dev/null +++ b/TimeKeeper/Arduino/Zeit/Zeit-V2/Zeit-V2.vcxproj.filters @@ -0,0 +1,40 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/TimeKeeper/Arduino/Zeit/Zeit-V2/button.h b/TimeKeeper/Arduino/Zeit/Zeit-V2/button.h new file mode 100644 index 0000000..6f379f8 --- /dev/null +++ b/TimeKeeper/Arduino/Zeit/Zeit-V2/button.h @@ -0,0 +1,27 @@ +class ButtonClass { + private: + void init(void); + public: + ButtonClass(void); + bool check(uint8_t job); + uint8_t read(void); +}; + + +ButtonClass::ButtonClass(void) { + this->init(); +} + +void ButtonClass::init(void) { + pinMode(2, INPUT_PULLUP); + pinMode(3, INPUT_PULLUP); +} + +bool ButtonClass::check(uint8_t job) { + return ((digitalRead(2) == LOW && job != 1) || (digitalRead(3) == LOW && job != 2)); +} + +uint8_t ButtonClass::read(void){ + return digitalRead(2)==LOW?1:2; +} + diff --git a/TimeKeeper/Arduino/Zeit/Zeit-V2/display.h b/TimeKeeper/Arduino/Zeit/Zeit-V2/display.h new file mode 100644 index 0000000..102973a --- /dev/null +++ b/TimeKeeper/Arduino/Zeit/Zeit-V2/display.h @@ -0,0 +1,59 @@ +#if !defined(DEBUG_FLAG) + #define DEBUG_FLAG false +#endif + +#include +#if DEBUG_FLAG + #include +#endif + +class DispClass { + private: + SoftwareSerial* serD; + #if DEBUG_FLAG + HardwareSerial* _debug; + #endif + void init(void); + public: + #if DEBUG_FLAG + DispClass(HardwareSerial *debug); + #else + DispClass(void); + #endif + void print(String text); + void setTimeout(unsigned long timeout); + String readStringUntil(char terminator); +}; + +#if DEBUG_FLAG + DispClass::DispClass(HardwareSerial *debug) { + this->_debug = debug; + this->init(); + } +#else + DispClass::DispClass(void) { + this->init(); + } +#endif + +void DispClass::init(void) { + this->serD = new SoftwareSerial(7, 6); + this->serD->begin(9600); +} + +void DispClass::print(String text) { + #if DEBUG_FLAG + this->_debug->println("d->: "+text); + #endif + this->serD->listen(); + this->serD->println(text); +} + +void DispClass::setTimeout(unsigned long timeout) { + this->serD->setTimeout(timeout); +} + +String DispClass::readStringUntil(char terminator) { + return this->serD->readStringUntil(terminator); +} + diff --git a/TimeKeeper/Arduino/Zeit/Zeit-V2/network.h b/TimeKeeper/Arduino/Zeit/Zeit-V2/network.h new file mode 100644 index 0000000..221b690 --- /dev/null +++ b/TimeKeeper/Arduino/Zeit/Zeit-V2/network.h @@ -0,0 +1,64 @@ +#if !defined(DEBUG_FLAG) + #define DEBUG_FLAG false +#endif + +#include +#include +#if DEBUG_FLAG + #include +#endif + +class NetClass { + private: + #if DEBUG_FLAG + HardwareSerial* _debug; + #endif + EthernetClass* e; + void init(void); + // Mac-Adress of the Ethernet-Shield + uint8_t mac[6] = { 0x90, 0xA2, 0xDA, 0x10, 0x4F, 0xA4 }; + public: + #if DEBUG_FLAG + NetClass(HardwareSerial *debug); + #else + NetClass(void); + #endif +}; + +#if DEBUG_FLAG + NetClass::NetClass(HardwareSerial *debug) { + this->_debug = debug; + this->init(); + } +#else + NetClass::NetClass(void) { + this->init(); + } +#endif + +void NetClass::init(void) { + pinMode(10, OUTPUT); + digitalWrite(10, HIGH); + #if DEBUG_FLAG + this->_debug->println("Start Network!"); + this->_debug->println("DHCP Request"); + #endif + this->e = &Ethernet; + if (this->e->begin(mac) == 0) { + #if DEBUG_FLAG + this->_debug->println("DHCP Failed, Use Link-Local Adress"); + #endif + this->e->begin(mac, IPAddress(169, 254, 1, 177), IPAddress(169, 254, 0, 1), IPAddress(255, 255, 0, 0)); + } + #if DEBUG_FLAG + this->_debug->print("Ethernet Started! IP: "); + IPAddress ip = Ethernet.localIP(); + for (byte thisByte = 0; thisByte < 4; thisByte++) { + // print the value of each byte of the IP address: + this->_debug->print(ip[thisByte], DEC); + this->_debug->print("."); + } + this->_debug->println(); + #endif +} + diff --git a/TimeKeeper/Arduino/Zeit/Zeit-V2/programm.h b/TimeKeeper/Arduino/Zeit/Zeit-V2/programm.h new file mode 100644 index 0000000..7886a7c --- /dev/null +++ b/TimeKeeper/Arduino/Zeit/Zeit-V2/programm.h @@ -0,0 +1,194 @@ +#if !defined(DEBUG_FLAG) + #define DEBUG_FLAG false +#endif + +#include +#include +#include +#include "display.h" +#include "network.h" +#include "rfid.h" +#include "button.h" + +class ProgClass { + private: + static const int MAX_STORE_DATA = 8; + + HardwareSerial* _usb; + DispClass* disp; + NetClass* net; + RfidClass* rfid; + ButtonClass* bu; + + int8_t _storeCount = -1; + int8_t _job = -1; + int8_t _online = -1; + bool _keep = false; + String _storeData[MAX_STORE_DATA]; + String _cmsg; + + void init(void); + void parse(String text); + bool keepAlive(void); + void doJob(String task, String value); + + public: + ProgClass(HardwareSerial *usb); + void loop(void); + void loadFromDisplay(void); +}; + +ProgClass::ProgClass(HardwareSerial *usb) { + this->_usb = usb; + this->init(); +} + +void ProgClass::init(void) { + #if DEBUG_FLAG + this->_usb->println("Init...."); + this->disp = new DispClass(this->_usb); + this->net = new NetClass(this->_usb); + #else + this->disp = new DispClass(); + this->net = new NetClass(); + #endif + this->rfid = new RfidClass(); + this->bu = new ButtonClass(); + this->_usb->println("t="+String(now())); +} + +void ProgClass::loop(void) { + char c; + if (this->rfid->hasData()) { + if (this->rfid->allowed()) { + this->_online = this->_online == 1 ? 0 : 1; + this->doJob("tag", this->rfid->getData()); + this->doJob("online", String(this->_online)); + delay(1000); + } + this->rfid->clear(); + } + if (this->_usb->available()) { + c = this->_usb->read(); + if (c == '\n') { + this->parse(this->_cmsg); + this->_cmsg = ""; + } + else { + this->_cmsg += c; + } + } + if (this->bu->check(this->_job)) { + this->_job = this->bu->read(); + this->doJob("job", String(this->_job)); + this->rfid->clear(); + } +} + +void ProgClass::loadFromDisplay(void) { + this->disp->setTimeout(1000); + this->disp->print("getJob=1"); + this->parse(this->disp->readStringUntil('\n')); + this->disp->print("getOnline=1"); + this->parse(this->disp->readStringUntil('\n')); + if (this->keepAlive()) { + this->disp->print("getStoreCount=1"); + this->parse(this->disp->readStringUntil('\n')); + if (this->_storeCount > 0) { + this->disp->print("getStoreData=1"); + this->parse(this->disp->readStringUntil('\n')); + } + } + if (this->keepAlive()) { + this->doJob("getStore", "1"); + } +} + +void ProgClass::parse(String text) { + #if DEBUG_FLAG + this->_usb->println("i<-: " + text); + #endif + text.trim(); + String task = ""; + String value = ""; + if (text.indexOf("=") != -1) { + task = text.substring(0, text.indexOf("=")); + value = text.substring(text.indexOf("=") + 1); + this->doJob(task, value); + } +} + +bool ProgClass::keepAlive(void) { + this->_usb->setTimeout(1000); + this->_keep = false; + this->_usb->println("requestKeep=1"); + String a = this->_usb->readStringUntil('\n'); + if (a != "") { + this->parse(a); + } + return this->_keep; +} + +void ProgClass::doJob(String task, String value) { + if (task == "tag") { + char hex[15]; + value.toCharArray(hex, 14); + String answ = "tag=" + String(strtol(hex, NULL, 16)); + answ += ";time=" + String(now()); + answ += ";job=" + String(this->_job); + answ += ";online=" + String(this->_online); + if (this->keepAlive()) { + this->_usb->println(answ); + } + else { + this->disp->print(answ); + } + } + else if (task == "job") { + this->disp->print("job=" + value); + } + else if (task == "online") { + this->disp->print("online=" + value); + } + else if (task == "time") { + setTime(value.toInt()); + this->_usb->println("t=" + String(now())); + } + else if (task == "setJob") { + this->_job = value.toInt(); + } + else if (task == "setOnline") { + this->_online = value.toInt(); + } + else if (task == "keep") { + this->_keep = true; + } + else if (task == "hasCount") { + this->_storeCount = value.toInt(); + } + else if (task == "dataStore") { + int i = 0; + while (true) { + if (i == MAX_STORE_DATA) { + break; + } + if (value.indexOf('|') == -1) { + this->_storeData[i] = value; + i++; + break; + } + this->_storeData[i] = value.substring(0, value.indexOf('|')); + value = value.substring(value.indexOf('|') + 1); + i++; + } + this->_storeCount = i; + } + else if (task == "getStore") { + if (this->_storeCount > 0) { + for (int i = 0; i < this->_storeCount; i++) { + this->_usb->println(this->_storeData[i]); + } + this->_storeCount = 0; + } + } +} \ No newline at end of file diff --git a/TimeKeeper/Arduino/Zeit/Zeit-V2/rfid.h b/TimeKeeper/Arduino/Zeit/Zeit-V2/rfid.h new file mode 100644 index 0000000..57534b1 --- /dev/null +++ b/TimeKeeper/Arduino/Zeit/Zeit-V2/rfid.h @@ -0,0 +1,48 @@ +#include + +class RfidClass { + private: + SoftwareSerial* serD; + void init(void); + String rmsg; + public: + RfidClass(void); + bool hasData(void); + String getData(void); + bool allowed(void); + void clear(void); +}; + +RfidClass::RfidClass(void) { + this->init(); +} + +void RfidClass::init(void) { + this->serD = new SoftwareSerial (9, 8); + this->serD->begin(9600); +} + +bool RfidClass::hasData(void) { + this->serD->listen(); + if(this->serD->available()) { + this->rmsg += (char)this->serD->read(); + } + if(this->rmsg.length() >= 14) { + this->rmsg = this->rmsg.substring(1,13); + return true; + } + return false; +} + +String RfidClass::getData(void){ + return this->rmsg; +} + +bool RfidClass::allowed() { + return (this->rmsg == "0A006AB7AE79"); +} + +void RfidClass::clear(void) { + this->rmsg = ""; +} + diff --git a/TimeKeeper/TimeKeeper.sln b/TimeKeeper/TimeKeeper.sln new file mode 100644 index 0000000..eecca72 --- /dev/null +++ b/TimeKeeper/TimeKeeper.sln @@ -0,0 +1,46 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.25123.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TimeKeeper", "TimeKeeper\TimeKeeper.csproj", "{25F58397-71CB-4298-979E-BAACE80C61CB}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Utils", "..\Utils\Utils\Utils.csproj", "{FAC8CE64-BF13-4ECE-8097-AEB5DD060098}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Zeit-V2", "Arduino\Zeit\Zeit-V2\Zeit-V2.vcxproj", "{C5F80730-F44F-4478-BDAE-6634EFC2CA88}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {25F58397-71CB-4298-979E-BAACE80C61CB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {25F58397-71CB-4298-979E-BAACE80C61CB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {25F58397-71CB-4298-979E-BAACE80C61CB}.Debug|x86.ActiveCfg = Debug|Any CPU + {25F58397-71CB-4298-979E-BAACE80C61CB}.Debug|x86.Build.0 = Debug|Any CPU + {25F58397-71CB-4298-979E-BAACE80C61CB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {25F58397-71CB-4298-979E-BAACE80C61CB}.Release|Any CPU.Build.0 = Release|Any CPU + {25F58397-71CB-4298-979E-BAACE80C61CB}.Release|x86.ActiveCfg = Release|Any CPU + {25F58397-71CB-4298-979E-BAACE80C61CB}.Release|x86.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}.Debug|x86.ActiveCfg = Debug|Any CPU + {FAC8CE64-BF13-4ECE-8097-AEB5DD060098}.Debug|x86.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 + {FAC8CE64-BF13-4ECE-8097-AEB5DD060098}.Release|x86.ActiveCfg = Release|Any CPU + {FAC8CE64-BF13-4ECE-8097-AEB5DD060098}.Release|x86.Build.0 = Release|Any CPU + {C5F80730-F44F-4478-BDAE-6634EFC2CA88}.Debug|Any CPU.ActiveCfg = Debug|Win32 + {C5F80730-F44F-4478-BDAE-6634EFC2CA88}.Debug|x86.ActiveCfg = Debug|Win32 + {C5F80730-F44F-4478-BDAE-6634EFC2CA88}.Debug|x86.Build.0 = Debug|Win32 + {C5F80730-F44F-4478-BDAE-6634EFC2CA88}.Release|Any CPU.ActiveCfg = Release|Win32 + {C5F80730-F44F-4478-BDAE-6634EFC2CA88}.Release|x86.ActiveCfg = Release|Win32 + {C5F80730-F44F-4478-BDAE-6634EFC2CA88}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/TimeKeeper/TimeKeeper/Controller/CTray.cs b/TimeKeeper/TimeKeeper/Controller/CTray.cs new file mode 100644 index 0000000..6f62748 --- /dev/null +++ b/TimeKeeper/TimeKeeper/Controller/CTray.cs @@ -0,0 +1,47 @@ +using BlubbFish.Utils; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace TimeKeeper.Controller { + class Tray : OwnController { + private static View.Tray tray; + private static Controller.Window window; + + override protected void init() { + tray = new View.Tray(); + window = new Controller.Window(); + } + + /// + /// User klickt Doppelt auf das TrayIcon + /// + /// + /// + internal static void Click_Tray(object sender, EventArgs e) { + Click_Open(sender, e); + } + + /// + /// User klickt auf den Eintrag Öffnen + /// + /// + /// + internal static void Click_Open(object sender, EventArgs e) { + window.execute(); + } + + /// + /// User klickt auf den Eintrag Beenden + /// + /// + /// + internal static void Click_Quit(object sender, EventArgs e) { + tray.Dispose(); + Application.Exit(); + } + } +} diff --git a/TimeKeeper/TimeKeeper/Controller/CWindow.cs b/TimeKeeper/TimeKeeper/Controller/CWindow.cs new file mode 100644 index 0000000..713bd44 --- /dev/null +++ b/TimeKeeper/TimeKeeper/Controller/CWindow.cs @@ -0,0 +1,25 @@ +using BlubbFish.Utils; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace TimeKeeper.Controller { + class Window : OwnController { + private static View.Window window; + + public Window() { + + } + + override protected void init() { + window = new View.Window(); + } + + public static void FormClosed(object sender, FormClosedEventArgs e) { + window.Dispose(); + } + } +} diff --git a/TimeKeeper/TimeKeeper/Database/DatabaseDriver.cs b/TimeKeeper/TimeKeeper/Database/DatabaseDriver.cs new file mode 100644 index 0000000..82786cd --- /dev/null +++ b/TimeKeeper/TimeKeeper/Database/DatabaseDriver.cs @@ -0,0 +1,469 @@ +using System; +using System.IO; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Data; +using System.Data.Common; +using System.Data.SqlClient; +using System.Data.SQLite; +using MySql; +using MySql.Data.Common; +using MySql.Data.MySqlClient; +using TimeKeeper.Exceptions; + +namespace TimeKeeper.Database { + public class DatabaseDriver : IDisposable { + /// + /// Current DB Engine + /// + public DatabaseEngine DatabaseEngine { get; protected set; } + + /// + /// The database connection + /// + public DbConnection Connection { get; protected set; } + + /// + /// Returns whether the Database connection is open + /// + public bool IsConnected { + get { return (Connection.State == ConnectionState.Open); } + } + + /// + /// Returns the current conenction state of the database + /// + public ConnectionState State { + get { return Connection.State; } + } + + /// + /// Gets the number of queries ran by this instance + /// + public int NumQueries = 0; + + /// + /// Random, yes... But its used here when building queries dynamically + /// + protected static char Comma = ','; + + /// + /// Indicates whether the disposed method was called + /// + protected bool IsDisposed = false; + + /// + /// Constructor + /// + /// The string name, for the GetDatabaseEngine() method + /// The Database server IP Address + /// The Database server Port Number + /// The name of the database + /// A username, with database privliages + /// The password to the User + public DatabaseDriver(string Engine, string Host, int Port, string DatabaseName, string User, string Pass, DatabaseEngine[] allowedEngines) { + // Set class variables, and create a new connection builder + this.DatabaseEngine = GetDatabaseEngine(Engine); + DbConnectionStringBuilder Builder; + + // Establish the connection + if(this.DatabaseEngine == DatabaseEngine.Sqlite && allowedEngines.Contains(DatabaseEngine.Sqlite)) { + // Create the connection + Builder = new SQLiteConnectionStringBuilder(); + Builder.Add("Data Source", Path.Combine(StaticConfig.RootPath, DatabaseName + ".sqlite3")); + Connection = new SQLiteConnection(Builder.ConnectionString); + } else if(this.DatabaseEngine == DatabaseEngine.Mysql && allowedEngines.Contains(DatabaseEngine.Mysql)) { + // Create the connection + Builder = new MySqlConnectionStringBuilder(); + Builder.Add("Server", Host); + Builder.Add("Port", Port); + Builder.Add("User ID", User); + Builder.Add("Password", Pass); + Builder.Add("Database", DatabaseName); + Builder.Add("Convert Zero Datetime", "true"); + Connection = new MySqlConnection(Builder.ConnectionString); + } else { + throw new Exception("Invalid Database type."); + } + } + + /// + /// Destructor + /// + ~DatabaseDriver() { + Dispose(); + } + + /// + /// Disposes the DB connection + /// + public void Dispose() { + if(Connection != null && !IsDisposed) { + try { + Connection.Close(); + Connection.Dispose(); + } catch(ObjectDisposedException) { } + + IsDisposed = true; + } + } + + /// + /// Opens the database connection + /// + public void Connect() { + if(Connection.State != ConnectionState.Open) { + try { + Connection.Open(); + } catch(Exception e) { + throw new DbConnectException("Unable to etablish database connection", e); + } + } + } + + /// + /// Closes the connection to the database + /// + public void Close() { + try { + if(Connection.State != ConnectionState.Closed) + Connection.Close(); + } catch(ObjectDisposedException) { } + } + + /// + /// Creates a new command to be executed on the database + /// + /// + public DbCommand CreateCommand(string QueryString) { + if(DatabaseEngine == Database.DatabaseEngine.Sqlite) + return new SQLiteCommand(QueryString, Connection as SQLiteConnection); + else + return new MySqlCommand(QueryString, Connection as MySqlConnection); + } + + /// + /// Creates a DbParameter using the current Database engine's Parameter object + /// + /// + public DbParameter CreateParam() { + if(DatabaseEngine == Database.DatabaseEngine.Sqlite) + return (new SQLiteParameter() as DbParameter); + else + return (new MySqlParameter() as DbParameter); + } + + /// + /// Queries the database, and returns a result set + /// + /// The SQL Statement to run on the database + /// + public List> Query(string Sql) { + return this.Query(Sql, new List()); + } + + /// + /// Queries the database, and returns a result set + /// + /// The SQL Statement to run on the database + /// Additional parameters are parameter values for the query. + /// The first parameter replaces @P0, second @P1 etc etc. + /// + /// + public List> Query(string Sql, params object[] Items) { + List Params = new List(Items.Length); + for(int i = 0; i < Items.Length; i++) { + DbParameter Param = this.CreateParam(); + Param.ParameterName = "@P" + i; + Param.Value = Items[i]; + Params.Add(Param); + } + + return this.Query(Sql, Params); + } + + /// + /// Queries the database, and returns a result set + /// + /// The SQL Statement to run on the database + /// A list of sql params to add to the command + /// + public List> Query(string Sql, List Params) { + // Create our Rows result + List> Rows = new List>(); + + // Increase Query Count + NumQueries++; + + // Create the SQL Command + using(DbCommand Command = this.CreateCommand(Sql)) { + // Add params + foreach(DbParameter Param in Params) + Command.Parameters.Add(Param); + + // Execute the query + using(DbDataReader Reader = Command.ExecuteReader()) { + // If we have rows, add them to the list + if(Reader.HasRows) { + // Add each row to the rows list + while(Reader.Read()) { + Dictionary Row = new Dictionary(Reader.FieldCount); + for(int i = 0; i < Reader.FieldCount; ++i) + Row.Add(Reader.GetName(i), Reader.GetValue(i)); + + Rows.Add(Row); + } + } + + // Cleanup + Reader.Close(); + } + } + + // Return Rows + return Rows; + } + + /// + /// Queries the database, and returns 1 row at a time until all rows are returned + /// + /// The SQL Statement to run on the database + /// + public IEnumerable> QueryReader(string Sql) { + // Increase Query Count + NumQueries++; + + // Create the SQL Command, and execute the reader + using(DbCommand Command = this.CreateCommand(Sql)) + using(DbDataReader Reader = Command.ExecuteReader()) { + // If we have rows, add them to the list + if(Reader.HasRows) { + // Add each row to the rows list + while(Reader.Read()) { + Dictionary Row = new Dictionary(Reader.FieldCount); + for(int i = 0; i < Reader.FieldCount; ++i) + Row.Add(Reader.GetName(i), Reader.GetValue(i)); + + yield return Row; + } + } + + // Cleanup + Reader.Close(); + } + } + + /// + /// Executes a command, and returns 1 row at a time until all rows are returned + /// + /// The database command to execute the reader on + /// + public IEnumerable> QueryReader(DbCommand Command) { + // Increase Query Count + NumQueries++; + + // Execute the query + using(Command) + using(DbDataReader Reader = Command.ExecuteReader()) { + // If we have rows, add them to the list + if(Reader.HasRows) { + // Add each row to the rows list + while(Reader.Read()) { + Dictionary Row = new Dictionary(Reader.FieldCount); + for(int i = 0; i < Reader.FieldCount; ++i) + Row.Add(Reader.GetName(i), Reader.GetValue(i)); + + yield return Row; + } + } + + // Cleanup + Reader.Close(); + } + } + + + /// + /// Executes a command, and returns the resulting rows + /// + /// The database command to execute the reader on + /// + public List> ExecuteReader(DbCommand Command) { + // Execute the query + List> Rows = new List>(); + + // Increase Query Count + NumQueries++; + + using(Command) + using(DbDataReader Reader = Command.ExecuteReader()) { + // If we have rows, add them to the list + if(Reader.HasRows) { + // Add each row to the rows list + while(Reader.Read()) { + Dictionary Row = new Dictionary(Reader.FieldCount); + for(int i = 0; i < Reader.FieldCount; ++i) + Row.Add(Reader.GetName(i), Reader.GetValue(i)); + + Rows.Add(Row); + } + } + + // Cleanup + Reader.Close(); + } + + // Return Rows + return Rows; + } + + /// + /// Executes a statement on the database (Update, Delete, Insert) + /// + /// The SQL statement to be executes + /// Returns the number of rows affected by the statement + public int Execute(string Sql) { + // Create the SQL Command + using(DbCommand Command = this.CreateCommand(Sql)) + return Command.ExecuteNonQuery(); + } + + /// + /// Executes a statement on the database (Update, Delete, Insert) + /// + /// The SQL statement to be executed + /// A list of Sqlparameters + /// Returns the number of rows affected by the statement + public int Execute(string Sql, List Params) { + // Create the SQL Command + using(DbCommand Command = this.CreateCommand(Sql)) { + // Increase Query Count + NumQueries++; + + // Add params + foreach(DbParameter Param in Params) + Command.Parameters.Add(Param); + + // Execute command, and dispose of the command + return Command.ExecuteNonQuery(); + } + } + + /// + /// Executes a statement on the database (Update, Delete, Insert) + /// + /// The SQL statement to be executed + /// Additional parameters are parameter values for the query. + /// The first parameter replaces @P0, second @P1 etc etc. + /// + /// Returns the number of rows affected by the statement + public int Execute(string Sql, params object[] Items) { + // Create the SQL Command + using(DbCommand Command = this.CreateCommand(Sql)) { + // Add params + for(int i = 0; i < Items.Length; i++) { + DbParameter Param = this.CreateParam(); + Param.ParameterName = "@P" + i; + Param.Value = Items[i]; + Command.Parameters.Add(Param); + } + + // Increase Query Count + NumQueries++; + + // Execute command, and dispose of the command + return Command.ExecuteNonQuery(); + } + } + + /// + /// Executes the query, and returns the first column of the first row in the result + /// set returned by the query. Additional columns or rows are ignored. + /// + /// The SQL statement to be executed + /// + public object ExecuteScalar(string Sql) { + // Increase Query Count + NumQueries++; + + // Create the SQL Command + using(DbCommand Command = this.CreateCommand(Sql)) + return Command.ExecuteScalar(); + } + + /// + /// Executes the query, and returns the first column of the first row in the result + /// set returned by the query. Additional columns or rows are ignored. + /// + /// The SQL statement to be executed + /// A list of Sqlparameters + /// + public object ExecuteScalar(string Sql, List Params) { + // Create the SQL Command + using(DbCommand Command = this.CreateCommand(Sql)) { + // Increase Query Count + NumQueries++; + + // Add params + foreach(DbParameter Param in Params) + Command.Parameters.Add(Param); + + // Execute command, and dispose of the command + return Command.ExecuteScalar(); + } + } + + /// + /// Executes the query, and returns the first column of the first row in the result + /// set returned by the query. Additional columns or rows are ignored. + /// + /// The SQL statement to be executed + /// + /// + public object ExecuteScalar(string Sql, params object[] Items) { + // Create the SQL Command + using(DbCommand Command = this.CreateCommand(Sql)) { + // Add params + for(int i = 0; i < Items.Length; i++) { + DbParameter Param = this.CreateParam(); + Param.ParameterName = "@P" + i; + Param.Value = Items[i]; + Command.Parameters.Add(Param); + } + + // Increase Query Count + NumQueries++; + + // Execute command, and dispose of the command + return Command.ExecuteScalar(); + } + } + + /// + /// Begins a new database transaction + /// + /// + public DbTransaction BeginTransaction() { + return Connection.BeginTransaction(); + } + + /// + /// Begins a new database transaction + /// + /// + /// + public DbTransaction BeginTransaction(IsolationLevel Level) { + return Connection.BeginTransaction(Level); + } + + /// + /// Converts a database string name to a DatabaseEngine type. + /// + /// + /// + public static DatabaseEngine GetDatabaseEngine(string Name) { + return ((DatabaseEngine)Enum.Parse(typeof(DatabaseEngine), Name, true)); + } + } +} diff --git a/TimeKeeper/TimeKeeper/Database/DatabaseEngine.cs b/TimeKeeper/TimeKeeper/Database/DatabaseEngine.cs new file mode 100644 index 0000000..9e8aeac --- /dev/null +++ b/TimeKeeper/TimeKeeper/Database/DatabaseEngine.cs @@ -0,0 +1,8 @@ +namespace TimeKeeper.Database +{ + public enum DatabaseEngine + { + Sqlite, + Mysql, + } +} diff --git a/TimeKeeper/TimeKeeper/Database/SQL/MySQL.Install.sql b/TimeKeeper/TimeKeeper/Database/SQL/MySQL.Install.sql new file mode 100644 index 0000000..24e0ea5 --- /dev/null +++ b/TimeKeeper/TimeKeeper/Database/SQL/MySQL.Install.sql @@ -0,0 +1,98 @@ +-- phpMyAdmin SQL Dump +-- version 3.4.11.1deb2+deb7u2 +-- http://www.phpmyadmin.net +-- +-- Host: localhost +-- Erstellungszeit: 26. Jan 2016 um 10:01 +-- Server Version: 5.6.25 +-- PHP-Version: 5.4.45-1~dotdeb+7.1 + +SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO"; +SET time_zone = "+00:00"; + +-- +-- Datenbank: `worktime` +-- + +-- -------------------------------------------------------- + +-- +-- Tabellenstruktur für Tabelle `location` +-- + +CREATE TABLE IF NOT EXISTS `location` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `name` varchar(255) NOT NULL, + `tag` varchar(10) NOT NULL, + `weeklength` float NOT NULL, + `days` text NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Tabellenstruktur für Tabelle `month` +-- + +CREATE TABLE IF NOT EXISTS `month` ( + `year` int(11) NOT NULL, + `month` int(11) NOT NULL, + `duration` double NOT NULL, + `location` int(11) DEFAULT NULL, + UNIQUE KEY `year` (`year`,`month`,`location`), + KEY `location` (`location`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Tabellenstruktur für Tabelle `work` +-- + +CREATE TABLE IF NOT EXISTS `work` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `date` date NOT NULL, + `start` time NOT NULL, + `stop` time NOT NULL, + `pause` int(11) DEFAULT NULL, + `type` enum('ok','free','we','ill','vac','feiertag') NOT NULL, + `notice` varchar(200) DEFAULT NULL, + `location` int(11) DEFAULT NULL, + PRIMARY KEY (`id`), + KEY `location` (`location`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- -------------------------------------------------------- + +-- +-- Tabellenstruktur für Tabelle `_version` +-- + +CREATE TABLE IF NOT EXISTS `_version` ( + `dbver` int(4) NOT NULL, + `dbdate` datetime NOT NULL, + PRIMARY KEY (`dbver`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- +-- Constraints der exportierten Tabellen +-- + +-- +-- Constraints der Tabelle `month` +-- +ALTER TABLE `month` + ADD CONSTRAINT `month_ibfk_1` FOREIGN KEY (`location`) REFERENCES `location` (`id`) ON DELETE SET NULL ON UPDATE SET NULL; + +-- +-- Constraints der Tabelle `work` +-- +ALTER TABLE `work` + ADD CONSTRAINT `work_ibfk_1` FOREIGN KEY (`location`) REFERENCES `location` (`id`) ON DELETE SET NULL ON UPDATE SET NULL; + +-- +-- Daten +-- + +INSERT INTO `_version` (`dbver` ,`dbdate`) VALUES ('1', CURRENT_TIMESTAMP); diff --git a/TimeKeeper/TimeKeeper/Database/TDatabase.cs b/TimeKeeper/TimeKeeper/Database/TDatabase.cs new file mode 100644 index 0000000..d370285 --- /dev/null +++ b/TimeKeeper/TimeKeeper/Database/TDatabase.cs @@ -0,0 +1,94 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using TimeKeeper.Models.Types; + +namespace TimeKeeper.Database { + public class TDatabase : DatabaseDriver, IDisposable { + private static TDatabase instance; + + private TDatabase() : base(StaticConfig.DbConfig.Engine, StaticConfig.DbConfig.Host, StaticConfig.DbConfig.Port, StaticConfig.DbConfig.Db, StaticConfig.DbConfig.User, StaticConfig.DbConfig.Pass, new DatabaseEngine[] { DatabaseEngine.Mysql}) { + // Try and Reconnect + try { + Connect(); + + // Try to get the database version + try { + if(base.Query("SELECT dbver FROM _version LIMIT 1").Count == 0) + throw new Exception(); + } catch { + base.Execute(Utils.GetResourceAsString("TimeKeeper.Database.SQL.MySQL.Install.sql")); + } + } catch(Exception) { + if(Connection != null) + Connection.Dispose(); + + throw; + } + } + + public static TDatabase getInstance() { + if(instance == null) { + instance = new TDatabase(); + } + return instance; + } + + ~TDatabase() { + if(!IsDisposed) + base.Dispose(); + } + + internal void addWorking(WorkMessage m) { + List> dayItems = this.getWorkOnDay(m.time); + if(dayItems.Count == 0 && m.working == 1) { + this.insertStartWork(m.time, m.jobID); + } else if(dayItems.Count > 0) { + int started = -1; + int job = -1; + foreach(Dictionary dayItem in dayItems) { + if((TimeSpan)dayItem["stop"] == TimeSpan.Zero) { + started = (int)dayItem["id"]; + job = (int)dayItem["location"]; + break; + } + } + if(started != -1 && m.working == 0 && m.jobID == job) { + this.updateStopWorking(started, m.time); + } else if(started == -1 && m.working == 1) { + this.insertStartWork(m.time, m.jobID); + } else { + throw new NotImplementedException(); + } + } else { + throw new NotImplementedException(); + } + } + + private void updateStopWorking(Int32 started, DateTime time) { + base.Execute("UPDATE `work` SET stop=@P0 WHERE id=@P1", + time.ToString("HH:mm:ss"), started.ToString()); + } + + internal bool insertStartWork(DateTime time, Int32 jobID) { + int Rows = base.Execute("INSERT INTO `work` (`date`, `start`, `type`, `location`) VALUES (@P0, @P1, @P2, @P3)", + time.ToString("yyyy-MM-dd"), time.ToString("HH:mm:ss"), "ok", jobID.ToString() + ); + return (Rows != 0); + } + + internal List> getWorkOnDay(DateTime time) { + return base.Query("SELECT * FROM `work` WHERE date=@P0 ORDER BY `start` ASC", time.ToString("yyyy-MM-dd")); + } + + /// + /// Returns the number of accounts in the database + /// + /// + public int GetNumAccounts() { + var Row = base.Query("SELECT COUNT(id) AS count FROM accounts"); + return Int32.Parse(Row[0]["count"].ToString()); + } + } +} diff --git a/TimeKeeper/TimeKeeper/Exceptions/DbConnectException.cs b/TimeKeeper/TimeKeeper/Exceptions/DbConnectException.cs new file mode 100644 index 0000000..2f5b102 --- /dev/null +++ b/TimeKeeper/TimeKeeper/Exceptions/DbConnectException.cs @@ -0,0 +1,7 @@ +using System; + +namespace TimeKeeper.Exceptions { + class DbConnectException : Exception { + public DbConnectException(string Message, Exception Inner) : base(Message, Inner) { } + } +} diff --git a/TimeKeeper/TimeKeeper/Exceptions/IllegalDataException.cs b/TimeKeeper/TimeKeeper/Exceptions/IllegalDataException.cs new file mode 100644 index 0000000..a2168f5 --- /dev/null +++ b/TimeKeeper/TimeKeeper/Exceptions/IllegalDataException.cs @@ -0,0 +1,7 @@ +using System; + +namespace TimeKeeper.Exceptions { + class IllegalDataException : Exception { + public IllegalDataException(string Message, Exception Inner) : base(Message, Inner) { } + } +} diff --git a/TimeKeeper/TimeKeeper/Misc/StaticConfig.cs b/TimeKeeper/TimeKeeper/Misc/StaticConfig.cs new file mode 100644 index 0000000..62cb37d --- /dev/null +++ b/TimeKeeper/TimeKeeper/Misc/StaticConfig.cs @@ -0,0 +1,17 @@ +using BlubbFish.Utils; +using System.Windows.Forms; + +namespace TimeKeeper { + class StaticConfig { + public static class DbConfig { + private static InIReader i = InIReader.getInstance("settings.ini"); + public static string Engine { get { return i.getValue("database", "engine"); } } + public static string Host { get { return i.getValue("database", "host"); } } + public static int Port { get { return int.Parse(i.getValue("database", "port")); } } + public static string Db { get { return i.getValue("database", "db"); } } + public static string User { get { return i.getValue("database", "user"); } } + public static string Pass { get { return i.getValue("database", "pass"); } } + } + public static readonly string RootPath = Application.StartupPath; + } +} diff --git a/TimeKeeper/TimeKeeper/Misc/UDPListener.cs b/TimeKeeper/TimeKeeper/Misc/UDPListener.cs new file mode 100644 index 0000000..050b55f --- /dev/null +++ b/TimeKeeper/TimeKeeper/Misc/UDPListener.cs @@ -0,0 +1,75 @@ +using System; +using System.Text; +using System.Net; +using System.Net.Sockets; +using System.Threading; +using TimeKeeper.Models.Types; + +namespace TimeKeeper { + class UDPListener { + private int m_portToListen = 2003; + private volatile bool listening; + Thread m_ListeningThread; + public event EventHandler NewMessageReceived; + UdpClient listener = null; + private IPAddress lastAddress; + private Int32 tport; + + //constructor + public UDPListener(int port, int targetPort) { + this.tport = targetPort; + this.listening = false; + this.m_portToListen = port; + this.listener = new UdpClient(this.m_portToListen); + } + + public void StartListener() { + if(!this.listening) { + m_ListeningThread = new Thread(ListenForUDPPackages); + m_ListeningThread.IsBackground = true; + this.listening = true; + m_ListeningThread.Start(); + } + } + + public void StopListener() { + this.listening = false; + this.listener.Close(); + } + + public void ListenForUDPPackages() { + + try { + + } catch(SocketException) { + //do nothing + } + + if(this.listener != null) { + IPEndPoint groupEP = new IPEndPoint(IPAddress.Any, m_portToListen); + + try { + while(this.listening) { + Console.WriteLine("Waiting for UDP broadcast to port " + m_portToListen); + byte[] bytes = this.listener.Receive(ref groupEP); + this.lastAddress = groupEP.Address; + string s = Encoding.ASCII.GetString(bytes); + //raise event + NewMessageReceived(this, new MyMessageArgs(s)); + } + } catch(Exception e) { + Console.WriteLine(e.ToString()); + } finally { + this.listener.Close(); + Console.WriteLine("Done listening for UDP broadcast"); + } + } + } + + internal void WriteLine(String text) { + byte[] s = Encoding.ASCII.GetBytes(text); + IPEndPoint endpoint = new IPEndPoint(this.lastAddress, this.tport); + this.listener.SendAsync(s, s.Length, endpoint); + } + } +} diff --git a/TimeKeeper/TimeKeeper/Misc/Utils.cs b/TimeKeeper/TimeKeeper/Misc/Utils.cs new file mode 100644 index 0000000..20a4acb --- /dev/null +++ b/TimeKeeper/TimeKeeper/Misc/Utils.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +namespace TimeKeeper { + class Utils { + public static string GetResourceAsString(string ResName) { + string Res = ""; + using(Stream ResourceStream = Assembly.GetExecutingAssembly().GetManifestResourceStream(ResName)) { + using(StreamReader Reader = new StreamReader(ResourceStream)) { + Res = Reader.ReadToEnd(); + } + } + return Res; + } + } +} diff --git a/TimeKeeper/TimeKeeper/Models/MDatabase.cs b/TimeKeeper/TimeKeeper/Models/MDatabase.cs new file mode 100644 index 0000000..149ab65 --- /dev/null +++ b/TimeKeeper/TimeKeeper/Models/MDatabase.cs @@ -0,0 +1,31 @@ +using BlubbFish.Utils; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using TimeKeeper.Database; +using TimeKeeper.Models.Types; + +namespace TimeKeeper.Models { + class Database : OwnModel { + private TDatabase database; + + public Queue Messages { get; internal set; } + + protected override void init() { + this.database = TDatabase.getInstance(); + } + + private Database() { + this.init(); + } + + internal void checkinMessages() { + while(this.Messages.Count > 0) { + WorkMessage m = this.Messages.Dequeue(); + this.database.addWorking(m); + } + } + } +} diff --git a/TimeKeeper/TimeKeeper/Models/MTray.cs b/TimeKeeper/TimeKeeper/Models/MTray.cs new file mode 100644 index 0000000..c27cc60 --- /dev/null +++ b/TimeKeeper/TimeKeeper/Models/MTray.cs @@ -0,0 +1,137 @@ +using BlubbFish.Utils; +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using System.Threading; +using TimeKeeper.Exceptions; +using TimeKeeper.Models.Types; + +namespace TimeKeeper.Models { + class Tray : OwnModel { + private Boolean isConnectedValue = false; + private TimeSpan OffsetTimeValue = new TimeSpan(); + private UDPListener network; + private Thread setTimeThread; + private InIReader settingsfile; + private FileLogger sLogger; + private Queue MessagesValue = new Queue(); + private Database DatabaseModel; + private Boolean initComplete = false; + + private Tray() { + this.sLogger = FileLogger.getInstance("network.log", false); + this.init(); + } + + public Boolean isConnected { + get { return this.isConnectedValue; } + set { this.isConnectedValue = value; this.update(); } + } + + public TimeSpan OffsetTime { + get { return this.OffsetTimeValue; } + set { this.OffsetTimeValue = value; this.update(); } + } + + public Queue Messages { + get { return this.MessagesValue; } + } + + public void MessagesPush(WorkMessage m) { + this.MessagesValue.Enqueue(m); + this.update(); + this.DatabaseModel.Messages = this.Messages; + this.DatabaseModel.checkinMessages(); + } + + override protected void init() { + this.settingsfile = InIReader.getInstance("settings.ini"); + this.network = new UDPListener(Int32.Parse(this.settingsfile.getValue("general", "port")), Int32.Parse(this.settingsfile.getValue("general", "arduinoport"))); + this.network.NewMessageReceived += DataReceivedHandler; + this.network.StartListener(); + this.setTimeThread = new Thread(timeRunner); + this.setTimeThread.Start(); + this.DatabaseModel = Database.Instance; + } + + internal void Dispose() { + this.setTimeThread.Abort(); + this.network.NewMessageReceived -= DataReceivedHandler; + this.network.StopListener(); + } + + private void timeRunner() { + while(!this.initComplete) { + Thread.Sleep(100); + } + while(true) { + DateTime n = DateTime.UtcNow; + this.DataSendHandler("time=" + ((int)((n - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalSeconds)).ToString()); + Thread.Sleep(1000 * 60 * 5); + } + } + + private void DataReceivedHandler(Object sender, MyMessageArgs s) { + sLogger.setLine("<-: " + s.data, DateTime.Now); + this.parseSerial(s.data); + } + + [MethodImpl(MethodImplOptions.Synchronized)] + private void DataSendHandler(String v) { + sLogger.setLine("->: " + v, DateTime.Now); + this.network.WriteLine(v); + } + + private void parseSerial(String s) { + if(s == "requestKeep=1") { + this.DataSendHandler("keep=1"); + } else if(s == "Init...." || + s == "Init loading!" || + s == "Start Network!" || + s == "DHCP Request" || + s == "Ethernet Started! IP: 129.26.160.107.") { + //Ignore that Stuff + } else if(s == "Init finished!") { + this.initComplete = true; + } else if((s.Length > 4 && s.Substring(0, 4) == "d->:") || (s.Length > 4 && s.Substring(0, 4) == "i<-:")) { + //Ignore that Stuff also.... + } else if(s.Length > 2 && s.Substring(0, 2) == "t=") { + this.setOffset(s.Split('=')[1]); + } else if(s.Length > 4 && s.Substring(0, 4) == "tag=") { + this.parseTag(s); + } else { + throw new NotImplementedException(); + } + } + + private void parseTag(String s) { + string[] parts = s.Split(';'); + long userID = 0; + DateTime time = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); + int jobID = 0; + int working = 0; + foreach(String part in parts) { + string[] t = part.Split('='); + if(t[0] == "tag") { + userID = long.Parse(t[1]); + } else if(t[0] == "time") { + time = time.AddSeconds(int.Parse(t[1])).ToLocalTime(); + } else if(t[0] == "job") { + jobID = int.Parse(t[1]); + if(jobID == -1) { + throw new IllegalDataException("JobID ist -1", null); + } + } else if(t[0] == "online") { + working = int.Parse(t[1]); + } + } + this.MessagesPush(new WorkMessage(userID, time, jobID, working)); + } + + private void setOffset(String v) { + DateTime ctime = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); + ctime = ctime.AddSeconds(int.Parse(v)).ToLocalTime(); + this.OffsetTime = ctime - DateTime.Now; + } + } +} diff --git a/TimeKeeper/TimeKeeper/Models/MWindow.cs b/TimeKeeper/TimeKeeper/Models/MWindow.cs new file mode 100644 index 0000000..d56ac60 --- /dev/null +++ b/TimeKeeper/TimeKeeper/Models/MWindow.cs @@ -0,0 +1,19 @@ +using BlubbFish.Utils; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace TimeKeeper.Models { + class Window : OwnModel { + + private Window() { + this.init(); + } + + override protected void init() { + + } + } +} diff --git a/TimeKeeper/TimeKeeper/Models/Types/MyMessageArgs.cs b/TimeKeeper/TimeKeeper/Models/Types/MyMessageArgs.cs new file mode 100644 index 0000000..3f68e8d --- /dev/null +++ b/TimeKeeper/TimeKeeper/Models/Types/MyMessageArgs.cs @@ -0,0 +1,11 @@ +using System; + +namespace TimeKeeper.Models.Types { + public class MyMessageArgs : EventArgs { + public string data { get; set; } + + public MyMessageArgs(string newData) { + data = newData; + } + } +} diff --git a/TimeKeeper/TimeKeeper/Models/Types/WorkMessage.cs b/TimeKeeper/TimeKeeper/Models/Types/WorkMessage.cs new file mode 100644 index 0000000..6df46f6 --- /dev/null +++ b/TimeKeeper/TimeKeeper/Models/Types/WorkMessage.cs @@ -0,0 +1,17 @@ +using System; + +namespace TimeKeeper.Models.Types { + class WorkMessage { + public Int32 jobID; + public DateTime time; + public Int64 userID; + public Int32 working; + + public WorkMessage(Int64 userID, DateTime time, Int32 jobID, Int32 working) { + this.userID = userID; + this.time = time; + this.jobID = jobID; + this.working = working; + } + } +} diff --git a/TimeKeeper/TimeKeeper/Program.cs b/TimeKeeper/TimeKeeper/Program.cs new file mode 100644 index 0000000..e43401a --- /dev/null +++ b/TimeKeeper/TimeKeeper/Program.cs @@ -0,0 +1,21 @@ +using System; +using System.Windows.Forms; +using BlubbFish.Utils; + +namespace TimeKeeper { + class Program { + static void Main(string[] args) { + FileLogger.setLogDir("logs"); + try { + Controller.Tray t = new Controller.Tray(); + t.execute(); + Application.Run(); + } catch(Exception e) { + if(e.InnerException != null) { + e = e.InnerException; + } + MessageBox.Show("Fehler: " + e.Message + "\nStack: " + e.StackTrace, "Exception: " + e.GetType().ToString(), MessageBoxButtons.OK, MessageBoxIcon.Error); + } + } + } +} diff --git a/TimeKeeper/TimeKeeper/Properties/AssemblyInfo.cs b/TimeKeeper/TimeKeeper/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..5f9a202 --- /dev/null +++ b/TimeKeeper/TimeKeeper/Properties/AssemblyInfo.cs @@ -0,0 +1,38 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Resources; + +// Allgemeine Informationen über eine Assembly werden über die folgenden +// Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern, +// die mit einer Assembly verknüpft sind. +[assembly: AssemblyTitle("TimeKeeper")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("TimeKeeper")] +[assembly: AssemblyCopyright("Copyright BlubbFish © 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Durch Festlegen von ComVisible auf "false" werden die Typen in dieser Assembly unsichtbar +// für COM-Komponenten. Wenn Sie auf einen Typ in dieser Assembly von +// COM zugreifen müssen, legen Sie das ComVisible-Attribut für diesen Typ auf "true" fest. +[assembly: ComVisible(false)] + +// Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird +[assembly: Guid("7df6ab3d-639f-4549-a770-10ba3540a26b")] + +// Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten: +// +// Hauptversion +// Nebenversion +// Buildnummer +// Revision +// +// Sie können alle Werte angeben oder die standardmäßigen Build- und Revisionsnummern +// übernehmen, indem Sie "*" eingeben: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: NeutralResourcesLanguageAttribute("de-DE")] diff --git a/TimeKeeper/TimeKeeper/Properties/Resources.Designer.cs b/TimeKeeper/TimeKeeper/Properties/Resources.Designer.cs new file mode 100644 index 0000000..5d3e41a --- /dev/null +++ b/TimeKeeper/TimeKeeper/Properties/Resources.Designer.cs @@ -0,0 +1,103 @@ +//------------------------------------------------------------------------------ +// +// Dieser Code wurde von einem Tool generiert. +// Laufzeitversion:4.0.30319.34209 +// +// Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn +// der Code erneut generiert wird. +// +//------------------------------------------------------------------------------ + +namespace TimeKeeper.Properties { + using System; + + + /// + /// Eine stark typisierte Ressourcenklasse zum Suchen von lokalisierten Zeichenfolgen usw. + /// + // Diese Klasse wurde von der StronglyTypedResourceBuilder automatisch generiert + // -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 /str-Option erneut aus, oder Sie erstellen 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() { + } + + /// + /// Gibt die zwischengespeicherte ResourceManager-Instanz zurück, die von dieser Klasse verwendet wird. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("TimeKeeper.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Überschreibt die CurrentUICulture-Eigenschaft des aktuellen Threads für alle + /// Ressourcenzuordnungen, die diese stark typisierte Ressourcenklasse verwenden. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Icon ähnlich wie (Symbol). + /// + internal static System.Drawing.Icon IconMain { + get { + object obj = ResourceManager.GetObject("IconMain", resourceCulture); + return ((System.Drawing.Icon)(obj)); + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap MenuImagesQuit { + get { + object obj = ResourceManager.GetObject("MenuImagesQuit", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Icon ähnlich wie (Symbol). + /// + internal static System.Drawing.Icon TrayIconConnected { + get { + object obj = ResourceManager.GetObject("TrayIconConnected", resourceCulture); + return ((System.Drawing.Icon)(obj)); + } + } + + /// + /// Sucht eine lokalisierte Ressource vom Typ System.Drawing.Icon ähnlich wie (Symbol). + /// + internal static System.Drawing.Icon TrayIconDisconnected { + get { + object obj = ResourceManager.GetObject("TrayIconDisconnected", resourceCulture); + return ((System.Drawing.Icon)(obj)); + } + } + } +} diff --git a/TimeKeeper/TimeKeeper/Properties/Resources.resx b/TimeKeeper/TimeKeeper/Properties/Resources.resx new file mode 100644 index 0000000..5f9c014 --- /dev/null +++ b/TimeKeeper/TimeKeeper/Properties/Resources.resx @@ -0,0 +1,133 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + ..\Resources\Icons\main.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\Icons\door_open.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\Icons\main_con.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\Icons\main_dis.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + \ No newline at end of file diff --git a/TimeKeeper/TimeKeeper/Resources/Icons/connect.png b/TimeKeeper/TimeKeeper/Resources/Icons/connect.png new file mode 100644 index 0000000..6c78bbd Binary files /dev/null and b/TimeKeeper/TimeKeeper/Resources/Icons/connect.png differ diff --git a/TimeKeeper/TimeKeeper/Resources/Icons/disconnect.png b/TimeKeeper/TimeKeeper/Resources/Icons/disconnect.png new file mode 100644 index 0000000..4ffb7fc Binary files /dev/null and b/TimeKeeper/TimeKeeper/Resources/Icons/disconnect.png differ diff --git a/TimeKeeper/TimeKeeper/Resources/Icons/door_open.png b/TimeKeeper/TimeKeeper/Resources/Icons/door_open.png new file mode 100644 index 0000000..64bab57 Binary files /dev/null and b/TimeKeeper/TimeKeeper/Resources/Icons/door_open.png differ diff --git a/TimeKeeper/TimeKeeper/Resources/Icons/main.ico b/TimeKeeper/TimeKeeper/Resources/Icons/main.ico new file mode 100644 index 0000000..d87a506 Binary files /dev/null and b/TimeKeeper/TimeKeeper/Resources/Icons/main.ico differ diff --git a/TimeKeeper/TimeKeeper/Resources/Icons/main_con.ico b/TimeKeeper/TimeKeeper/Resources/Icons/main_con.ico new file mode 100644 index 0000000..35adfe6 Binary files /dev/null and b/TimeKeeper/TimeKeeper/Resources/Icons/main_con.ico differ diff --git a/TimeKeeper/TimeKeeper/Resources/Icons/main_dis.ico b/TimeKeeper/TimeKeeper/Resources/Icons/main_dis.ico new file mode 100644 index 0000000..0eebf30 Binary files /dev/null and b/TimeKeeper/TimeKeeper/Resources/Icons/main_dis.ico differ diff --git a/TimeKeeper/TimeKeeper/TimeKeeper.csproj b/TimeKeeper/TimeKeeper/TimeKeeper.csproj new file mode 100644 index 0000000..c79d241 --- /dev/null +++ b/TimeKeeper/TimeKeeper/TimeKeeper.csproj @@ -0,0 +1,123 @@ + + + + + Debug + AnyCPU + {25F58397-71CB-4298-979E-BAACE80C61CB} + WinExe + Properties + TimeKeeper + TimeKeeper + v4.5 + 512 + + + x64 + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + x64 + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + TimeKeeper.Program + + + Resources\Icons\main.ico + + + + ..\lib\MySql.Data.dll + + + + + False + ..\lib\System.Data.SQLite.dll + + + + + + + + + + + + + + + + + + + + + + + + + + + + True + True + Resources.resx + + + + Form + + + ViewWindowForm.cs + + + + + + + {fac8ce64-bf13-4ece-8097-aeb5dd060098} + Utils + + + + + ResXFileCodeGenerator + Resources.Designer.cs + + + + + + PreserveNewest + + + + + + + + + + + + \ No newline at end of file diff --git a/TimeKeeper/TimeKeeper/View/VTray.cs b/TimeKeeper/TimeKeeper/View/VTray.cs new file mode 100644 index 0000000..2d5e724 --- /dev/null +++ b/TimeKeeper/TimeKeeper/View/VTray.cs @@ -0,0 +1,87 @@ +using BlubbFish.Utils; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; +using TimeKeeper.Properties; +using System.Drawing; +using TimeKeeper.Models; + +namespace TimeKeeper.View { + class Tray : OwnView { + public Models.Tray Model { get; private set; } + + private NotifyIcon trayi; + private Icon[] trayIcons = { new Icon(Resources.TrayIconConnected, 40, 40), new Icon(Resources.TrayIconDisconnected, 40, 40) }; + private Boolean offsetTimeFail; + + public Tray() { + this.init(); + this.Model = Models.Tray.Instance; + this.Model.setObserver(this); + } + + public override void update() { + this.trayi.ContextMenuStrip = this.genMenu(); + this.trayi.Icon = (this.Model.isConnected) ? this.trayIcons[0] : this.trayIcons[1]; + if(this.Model.Messages.Count > 0) { + Models.Types.WorkMessage m = this.Model.Messages.Peek(); + string text = (m.working==1)?"Angefangen zu arbeiten ":"Aufgehört zu arbeiten "; + text += "am " + m.time.ToShortDateString() + " " + m.time.ToLongTimeString() + " "; + text += "in Job " + m.jobID.ToString(); + this.showBallonTooltip(text, ToolTipIcon.Info); + } else if(Math.Abs(this.Model.OffsetTime.TotalSeconds) >= 2) { + this.showBallonTooltip("Achtung Abweichung von der Zeit: " + this.Model.OffsetTime.TotalSeconds, ToolTipIcon.Warning); + this.offsetTimeFail = true; + } else if(Math.Abs(this.Model.OffsetTime.TotalSeconds) < 2 && this.offsetTimeFail) { + this.showBallonTooltip("Zeitabweichung ok: " + this.Model.OffsetTime.TotalSeconds, ToolTipIcon.Info); + this.offsetTimeFail = false; + } + } + + override protected void init() { + this.trayi = new NotifyIcon(); + this.trayi.Visible = true; + this.trayi.Icon = this.trayIcons[1]; + this.trayi.Text = "TimeKeeper"; + this.trayi.DoubleClick += Controller.Tray.Click_Tray; + } + + override public void Dispose() { + this.trayi.Visible = false; + this.Model.Dispose(); + Application.ExitThread(); + } + + private ContextMenuStrip genMenu() { + ContextMenuStrip menu = new ContextMenuStrip(); + ToolStripMenuItem mo = new ToolStripMenuItem("Öffnen"); + mo.Image = Resources.MenuImagesQuit; + mo.Click += Controller.Tray.Click_Open; + mo.Name = "Open"; + menu.Items.Add(mo); + + menu.Items.Add(new ToolStripSeparator()); + + ToolStripMenuItem mq = new ToolStripMenuItem("Beenden"); + mq.Image = Resources.MenuImagesQuit; + mq.Click += Controller.Tray.Click_Quit; + mq.Name = "Quit"; + menu.Items.Add(mq); + return menu; + } + + private void showBallonTooltip(string text, ToolTipIcon toolTipIcon, string title = "TimeKeeper Tray") { + this.trayi.BalloonTipIcon = toolTipIcon; + this.trayi.BalloonTipText = text; + this.trayi.BalloonTipTitle = title; + this.trayi.ShowBalloonTip(100); + } + + internal void showError(string text) { + this.showBallonTooltip(text, ToolTipIcon.Error); + } + } +} diff --git a/TimeKeeper/TimeKeeper/View/VWindow.cs b/TimeKeeper/TimeKeeper/View/VWindow.cs new file mode 100644 index 0000000..10f7ad0 --- /dev/null +++ b/TimeKeeper/TimeKeeper/View/VWindow.cs @@ -0,0 +1,35 @@ +using BlubbFish.Utils; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace TimeKeeper.View { + class Window : OwnView { + private ViewWindowForm form; + public Window() { + this.form = new ViewWindowForm(); + this.init(); + this.Model.setObserver(this); + } + + public override void update() { + this.form.UpdateForm(); + } + + protected override void init() { + this.Model = Models.Window.Instance; + this.form.SetModel(this.Model); + this.form.Show(); + } + + public override void Dispose() { + this.form.BeginInvoke((Action)(() => { + this.form.Dispose(); + })); + } + + public Models.Window Model { get; private set; } + } +} diff --git a/TimeKeeper/TimeKeeper/View/ViewWindowForm.Designer.cs b/TimeKeeper/TimeKeeper/View/ViewWindowForm.Designer.cs new file mode 100644 index 0000000..9ffc2e7 --- /dev/null +++ b/TimeKeeper/TimeKeeper/View/ViewWindowForm.Designer.cs @@ -0,0 +1,33 @@ +namespace TimeKeeper.View { + partial class ViewWindowForm { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) { + if(disposing && (components != null)) { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() { + this.components = new System.ComponentModel.Container(); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Text = "ViewWindowForm"; + } + + #endregion + } +} \ No newline at end of file diff --git a/TimeKeeper/TimeKeeper/View/ViewWindowForm.cs b/TimeKeeper/TimeKeeper/View/ViewWindowForm.cs new file mode 100644 index 0000000..9addef3 --- /dev/null +++ b/TimeKeeper/TimeKeeper/View/ViewWindowForm.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace TimeKeeper.View { + public partial class ViewWindowForm : Form { + private Models.Window model; + + public ViewWindowForm() { + InitializeComponent(); + this.FormClosed += Controller.Window.FormClosed; + this.Icon = TimeKeeper.Properties.Resources.IconMain; + } + + public void UpdateForm() { + this.BeginInvoke((Action)(() => { + + })); + } + + internal void SetModel(Models.Window window) { + this.model = window; + } + } +} diff --git a/TimeKeeper/TimeKeeper/bin/Release/TimeKeeper.exe b/TimeKeeper/TimeKeeper/bin/Release/TimeKeeper.exe new file mode 100644 index 0000000..00c5717 Binary files /dev/null and b/TimeKeeper/TimeKeeper/bin/Release/TimeKeeper.exe differ diff --git a/TimeKeeper/TimeKeeper/bin/Release/Utils.dll b/TimeKeeper/TimeKeeper/bin/Release/Utils.dll new file mode 100644 index 0000000..0dd4d12 Binary files /dev/null and b/TimeKeeper/TimeKeeper/bin/Release/Utils.dll differ diff --git a/TimeKeeper/TimeKeeper/bin/Release/settings.ini b/TimeKeeper/TimeKeeper/bin/Release/settings.ini new file mode 100644 index 0000000..d03527a --- /dev/null +++ b/TimeKeeper/TimeKeeper/bin/Release/settings.ini @@ -0,0 +1,2 @@ +[general] +comport=COM4 \ No newline at end of file diff --git a/TimeKeeper/TimeKeeper/settings.ini b/TimeKeeper/TimeKeeper/settings.ini new file mode 100644 index 0000000..b5bad6c --- /dev/null +++ b/TimeKeeper/TimeKeeper/settings.ini @@ -0,0 +1,11 @@ +[general] +port=28654 +arduinoport=25987 + +[database] +engine=Mysql +host=localhost +port=3306 +db=worktime +user=root +pass=mafia \ No newline at end of file diff --git a/TimeKeeper/lib/MySql.Data.dll b/TimeKeeper/lib/MySql.Data.dll new file mode 100644 index 0000000..fd3c20a Binary files /dev/null and b/TimeKeeper/lib/MySql.Data.dll differ diff --git a/TimeKeeper/lib/System.Data.SQLite.dll b/TimeKeeper/lib/System.Data.SQLite.dll new file mode 100644 index 0000000..ad11eca Binary files /dev/null and b/TimeKeeper/lib/System.Data.SQLite.dll differ diff --git a/Utils/Utils.sln b/Utils/Utils.sln new file mode 100644 index 0000000..012783f --- /dev/null +++ b/Utils/Utils.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "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 + {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 +EndGlobal diff --git a/Utils/Utils/CmdArgs.cs b/Utils/Utils/CmdArgs.cs new file mode 100644 index 0000000..ddadc6b --- /dev/null +++ b/Utils/Utils/CmdArgs.cs @@ -0,0 +1,186 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace BlubbFish.Utils +{ + public class CmdArgs + { + public enum ArgLength + { + Single, + Touple + } + #region Classes + public struct VaildArguments + { + public VaildArguments(ArgLength length, Boolean required) + { + this.Required = required; + this.Length = length; + } + public VaildArguments(ArgLength length) + { + this.Required = false; + this.Length = length; + } + + public ArgLength Length { get; private set; } + public Boolean Required { get; private set; } + } + private struct ArgTouple + { + public ArgTouple(String type, String data) + { + this.Type = type; + this.Data = data; + } + public ArgTouple(String type) + { + this.Type = type; + this.Data = ""; + } + public String Type { get; private set; } + public String Data { get; private set; } + + internal void SetData(String data) + { + if (data != "") { + this.Data = data; + } + } + } + #endregion + private String[] args; + private List argList; + private Dictionary argsPosible = new Dictionary(); + private static CmdArgs instances = null; + private Boolean isSetArguments = false; + + private CmdArgs() + { + } + + /// + /// Gibt eine Instanz der Klasse zurück + /// + /// Klasse + public static CmdArgs Instance + { + get { + if (instances == null) { + instances = new CmdArgs(); + } + return instances; + } + } + + /// + /// Übernimmt die Argumente für die Klasse + /// + /// Mögliche Komandozeilenargumente + /// Tatsächliche Komandozeilenargumente + public void SetArguments(Dictionary arguments, String[] args) + { + this.args = args; + if (!this.isSetArguments) { + this.isSetArguments = true; + this.argsPosible = arguments; + this.Init(); + } + } + + private void Init() + { + this.argList = new List(); + for (Int32 i = 0; i < this.args.Length; i++) { + if (this.argsPosible.Keys.Contains(this.args[i])) { + ArgTouple arg = new ArgTouple(this.args[i]); + if (this.argsPosible[this.args[i]].Length == ArgLength.Touple) { + if (this.args.Length > i + 1) { + arg.SetData(this.args[++i]); + } else { + throw new ArgumentException(); + } + } + this.argList.Add(arg); + } + } + } + + /// + /// Menge der angegebenen Komandozeilen-Argumente + /// + /// Menge + public Int32 GetArgsLength() + { + return this.argList.Count; + } + + /// + /// Gibt zurück ob ein Argument angegeben wurde + /// + /// Name des Arguments + /// true wenn angegeben + public Boolean HasArgumentType(String name) + { + foreach (ArgTouple t in this.argList) { + if (t.Type == name) { + return true; + } + } + return false; + } + + /// + /// Gibt den Inhalt des angegeben Arguments zurück, nur bei zweiteiligen Argumenten möglich + /// + /// Name des Arguments + /// Inhalt des Arguments oder ArgumentNullException + public String GetArgumentData(String name) + { + foreach (ArgTouple t in this.argList) { + if (t.Type == name && t.Data != null) { + return t.Data; + } else { + throw new ArgumentNullException(); + } + } + return null; + } + + public Boolean HasAllRequiredArguments() + { + foreach (KeyValuePair item in this.argsPosible) { + if (item.Value.Required && !this.HasArgumentType(item.Key)) { + return false; + } + } + return true; + } + + public String GetUsageList(String name) + { + String ret = "Usage: " + name + " Parameter\nParameter:\n"; + String req = ""; + String opt = ""; + foreach (KeyValuePair item in this.argsPosible) { + if (item.Value.Required) { + req += item.Key + " " + ((item.Value.Length == ArgLength.Touple) ? " [data]\n" : "\n"); + } + } + if (req != "") { + ret += "Benötigte Parameter:\n" + req; + } + foreach (KeyValuePair item in this.argsPosible) { + if (!item.Value.Required) { + opt += item.Key + " " + ((item.Value.Length == ArgLength.Touple) ? " [data]\n" : "\n"); + } + } + if (opt != "") { + ret += "Optionale Parameter:\n" + opt; + } + return ret; + } + } +} diff --git a/Utils/Utils/EventArgsHelper.cs b/Utils/Utils/EventArgsHelper.cs new file mode 100644 index 0000000..b87fd6f --- /dev/null +++ b/Utils/Utils/EventArgsHelper.cs @@ -0,0 +1,34 @@ +using System; + +namespace BlubbFish.Utils { + public class UpdaterEventArgs : EventArgs { + public UpdaterEventArgs(Boolean hasUpdates, String message) { + this.HasUpdates = hasUpdates; + this.Message = message; + } + public String Message { get; private set; } + public Boolean HasUpdates { get; private set; } + } + + public class UpdaterFailEventArgs : EventArgs { + public UpdaterFailEventArgs(Exception e) { + this.Except = e; + } + + public Exception Except { get; private set; } + } + + public class LogEventArgs : EventArgs { + public LogEventArgs(String location, String message, OwnObject.LogLevel level, DateTime date) { + this.Location = location; + this.Message = message; + this.Level = level; + this.Date = date; + } + + public String Location { get; private set; } + public String Message { get; private set; } + public OwnObject.LogLevel Level { get; private set; } + public DateTime Date { get; private set; } + } +} diff --git a/Utils/Utils/FileLogger.cs b/Utils/Utils/FileLogger.cs new file mode 100644 index 0000000..9dd397f --- /dev/null +++ b/Utils/Utils/FileLogger.cs @@ -0,0 +1,67 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.IO; +using System.Reflection; + +namespace BlubbFish.Utils +{ + public class FileLogger + { + private static Dictionary instances = new Dictionary(); + private static String logDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + Path.DirectorySeparatorChar; + private StreamWriter file; + private FileLogger(String filename, Boolean append) + { + filename = logDir + filename; + if (!File.Exists(filename)) { + String folder = Path.GetDirectoryName(Path.GetFullPath(filename)); + if (!Directory.Exists(folder)) { + Directory.CreateDirectory(folder); + } + } + this.file = new StreamWriter(filename, append, Encoding.UTF8) { + AutoFlush = true + }; + } + public static FileLogger GetInstance(String filename, Boolean append) + { + if (!instances.Keys.Contains(filename)) { + instances.Add(filename, new FileLogger(filename, append)); + } + return instances[filename]; + } + + public static void SetLogDir(String v) + { + v = v.Replace("..", ""); + v = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + Path.DirectorySeparatorChar + v; + if (Directory.Exists(v)) { + logDir = v; + } else { + Directory.CreateDirectory(v); + logDir = v; + } + if (logDir.Substring(logDir.Length - 1) != Path.DirectorySeparatorChar.ToString()) { + logDir = logDir + Path.DirectorySeparatorChar; + } + } + + public void SetArray(String[] text) + { + this.file.Write(String.Join(this.file.NewLine, text) + this.file.NewLine); + this.file.Flush(); + } + + public void SetLine(String text) + { + this.file.WriteLine(text); + this.file.Flush(); + } + public void SetLine(String text, DateTime d) + { + this.SetLine(d.ToString("[yyyy-MM-dd HH:mm:ss.ffff] ") + text); + } + } +} diff --git a/Utils/Utils/FileMutex.cs b/Utils/Utils/FileMutex.cs new file mode 100644 index 0000000..567b753 --- /dev/null +++ b/Utils/Utils/FileMutex.cs @@ -0,0 +1,71 @@ +using System; +using System.IO; +using System.Security.Cryptography; +using System.Text; + +namespace BlubbFish.Utils +{ + public class FileMutex : IDisposable + { + private static FileMutex instance; + private String filename; + private StreamWriter file; + private FileMutex() { } + + public static FileMutex Instance + { + get { + if (instance == null) { + instance = new FileMutex(); + } + return instance; + } + } + + public void SetName(String name) + { + String path = AppDomain.CurrentDomain.BaseDirectory; + this.filename = path + String.Join(String.Empty, Array.ConvertAll(new SHA512Managed().ComputeHash(Encoding.UTF8.GetBytes(name)), b => b.ToString("X2"))) + ".lock.txt"; + } + + public Boolean Create() + { + if (File.Exists(this.filename)) { + return false; + } + + this.file = new StreamWriter(this.filename); + InitFile(); + return File.Exists(this.filename) && this.file != null; + } + + private void InitFile() + { + this.file.Write("Created: " + DateTime.Now.ToUniversalTime() + "\n"); + this.file.Flush(); + } + + public Boolean Delete() + { + if(this.file != null) { + this.file.Close(); + } + + File.Delete(this.filename); + return !File.Exists(this.filename); + } + + protected virtual void Dispose(Boolean disposing) { + if (disposing) { + if(this.file != null) { + this.file.Close(); + } + } + } + + public void Dispose() { + Dispose(true); + GC.SuppressFinalize(this); + } + } +} diff --git a/Utils/Utils/InIReader.cs b/Utils/Utils/InIReader.cs new file mode 100644 index 0000000..c87b449 --- /dev/null +++ b/Utils/Utils/InIReader.cs @@ -0,0 +1,203 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; + +namespace BlubbFish.Utils +{ + public class InIReader : IDisposable + { + private Dictionary> inifile; + private FileSystemWatcher k = new FileSystemWatcher(Directory.GetCurrentDirectory(), "*.ini"); + private String filename; + + private static Dictionary instances = new Dictionary(); + + private InIReader(String filename) + { + this.filename = filename; + this.k.Changed += new FileSystemEventHandler(this.ReadAgain); + LoadFile(); + } + + public static InIReader GetInstance(String filename) + { + if (!instances.Keys.Contains(filename)) { + instances.Add(filename, new InIReader(filename)); + } + return instances[filename]; + } + + private void ReadAgain(Object sender, EventArgs e) + { + this.LoadFile(); + } + + private void LoadFile() + { + this.inifile = new Dictionary>(); + StreamReader file = new StreamReader(this.filename); + List buf = new List(); + String fline = ""; + while (fline != null) { + fline = file.ReadLine(); + if (fline != null && fline.Length > 0 && fline.Substring(0, 1) != ";") { + buf.Add(fline); + } + } + file.Close(); + Dictionary sub = new Dictionary(); + String cap = ""; + foreach (String line in buf) { + Match match = Regex.Match(line, @"^\[[a-zA-ZäöüÄÖÜ0-9\-_ ]+\]\w*$", RegexOptions.IgnoreCase); + if (match.Success) { + if (sub.Count != 0 && cap != "") { + this.inifile.Add(cap, sub); + } + cap = line; + sub = new Dictionary(); + } else { + if (line != "" && cap != "") { + String key = line.Substring(0, line.IndexOf('=')); + String value = line.Substring(line.IndexOf('=') + 1); + sub.Add(key, value); + } + } + } + if (sub.Count != 0 && cap != "") { + this.inifile.Add(cap, sub); + } + } + + public List GetSections(Boolean withBrackets = true) + { + if(withBrackets) { + return this.inifile.Keys.ToList(); + } else { + List ret = new List(); + foreach (String item in this.inifile.Keys) { + ret.Add(item.Substring(1, item.Length - 2)); + } + return ret; + } + } + + public Dictionary GetSection(String section) { + if(this.inifile.Keys.Contains(section)) { + return this.inifile[section]; + } + if(this.inifile.Keys.Contains("["+section+"]")) { + return this.inifile["[" + section + "]"]; + } + return new Dictionary(); + } + + public String GetValue(String section, String key) + { + if (!section.StartsWith("[")) { + section = "[" + section + "]"; + } + if (this.inifile.Keys.Contains(section)) { + if (this.inifile[section].Keys.Contains(key)) { + return this.inifile[section][key]; + } + } + return null; + } + + + public void SetValue(String section, String key, String value) + { + if (!section.StartsWith("[")) { + section = "[" + section + "]"; + } + if (this.inifile.Keys.Contains(section)) { + if (this.inifile[section].Keys.Contains(key)) { + this.inifile[section][key] = value; + } else { + this.inifile[section].Add(key, value); + } + } else { + Dictionary sub = new Dictionary { + { key, value } + }; + this.inifile.Add(section, sub); + } + this.Changed(); + } + + private void Changed() + { + this.k.Changed -= null; + SaveSettings(); + LoadFile(); + this.k.Changed += new FileSystemEventHandler(this.ReadAgain); + } + + private void SaveSettings() + { + StreamWriter file = new StreamWriter(this.filename); + file.BaseStream.SetLength(0); + file.BaseStream.Flush(); + file.BaseStream.Seek(0, SeekOrigin.Begin); + foreach (KeyValuePair> cap in this.inifile) { + file.WriteLine(cap.Key); + foreach (KeyValuePair sub in cap.Value) { + file.WriteLine(sub.Key + "=" + sub.Value); + } + file.WriteLine(); + } + file.Flush(); + file.Close(); + } + + /// + /// Fügt eine neue Sektion in der Ini-Datei ein. + /// + /// Sektionsname + /// true if added, false if error + public Boolean AddSection(String name) + { + if (!name.StartsWith("[")) { + name = "[" + name + "]"; + } + if (this.inifile.Keys.Contains(name)) { + return false; + } + this.inifile.Add(name, new Dictionary()); + this.Changed(); + return true; + } + + /// + /// Löscht eine Sektion inklusive Unterpunkte aus der Ini-Datei. + /// + /// Sektionsname + /// true if removed, false if error + public Boolean RemoveSection(String name) + { + if (!name.StartsWith("[")) { + name = "[" + name + "]"; + } + if (!this.inifile.Keys.Contains(name)) { + return false; + } + this.inifile.Remove(name); + this.Changed(); + return false; + } + protected virtual void Dispose(Boolean disposing) { + if (disposing) { + this.k.Dispose(); + } + } + + public void Dispose() { + Dispose(true); + GC.SuppressFinalize(this); + } + } +} diff --git a/Utils/Utils/OwnController.cs b/Utils/Utils/OwnController.cs new file mode 100644 index 0000000..385827e --- /dev/null +++ b/Utils/Utils/OwnController.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace BlubbFish.Utils +{ + public abstract class OwnController + { + /// + /// Führt den Controller aus. + /// + public void Execute() + { + this.Init(); + } + abstract protected void Init(); + abstract public void Dispose(); + } +} diff --git a/Utils/Utils/OwnModel.cs b/Utils/Utils/OwnModel.cs new file mode 100644 index 0000000..7d566fe --- /dev/null +++ b/Utils/Utils/OwnModel.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BlubbFish.Utils +{ + public abstract class OwnModel where T : class + { + private static readonly Lazy _instance = new Lazy(() => CreateInstanceOfT()); + private List observer = new List(); + public static T Instance + { + get { + return _instance.Value; + } + } + private static T CreateInstanceOfT() + { + return Activator.CreateInstance(typeof(T), true) as T; + } + + public void SetObserver(OwnView view) + { + this.observer.Add(view); + view.Update(); + } + + public void RemoveObserver(OwnView view) { + this.observer.Remove(view); + } + protected void Update() + { + this.observer.ForEach(delegate (OwnView view) { view.Update(); }); + } + abstract protected void Init(); + } +} diff --git a/Utils/Utils/OwnObject.cs b/Utils/Utils/OwnObject.cs new file mode 100644 index 0000000..7a6c661 --- /dev/null +++ b/Utils/Utils/OwnObject.cs @@ -0,0 +1,110 @@ +using System; +using System.Collections.Generic; + +namespace BlubbFish.Utils +{ + abstract public class OwnObject + { + public struct LogObject { + public LogObject(DateTime date, String location, String message, LogLevel level) { + this.Date = date; + this.Location = location; + this.Message = message; + this.Level = level; + } + + public DateTime Date { get; set; } + public String Location { get; set; } + public String Message { get; set; } + public LogLevel Level { get; set; } + /// + /// Formates a LogMessage to a String + /// + /// Formated String + public override String ToString() { + return "[" + this.Date.ToString("R") + "]: " + this.Level.ToString() + " "+ this.Location + ", " + this.Message; + } + /// + /// Formates a LogMessage to a String + /// + /// Enables the output of the location + /// Enables the output of the date + /// Formated String + public String ToString(Boolean classNames, Boolean timeStamps) { + return (timeStamps ? "[" + this.Date.ToString("R") + "]: " + this.Level.ToString() + " " : "") + (classNames ? this.Location + ", " : "") + this.Message; + } + } + + private List loglist = new List(); + + public delegate void LogEvent(Object sender, LogEventArgs e); + public enum LogLevel : Int32 { + Debug = 1, + Notice = 2, + Info = 4, + Warn = 8, + Error = 16 + } + + public event LogEvent EventDebug; + public event LogEvent EventNotice; + public event LogEvent EventInfo; + public event LogEvent EventWarn; + public event LogEvent EventError; + public event LogEvent EventLog; + + /// + /// Get the Complete Log + /// + public List GetLog(LogLevel level, Boolean classNames, Boolean timeStamps) { + List ret = new List(); + foreach (LogObject t in this.loglist) { + if (t.Level >= level) { + ret.Add(t.ToString(classNames, timeStamps)); + } + } + return ret; + } + + /// + /// Put a message in the log + /// + /// Where the event arrives + /// The logmessage itselfs + /// Level of the message + protected void AddLog(String location, String message, LogLevel level) + { + this.AddLog(location, message, level, DateTime.Now); + } + + /// + /// Put a message in the log + /// + /// Where the event arrives + /// The logmessage itselfs + /// Level of the message + /// Date of the message + protected void AddLog(String location, String message, LogLevel level, DateTime date) + { + LogEventArgs e = new LogEventArgs(location, message, level, date); + if (EventDebug != null && level >= LogLevel.Debug) { + EventDebug(this, e); + } + if (EventNotice != null && level >= LogLevel.Notice) { + EventNotice(this, e); + } + if (EventInfo != null && level >= LogLevel.Info) { + EventInfo(this, e); + } + if (EventWarn != null && level >= LogLevel.Warn) { + EventWarn(this, e); + } + if (EventError != null && level >= LogLevel.Error) { + EventError(this, e); + } + EventLog?.Invoke(this, e); + + this.loglist.Add(new LogObject(date, location, message, level)); + } + } +} diff --git a/Utils/Utils/OwnView.cs b/Utils/Utils/OwnView.cs new file mode 100644 index 0000000..bd30612 --- /dev/null +++ b/Utils/Utils/OwnView.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BlubbFish.Utils { + public abstract class OwnView { + + protected OwnView() { } + /// + /// Called if the Oberver (Model) updates its View + /// + public abstract void Update(); + /// + /// Called if view is viewed + /// + //protected abstract void Init(); + /// + /// Called if Form is Disposed + /// + public abstract void Dispose(); + } +} diff --git a/Utils/Utils/Properties/AssemblyInfo.cs b/Utils/Utils/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..0e88670 --- /dev/null +++ b/Utils/Utils/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// Allgemeine Informationen über eine Assembly werden über die folgenden +// Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern, +// die mit einer Assembly verknüpft sind. +[assembly: AssemblyTitle("Utils")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Utils")] +[assembly: AssemblyCopyright("Copyright © 2014 - 25.09.2017")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Durch Festlegen von ComVisible auf "false" werden die Typen in dieser Assembly unsichtbar +// für COM-Komponenten. Wenn Sie auf einen Typ in dieser Assembly von +// COM zugreifen müssen, legen Sie das ComVisible-Attribut für diesen Typ auf "true" fest. +[assembly: ComVisible(false)] + +// Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird +[assembly: Guid("6f20376a-5c71-4979-9932-13c105d1c6e6")] + +// Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten: +// +// Hauptversion +// Nebenversion +// Buildnummer +// Revision +// +// Sie können alle Werte angeben oder die standardmäßigen Build- und Revisionsnummern +// übernehmen, indem Sie "*" eingeben: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.5.2")] +[assembly: AssemblyFileVersion("1.0.5.2")] diff --git a/Utils/Utils/Updater.cs b/Utils/Utils/Updater.cs new file mode 100644 index 0000000..fc4eb0e --- /dev/null +++ b/Utils/Utils/Updater.cs @@ -0,0 +1,192 @@ + +using System; +using System.IO; +using System.Net; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading; +using System.Xml; + +namespace BlubbFish.Utils { + public class Updater : OwnObject { + private static Updater instances; + private String url; + private VersionInfo[] versions; + private Thread t; + + public struct VersionInfo { + public VersionInfo(Type type) { + this.Name = type.Assembly.GetName().Name; + this.Version = type.Assembly.GetName().Version.ToString(); + this.Filename = type.Assembly.ManifestModule.Name; + this.GUID = ((GuidAttribute)type.Assembly.GetCustomAttribute(typeof(GuidAttribute))).Value; + this.HasUpdate = false; + } + + public String Name { get; private set; } + public String Version { get; private set; } + public String Filename { get; private set; } + public String GUID { get; private set; } + public Boolean HasUpdate { get; set; } + } + + public delegate void UpdateStatus(Object sender, UpdaterEventArgs e); + public delegate void UpdateFail(Object sender, UpdaterFailEventArgs e); + + public event UpdateStatus UpdateResult; + public event UpdateFail ErrorRaised; + + private Updater() { } + + /// + /// Get Instance of Updater + /// + public static Updater Instance { + get { + if(instances == null) { + instances = new Updater(); + } + return instances; + } + } + + /// + /// Waits for the Result of the Updater thread. + /// + public void WaitForExit(Boolean exceuteUpdate = true) { + while (this.t.ThreadState == ThreadState.Running) { } + if(exceuteUpdate) { + if(File.Exists("update.bat")) { + System.Diagnostics.Process.Start("update.bat"); + } + } + } + + /// + /// Set Path to check for Updates + /// + /// HTTP URI + public void SetUpdateInfo(String url, VersionInfo[] versions) { + this.url = url; + this.versions = versions; + FileStream file = new FileStream("version.xml",FileMode.Create); + XmlTextWriter xml = new XmlTextWriter(file, Encoding.UTF8); + xml.WriteStartDocument(); + xml.WriteWhitespace("\n"); + xml.WriteStartElement("filelist"); + xml.WriteWhitespace("\n"); + foreach (VersionInfo version in versions) { + xml.WriteWhitespace("\t"); + xml.WriteStartElement("file"); + xml.WriteAttributeString("Version", version.Version); + xml.WriteAttributeString("Filename", version.Filename); + xml.WriteAttributeString("GUID", version.GUID); + xml.WriteString(version.Name); + xml.WriteEndElement(); + xml.WriteWhitespace("\n"); + } + xml.WriteEndElement(); + xml.Flush(); + file.Flush(); + file.Close(); + } + + /// + /// Check for Updates + /// + /// + public void Check() { + if(this.url == "") { + throw new ArgumentException("Zuerst eine URL setzen!"); + } + if(this.versions.Length == 0) { + throw new ArgumentException("Zuerst Dateien registrieren!"); + } + if(this.UpdateResult == null) { + throw new ArgumentNullException("Zuerst das Update Event anhängen."); + } + this.t = new Thread(this.Runner); + this.t.Start(); + } + + private void Runner() { + Thread.Sleep(1000); + try { + Stream stream = WebRequest.Create(this.url + "version.xml").GetResponse().GetResponseStream(); + String content = new StreamReader(stream).ReadToEnd(); + Boolean update = false; + XmlDocument doc = new XmlDocument(); + doc.LoadXml(content); + foreach (XmlNode node in doc.DocumentElement.ChildNodes) { + String guid = node.Attributes["GUID"].Value; + String version = node.Attributes["Version"].Value; + for(Int32 i=0;i + /// Update the file + /// + /// Updates the Programm after it has been closed + /// + public Boolean Update(Boolean afterExit = true) { + try { + if (afterExit) { + this.UpdateAfter(); + } else { + this.UpdateNow(); + } + } catch (Exception e) { + this.ErrorRaised?.Invoke(this, new UpdaterFailEventArgs(e)); + return false; + } + return true; + } + + private void UpdateAfter() { + this.UpdateNow(true); + StreamWriter update = new StreamWriter("update.bat", false); + update.WriteLine("echo off"); + update.WriteLine("echo \"Warte 10s\""); + update.WriteLine("ping 127.0.0.1 -n 10"); + update.WriteLine("echo \"Kopiere Dateien....\""); + foreach (VersionInfo file in this.versions) { + if (file.HasUpdate) { + update.WriteLine("echo \"Kopiere " + file.Filename + "\""); + update.WriteLine("del " + file.Filename); + update.WriteLine("move " + file.Filename + "_ " + file.Filename); + } + } + update.WriteLine("start cmd /C ping 127.0.0.1 -n 10 & del update.bat"); + update.Flush(); + update.Close(); + } + + private void UpdateNow(Boolean forAfter = false) { + foreach (VersionInfo file in this.versions) { + if (file.HasUpdate) { + Stream stream = WebRequest.Create(this.url + file.Filename).GetResponse().GetResponseStream(); + FileStream target = new FileStream(file.Filename + (forAfter ? "_" : ""), FileMode.Create); + stream.CopyTo(target); + target.Flush(); + target.Close(); + } + } + } + } +} diff --git a/Utils/Utils/Utils.csproj b/Utils/Utils/Utils.csproj new file mode 100644 index 0000000..61274ab --- /dev/null +++ b/Utils/Utils/Utils.csproj @@ -0,0 +1,63 @@ + + + + + Debug + AnyCPU + {FAC8CE64-BF13-4ECE-8097-AEB5DD060098} + Library + Properties + BlubbFish.Utils + Utils + v4.5 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Utils/Utils/bin/Release/Utils.dll b/Utils/Utils/bin/Release/Utils.dll new file mode 100644 index 0000000..28f5d3d Binary files /dev/null and b/Utils/Utils/bin/Release/Utils.dll differ diff --git a/ebbits/AdvancedServo-simple/Arduino/AbstractArduino.cs b/ebbits/AdvancedServo-simple/Arduino/AbstractArduino.cs new file mode 100644 index 0000000..54290cf --- /dev/null +++ b/ebbits/AdvancedServo-simple/Arduino/AbstractArduino.cs @@ -0,0 +1,114 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.IO.Ports; +using System.Text.RegularExpressions; + +namespace ebbits.Arduino { + abstract class AbstractArduino { + protected SerialPort arduino; + protected LinkedList readStack = new LinkedList(); + protected void init(string port) { + arduino = new SerialPort(port, 57600); + arduino.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler); + arduino.Open(); + arduino.WriteLine(""); + + } + private void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e) { + SerialPort sp = (SerialPort)sender; + string s = sp.ReadLine(); + Logger.Serial("in", s); + if(ArduinoInput.check(s)) { + readStack.AddLast(new ArduinoInput(s)); + } + } + protected void serialSend(char key, byte pos, int val) { + char c = ArduinoInput.checksum(key + pos.ToString() + "=" + val.ToString()); + string s = "*" + key + pos.ToString() + "=" + val + "$" + c + "#"; + arduino.WriteLine(s); + Logger.Serial("out", s); + } + + protected ArduinoInput getInput(char key, byte id = 255) { + LinkedList.Enumerator e = readStack.GetEnumerator(); + try { + while(e.MoveNext()) { + if((e.Current.key == key && e.Current.id == id) || (id == 255 && e.Current.key == key)) { + ArduinoInput a = e.Current; + readStack.Remove(a); + return a; + } + } + } catch(InvalidOperationException) { + return null; + } + return null; + } + + protected ArduinoInput getInputWait(char key, byte id = 255) { + while(true) { + ArduinoInput a = getInput(key, id); + if(a != null) { + return a; + } + System.Threading.Thread.Sleep(1); + } + } + + internal void clearStack() { + readStack.Clear(); + } + + internal void clearStack(char key) { + LinkedList.Enumerator e = readStack.GetEnumerator(); + try { + while(e.MoveNext()) { + if(e.Current.key == key) { + readStack.Remove(e.Current); + } + } + } catch(InvalidOperationException) { + return; + } + } + } + class ArduinoInput { + public ArduinoInput(string indata) { + string reg = "\\*([a-z])(\\d)=([a-fA-F0-9]*)\\$(.)#"; + Match m = Regex.Match(indata, reg); + this.key = m.Groups[1].ToString().ToCharArray()[0]; + this.id = byte.Parse(m.Groups[2].ToString()); + string val = m.Groups[3].ToString().ToUpper(); + if(val == "") { + this.value = 0; + } else if(val.IndexOfAny(new char[] { 'A', 'B', 'C', 'D', 'E', 'F' }) != -1) { + this.value = Int64.Parse(val, System.Globalization.NumberStyles.HexNumber); + } else { + this.value = Int64.Parse(val); + } + } + + public static char checksum(String data) { + char c = '$'; + foreach(char t in data) { + c = (char)(c ^ t); + } + return c; + } + + public static bool check(string indata) { + string reg = "\\*([a-z]\\d)=([a-fA-F0-9]*)\\$(.)#"; + Match m = Regex.Match(indata, reg); + if(!m.Success) { + return false; + } + String rec = m.Groups[1].ToString() + "=" + m.Groups[2].ToString(); + return (ArduinoInput.checksum(rec) == m.Groups[3].ToString().ToCharArray()[0]); + } + + public char key { get; private set; } + public byte id { get; private set; } + public Int64 value { get; private set; } + } +} diff --git a/ebbits/AdvancedServo-simple/Arduino/MainArduino.cs b/ebbits/AdvancedServo-simple/Arduino/MainArduino.cs new file mode 100644 index 0000000..712e99c --- /dev/null +++ b/ebbits/AdvancedServo-simple/Arduino/MainArduino.cs @@ -0,0 +1,142 @@ +using System; +using System.Collections.Generic; +using System.Text; + + +namespace ebbits.Arduino { + class MainArduino : AbstractArduino { + public const int ON = 1; + public const int OFF = 0; + public const int RED = 2; + public const int WHITE = 7; + + public MainArduino(string port) { + init(port); + trainOn(1); + } + + public void setLaser(byte p) { + serialSend('l', 1, p); + } + + public void setColor(byte p) { + serialSend('c', 1, p); + } + + public void trainOn(byte dir) { + serialSend('p', 2, 70); //Speed = 1 + changeDir(dir); //Richtung = 1 + serialSend('b', 2, 1); //Bremse = an + } + + public void trainMove(byte speed) { + serialSend('b', 2, 0); //Bremse aus + serialSend('p', 2, speed); + } + + internal void changeDir(byte dir) { + serialSend('d', 2, dir); //Richtung = 0 + } + + public bool readStop(char key, byte id) { + ArduinoInput a = base.getInputWait(key, id); + return true; + } + + public void measureAndStop(char key, byte id) { + System.Threading.Thread t = new System.Threading.Thread(current_runnter); + t.Start(); + this.readStop(key, id); + t.Abort(); + base.clearStack('u'); + } + + private void current_runnter(object obj) { + DateTime t = DateTime.Now; + float current = 0; + while(true) { + long c = readCurrent(); + current += ((float)c / 1000 * 12 * (DateTime.Now.Ticks - t.Ticks)) / 1000000; + t = DateTime.Now; + Logger.Info("Train Watt: " + current.ToString()); + System.Threading.Thread.Sleep(100); + } + } + + public long whereRead() { + serialSend('q', 0, 0); + ArduinoInput a = base.getInputWait('q'); + return a.value; + } + + public long readCurrent() { + serialSend('u', 1, 0); + ArduinoInput a = base.getInputWait('u'); + return a.value; + } + + public bool findStart() { + changeDir(0); + if(this.whereRead() == 0) { + trainMove(70); + System.Threading.Thread.Sleep(3000); + } + if(this.whereRead() == 0) { + changeDir(1); + System.Threading.Thread.Sleep(3000); + } + if(this.whereRead() == 0) { + trainOn(1); + return false; + } + trainOn(1); + changeDir(0); + Logger.Info("Lock gefunden und stehe auf: " + this.whereRead()); + base.clearStack(); + switch(this.whereRead()) { + case 6: + Logger.Info("Fahre von 6 nach 5"); + trainMove(70); + readStop('r',4); + trainMove(70); + readStop('r',5); + break; + case 4: + Logger.Info("Fahre von 4 nach 5"); + trainMove(70); + readStop('r',5); + break; + case 3: + Logger.Info("Fahre von 3 nach 5"); + trainMove(70); + readStop('r',2); + trainMove(70); + readStop('r',1); + trainMove(70); + readStop('r',5); + break; + case 2: + Logger.Info("Fahre von 2 nach 5"); + trainMove(70); + readStop('r',1); + trainMove(70); + readStop('r',5); + break; + case 1: + Logger.Info("Fahre von 1 nach 5"); + trainMove(70); + readStop('r',5); + break; + } + trainOn(1); + Logger.Info("Stehe nun auf: " + this.whereRead()); + return (this.whereRead() == 5); + } + + public bool trainSwitchIsOff() { + serialSend('s', 0, 0); + ArduinoInput a = base.getInputWait('s'); + return a.value == 0; + } + } +} diff --git a/ebbits/AdvancedServo-simple/Logger.cs b/ebbits/AdvancedServo-simple/Logger.cs new file mode 100644 index 0000000..02a4df3 --- /dev/null +++ b/ebbits/AdvancedServo-simple/Logger.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace ebbits { + class Logger { + public static void Info(string msg) { + Logger.Message(msg, "INFO"); + } + private static void Message(string msg, string type) { + DateTime d = DateTime.Now; + Console.WriteLine("[" + d.ToLongTimeString() + "." + d.Millisecond.ToString().PadLeft(3,'0') + "] " + type + ": " + msg); + } + + public static void Notice(string msg) { + Logger.Message(msg, "NOTICE"); + } + + public static void Warn(string msg) { + Logger.Message(msg, "WARN"); + } + + public static void Message(string msg) { + Logger.Message(msg, "MESSAGE"); + } + + public static bool LogSerial { get; set; } + + public static void Serial(string dir, string msg) { + if(LogSerial) { + Logger.Message(msg, "SERIAL "+dir.ToUpper()); + } + } + } +} diff --git a/ebbits/AdvancedServo-simple/Program.cs b/ebbits/AdvancedServo-simple/Program.cs new file mode 100644 index 0000000..eec6e92 --- /dev/null +++ b/ebbits/AdvancedServo-simple/Program.cs @@ -0,0 +1,100 @@ +/*- AdvancedServo simple - +0**************************************************************************************** + * This example simply displays the Phidget AdvancedServo serial number when it is + * attached and sets the servo positions, velocity, and acceleration to 0. Then we will + * do a simple simulation of a basic movement of a servo motor at 100.00 velocity and + * 100.00 Acceleration. I decided to leave out the current change event handler for + * easier readability. For a more detailed example, see the Servo-full example. + * + * Please note that this example was designed to work with only one Phidget AdvanceServo + * connected. + * For an example showing how to use two Phidgets of the same time concurrently, please see the + * Servo-multi example in the Servo Examples. + + * Copyright 2007 Phidgets Inc. All rights reserved.*/ + +using System; +using System.Collections.Generic; +using System.Text; +//Needed for the AdvancedServo class, phidget base classes, and PhidgetException class + +//Needed for the event handling classes +using Phidgets.Events; +//Using this simply for the sleep() method so that the for loop will wail for the motor +//to finish moving to the previous new position before setting a new position +using System.Threading; + + + +using ebbits.Robots; +using ebbits.Arduino; + +namespace ebbits { + class Program { + static void Main(string[] args) { + Logger.LogSerial = false; + MainArduino a = new MainArduino("COM50"); + //AbstractRobot l = new LaserBot(169861, a); + AbstractRobot p = new PaintBot(169889, a); + //AbstractRobot g = new GlassBot(169887); + + Console.WriteLine("All Engaged. Press Key to Start."); + Console.ReadLine(); + + while(true) { + a.clearStack(); + a.trainOn(1); + if(a.whereRead() != 5) { + Logger.Warn("Achtung! Steht nicht auf Start!"); + //Console.ReadLine(); + if(!a.findStart()) { + Logger.Warn("ABBRUCH! Konnte die Bahn nicht Finden oder einstellen!"); + //Console.ReadLine(); + continue; + } + } + while(a.trainSwitchIsOff()) { + Thread.Sleep(100); + } + + Logger.Message("Move from Start to Welding Pos"); + a.trainMove(70); + a.measureAndStop('r', 1); + + Logger.Message("Welding"); + Thread.Sleep(1000);//l.run(); + + Logger.Message("Move from Welding to Paint Pos"); + a.trainMove(68); + a.measureAndStop('r', 2); + + Logger.Message("Paint"); + p.run(); + Console.ReadLine(); + + Logger.Message("Move from Paint to Glas Pos"); + a.trainMove(68); + a.measureAndStop('r', 3); + + Logger.Message("Glas"); + Thread.Sleep(1000);//g.run(); + + Logger.Message("Move from Glas to Turn around Pos"); + a.trainMove(78); + a.measureAndStop('r',6); + + Logger.Message("Turn aroud and move from Turn around to Waiting Pos"); + System.Threading.Thread.Sleep(500); + a.changeDir(0); + a.trainMove(90); + a.readStop('r',4); + + Logger.Message("Move from Waiting Pos to Start Pos"); + a.trainMove(90); + a.readStop('r', 5); + + Logger.Info("Runde zuende!"); + } + } + } +} diff --git a/ebbits/AdvancedServo-simple/Properties/AssemblyInfo.cs b/ebbits/AdvancedServo-simple/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..e53ca52 --- /dev/null +++ b/ebbits/AdvancedServo-simple/Properties/AssemblyInfo.cs @@ -0,0 +1,33 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("AdvancedServo-simple")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Phidgets Inc.")] +[assembly: AssemblyProduct("AdvancedServo-simple")] +[assembly: AssemblyCopyright("Copyright © Phidgets Inc. 2007")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("35c7dfbc-b70d-4603-9844-3fd32bce5b60")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/ebbits/AdvancedServo-simple/Robots/AbstractRobot.cs b/ebbits/AdvancedServo-simple/Robots/AbstractRobot.cs new file mode 100644 index 0000000..86e80b2 --- /dev/null +++ b/ebbits/AdvancedServo-simple/Robots/AbstractRobot.cs @@ -0,0 +1,90 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Phidgets; +using System.Threading; + +namespace ebbits.Robots { + public abstract class AbstractRobot { + protected AdvancedServo servo; + protected int cservos; + protected string name; + private Thread t; + protected void init(int id) { + servo = new AdvancedServo(); + servo.open(id); + Logger.Info("Waiting for Servo \"" + id + "\" is attached"); + servo.waitForAttachment(); + if(!servo.Attached) { throw new AccessViolationException("Robot not Found"); } + } + public abstract void run(); + protected void setPosition(int[] pos, int speed) { + for(int i = 0; i < cservos; i++) { + if(pos[i] != -1) { + AdvancedServoServo s = servo.servos[i+ 5 - cservos]; + s.Acceleration = speed; + s.Position = pos[i]; + } + } + + bool waiting = true; + while(waiting) { + waiting = false; + for(int i = 0; i < cservos; i++) { + if(pos[i] != -1) { + AdvancedServoServo s = servo.servos[i + 5 - cservos]; + s.Position = pos[i]; + try { + if(Math.Abs(s.Position - pos[i]) > 0.01) { + waiting = true; + } + } catch(PhidgetException) { + Logger.Warn("Exeption!"); + s.Position = pos[i]; + } + Thread.Sleep(10); + } + } + } + } + protected void setStartPosition(int[] positions, int sleep) { + for(int i = 0; i < cservos; i++) { + AdvancedServoServo s = servo.servos[i + 5 - cservos]; + s.Type = ServoServo.ServoType.TOWERPRO_MG90; + s.Acceleration = 10000; + s.VelocityLimit = 200; + s.Position = positions[i]; + s.Engaged = true; + } + Thread.Sleep(sleep); + } + protected void shutdownServo() { + for(int i = 0; i < cservos; i++) { + servo.servos[i + 5 - cservos].Engaged = false; + } + if(t.IsAlive) { + t.Abort(); + } + } + + protected void startPowerMess() { + this.t = new System.Threading.Thread(current_runnter); + t.Start(); + } + + private void current_runnter(object obj) { + DateTime t = DateTime.Now; + double current = 0; + while(true) { + double c = 0; + for(int i = 0; i < 5; i++) { + c += this.servo.servos[0].Current; + } + current += (c * 12 * (DateTime.Now.Ticks - t.Ticks)) / 1000000; + t = DateTime.Now; + Logger.Info(this.name+" Watt: " + current.ToString()); + System.Threading.Thread.Sleep(100); + } + } + } +} \ No newline at end of file diff --git a/ebbits/AdvancedServo-simple/Robots/GlassBot.cs b/ebbits/AdvancedServo-simple/Robots/GlassBot.cs new file mode 100644 index 0000000..a9096cf --- /dev/null +++ b/ebbits/AdvancedServo-simple/Robots/GlassBot.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace ebbits.Robots { + class GlassBot : AbstractRobot { + public GlassBot(int id) { + init(id); + this.cservos = 5; + base.name = "Glas"; + } + public override void run() { + base.startPowerMess(); + setStartPosition(new int[] { 20, 68, 175, 175, 20 }, 500); + + setPosition(new int[] { 20, 68, 160, 162, 20 }, 400); + setPosition(new int[] { -1, 154, 88, 88, -1 }, 400); + setPosition(new int[] { -1, -1, 86, 116, 42 }, 200); + setPosition(new int[] { -1, -1, 77, -1, 48 }, 50); + setPosition(new int[] { 160, -1, -1, -1, -1 }, 200); + setPosition(new int[] { -1, -1, 85, -1, -1 }, 20); + setPosition(new int[] { -1, -1, -1, 106, -1 }, 200); + setPosition(new int[] { -1, -1, 118, 122, 174 }, 200); + + setPosition(new int[] { -1, 13, -1, -1, -1 }, 300); + setPosition(new int[] { -1, -1, 90, 100, 20 }, 200); + + setPosition(new int[] { -1, -1, 80, 94, 26 }, 20); // Fine Settings + System.Threading.Thread.Sleep(1000); + setPosition(new int[] { -1, -1, 90, 90, 20 }, 20); // Fine Lift + + setPosition(new int[] { -1, -1, 103, 105, 80 }, 150); + setPosition(new int[] { -1, 154, 118, 122, 174 }, 300); + setPosition(new int[] { -1, -1, 86, 102, 42 }, 300); + setPosition(new int[] { -1, -1, 83, 113, 48 }, 100); + setPosition(new int[] { -1, -1, -1, 117, -1 }, 20); + setPosition(new int[] { 20, -1, 78, -1, -1 }, 150); + setPosition(new int[] { -1, -1, 81, 111, -1 }, 20); + setPosition(new int[] { -1, -1, 90, -1, -1 }, 100); + + setPosition(new int[] { 20, 68, 160, 162, 20 }, 400); + setPosition(new int[] { 20, 68, 175, 175, 20 }, 400); + + shutdownServo(); + } + } +} diff --git a/ebbits/AdvancedServo-simple/Robots/LaserBot.cs b/ebbits/AdvancedServo-simple/Robots/LaserBot.cs new file mode 100644 index 0000000..c2ca21f --- /dev/null +++ b/ebbits/AdvancedServo-simple/Robots/LaserBot.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.Text; +using ebbits.Arduino; + +namespace ebbits.Robots { + class LaserBot : AbstractRobot { + private Arduino.MainArduino Arduino; + public LaserBot(int id, MainArduino a) { + init(id); + base.cservos = 4; + this.Arduino = a; + base.name = "Laser"; + } + + override public void run() { + base.startPowerMess(); + + base.setStartPosition(new int[] {77, 175, 155, 84 }, 500); + + base.setPosition(new int[] { 77, 157, 134, 84 }, 400); + base.setPosition(new int[] { 83, 96, 114, 44 }, 200); + Arduino.setLaser(MainArduino.ON); + base.setPosition(new int[] { 101, 91, 107, 45 }, 20); + base.setPosition(new int[] { 98, 78, 88, 49 }, 20); + base.setPosition(new int[] { 83, 82, 95, 46 }, 20); + base.setPosition(new int[] { 83, 96, 114, 44 }, 20); + Arduino.setLaser(MainArduino.OFF); + base.setPosition(new int[] { 77, 157, 134, 84 }, 400); + base.setPosition(new int[] { 77, 175, 155, 84 }, 400); + + base.shutdownServo(); + } + } +} diff --git a/ebbits/AdvancedServo-simple/Robots/PaintBot.cs b/ebbits/AdvancedServo-simple/Robots/PaintBot.cs new file mode 100644 index 0000000..eb45319 --- /dev/null +++ b/ebbits/AdvancedServo-simple/Robots/PaintBot.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.Text; +using ebbits.Arduino; + +namespace ebbits.Robots { + class PaintBot : AbstractRobot { + private MainArduino Arduino; + public PaintBot(int id, MainArduino a) { + init(id); + this.cservos = 4; + this.Arduino = a; + base.name = "Paint"; + } + public override void run() { + base.startPowerMess(); + setStartPosition(new int[] {87, 175, 160, 92 }, 500); + + setPosition(new int[] {87, 153, 138, 92 }, 400); + setPosition(new int[] {47, 101, 158, 48 }, 200); + Arduino.setColor(MainArduino.RED); + setPosition(new int[] {91, 122, 161, 78 }, 50); + Arduino.setColor(MainArduino.OFF); + setPosition(new int[] {-1, 140, -1, -1 }, 200); + setPosition(new int[] {-1, 71, 55, 110 }, 200); + setPosition(new int[] {-1, 43, 42, 175 }, 200); + Arduino.setColor(MainArduino.RED); + setPosition(new int[] { 79, 42, 39, -1 }, 50); + setPosition(new int[] { 68, 39, 30, -1 }, 50); + setPosition(new int[] { -1, 36, 20, -1 }, 50); + setPosition(new int[] { 64, -1, -1, -1 }, 50); + Arduino.setColor(MainArduino.OFF); + setPosition(new int[] {-1, 44, -1, 150 }, 200); + setPosition(new int[] {57, 68, 70, 139 }, 200); + Arduino.setColor(MainArduino.WHITE); + setPosition(new int[] {53, 74, 79, 158 }, 50); + setPosition(new int[] {89, 86, 98, 150 }, 50); + setPosition(new int[] {-1, 75, 85, 143 }, 50); + setPosition(new int[] { 57, 68, 70, 139 }, 50); + Arduino.setColor(MainArduino.OFF); + setPosition(new int[] { -1, 153, 138, 92 }, 400); + setPosition(new int[] { 87, 175, 160, 92 }, 400); + + shutdownServo(); + } + } +} diff --git a/ebbits/AdvancedServo-simple/ebbits.csproj b/ebbits/AdvancedServo-simple/ebbits.csproj new file mode 100644 index 0000000..e097253 --- /dev/null +++ b/ebbits/AdvancedServo-simple/ebbits.csproj @@ -0,0 +1,64 @@ + + + + Debug + AnyCPU + 8.0.50727 + 2.0 + {94AEADEA-85AF-4DBD-AA16-4BE165FF538B} + Exe + Properties + ebbits + AdvancedServo-simple + v2.0 + + + + + 2.0 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + False + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ebbits/ebbits.sln b/ebbits/ebbits.sln new file mode 100644 index 0000000..5d4332f --- /dev/null +++ b/ebbits/ebbits.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ebbits", "AdvancedServo-simple\ebbits.csproj", "{94AEADEA-85AF-4DBD-AA16-4BE165FF538B}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {94AEADEA-85AF-4DBD-AA16-4BE165FF538B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {94AEADEA-85AF-4DBD-AA16-4BE165FF538B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {94AEADEA-85AF-4DBD-AA16-4BE165FF538B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {94AEADEA-85AF-4DBD-AA16-4BE165FF538B}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal