This commit is contained in:
BlubbFish 2019-04-17 16:07:23 +02:00
commit 5e1a38fd9e
8 changed files with 480 additions and 0 deletions

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
/.vs
/MonicaScral/bin
/MonicaScral/obj

61
MonicaScral.sln Normal file
View File

@ -0,0 +1,61 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.27703.2026
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MonicaScral", "MonicaScral\MonicaScral.csproj", "{AF25B9BC-7D93-4CEC-B5E2-8A8383679787}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Utils-IoT", "..\Utils\Utils-IoT\Utils-IoT\Utils-IoT.csproj", "{B870E4D5-6806-4A0B-B233-8907EEDC5AFC}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ConnectorDataMqtt", "..\Utils\ConnectorDataMqtt\ConnectorDataMqtt\ConnectorDataMqtt.csproj", "{EE6C8F68-ED46-4C1C-ABDD-CFCDF75104F2}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "litjson_4.7.1", "..\Librarys\litjson\litjson\litjson_4.7.1.csproj", "{91A14CD2-2940-4500-8193-56D37EDDDBAA}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "M2Mqtt_4.7.1", "..\Librarys\mqtt\M2Mqtt\M2Mqtt_4.7.1.csproj", "{A11AEF5A-B246-4FE8-8330-06DB73CC8074}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Utils", "..\Utils\Utils\Utils\Utils.csproj", "{FAC8CE64-BF13-4ECE-8097-AEB5DD060098}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mono.Posix", "..\Librarys\Mono.Posix\Mono.Posix\Mono.Posix.csproj", "{E2CA132E-E85C-40AD-BE94-B138AA68772B}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{AF25B9BC-7D93-4CEC-B5E2-8A8383679787}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AF25B9BC-7D93-4CEC-B5E2-8A8383679787}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AF25B9BC-7D93-4CEC-B5E2-8A8383679787}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AF25B9BC-7D93-4CEC-B5E2-8A8383679787}.Release|Any CPU.Build.0 = Release|Any CPU
{B870E4D5-6806-4A0B-B233-8907EEDC5AFC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B870E4D5-6806-4A0B-B233-8907EEDC5AFC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B870E4D5-6806-4A0B-B233-8907EEDC5AFC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B870E4D5-6806-4A0B-B233-8907EEDC5AFC}.Release|Any CPU.Build.0 = Release|Any CPU
{EE6C8F68-ED46-4C1C-ABDD-CFCDF75104F2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EE6C8F68-ED46-4C1C-ABDD-CFCDF75104F2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EE6C8F68-ED46-4C1C-ABDD-CFCDF75104F2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EE6C8F68-ED46-4C1C-ABDD-CFCDF75104F2}.Release|Any CPU.Build.0 = Release|Any CPU
{91A14CD2-2940-4500-8193-56D37EDDDBAA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{91A14CD2-2940-4500-8193-56D37EDDDBAA}.Debug|Any CPU.Build.0 = Debug|Any CPU
{91A14CD2-2940-4500-8193-56D37EDDDBAA}.Release|Any CPU.ActiveCfg = Release|Any CPU
{91A14CD2-2940-4500-8193-56D37EDDDBAA}.Release|Any CPU.Build.0 = Release|Any CPU
{A11AEF5A-B246-4FE8-8330-06DB73CC8074}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A11AEF5A-B246-4FE8-8330-06DB73CC8074}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A11AEF5A-B246-4FE8-8330-06DB73CC8074}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A11AEF5A-B246-4FE8-8330-06DB73CC8074}.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
{E2CA132E-E85C-40AD-BE94-B138AA68772B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E2CA132E-E85C-40AD-BE94-B138AA68772B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E2CA132E-E85C-40AD-BE94-B138AA68772B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E2CA132E-E85C-40AD-BE94-B138AA68772B}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {CE98D3EF-81C6-4C8D-B8EF-E1C6A72FDD29}
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,74 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{AF25B9BC-7D93-4CEC-B5E2-8A8383679787}</ProjectGuid>
<OutputType>Exe</OutputType>
<RootNamespace>Fraunhofer.Fit.IoT.MonicaScral</RootNamespace>
<AssemblyName>MonicaScral</AssemblyName>
<TargetFrameworkVersion>v4.7.1</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="MqttEvents.cs" />
<Compile Include="MqttListener.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ScralPusher.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Librarys\litjson\litjson\litjson_4.7.1.csproj">
<Project>{91a14cd2-2940-4500-8193-56d37edddbaa}</Project>
<Name>litjson_4.7.1</Name>
</ProjectReference>
<ProjectReference Include="..\..\Librarys\Mono.Posix\Mono.Posix\Mono.Posix.csproj">
<Project>{e2ca132e-e85c-40ad-be94-b138aa68772b}</Project>
<Name>Mono.Posix</Name>
</ProjectReference>
<ProjectReference Include="..\..\Utils\ConnectorDataMqtt\ConnectorDataMqtt\ConnectorDataMqtt.csproj">
<Project>{ee6c8f68-ed46-4c1c-abdd-cfcdf75104f2}</Project>
<Name>ConnectorDataMqtt</Name>
</ProjectReference>
<ProjectReference Include="..\..\Utils\Utils-IoT\Utils-IoT\Utils-IoT.csproj">
<Project>{b870e4d5-6806-4a0b-b233-8907eedc5afc}</Project>
<Name>Utils-IoT</Name>
</ProjectReference>
<ProjectReference Include="..\..\Utils\Utils\Utils\Utils.csproj">
<Project>{fac8ce64-bf13-4ece-8097-aeb5dd060098}</Project>
<Name>Utils</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

19
MonicaScral/MqttEvents.cs Normal file
View File

@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Fraunhofer.Fit.IoT.MonicaScral {
class MqttEvents : EventArgs {
public MqttEvents(String topic, String message, DateTime date) {
this.Topic = topic;
this.Message = message;
this.Date = date;
}
public String Topic { get; }
public String Message { get; }
public DateTime Date { get; }
}
}

View File

@ -0,0 +1,66 @@
using System;
using System.Collections.Generic;
using System.Threading;
using BlubbFish.Utils.IoT.Connector;
using BlubbFish.Utils.IoT.Events;
namespace Fraunhofer.Fit.IoT.MonicaScral {
class MqttListener {
protected readonly Thread connectionWatcher;
protected ABackend mqtt;
private readonly Dictionary<String, String> config;
public delegate void InputData(Object sender, MqttEvents e);
public event InputData Update;
public MqttListener(Dictionary<String, String> settings) {
this.config = settings;
if(this.config.ContainsKey("type")) {
this.connectionWatcher = new Thread(this.ConnectionWatcherRunner);
this.connectionWatcher.Start();
} else {
throw new ArgumentException("Setting section [mqtt] is missing or wrong!");
}
}
protected void ConnectionWatcherRunner() {
while(true) {
try {
if(this.mqtt == null || !this.mqtt.IsConnected) {
this.Reconnect();
}
Thread.Sleep(10000);
} catch(Exception) { }
}
}
protected void Reconnect() {
Console.WriteLine("Fraunhofer.Fit.IoT.MonicaScral.Reconnect()");
this.Disconnect();
this.Connect();
}
protected void Connect() {
this.mqtt = ABackend.GetInstance(this.config, ABackend.BackendType.Data);
this.mqtt.MessageIncomming += this.MqttData;
Console.WriteLine("Fraunhofer.Fit.IoT.MonicaScral.Connect()");
}
private void MqttData(Object sender, BackendEvent e) => this.Update?.Invoke(this, new MqttEvents(e.From.ToString(), e.Message, e.Date));
protected void Disconnect() {
if(this.mqtt != null) {
this.mqtt.MessageIncomming -= this.MqttData;
this.mqtt.Dispose();
}
this.mqtt = null;
Console.WriteLine("Fraunhofer.Fit.IoT.MonicaScral.Disconnect()");
}
public void Dispose() {
this.connectionWatcher.Abort();
while(this.connectionWatcher.ThreadState == ThreadState.Running) { Thread.Sleep(10); }
this.Disconnect();
}
}
}

61
MonicaScral/Program.cs Normal file
View File

@ -0,0 +1,61 @@
using System;
using System.Collections.Generic;
using System.Threading;
using BlubbFish.Utils;
namespace Fraunhofer.Fit.IoT.MonicaScral {
class Program {
private Thread sig_thread;
private Boolean RunningProcess = true;
protected ProgramLogger logger = new ProgramLogger();
static void Main(String[] args) => new Program(args);
public Program(String[] args) {
MqttListener m = new MqttListener(new Dictionary<String, String>() { { "type", "mqtt" }, { "server", "10.100.0.20" }, { "topic", "lora/data/+;lora/panic/+" } });
ScralPusher s = new ScralPusher(new Dictionary<String, String>() {
{ "server", "http://monappdwp3.monica-cloud.eu:8250" },
{ "register_addr", "/scral/v1.0/gps-tracker-gw/gps-tag" },
{ "register_method", "post" },
{ "update_addr", "/scral/v1.0/gps-tracker-gw/gps-tag/localization" },
{ "update_method", "put" },
{ "panic_addr", "/scral/v1.0/gps-tracker-gw/gps-tag/alert" },
{ "panic_method", "put" },});
m.Update += s.DataInput;
this.WaitForShutdown();
m.Dispose();
s.Dispose();
}
protected void WaitForShutdown() {
if(Type.GetType("Mono.Runtime") != null) {
this.sig_thread = new Thread(delegate () {
Mono.Unix.UnixSignal[] signals = new Mono.Unix.UnixSignal[] {
new Mono.Unix.UnixSignal(Mono.Unix.Native.Signum.SIGTERM),
new Mono.Unix.UnixSignal(Mono.Unix.Native.Signum.SIGINT)
};
Console.WriteLine("BlubbFish.Utils.IoT.Bots.Bot.WaitForShutdown: Signalhandler Mono attached.");
while(true) {
Int32 i = Mono.Unix.UnixSignal.WaitAny(signals, -1);
Console.WriteLine("BlubbFish.Utils.IoT.Bots.Bot.WaitForShutdown: Signalhandler Mono INT recieved " + i + ".");
this.RunningProcess = false;
break;
}
});
this.sig_thread.Start();
} else {
Console.CancelKeyPress += new ConsoleCancelEventHandler(this.SetupShutdown);
Console.WriteLine("BlubbFish.Utils.IoT.Bots.Bot.WaitForShutdown: Signalhandler Windows attached.");
}
while(this.RunningProcess) {
Thread.Sleep(100);
}
}
private void SetupShutdown(Object sender, ConsoleCancelEventArgs e) {
e.Cancel = true;
Console.WriteLine("BlubbFish.Utils.IoT.Bots.Bot.SetupShutdown: Signalhandler Windows INT recieved.");
this.RunningProcess = false;
}
}
}

View File

@ -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("MonicaScral")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("MonicaScral")]
[assembly: AssemblyCopyright("Copyright © 2019")]
[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("af25b9bc-7d93-4cec-b5e2-8a8383679787")]
// 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")]

160
MonicaScral/ScralPusher.cs Normal file
View File

@ -0,0 +1,160 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using BlubbFish.Utils;
using LitJson;
namespace Fraunhofer.Fit.IoT.MonicaScral {
class ScralPusher {
private readonly List<String> nodes = new List<String>();
private readonly Dictionary<String, String> config;
private readonly Object getLock = new Object();
private readonly Boolean authRequired = false;
private readonly String auth = "";
public ScralPusher(Dictionary<String, String> settings) => this.config = settings;
internal async void DataInput(Object sender, MqttEvents e) => await Task.Run(() => {
try {
JsonData data = JsonMapper.ToObject(e.Message);
if(this.CheckRegister(data)) {
if(e.Topic.StartsWith("lora/data")) {
this.SendUpdate(data);
} else if(e.Topic.StartsWith("lora/panic")) {
this.SendPanic(data);
}
}
} catch(Exception ex) {
Helper.WriteError("Something is wrong: " + ex.Message);
}
});
private Boolean CheckRegister(JsonData data) {
if(data.ContainsKey("Name") && data["Name"].IsString) {
if(!this.nodes.Contains((String)data["Name"])) {
this.SendRegister(data);
this.nodes.Add((String)data["Name"]);
}
return true;
}
return false;
}
private void SendRegister(JsonData data) {
Dictionary<String, Object> d = new Dictionary<String, Object> {
{ "device", "wearable" },
{ "sensor", "tag" },
{ "type", "uwb" },
{ "tagId", (String)data["Name"] },
{ "timestamp", DateTime.Now.ToString("o") },
{ "unitOfMeasurements", "meters" },
{ "observationType", "propietary" },
{ "state", "active" }
};
try {
String addr = this.config["register_addr"];
if(Enum.TryParse(this.config["register_method"], true, out RequestMethod meth)) {
this.RequestString(addr, JsonMapper.ToJson(d), false, meth);
Console.WriteLine(meth.ToString() + " " + this.config["register_addr"] + ": " + JsonMapper.ToJson(d));
}
} catch(Exception e) {
Helper.WriteError("Fraunhofer.Fit.IoT.MonicaScral.SendRegister: " + e.Message);
}
}
private void SendUpdate(JsonData data) {
if((Boolean)data["Gps"]["Fix"]) {
Dictionary<String, Object> d = new Dictionary<String, Object> {
{ "type", "uwb" },
{ "tagId", (String)data["Name"] },
{ "timestamp", DateTime.Now.ToString("o") },
{ "lat", (Double)data["Gps"]["Latitude"] },
{ "lon", (Double)data["Gps"]["Longitude"] },
{ "height", (Double)data["Gps"]["Height"] },
{ "hdop", (Double)data["Gps"]["Hdop"] },
{ "snr", (Double)data["Snr"] },
{ "battery_level", (Double)data["BatteryLevel"] },
{ "host", (String)data["Host"]}
};
try {
String addr = this.config["update_addr"];
if(Enum.TryParse(this.config["update_method"], true, out RequestMethod meth)) {
this.RequestString(addr, JsonMapper.ToJson(d), false, meth);
Console.WriteLine(meth.ToString() + " " + this.config["update_addr"] + ": " + JsonMapper.ToJson(d));
}
} catch(Exception e) {
Helper.WriteError("Fraunhofer.Fit.IoT.MonicaScral.SendUpdate: " + e.Message);
}
}
}
private void SendPanic(JsonData data) {
Dictionary<String, Object> d = new Dictionary<String, Object> {
{ "type", "uwb" },
{ "tagId", (String)data["Name"] },
{ "timestamp", DateTime.Now.ToString("o") },
{ "last_known_lat", (Double)data["Gps"]["LastLatitude"] },
{ "last_known_lon", (Double)data["Gps"]["LastLongitude"] },
{ "last_known_gps", DateTime.Parse((String)data["Gps"]["LastGPSPos"], DateTimeFormatInfo.InvariantInfo, DateTimeStyles.AssumeUniversal).ToLocalTime().ToString("o") }
};
try {
String addr = this.config["panic_addr"];
if(Enum.TryParse(this.config["panic_method"], true, out RequestMethod meth)) {
this.RequestString(addr, JsonMapper.ToJson(d), false, meth);
Console.WriteLine(meth.ToString() + " " + this.config["panic_addr"] + ": " + JsonMapper.ToJson(d));
}
} catch(Exception e) {
Helper.WriteError("Fraunhofer.Fit.IoT.MonicaScral.SendRegister: " + e.Message);
}
}
#region HTTP Request
private String RequestString(String address, String json = "", Boolean withoutput = true, RequestMethod method = RequestMethod.GET) {
String ret = null;
lock(this.getLock) {
HttpWebRequest request = WebRequest.CreateHttp(this.config["server"] + address);
request.Timeout = 2000;
if(this.authRequired) {
request.Headers.Add(HttpRequestHeader.Authorization, this.auth);
}
if(method == RequestMethod.POST || method == RequestMethod.PUT) {
Byte[] requestdata = Encoding.ASCII.GetBytes(json);
request.ContentLength = requestdata.Length;
request.Method = method.ToString();
request.ContentType = "application/json";
using(Stream stream = request.GetRequestStream()) {
stream.Write(requestdata, 0, requestdata.Length);
}
}
try {
using(HttpWebResponse response = (HttpWebResponse)request.GetResponse()) {
if(response.StatusCode == HttpStatusCode.Unauthorized) {
Console.Error.WriteLine("Benutzer oder Passwort falsch!");
throw new Exception("Benutzer oder Passwort falsch!");
}
if(withoutput) {
StreamReader reader = new StreamReader(response.GetResponseStream());
ret = reader.ReadToEnd();
}
}
} catch(Exception e) {
throw new WebException("Error while uploading to Scal. Resource: \"" + this.config["server"] + address + "\" Method: " + method + " Data: " + json + " Fehler: " + e.Message);
}
}
return ret;
}
private enum RequestMethod {
GET,
POST,
PUT
}
#endregion
internal void Dispose() { }
}
}