Compare commits

...

17 Commits

Author SHA1 Message Date
abc48e5011 Update Changelog 2021-08-31 23:03:00 +02:00
8ff0d679d9 Rename a function 2021-08-31 23:02:45 +02:00
fcb73810fd Add posibility to make the past of a marker visible 2021-08-31 23:02:27 +02:00
aa9c667d03 Update leaflet to 1.7.1 2021-08-31 23:01:21 +02:00
1e4c2db716 otify other Objects when Settings are changed. 2021-08-31 23:00:47 +02:00
c5ff258793 Fixing logic bug in githubactions 2021-08-29 20:29:14 +02:00
85b309cbb0 Run Github Actions on every commit, at least compiling the code for checking 2021-08-29 20:26:30 +02:00
fb2c98219a Update the Readme to the current progress 2021-08-29 00:49:49 +02:00
c052c57b7e Coreccting the imagesize in the admin menu for SVG 2021-08-29 00:49:18 +02:00
3309972d71 Used the new methods of AWebserverDataBackend 2021-08-29 00:49:00 +02:00
6702c6392c Fixing a bug when open the nameseditor directly after start that images are not created 2021-08-29 00:48:41 +02:00
47fe56304f Change the SVG link to the correct array behavour 2021-08-29 00:48:21 +02:00
410f3e9f81 Add posibility to make the past of a marker visible 2021-08-29 00:47:19 +02:00
df7e4f2044 If the settings are changed while collecting weather, ignore the exception 2021-08-29 00:46:46 +02:00
00b228c008 Validating the input of Json, against defined models and only parse them if the match 2021-08-29 00:46:11 +02:00
e90bd678c1 add settings for History 2021-04-13 21:11:35 +02:00
f67d1b465c running github actions only on master, so we can develop and commit and not everytime a nightly is generated 2021-04-10 21:41:21 +02:00
29 changed files with 15218 additions and 14501 deletions

View File

@ -28,7 +28,7 @@ jobs:
working-directory: ../map-project/Lora-Map working-directory: ../map-project/Lora-Map
- name: Create deb files - name: Create deb files
if: success() if: ${{ success() && github.event.ref == 'refs/heads/master' }}
run: | run: |
mkdir ../../../Builds mkdir ../../../Builds
chmod oug+x make-deb.sh chmod oug+x make-deb.sh
@ -38,7 +38,7 @@ jobs:
working-directory: ../map-project/Lora-Map/Lora-Map/dpkg working-directory: ../map-project/Lora-Map/Lora-Map/dpkg
- name: Create release - name: Create release
if: success() if: ${{ success() && github.event.ref == 'refs/heads/master' }}
id: nightly_release id: nightly_release
uses: actions/create-release@v1 uses: actions/create-release@v1
env: env:
@ -51,7 +51,7 @@ jobs:
prerelease: true prerelease: true
- name: Upload release asset amd64 - name: Upload release asset amd64
if: success() if: ${{ success() && github.event.ref == 'refs/heads/master' }}
id: upload-release-asset-amd64 id: upload-release-asset-amd64
uses: actions/upload-release-asset@v1.0.1 uses: actions/upload-release-asset@v1.0.1
env: env:
@ -63,7 +63,7 @@ jobs:
asset_content_type: application/x-deb asset_content_type: application/x-deb
- name: Upload release asset armhf - name: Upload release asset armhf
if: success() if: ${{ success() && github.event.ref == 'refs/heads/master' }}
id: upload-release-asset-armhf id: upload-release-asset-armhf
uses: actions/upload-release-asset@v1.0.1 uses: actions/upload-release-asset@v1.0.1
env: env:
@ -77,6 +77,7 @@ jobs:
docker: docker:
name: Build and push dockerfile name: Build and push dockerfile
runs-on: ubuntu-latest runs-on: ubuntu-latest
if: ${{ github.event.ref == 'refs/heads/master' }}
steps: steps:
- name: Checkout parent project with dependencys - name: Checkout parent project with dependencys
uses: actions/checkout@v1 uses: actions/checkout@v1
@ -86,10 +87,12 @@ jobs:
submodules: true submodules: true
- name: Checkout last versions - name: Checkout last versions
if: success()
run: git -C Lora-Map checkout --progress --force ${{ github.sha }} run: git -C Lora-Map checkout --progress --force ${{ github.sha }}
working-directory: ../map-project working-directory: ../map-project
- name: Docker build - name: Docker build
if: success()
id: docker_build id: docker_build
run: | run: |
DOCKERTAG=$(date +%Y%m%d%H%M%S) DOCKERTAG=$(date +%Y%m%d%H%M%S)

View File

@ -1,5 +1,35 @@
# Changelogs # Changelogs
## 1.3.2 - Laufwege Visualisieren
### New Features
* Add posibility to make the past of a marker visible
* Validating the input of Json, against defined models and only parse them if the match
* Remove dublicated packets and if a correct one gets in replace the metadata of position
* Notify other Objects when Settings are changed.
### Bugfixes
* If the settings are changed while collecting weather, ignore the exception
* Fixing encoding problems in SVG
* Fixing overlay with icon editor to be on the correct place at the screen
* Coreccting the imagesize in the admin menu for SVG
* Fixing a bug when open the nameseditor directly after start that images are not created
### Changes
* Refactoring
* Change the SVG link to the correct array behavour
* Used the new methods of AWebserverDataBackend
* Run Github Actions on every commit, at least compiling the code for checking
* Update leaflet to 1.7.1
## 1.3.1 - Refactory is the king
### New Features
* Make a SVG Generator and not modify the SVG on the fly
* Split the js files on the admin pannel
* add a swagger file
### Bugfixes
### Changes
* Refactoring
* Update the Manual a bit
* Push to netcore 3.1
## 1.3.0 - New Gateway ## 1.3.0 - New Gateway
### New Features ### New Features
* Implement Lora-Gateway-Data 1.1.0 Format * Implement Lora-Gateway-Data 1.1.0 Format

View File

@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16 # Visual Studio Version 16
VisualStudioVersion = 16.0.29519.87 VisualStudioVersion = 16.0.29519.87
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Lora-Map_Core", "Lora-Map\Lora-Map.csproj", "{78136B15-FF0B-4DCE-94CA-1D6148DEA232}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Lora-Map", "Lora-Map\Lora-Map.csproj", "{78136B15-FF0B-4DCE-94CA-1D6148DEA232}"
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{7DD32F31-ACB0-4F5E-B3D8-78564A83ACEF}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{7DD32F31-ACB0-4F5E-B3D8-78564A83ACEF}"
ProjectSection(SolutionItems) = preProject ProjectSection(SolutionItems) = preProject

View File

@ -55,11 +55,11 @@
<ItemGroup> <ItemGroup>
<Content Include="../CHANGELOG.md" /> <Content Include="../CHANGELOG.md" />
<Content Include="../CONTRIBUTING.md" /> <Content Include="../CONTRIBUTING.md" />
<Content Include="../LICENSE" /> <Content Include="../LICENSE" />
<Content Include="../README.md" /> <Content Include="../README.md" />
<Content Include="../map-swagger.yml" /> <Content Include="../map-swagger.yml" />
<Content Include="../.github/workflows/dotnetcore.yml" /> <Content Include="../.github/workflows/dotnetcore.yml" />
<Content Include="../doc/Manual.md" /> <Content Include="../doc/Manual.md" />
</ItemGroup> </ItemGroup>
@ -196,6 +196,9 @@
<None Update="resources\js\leaflet\leaflet.js"> <None Update="resources\js\leaflet\leaflet.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None> </None>
<None Update="resources\js\leaflet\leaflet.js.map">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="resources\js\map.js"> <None Update="resources\js\map.js">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None> </None>

View File

@ -2,16 +2,21 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Net; using System.Net;
using System.Text;
using BlubbFish.Utils; using BlubbFish.Utils;
using BlubbFish.Utils.IoT.Bots; using BlubbFish.Utils.IoT.Bots;
using Fraunhofer.Fit.IoT.LoraMap.Model.JsonObjects;
using LitJson; using LitJson;
namespace Fraunhofer.Fit.IoT.LoraMap.Model.Admin { namespace Fraunhofer.Fit.IoT.LoraMap.Model.Admin {
class AdminModel { class AdminModel {
public delegate void AdminEvent(Object sender, EventArgs e); public delegate void AdminEvent(Object sender, EventArgs e);
#pragma warning disable 0067
//Supress never used warning (cause of reflection)
#pragma warning disable 0067
public event AdminEvent NamesUpdate; public event AdminEvent NamesUpdate;
public event AdminEvent GeoUpdate; public event AdminEvent GeoUpdate;
public event AdminEvent SettingsUpdate; public event AdminEvent SettingsUpdate;
@ -52,27 +57,33 @@ namespace Fraunhofer.Fit.IoT.LoraMap.Model.Admin {
} }
} }
Console.WriteLine("200 - Send names.json " + cont.Request.Url.PathAndQuery); Console.WriteLine("200 - Send names.json " + cont.Request.Url.PathAndQuery);
return Webserver.SendJsonResponse(ret, cont); return cont.SendStringResponse(JsonMapper.ToJson(ret));
} }
} else if(cont.Request.HttpMethod == "PUT") { } else if(cont.Request.HttpMethod == "PUT") {
if(cont.Request.Url.AbsolutePath.Length > 16) { if(cont.Request.Url.AbsolutePath.Length > 16) {
String part = cont.Request.Url.AbsolutePath[16..]; String part = cont.Request.Url.AbsolutePath[16..];
if(this.datastorage.ContainsKey(part)) { if(this.datastorage.ContainsKey(part)) {
return this.SetJsonFile(cont, "json/" + this.datastorage[part].Item1 + ".json", this.datastorage[part].Item2); return this.SetJsonFile(cont, part);
} }
} }
} }
} }
return Webserver.SendFileResponse(cont); return cont.SendFileResponse();
} }
private Boolean SetJsonFile(HttpListenerContext cont, String filename, String updatenotifier) { private Boolean SetJsonFile(HttpListenerContext cont, String part) {
StreamReader reader = new StreamReader(cont.Request.InputStream, cont.Request.ContentEncoding); StreamReader reader = new StreamReader(cont.Request.InputStream, cont.Request.ContentEncoding);
String filename = "json/" + this.datastorage[part].Item1 + ".json";
String rawData = reader.ReadToEnd(); String rawData = reader.ReadToEnd();
cont.Request.InputStream.Close(); cont.Request.InputStream.Close();
reader.Close(); reader.Close();
try { try {
_ = JsonMapper.ToObject(rawData); JsonData json = JsonMapper.ToObject(rawData);
if(part == "name") {
if(!NamesModel.CheckJson(json)) {
throw new Exception("Check against model failed.");
}
}
} catch (Exception) { } catch (Exception) {
Helper.WriteError("501 - Error recieving " + filename + ", no valid json " + cont.Request.Url.PathAndQuery); Helper.WriteError("501 - Error recieving " + filename + ", no valid json " + cont.Request.Url.PathAndQuery);
cont.Response.StatusCode = 501; cont.Response.StatusCode = 501;
@ -80,12 +91,12 @@ namespace Fraunhofer.Fit.IoT.LoraMap.Model.Admin {
} }
File.WriteAllText(filename, rawData); File.WriteAllText(filename, rawData);
Console.WriteLine("200 - PUT " + filename + " " + cont.Request.Url.PathAndQuery); Console.WriteLine("200 - PUT " + filename + " " + cont.Request.Url.PathAndQuery);
this.GetEvent<AdminEvent>(updatenotifier)?.Invoke(this, new EventArgs()); this.GetEvent<AdminEvent>(this.datastorage[part].Item2)?.Invoke(this, new EventArgs());
return true; return true;
} }
private Boolean Login(HttpListenerContext cont) { private Boolean Login(HttpListenerContext cont) {
Dictionary<String, String> POST = Webserver.GetPostParams(cont.Request); Dictionary<String, String> POST = cont.Request.GetPostParams();
if(POST.ContainsKey("user") && POST["user"] == this.settings["admin_user"] && POST.ContainsKey("pass") && POST["pass"] == this.settings["admin_pass"]) { if(POST.ContainsKey("user") && POST["user"] == this.settings["admin_user"] && POST.ContainsKey("pass") && POST["pass"] == this.settings["admin_pass"]) {
Int64 sessionid; Int64 sessionid;
while(true) { while(true) {

View File

@ -0,0 +1,99 @@
using System;
using System.Globalization;
using LitJson;
namespace Fraunhofer.Fit.IoT.LoraMap.Model.JsonObjects {
public class LoraData {
#region mandatory field
public Double BatteryLevel {
get;
}
public Boolean CorrectInterface {
get;
}
public LoraDataGps Gps {
get;
}
public String Hash {
get;
}
public String Name {
get;
}
#endregion
#region optional field
public DateTime Receivedtime {
get;
}
public Double Rssi {
get;
}
public Double Snr {
get;
}
#endregion
public static Boolean CheckJson(JsonData json) =>
json.ContainsKey("BatteryLevel") && (json["BatteryLevel"].IsDouble || json["BatteryLevel"].IsInt)
&& json.ContainsKey("CorrectInterface") && json["CorrectInterface"].IsBoolean
&& json.ContainsKey("Gps") && json["Gps"].IsObject
&& LoraDataGps.CheckJson(json["Gps"])
&& json.ContainsKey("Hash") && json["Hash"].IsString
&& json.ContainsKey("Name") && json["Name"].IsString;
public LoraData(JsonData json) {
//mandatory field
this.BatteryLevel = json["BatteryLevel"].IsInt ? (Int32)json["BatteryLevel"] : (Double)json["BatteryLevel"];
this.CorrectInterface = (Boolean)json["CorrectInterface"];
this.Gps = new LoraDataGps(json["Gps"]);
this.Hash = (String)json["Hash"];
this.Name = (String)json["Name"];
//optional field
this.Rssi = json.ContainsKey("Rssi") && (json["Rssi"].IsDouble || json["Rssi"].IsInt) ? json["Rssi"].IsInt ? (Int32)json["Rssi"] : (Double)json["Rssi"] : 0;
this.Snr = json.ContainsKey("Snr") && (json["Snr"].IsDouble || json["Snr"].IsInt) ? json["Snr"].IsInt ? (Int32)json["Snr"] : (Double)json["Snr"] : 0;
this.Receivedtime = json.ContainsKey("Receivedtime") && json["Receivedtime"].IsString && DateTime.TryParse((String)json["Receivedtime"], DateTimeFormatInfo.InvariantInfo, DateTimeStyles.AssumeUniversal, out DateTime updatetime) ? updatetime.ToUniversalTime() : DateTime.UtcNow;
}
}
public class LoraDataGps {
#region mandatory field
public Double Latitude {
get;
}
public Double Longitude {
get;
}
public Boolean Fix {
get;
}
public Double Height {
get;
}
#endregion
#region optional field
public Double Hdop {
get;
}
#endregion
public static Boolean CheckJson(JsonData json) =>
json.ContainsKey("Latitude") && (json["Latitude"].IsDouble || json["Latitude"].IsInt)
&& json.ContainsKey("Longitude") && (json["Longitude"].IsDouble || json["Longitude"].IsInt)
&& json.ContainsKey("Fix") && json["Fix"].IsBoolean
&& json.ContainsKey("Height") && (json["Height"].IsDouble || json["Height"].IsInt);
public LoraDataGps(JsonData json) {
//mandatory field
this.Latitude = json["Latitude"].IsInt ? (Int32)json["Latitude"] : (Double)json["Latitude"];
this.Longitude = json["Longitude"].IsInt ? (Int32)json["Longitude"] : (Double)json["Longitude"];
this.Fix = (Boolean)json["Fix"];
this.Height = json["Height"].IsInt ? (Int32)json["Height"] : (Double)json["Height"];
//optional field
this.Hdop = json.ContainsKey("Hdop") && (json["Hdop"].IsDouble || json["Hdop"].IsInt) ? json["Hdop"].IsInt ? (Int32)json["Hdop"] : (Double)json["Hdop"] : 0;
}
}
}

View File

@ -0,0 +1,149 @@
using System;
using System.Collections.Generic;
using System.IO;
using BlubbFish.Utils;
using LitJson;
namespace Fraunhofer.Fit.IoT.LoraMap.Model.JsonObjects {
public class NamesModel {
public SortedDictionary<String, NamesModelData> Items {
get;
}
public static Boolean CheckJson(JsonData json) {
if(!json.IsObject) {
return false;
}
foreach(String item in json.Keys) {
if(!NamesModelData.CheckJson(json[item])) {
return false;
}
}
return true;
}
public NamesModel() {
this.Items = new SortedDictionary<String, NamesModelData>();
JsonData json = this.LoadFromFile();
if(json != null && CheckJson(json)) {
foreach(String item in json.Keys) {
this.Items.Add(item, new NamesModelData(json[item]));
}
}
}
private JsonData LoadFromFile() {
try {
if(!Directory.Exists("json")) {
_ = Directory.CreateDirectory("json");
}
if(!File.Exists("json/names.json")) {
File.WriteAllText("json/names.json", "{}");
}
return JsonMapper.ToObject(File.ReadAllText("json/names.json"));
} catch {
Helper.WriteError("Could not load json/names.json");
return null;
}
}
}
public class NamesModelData {
#region mandatory field
public String Name {
get;
}
public String Group {
get;
}
#endregion
#region optional field
public String Icon {
get;
}
public NamesModelDataMarkerSvg MarkerSvg {
get;
}
#endregion
public static Boolean CheckJson(JsonData json) =>
json.ContainsKey("name") && json["name"].IsString
&& json.ContainsKey("Group") && json["Group"].IsString;
public NamesModelData(JsonData json) {
//mandatory field
this.Name = (String)json["name"];
this.Group = (String)json["Group"];
//optional field
this.MarkerSvg = json.ContainsKey("marker.svg") && json["marker.svg"].IsObject && NamesModelDataMarkerSvg.CheckJson(json["marker.svg"]) ? new NamesModelDataMarkerSvg(json["marker.svg"]) : null;
this.Icon = json.ContainsKey("icon") && json["icon"].IsString ? (String)json["icon"] : null;
}
}
public class NamesModelDataMarkerSvg {
#region optional field
public NamesModelDataMarkerSvgPerson Person {
get;
}
#endregion
public static Boolean CheckJson(JsonData json) =>
json.ContainsKey("person") && json["person"].IsObject;
public NamesModelDataMarkerSvg(JsonData json) {
//optional field
#pragma warning disable IDE0021 // Ausdruckskörper für Konstruktoren verwenden
this.Person = json.ContainsKey("person") && json["person"].IsObject && NamesModelDataMarkerSvgPerson.CheckJson(json["person"]) ? new NamesModelDataMarkerSvgPerson(json["person"]) : null;
#pragma warning restore IDE0021 // Ausdruckskörper für Konstruktoren verwenden
}
}
public class NamesModelDataMarkerSvgPerson {
#region mandatory field
public String Funktion {
get;
}
public String Organisation {
get;
}
public String Rang {
get;
}
#endregion
#region optional field
public String Text {
get;
}
public List<String> Typ {
get;
}
#endregion
public static Boolean CheckJson(JsonData json) =>
json.ContainsKey("org") && json["org"].IsString
&& json.ContainsKey("funct") && json["funct"].IsString
&& json.ContainsKey("rang") && json["rang"].IsString;
public NamesModelDataMarkerSvgPerson(JsonData json) {
//mandatory field
this.Organisation = (String)json["org"];
this.Funktion = (String)json["funct"];
this.Rang = (String)json["rang"];
//optional field
this.Text = json.ContainsKey("text") && json["text"].IsString ? (String)json["text"] : null;
List<String> typs = new List<String>();
if(json.ContainsKey("typ") && json["typ"].IsArray) {
foreach(JsonData item in json["typ"]) {
if(item.IsString) {
typs.Add(item.ToString());
}
}
}
this.Typ = typs;
}
}
}

View File

@ -1,7 +1,8 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using LitJson;
using Fraunhofer.Fit.IoT.LoraMap.Model.JsonObjects;
namespace Fraunhofer.Fit.IoT.LoraMap.Model.Position { namespace Fraunhofer.Fit.IoT.LoraMap.Model.Position {
public class PositionAlarm : PositionItem { public class PositionAlarm : PositionItem {
@ -9,24 +10,21 @@ namespace Fraunhofer.Fit.IoT.LoraMap.Model.Position {
public List<DateTime> ButtonPressed => this.buttonhistory.Keys.ToList(); public List<DateTime> ButtonPressed => this.buttonhistory.Keys.ToList();
public PositionAlarm(JsonData json) : base(json, null) { public PositionAlarm(LoraData data) : base(data, null) {
} }
public override void Update(JsonData json) { public override void Update(LoraData data) {
base.Update(json); base.Update(data);
this.SetHistory(json); this.SetHistory(data);
} }
private void SetHistory(JsonData json) { private void SetHistory(LoraData data) {
if(json.ContainsKey("Hash") && json["Hash"].IsString) { if(!this.buttonhistory.ContainsValue(data.Hash)) {
String key = json["Hash"].ToString(); this.buttonhistory.Add(DateTime.UtcNow, data.Hash);
if(!this.buttonhistory.ContainsValue(key)) { if(this.buttonhistory.Count > 10) {
this.buttonhistory.Add(DateTime.UtcNow, key); _ = this.buttonhistory.Remove(this.buttonhistory.Keys.ToList().First());
if(this.buttonhistory.Count > 10) {
_ = this.buttonhistory.Remove(this.buttonhistory.Keys.ToList().First());
}
} }
} }
} }
} }
} }

View File

@ -1,14 +1,19 @@
using System; using System;
using System.Globalization; using System.Collections.Generic;
using System.Linq;
using Fraunhofer.Fit.IoT.LoraMap.Model.JsonObjects;
using Fraunhofer.Fit.IoT.LoraMap.Model.Svg; using Fraunhofer.Fit.IoT.LoraMap.Model.Svg;
using LitJson;
namespace Fraunhofer.Fit.IoT.LoraMap.Model.Position { namespace Fraunhofer.Fit.IoT.LoraMap.Model.Position {
public class PositionItem { public class PositionItem {
private Double _lastLat = 0; private Double _lastLat = 0;
private Double _lastLon = 0; private Double _lastLon = 0;
private readonly SortedDictionary<DateTime, Double[]> _history = new SortedDictionary<DateTime, Double[]>();
private String _lastHash = "";
private Boolean _isdublicate = false;
private Double _historycounter = 0;
private readonly Object lockHistory = new Object();
public Double Rssi { get; private set; } public Double Rssi { get; private set; }
public Double Snr { get; private set; } public Double Snr { get; private set; }
@ -27,19 +32,21 @@ namespace Fraunhofer.Fit.IoT.LoraMap.Model.Position {
public String Icon { get; private set; } public String Icon { get; private set; }
public String MenuIcon { get; private set; } public String MenuIcon { get; private set; }
public String Group { get; private set; } public String Group { get; private set; }
public List<Double[]> History => this._history.Values.ToList();
public PositionItem(JsonData json, JsonData marker) { public PositionItem(LoraData data, NamesModel marker) {
this.Update(json); this.Update(data);
this.UpdateMarker(marker, GetId(json)); this.UpdateMarker(marker, data.Name);
Settings.Instance.SettingsUpdate += this.UpdateSettings;
} }
public void UpdateMarker(JsonData marker, String id) { public void UpdateMarker(NamesModel marker, String id) {
if(marker != null && marker.ContainsKey(id)) { if(marker.Items.ContainsKey(id)) {
this.Name = marker[id].ContainsKey("name") && marker[id]["name"].IsString ? (String)marker[id]["name"] : id; this.Name = marker.Items[id].Name;
Tuple<String, String> icons = this.ParseIconConfig(marker[id]); Tuple<String, String> icons = this.ParseIconConfig(marker.Items[id]);
this.Icon = icons.Item1; this.Icon = icons.Item1;
this.MenuIcon = icons.Item2; this.MenuIcon = icons.Item2;
this.Group = marker[id].ContainsKey("Group") && marker[id]["Group"].IsString ? (String)marker[id]["Group"] : "no"; this.Group = marker.Items[id].Group;
} else { } else {
this.Name = id; this.Name = id;
this.Icon = null; this.Icon = null;
@ -47,44 +54,43 @@ namespace Fraunhofer.Fit.IoT.LoraMap.Model.Position {
} }
} }
private Tuple<String, String> ParseIconConfig(JsonData marker) { private Tuple<String, String> ParseIconConfig(NamesModelData marker) {
String icon = null; String icon = null;
String menu = null; String menu = null;
if(marker.ContainsKey("marker.svg") && marker["marker.svg"].IsObject) { if(marker.MarkerSvg != null) {
icon = SVGMarker.ParseConfig(marker["marker.svg"], this.Name); icon = SVGMarker.ParseConfig(marker.MarkerSvg, this.Name);
if(marker["marker.svg"].ContainsKey("person") && marker["marker.svg"]["person"].IsObject) { if(marker.MarkerSvg.Person != null) {
menu = SVGPerson.ParseConfig(marker["marker.svg"]["person"]); menu = SVGPerson.ParseConfig(marker.MarkerSvg.Person);
} }
} else if(marker.ContainsKey("icon") && marker["icon"].IsString) { } else if(marker.Icon != null) {
icon = (String)marker["icon"]; icon = marker.Icon;
} }
return new Tuple<String, String>(icon, menu); return new Tuple<String, String>(icon, menu);
} }
public static Boolean CheckJson(JsonData json) => public virtual void Update(LoraData data) {
json.ContainsKey("BatteryLevel") && (json["BatteryLevel"].IsDouble || json["BatteryLevel"].IsInt) this._isdublicate = false;
&& json.ContainsKey("Gps") && json["Gps"].IsObject if(data.Hash == this._lastHash) {
&& json["Gps"].ContainsKey("Latitude") && (json["Gps"]["Latitude"].IsDouble || json["Gps"]["Latitude"].IsInt) if(!data.CorrectInterface) {
&& json["Gps"].ContainsKey("Longitude") && (json["Gps"]["Longitude"].IsDouble || json["Gps"]["Longitude"].IsInt) Console.WriteLine("dublicate-Paket, reomove wrong reciever!");
&& json["Gps"].ContainsKey("Fix") && json["Gps"]["Fix"].IsBoolean return;
&& json["Gps"].ContainsKey("Height") && (json["Gps"]["Height"].IsDouble || json["Gps"]["Height"].IsInt) }
&& json.ContainsKey("Name") && json["Name"].IsString; this._isdublicate = true;
Console.WriteLine("dublicate-Paket!");
public static String GetId(JsonData json) => (String)json["Name"]; }
this._lastHash = data.Hash;
public virtual void Update(JsonData json) { this.Rssi = data.Rssi;
this.Rssi = json.ContainsKey("Rssi") && (json["Rssi"].IsDouble || json["Rssi"].IsInt) && Double.TryParse(json["Rssi"].ToString(), out Double rssi) ? rssi : 0; this.Snr = data.Snr;
this.Snr = json.ContainsKey("Snr") && (json["Snr"].IsDouble || json["Snr"].IsInt) && Double.TryParse(json["Snr"].ToString(), out Double snr) ? snr : 0; this.Lorarecievedtime = data.Receivedtime;
this.Lorarecievedtime = json.ContainsKey("Receivedtime") && json["Receivedtime"].IsString && DateTime.TryParse((String)json["Receivedtime"], DateTimeFormatInfo.InvariantInfo, DateTimeStyles.AssumeUniversal, out DateTime updatetime) ? updatetime.ToUniversalTime() : DateTime.UtcNow;
this.Recievedtime = DateTime.UtcNow; this.Recievedtime = DateTime.UtcNow;
this.Battery = Math.Round(json["BatteryLevel"].IsInt ? (Int32)json["BatteryLevel"] : (Double)json["BatteryLevel"], 2); this.Battery = Math.Round(data.BatteryLevel, 2);
this.Batterysimple = this.Battery < 3.44 ? 0 : this.Battery < 3.53 ? 1 : this.Battery < 3.6525 ? 2 : this.Battery < 3.8825 ? 3 : 4; this.Batterysimple = this.Battery < 3.44 ? 0 : this.Battery < 3.53 ? 1 : this.Battery < 3.6525 ? 2 : this.Battery < 3.8825 ? 3 : 4;
this.Latitude = json["Gps"]["Latitude"].IsInt ? (Int32)json["Gps"]["Latitude"] : (Double)json["Gps"]["Latitude"]; this.Latitude = data.Gps.Latitude;
this.Longitude = json["Gps"]["Longitude"].IsInt ? (Int32)json["Gps"]["Longitude"] : (Double)json["Gps"]["Longitude"]; this.Longitude = data.Gps.Longitude;
this.Fix = (Boolean)json["Gps"]["Fix"]; this.Fix = data.Gps.Fix;
this.Height = json["Gps"]["Height"].IsInt ? (Int32)json["Gps"]["Height"] : (Double)json["Gps"]["Height"]; this.Height = data.Gps.Height;
this.Hdop = json["Gps"].ContainsKey("Hdop") && (json["Gps"]["Hdop"].IsDouble || json["Gps"]["Hdop"].IsInt) && Double.TryParse(json["Gps"]["Hdop"].ToString(), out Double hdop) ? hdop : 0; this.Hdop = data.Gps.Hdop;
if(!this.Fix) { if(!this.Fix) {
this.Latitude = this._lastLat; this.Latitude = this._lastLat;
@ -93,10 +99,46 @@ namespace Fraunhofer.Fit.IoT.LoraMap.Model.Position {
this._lastLat = this.Latitude; this._lastLat = this.Latitude;
this._lastLon = this.Longitude; this._lastLon = this.Longitude;
this.Lastgpspostime = DateTime.UtcNow; this.Lastgpspostime = DateTime.UtcNow;
if(!this._isdublicate) {
this.StoreHistory();
}
} }
this.UTM = new UTMData(this.Latitude, this.Longitude); this.UTM = new UTMData(this.Latitude, this.Longitude);
} }
private void StoreHistory() {
lock(this.lockHistory) {
if(Settings.Instance.Internal.History.Enabled) {
if(Settings.Instance.Internal.History.Amount != 0 && this._history.Count > Settings.Instance.Internal.History.Amount) {
_ = this._history.Remove(this._history.Keys.ToList().First());
}
if(Settings.Instance.Internal.History.Time != 0) {
List<DateTime> removeCandidates = new List<DateTime>();
DateTime now = DateTime.UtcNow;
foreach(KeyValuePair<DateTime, Double[]> item in this._history) {
if((now - item.Key).TotalSeconds > Settings.Instance.Internal.History.Time) {
removeCandidates.Add(item.Key);
}
}
if(removeCandidates.Count > 0) {
foreach(DateTime item in removeCandidates) {
_ = this._history.Remove(item);
}
}
}
if(!this._history.ContainsKey(this.Recievedtime)) {
this._history.Add(this.Recievedtime, new Double[] { this.Latitude, this.Longitude, this._historycounter++ });
}
} else {
this._history.Clear();
}
}
}
private void UpdateSettings(Object sender, EventArgs e) {
lock(this.lockHistory) {
this._history.Clear();
}
}
} }
} }

View File

@ -1,16 +1,17 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO;
using BlubbFish.Utils; using BlubbFish.Utils;
using Fraunhofer.Fit.IoT.LoraMap.Model.JsonObjects;
using LitJson; using LitJson;
namespace Fraunhofer.Fit.IoT.LoraMap.Model.Position { namespace Fraunhofer.Fit.IoT.LoraMap.Model.Position {
public class PositionModel : OwnSingeton<PositionModel> { public class PositionModel : OwnSingeton<PositionModel> {
private readonly Object lockData = new Object(); private readonly Object lockData = new Object();
private readonly Object lockPanic = new Object(); private readonly Object lockAlarm = new Object();
private JsonData marker; private NamesModel marker;
public SortedDictionary<String, PositionItem> Positions { public SortedDictionary<String, PositionItem> Positions {
get; private set; get; private set;
@ -23,27 +24,25 @@ namespace Fraunhofer.Fit.IoT.LoraMap.Model.Position {
protected PositionModel() { protected PositionModel() {
this.Positions = new SortedDictionary<String, PositionItem>(); this.Positions = new SortedDictionary<String, PositionItem>();
this.Alarms = new SortedDictionary<String, PositionAlarm>(); this.Alarms = new SortedDictionary<String, PositionAlarm>();
this.CheckJsonFile(); this.marker = new NamesModel();
this.marker = JsonMapper.ToObject(File.ReadAllText("json/names.json"));
} }
public void ParseMqttJson(JsonData mqtt, String from) { public void ParseMqttJson(JsonData mqtt, String from) {
if((from.Contains("lora/data") || from.Contains("lora/panic")) && PositionItem.CheckJson(mqtt)) { if((from.Contains("lora/data") || from.Contains("lora/panic")) && LoraData.CheckJson(mqtt)) {
String name = PositionItem.GetId(mqtt); LoraData data = new LoraData(mqtt);
lock(this.lockData) { lock(this.lockData) {
if(this.Positions.ContainsKey(name)) { if(this.Positions.ContainsKey(data.Name)) {
this.Positions[name].Update(mqtt); this.Positions[data.Name].Update(data);
} else { } else {
this.Positions.Add(name, new PositionItem(mqtt, this.marker)); this.Positions.Add(data.Name, new PositionItem(data, this.marker));
} }
} }
if(from.Contains("lora/panic")) { if(from.Contains("lora/panic")) {
lock(this.lockPanic) { lock(this.lockAlarm) {
if(this.Alarms.ContainsKey(name)) { if(this.Alarms.ContainsKey(data.Name)) {
this.Alarms[name].Update(mqtt); this.Alarms[data.Name].Update(data);
} else { } else {
this.Alarms.Add(name, new PositionAlarm(mqtt)); this.Alarms.Add(data.Name, new PositionAlarm(data));
} }
} }
Console.WriteLine("PANIC erhalten!"); Console.WriteLine("PANIC erhalten!");
@ -53,21 +52,11 @@ namespace Fraunhofer.Fit.IoT.LoraMap.Model.Position {
} }
public void ReloadNames(Object sender, EventArgs e) { public void ReloadNames(Object sender, EventArgs e) {
this.CheckJsonFile(); this.marker = new NamesModel();
this.marker = JsonMapper.ToObject(File.ReadAllText("json/names.json"));
foreach(KeyValuePair<String, PositionItem> item in this.Positions) { foreach(KeyValuePair<String, PositionItem> item in this.Positions) {
item.Value.UpdateMarker(this.marker, item.Key); item.Value.UpdateMarker(this.marker, item.Key);
} }
Console.WriteLine("Namen und Icons aktualisiert!"); Console.WriteLine("Namen und Icons aktualisiert!");
} }
private void CheckJsonFile() {
if(!Directory.Exists("json")) {
_ = Directory.CreateDirectory("json");
}
if(!File.Exists("json/names.json")) {
File.WriteAllText("json/names.json", "{}");
}
}
} }
} }

View File

@ -25,25 +25,27 @@ namespace Fraunhofer.Fit.IoT.LoraMap.Model.Sensor {
private void BackGroundRunner() { private void BackGroundRunner() {
while(this.backgroundrunnerAlive) { while(this.backgroundrunnerAlive) {
List<Warning> ret = new List<Warning>(); try {
foreach(Int32 item in Settings.Instance.Internal.WeatherCellIDs) { List<Warning> ret = new List<Warning>();
try { foreach(Int32 item in Settings.Instance.Internal.WeatherCellIDs) {
JsonData json = this.webrequests.GetJson("https://maps.dwd.de/geoserver/wfs?SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature&typeName=dwd:Warnungen_Gemeinden&outputFormat=application/json&cql_filter=WARNCELLID=" + item); try {
if (json.ContainsKey("features") && json["features"].IsArray && json["features"].Count > 0) { JsonData json = this.webrequests.GetJson("https://maps.dwd.de/geoserver/wfs?SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature&typeName=dwd:Warnungen_Gemeinden&outputFormat=application/json&cql_filter=WARNCELLID=" + item);
foreach (JsonData warning in json["features"]) { if(json.ContainsKey("features") && json["features"].IsArray && json["features"].Count > 0) {
try { foreach(JsonData warning in json["features"]) {
ret.Add(new Warning(warning)); try {
} catch { } ret.Add(new Warning(warning));
} catch { }
}
} }
} } catch { }
} catch { }
}
this.Warnungen = ret;
for (Int32 i = 0; i < 1000; i++) {
if (this.backgroundrunnerAlive) {
Thread.Sleep(60);
} }
} this.Warnungen = ret;
for(Int32 i = 0; i < 1000; i++) {
if(this.backgroundrunnerAlive) {
Thread.Sleep(60);
}
}
} catch { }
} }
} }

View File

@ -8,9 +8,12 @@ using System.IO;
namespace Fraunhofer.Fit.IoT.LoraMap.Model { namespace Fraunhofer.Fit.IoT.LoraMap.Model {
public class Settings : OwnSingeton<Settings> { public class Settings : OwnSingeton<Settings> {
private Int32 gridradius; private Int32 gridradius;
public delegate void SettingsEvent(Object sender, EventArgs e);
public event SettingsEvent SettingsUpdate;
public PublicSettings External { public PublicSettings External {
get; set; get; set;
} }
@ -124,9 +127,22 @@ namespace Fraunhofer.Fit.IoT.LoraMap.Model {
} }
this.External.Sensors = sensors; this.External.Sensors = sensors;
} }
if(json.ContainsKey("History") && json["History"].IsObject) {
if(json["History"].ContainsKey("enabled") && json["History"]["enabled"].IsBoolean) {
this.Internal.History.Enabled = (Boolean)json["History"]["enabled"];
}
if(this.Internal.History.Enabled) {
this.Internal.History.Time = json["History"].ContainsKey("time") && json["History"]["time"].IsInt ? (Int32)json["History"]["time"] : 0;
this.Internal.History.Amount = json["History"].ContainsKey("amount") && json["History"]["amount"].IsInt ? (Int32)json["History"]["amount"] : 0;
} else {
this.Internal.History.Amount = 0;
this.Internal.History.Time = 0;
}
}
this.gridradius = json.ContainsKey("GridRadius") && json["GridRadius"].IsInt && this.External.Startloclat != 0 && this.External.Startloclon != 0 ? (Int32)json["GridRadius"] : 0; this.gridradius = json.ContainsKey("GridRadius") && json["GridRadius"].IsInt && this.External.Startloclat != 0 && this.External.Startloclon != 0 ? (Int32)json["GridRadius"] : 0;
this.GenerateGrid(); this.GenerateGrid();
this.FindMapLayer(); this.FindMapLayer();
this.SettingsUpdate?.Invoke(this, new EventArgs());
} }
private void ParseGeoJson() { private void ParseGeoJson() {
@ -294,6 +310,18 @@ namespace Fraunhofer.Fit.IoT.LoraMap.Model {
} }
} }
public class History {
public Boolean Enabled {
get; set;
} = false;
public Int32 Time {
get; set;
} = 0;
public Int32 Amount {
get; set;
} = 0;
}
public class PublicSettings { public class PublicSettings {
public Double Startloclat { public Double Startloclat {
get; set; get; set;
@ -323,6 +351,9 @@ namespace Fraunhofer.Fit.IoT.LoraMap.Model {
public class PrivateSettings { public class PrivateSettings {
public List<Int32> WeatherCellIDs { get; set; } = new List<Int32>(); public List<Int32> WeatherCellIDs { get; set; } = new List<Int32>();
public History History {
get; set;
} = new History();
} }
} }
} }

View File

@ -72,13 +72,15 @@ namespace Fraunhofer.Fit.IoT.LoraMap.Model.Svg {
#endregion #endregion
} }
protected static String DictionaryConfigToString(Dictionary<String, String> config) { protected static String DictionaryConfigToString(Dictionary<String, List<String>> config) {
String query = ""; String query = "";
if(config.Count > 0) { if(config.Count > 0) {
query += "?"; query += "?";
List<String> queryparts = new List<String>(); List<String> queryparts = new List<String>();
foreach(KeyValuePair<String, String> item in config) { foreach(KeyValuePair<String, List<String>> items in config) {
queryparts.Add(HttpUtility.UrlEncode(item.Key) + "=" + HttpUtility.UrlEncode(item.Value)); foreach(String item in items.Value) {
queryparts.Add(items.Key + "=" + HttpUtility.UrlEncode(item));
}
} }
query += String.Join("&", queryparts); query += String.Join("&", queryparts);
} }

View File

@ -1,9 +1,9 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Web;
using LitJson; using Fraunhofer.Fit.IoT.LoraMap.Model.JsonObjects;
namespace Fraunhofer.Fit.IoT.LoraMap.Model.Svg { namespace Fraunhofer.Fit.IoT.LoraMap.Model.Svg {
public class SVGMarker : SVGFile { public class SVGMarker : SVGFile {
@ -12,7 +12,7 @@ namespace Fraunhofer.Fit.IoT.LoraMap.Model.Svg {
public SVGMarker(String query) : base(query, 86, 121.25, new List<Double>() { 0, 0, 86, 121.25 }) => this.css.Add("#marker-name tspan {\n font-size: 20px;\n font-family: DIN1451;\n}"); public SVGMarker(String query) : base(query, 86, 121.25, new List<Double>() { 0, 0, 86, 121.25 }) => this.css.Add("#marker-name tspan {\n font-size: 20px;\n font-family: DIN1451;\n}");
public static String ParseConfig(JsonData json, String name) => "api/svg/marker.svg" + DictionaryConfigToString(GenerateConfig(json, name)); public static String ParseConfig(NamesModelDataMarkerSvg json, String name) => "api/svg/marker.svg" + DictionaryConfigToString(GenerateConfig(json, name));
protected override void ParseParams() { protected override void ParseParams() {
String[] parts = this.query.Split('&'); String[] parts = this.query.Split('&');
@ -21,7 +21,7 @@ namespace Fraunhofer.Fit.IoT.LoraMap.Model.Svg {
if(keyvalue.Length == 2) { if(keyvalue.Length == 2) {
switch(keyvalue[0].ToLower()) { switch(keyvalue[0].ToLower()) {
case "name": case "name":
this.name = keyvalue[1]; this.name = HttpUtility.UrlDecode(keyvalue[1]);
break; break;
case "icon": case "icon":
this.icon = keyvalue[1].ToLower(); this.icon = keyvalue[1].ToLower();
@ -31,14 +31,14 @@ namespace Fraunhofer.Fit.IoT.LoraMap.Model.Svg {
} }
} }
public static Dictionary<String, String> GenerateConfig(JsonData json, String name) { public static Dictionary<String, List<String>> GenerateConfig(NamesModelDataMarkerSvg json, String name) {
Dictionary<String, String> config = new Dictionary<String, String>(); Dictionary<String, List<String>> config = new Dictionary<String, List<String>>();
if(name != "") { if(name != "") {
config.Add("name", name); config.Add("name", new List<String>() { name });
} }
if(json.ContainsKey("person") && json["person"].IsObject) { if(json.Person != null) {
config.Add("icon", "person"); config.Add("icon", new List<String>() { "person" });
Dictionary<String, String> personconfig = SVGPerson.GenerateConfig(json["person"]); Dictionary<String, List<String>> personconfig = SVGPerson.GenerateConfig(json.Person);
personconfig.ToList().ForEach(x => config.Add(x.Key, x.Value)); personconfig.ToList().ForEach(x => config.Add(x.Key, x.Value));
} }
return config; return config;
@ -52,7 +52,7 @@ namespace Fraunhofer.Fit.IoT.LoraMap.Model.Svg {
svg += "</g>\n"; svg += "</g>\n";
svg += "<g inkscape:groupmode=\"layer\" id=\"marker-name\" inkscape:label=\"Name\">\n"; svg += "<g inkscape:groupmode=\"layer\" id=\"marker-name\" inkscape:label=\"Name\">\n";
svg += $"<text><tspan x=\"5\" y=\"20\" id=\"marker-name-text\">{this.name}</tspan></text>\n"; svg += $"<text><tspan x=\"5\" y=\"20\" id=\"marker-name-text\">{HttpUtility.HtmlEncode(this.name)}</tspan></text>\n";
svg += "</g>\n"; svg += "</g>\n";
if(this.icon == "person") { if(this.icon == "person") {

View File

@ -2,8 +2,9 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.Linq; using System.Linq;
using System.Web;
using LitJson; using Fraunhofer.Fit.IoT.LoraMap.Model.JsonObjects;
namespace Fraunhofer.Fit.IoT.LoraMap.Model.Svg { namespace Fraunhofer.Fit.IoT.LoraMap.Model.Svg {
public class SVGPerson : SVGFile { public class SVGPerson : SVGFile {
@ -11,7 +12,7 @@ namespace Fraunhofer.Fit.IoT.LoraMap.Model.Svg {
private String function; private String function;
private String rang; private String rang;
private String text; private String text;
private String[] typs; private readonly List<String> typs = new List<String>();
@ -23,7 +24,7 @@ namespace Fraunhofer.Fit.IoT.LoraMap.Model.Svg {
this.css.Add("#person-layer-typ line {\n stroke-width: 3px;\n stroke: black;\n}"); this.css.Add("#person-layer-typ line {\n stroke-width: 3px;\n stroke: black;\n}");
} }
public static String ParseConfig(JsonData json) => "api/svg/person.svg" + DictionaryConfigToString(GenerateConfig(json)); public static String ParseConfig(NamesModelDataMarkerSvgPerson json) => "api/svg/person.svg" + DictionaryConfigToString(GenerateConfig(json));
protected override void ParseParams() { protected override void ParseParams() {
String[] parts = this.query.Split('&'); String[] parts = this.query.Split('&');
@ -41,38 +42,27 @@ namespace Fraunhofer.Fit.IoT.LoraMap.Model.Svg {
this.rang = keyvalue[1].ToLower(); this.rang = keyvalue[1].ToLower();
break; break;
case "person-text": case "person-text":
this.text = keyvalue[1]; this.text = HttpUtility.UrlDecode(keyvalue[1]);
break; break;
case "person-typ": case "person-typ[]":
this.typs = keyvalue[1].ToLower().Split(","); this.typs.Add(HttpUtility.UrlDecode(keyvalue[1]).ToLower());
break; break;
} }
} }
} }
} }
public static Dictionary<String, String> GenerateConfig(JsonData json) { public static Dictionary<String, List<String>> GenerateConfig(NamesModelDataMarkerSvgPerson json) {
Dictionary<String, String> config = new Dictionary<String, String>(); Dictionary<String, List<String>> config = new Dictionary<String, List<String>> {
if(json.ContainsKey("org") && json["org"].IsString) { { "person-org", new List<String>() { json.Organisation } },
config.Add("person-org", json["org"].ToString()); { "person-funct", new List<String>() { json.Funktion } },
{ "person-rang", new List<String>() { json.Rang } }
};
if(json.Text != null) {
config.Add("person-text", new List<String>() { json.Text });
} }
if(json.ContainsKey("funct") && json["funct"].IsString) { if(json.Typ.Count > 0) {
config.Add("person-funct", json["funct"].ToString()); config.Add("person-typ[]", json.Typ);
}
if(json.ContainsKey("rang") && json["rang"].IsString) {
config.Add("person-rang", json["rang"].ToString());
}
if(json.ContainsKey("text") && json["text"].IsString) {
config.Add("person-text", json["text"].ToString());
}
if(json.ContainsKey("typ") && json["typ"].IsArray) {
List<String> typs = new List<String>();
foreach(JsonData item in json["person"]["typ"]) {
if(item.IsString) {
typs.Add(item.ToString());
}
}
config.Add("person-typ", String.Join(",", typs));
} }
return config; return config;
} }
@ -104,12 +94,11 @@ namespace Fraunhofer.Fit.IoT.LoraMap.Model.Svg {
svg += "</g>\n"; svg += "</g>\n";
svg += "</g>\n"; svg += "</g>\n";
} }
if(this.text != null || this.typs != null && this.typs.All(x => this.typlookup.ContainsKey(x))) { if(this.text != null || this.typs.Count > 0 && this.typs.All(x => this.typlookup.ContainsKey(x))) {
svg += "<g inkscape:groupmode=\"layer\" id=\"person-layer-typ\" inkscape:label=\"Typ\">\n"; svg += "<g inkscape:groupmode=\"layer\" id=\"person-layer-typ\" inkscape:label=\"Typ\">\n";
if(this.text != null && this.typs == null) { if(this.text != null) {
svg += $"<text><tspan y=\"42\" x=\"0\" id=\"person-layer-typ-text\">{this.text}</tspan></text>\n"; svg += $"<text><tspan y=\"42\" x=\"0\" id=\"person-layer-typ-text\">{HttpUtility.HtmlEncode(this.text)}</tspan></text>\n";
} } else if(this.typs.Count > 0 && this.typs.All(x => this.typlookup.ContainsKey(x))) {
if(this.text == null && this.typs != null && this.typs.All(x => this.typlookup.ContainsKey(x))) {
foreach(String typ in this.typs) { foreach(String typ in this.typs) {
svg += $"<g id=\"person-layer-typ-{typ}\" inkscape:label=\"{this.typlookup[typ].Name}\">\n"; svg += $"<g id=\"person-layer-typ-{typ}\" inkscape:label=\"{this.typlookup[typ].Name}\">\n";
foreach(Tuple<Double, Double, Double, Double> item in this.typlookup[typ].Lines) { foreach(Tuple<Double, Double, Double, Double> item in this.typlookup[typ].Lines) {

View File

@ -8,6 +8,8 @@ using BlubbFish.Utils;
namespace Fraunhofer.Fit.IoT.LoraMap.Model.Svg { namespace Fraunhofer.Fit.IoT.LoraMap.Model.Svg {
public class SvgModel : OwnSingeton<SvgModel> { public class SvgModel : OwnSingeton<SvgModel> {
private readonly Dictionary<String, SVGFile> svgtable = new Dictionary<String, SVGFile>(); private readonly Dictionary<String, SVGFile> svgtable = new Dictionary<String, SVGFile>();
private readonly Object lockSVG = new Object();
public Boolean ParseRequest(HttpListenerContext cont) { public Boolean ParseRequest(HttpListenerContext cont) {
Byte[] svg = this.GetSvg(cont.Request.Url.PathAndQuery); Byte[] svg = this.GetSvg(cont.Request.Url.PathAndQuery);
if(svg.Length > 0) { if(svg.Length > 0) {
@ -26,14 +28,16 @@ namespace Fraunhofer.Fit.IoT.LoraMap.Model.Svg {
if(this.svgtable.ContainsKey(pathAndQuery)) { if(this.svgtable.ContainsKey(pathAndQuery)) {
return Encoding.UTF8.GetBytes(this.svgtable[pathAndQuery].ToString()); return Encoding.UTF8.GetBytes(this.svgtable[pathAndQuery].ToString());
} else { } else {
if(pathAndQuery.StartsWith("/api/svg/marker.svg") && pathAndQuery.Contains("?")) { lock(this.lockSVG) {
String query = pathAndQuery[(pathAndQuery.IndexOf('?') + 1)..]; if(pathAndQuery.StartsWith("/api/svg/marker.svg") && pathAndQuery.Contains("?")) {
this.svgtable.Add(pathAndQuery, new SVGMarker(query)); String query = pathAndQuery[(pathAndQuery.IndexOf('?') + 1)..];
return Encoding.UTF8.GetBytes(this.svgtable[pathAndQuery].ToString()); this.svgtable.Add(pathAndQuery, new SVGMarker(query));
} else if(pathAndQuery.StartsWith("/api/svg/person.svg") && pathAndQuery.Contains("?")) { return Encoding.UTF8.GetBytes(this.svgtable[pathAndQuery].ToString());
String query = pathAndQuery[(pathAndQuery.IndexOf('?') + 1)..]; } else if(pathAndQuery.StartsWith("/api/svg/person.svg") && pathAndQuery.Contains("?")) {
this.svgtable.Add(pathAndQuery, new SVGPerson(query)); String query = pathAndQuery[(pathAndQuery.IndexOf('?') + 1)..];
return Encoding.UTF8.GetBytes(this.svgtable[pathAndQuery].ToString()); this.svgtable.Add(pathAndQuery, new SVGPerson(query));
return Encoding.UTF8.GetBytes(this.svgtable[pathAndQuery].ToString());
}
} }
} }
return new Byte[0]; return new Byte[0];

View File

@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Net; using System.Net;
using System.Text;
using BlubbFish.Utils; using BlubbFish.Utils;
using BlubbFish.Utils.IoT.Bots; using BlubbFish.Utils.IoT.Bots;
@ -17,7 +18,7 @@ using Fraunhofer.Fit.IoT.LoraMap.Model.Svg;
using LitJson; using LitJson;
namespace Fraunhofer.Fit.IoT.LoraMap { namespace Fraunhofer.Fit.IoT.LoraMap {
class Server : Webserver { class Server : AWebserverDataBackend {
private readonly SortedDictionary<String, Object> jsonapi = new SortedDictionary<String, Object>() { private readonly SortedDictionary<String, Object> jsonapi = new SortedDictionary<String, Object>() {
{ "camera", CameraModel.Instance }, { "camera", CameraModel.Instance },
{ "position", PositionModel.Instance }, { "position", PositionModel.Instance },
@ -26,12 +27,13 @@ namespace Fraunhofer.Fit.IoT.LoraMap {
}; };
private readonly AdminModel admin; private readonly AdminModel admin;
public Server(ADataBackend backend, Dictionary<String, String> settings) : base(backend, settings, null) { public Server(ADataBackend backend, Dictionary<String, String> settings) : base(backend, settings) {
this.logger.SetPath(settings["loggingpath"]); this.logger.SetPath(settings["loggingpath"]);
this.admin = new AdminModel(settings); this.admin = new AdminModel(settings);
this.admin.SettingsUpdate += Settings.Instance.ReloadSettings; this.admin.SettingsUpdate += Settings.Instance.ReloadSettings;
this.admin.GeoUpdate += Settings.Instance.ReloadGeo; this.admin.GeoUpdate += Settings.Instance.ReloadGeo;
this.admin.NamesUpdate += PositionModel.Instance.ReloadNames; this.admin.NamesUpdate += PositionModel.Instance.ReloadNames;
this.StartDataBackend();
this.StartListen(); this.StartListen();
this.WaitForShutdown(); this.WaitForShutdown();
this.Dispose(); this.Dispose();
@ -59,23 +61,23 @@ namespace Fraunhofer.Fit.IoT.LoraMap {
ret.Add(part, this.jsonapi[part]); ret.Add(part, this.jsonapi[part]);
} }
} }
return SendJsonResponse(ret, cont); return cont.SendStringResponse(JsonMapper.ToJson(ret));
} }
} else if(cont.Request.Url.AbsolutePath.StartsWith("/api/time")) { } else if(cont.Request.Url.AbsolutePath.StartsWith("/api/time")) {
return SendJsonResponse(new Dictionary<String, DateTime>() { { "utc", DateTime.UtcNow } }, cont); return cont.SendStringResponse(JsonMapper.ToJson(new Dictionary<String, DateTime>() { { "utc", DateTime.UtcNow } }));
} else if(cont.Request.Url.AbsolutePath.StartsWith("/api/svg/")) { } else if(cont.Request.Url.AbsolutePath.StartsWith("/api/svg/")) {
return SvgModel.Instance.ParseRequest(cont); return SvgModel.Instance.ParseRequest(cont);
} else if(cont.Request.Url.PathAndQuery.StartsWith("/admin/")) { } else if(cont.Request.Url.PathAndQuery.StartsWith("/admin/")) {
return this.admin.ParseReuqest(cont); return this.admin.ParseReuqest(cont);
} else if(cont.Request.Url.PathAndQuery.StartsWith("/maps/")) { } else if(cont.Request.Url.PathAndQuery.StartsWith("/maps/")) {
return SendFileResponse(cont, "resources", false); return cont.SendFileResponse("resources", false);
} }
} catch(Exception e) { } catch(Exception e) {
Helper.WriteError("SendWebserverResponse(): 500 - " + e.Message + "\n\n" + e.StackTrace); Helper.WriteError("SendWebserverResponse(): 500 - " + e.Message + "\n\n" + e.StackTrace);
cont.Response.StatusCode = 500; cont.Response.StatusCode = 500;
return false; return false;
} }
return SendFileResponse(cont); return cont.SendFileResponse();
} }
public override void Dispose() { public override void Dispose() {

View File

@ -69,7 +69,7 @@
} }
#iconeditor { #iconeditor {
position: absolute; position: fixed;
top: 0; top: 0;
left: 0; left: 0;
right: 0; right: 0;

View File

@ -32,21 +32,21 @@
if (Object.prototype.hasOwnProperty.call(query, "person-text")) { if (Object.prototype.hasOwnProperty.call(query, "person-text")) {
markerobj["person"]["text"] = query["person-text"]; markerobj["person"]["text"] = query["person-text"];
} }
if (Object.prototype.hasOwnProperty.call(query, "person-typ")) { if (Object.prototype.hasOwnProperty.call(query, "person-typ[]")) {
if (Array.isArray(query["person-typ"])) { if (Array.isArray(query["person-typ[]"])) {
markerobj["person"]["typ"] = new Array(); markerobj["person"]["typ"] = new Array();
for (var i in query["person-typ"]) { for (var i in query["person-typ[]"]) {
markerobj["person"]["typ"].push(query["person-typ"][i]); markerobj["person"]["typ"].push(query["person-typ[]"][i]);
} }
} else { } else {
markerobj["person"]["typ"] = new Array(); markerobj["person"]["typ"] = new Array();
markerobj["person"]["typ"].push(query["person-typ"]); markerobj["person"]["typ"].push(query["person-typ[]"]);
} }
} }
} }
return markerobj; return markerobj;
}, },
ChangeLinkPreview: function (key, val) { ChangeLinkPreview: function (key, val, multiple) {
var cur = this.SplitUrlIntoParts(document.getElementById("markerprev").data); var cur = this.SplitUrlIntoParts(document.getElementById("markerprev").data);
var query = this.SplitQueryIntoObject(cur.query); var query = this.SplitQueryIntoObject(cur.query);
if (typeof val === "object") { if (typeof val === "object") {
@ -71,13 +71,13 @@
var html = title !== "" ? title + ": " : ""; var html = title !== "" ? title + ": " : "";
var onchange = ""; var onchange = "";
if (!(typeof noonchange !== "undefined" && noonchange === true)) { if (!(typeof noonchange !== "undefined" && noonchange === true)) {
var eventtext = "NamesEditor.ChangeLinkPreview(\"" + key + "\",this.selectedOptions);"; var eventtext = "NamesEditor.ChangeLinkPreview(\"" + key + "\", this.selectedOptions, multiple);";
if (typeof group !== "undefined" && group !== null) { if (typeof group !== "undefined" && group !== null) {
eventtext += " document.getElementById(\"" + group + "\"+this.value).style.display = \"block\";'"; eventtext += " document.getElementById(\"" + group + "\"+this.value).style.display = \"block\";'";
} }
onchange = " onchange='" + eventtext + "'"; onchange = " onchange='" + eventtext + "'";
} }
html += "<select" + onchange + (typeof muliple !== "undefined" && muliple !== null ? " multiple" : "") + ">"; html += "<select" + onchange + (typeof muliple !== "undefined" && muliple === true ? " multiple" : "") + ">";
if (typeof muliple === "undefined" || muliple === null) { if (typeof muliple === "undefined" || muliple === null) {
html += "<option>---</option>"; html += "<option>---</option>";
} }
@ -122,7 +122,7 @@
if (url === null) { if (url === null) {
el.innerHTML += "<td><img src='../icons/general/icon_edit.png' onclick='NamesEditor.IconEditor(this.parentNode)' class='pointer'> wähle Icon</td>"; el.innerHTML += "<td><img src='../icons/general/icon_edit.png' onclick='NamesEditor.IconEditor(this.parentNode)' class='pointer'> wähle Icon</td>";
} else { } else {
el.innerHTML += "<td><img src='../icons/general/icon_edit.png' onclick='NamesEditor.IconEditor(this.parentNode)' class='pointer'> <object data='" + url + "' type='image/svg+xml' style='height:50px; width:50px;'></object></td>"; el.innerHTML += "<td><img src='../icons/general/icon_edit.png' onclick='NamesEditor.IconEditor(this.parentNode)' class='pointer'> <object data='" + url + "' type='image/svg+xml' style='height:57px; width:50px;'></object></td>";
} }
el.innerHTML += "<td>" + this.CreateSelectBox("", "item", { item: gfilter }, this.filterGropus, null, null, true); el.innerHTML += "<td>" + this.CreateSelectBox("", "item", { item: gfilter }, this.filterGropus, null, null, true);
el.innerHTML += "<td><img src='../icons/general/save.png' onclick='NamesEditor.SaveRow(this.parentNode.parentNode)' class='pointer'> <img src='../icons/general/remove.png' onclick='NamesEditor.Abort(this.parentNode.parentNode)' class='pointer'></td>"; el.innerHTML += "<td><img src='../icons/general/save.png' onclick='NamesEditor.SaveRow(this.parentNode.parentNode)' class='pointer'> <img src='../icons/general/remove.png' onclick='NamesEditor.Abort(this.parentNode.parentNode)' class='pointer'></td>";
@ -137,15 +137,15 @@
var ie = document.createElement("div"); var ie = document.createElement("div");
ie.id = "iconeditor"; ie.id = "iconeditor";
ie.innerHTML = "<div class='innerbox'>" + ie.innerHTML = "<div class='innerbox'>" +
"<div class='preview'><object id='markerprev' data='" + url + "' type='image/svg+xml' style='height:200px; width:200px;'></object></div>" + "<div class='preview'><object id='markerprev' data='" + url + "' type='image/svg+xml' style='height:226px; width:200px;'></object></div>" +
"<div class='controls'>" + "<div class='controls'>" +
this.CreateSelectBox("Typ", "icon", query, { "person": "Person" }, null, "iconeditor-type-") + "<br>" + this.CreateSelectBox("Typ", "icon", query, { "person": "Person" }, null, "iconeditor-type-") + "<br>" +
"<div id='iconeditor-type-person' style='display: " + (Object.prototype.hasOwnProperty.call(query, "icon") && query["icon"] === "person" ? "block" : "none") + ";'>" + "<div id='iconeditor-type-person' style='display: " + (Object.prototype.hasOwnProperty.call(query, "icon") && query["icon"] === "person" ? "block" : "none") + ";'>" +
this.CreateSelectBox("Organisation", "person-org", query, { "fw": "Feuerwehr", "thw": "Technisches Hilfswerk", "hilo": "Hilfsorganisationen, Bundeswehr", "fueh": "Einrichtungen der Führung", "pol": "Polizei, Bundespolizei, Zoll", "sonst": "Sonstige Einrichtungen der Gefahrenabwehr" }) + "<br>" + this.CreateSelectBox("Organisation", "person-org", query, { "fw": "Feuerwehr", "thw": "Technisches Hilfswerk", "hilo": "Hilfsorganisationen, Bundeswehr", "fueh": "Einrichtungen der Führung", "pol": "Polizei, Bundespolizei, Zoll", "sonst": "Sonstige Einrichtungen der Gefahrenabwehr" }) + "<br>" +
this.CreateSelectBox("Funktion", "person-funct", query, { "sonder": "Sonder", "fueh": "Führung" }) + "<br>" + this.CreateSelectBox("Funktion", "person-funct", query, { "sonder": "Sonder", "fueh": "Führung" }) + "<br>" +
this.CreateSelectBox("Rang", "person-rang", query, { "trupp": "Trupp", "grupp": "Gruppe", "zug": "Zug" }) + "<br>" + this.CreateSelectBox("Rang", "person-rang", query, { "trupp": "Trupp", "grupp": "Gruppe", "zug": "Zug" }) + "<br>" +
"Text: <input onchange='NamesEditor.ChangeLinkPreview(\"person-text\",this.value);' value='" + (Object.prototype.hasOwnProperty.call(query, "person-text") ? query["person-text"] : "") + "'><br>" + "Text: <input onchange='NamesEditor.ChangeLinkPreview(\"person-text\", this.value, false);' value='" + (Object.prototype.hasOwnProperty.call(query, "person-text") ? query["person-text"] : "") + "'><br>" +
this.CreateSelectBox("Typ", "person-typ", query, { "loesch": "Brandbekämpfung/Löscheinsatz", "sani": "Rettungswesen, Sanitätswesen, Gesundheitswesen", "betreu": "Betreuung" }, true) + "<br>" + this.CreateSelectBox("Typ", "person-typ[]", query, { "loesch": "Brandbekämpfung/Löscheinsatz", "sani": "Rettungswesen, Sanitätswesen, Gesundheitswesen", "betreu": "Betreuung" }, true) + "<br>" +
"</div>" + "</div>" +
"</div>" + "</div>" +
"<div class='save'><button onclick='NamesEditor.SaveIconEditor(\"" + el.id + "\"); '>Schließen</botton></div>" + "<div class='save'><button onclick='NamesEditor.SaveIconEditor(\"" + el.id + "\"); '>Schließen</botton></div>" +
@ -157,10 +157,10 @@
for (var id in queryobj) { for (var id in queryobj) {
if (Array.isArray(queryobj[id])) { if (Array.isArray(queryobj[id])) {
for (var i in queryobj[id]) { for (var i in queryobj[id]) {
query.push(encodeURIComponent(id) + "=" + encodeURIComponent(queryobj[id][i])); query.push(id + "=" + encodeURIComponent(queryobj[id][i]));
} }
} else { } else {
query.push(encodeURIComponent(id) + "=" + encodeURIComponent(queryobj[id])); query.push(id + "=" + encodeURIComponent(queryobj[id]));
} }
} }
return query.join("&"); return query.join("&");
@ -183,11 +183,11 @@
} }
if (Object.prototype.hasOwnProperty.call(markerobj["person"], "typ") && Array.isArray(markerobj["person"]["typ"])) { if (Object.prototype.hasOwnProperty.call(markerobj["person"], "typ") && Array.isArray(markerobj["person"]["typ"])) {
for (i in markerobj["person"]["typ"]) { for (i in markerobj["person"]["typ"]) {
url += "&person-typ=" + markerobj["person"]["typ"][i]; url += "&person-typ[]=" + markerobj["person"]["typ"][i];
} }
} }
} }
return "<object data='" + url + "' type='image/svg+xml' style='height:50px; width:50px;'></object>"; return "<object data='" + url + "' type='image/svg+xml' style='height:57px; width:50px;'></object>";
}, },
ParseJson: function (namesconfig) { ParseJson: function (namesconfig) {
document.getElementById("content").innerHTML = ""; document.getElementById("content").innerHTML = "";
@ -249,7 +249,7 @@
}, },
SaveIconEditor: function (id) { SaveIconEditor: function (id) {
var cell = document.getElementById(id); var cell = document.getElementById(id);
cell.innerHTML = "<img src='../icons/general/icon_edit.png' onclick='NamesEditor.IconEditor(this.parentNode)' class='pointer'> <object data='" + document.getElementById("markerprev").data + "' type='image/svg+xml' style='height:50px; width:50px;'></object>"; cell.innerHTML = "<img src='../icons/general/icon_edit.png' onclick='NamesEditor.IconEditor(this.parentNode)' class='pointer'> <object data='" + document.getElementById("markerprev").data + "' type='image/svg+xml' style='height:57px; width:50px;'></object>";
cell.removeAttribute("id"); cell.removeAttribute("id");
document.getElementById("iconeditor").remove(); document.getElementById("iconeditor").remove();
}, },
@ -269,7 +269,7 @@
if (url === null) { if (url === null) {
el.innerHTML += "<td><img src='../js/leaflet/images/marker-icon.png'></td>"; el.innerHTML += "<td><img src='../js/leaflet/images/marker-icon.png'></td>";
} else { } else {
el.innerHTML += "<td><object data='" + url + "' type='image/svg+xml' style='height:50px; width:50px;'></object></td>"; el.innerHTML += "<td><object data='" + url + "' type='image/svg+xml' style='height:57px; width:50px;'></object></td>";
} }
el.innerHTML += "<td rel='" + gfilter + "'>" + this.filterGropus[gfilter] + "</td>"; el.innerHTML += "<td rel='" + gfilter + "'>" + this.filterGropus[gfilter] + "</td>";
el.innerHTML += "<td><img src='../icons/general/edit.png' onclick='NamesEditor.Edit(this.parentNode.parentNode)' class='pointer'> <img src='../icons/general/remove.png' onclick='NamesEditor.Delete(this.parentNode.parentNode)' class='pointer'></td>"; el.innerHTML += "<td><img src='../icons/general/edit.png' onclick='NamesEditor.Edit(this.parentNode.parentNode)' class='pointer'> <img src='../icons/general/remove.png' onclick='NamesEditor.Delete(this.parentNode.parentNode)' class='pointer'></td>";

View File

@ -58,34 +58,38 @@
"<td><img src='../icons/general/save.png' onclick='Settings.SaveRowSensor(this.parentNode.parentNode)' class='pointer'> <img src='../icons/general/remove.png' onclick='Settings.Abort(this.parentNode.parentNode)' class='pointer'></td>"; "<td><img src='../icons/general/save.png' onclick='Settings.SaveRowSensor(this.parentNode.parentNode)' class='pointer'> <img src='../icons/general/remove.png' onclick='Settings.Abort(this.parentNode.parentNode)' class='pointer'></td>";
}, },
ParseJson: function (jsonsettings) { ParseJson: function (jsonsettings) {
if (typeof jsonsettings.StartPos === "undefined") { if (!Object.prototype.hasOwnProperty.call(jsonsettings, "StartPos")) {
jsonsettings.StartPos = { lat: 0, lon: 0 }; jsonsettings.StartPos = { lat: 0, lon: 0 };
} }
if (typeof jsonsettings.CellIds === "undefined") { if (!Object.prototype.hasOwnProperty.call(jsonsettings, "CellIds")) {
jsonsettings.CellIds = []; jsonsettings.CellIds = [];
} }
if (typeof jsonsettings.GridRadius === "undefined") { if (!Object.prototype.hasOwnProperty.call(jsonsettings, "GridRadius")) {
jsonsettings.GridRadius = 1000; jsonsettings.GridRadius = 1000;
} }
if (typeof jsonsettings.FightDedection === "undefined") { if (!Object.prototype.hasOwnProperty.call(jsonsettings, "FightDedection")) {
jsonsettings.FightDedection = []; jsonsettings.FightDedection = [];
} }
if (typeof jsonsettings.CrwodDensity === "undefined") { if (!Object.prototype.hasOwnProperty.call(jsonsettings, "CrwodDensity")) {
jsonsettings.CrwodDensity = []; jsonsettings.CrwodDensity = [];
} }
if (typeof jsonsettings.Counting === "undefined") { if (!Object.prototype.hasOwnProperty.call(jsonsettings, "Counting")) {
jsonsettings.Counting = []; jsonsettings.Counting = [];
} }
if (typeof jsonsettings.Sensors === "undefined") { if (!Object.prototype.hasOwnProperty.call(jsonsettings, "Sensors")) {
jsonsettings.Sensors = []; jsonsettings.Sensors = [];
} }
if (!Object.prototype.hasOwnProperty.call(jsonsettings, "History")) {
jsonsettings.History = [];
}
var html = "<div id='settingseditor'><div class='title'>Einstellungen</div>"; var html = "<div id='settingseditor'><div class='title'>Einstellungen</div>";
html += "<div class='startloc'>Startpunkt: <input value='" + jsonsettings.StartPos.lat + "' id='startlat'> Lat, <input value='" + jsonsettings.StartPos.lon + "' id='startlon'> Lon</div>"; html += "<div class='startloc'>Startpunkt: <input value='" + jsonsettings.StartPos.lat + "' id='startlat'> Lat, <input value='" + jsonsettings.StartPos.lon + "' id='startlon'> Lon</div><hr>";
html += "<div class='wetterwarnings'>CellId's für DWD-Wetterwarnungen: <input value='" + jsonsettings.CellIds.join(";") + "' id='wetterids'> (Trennen durch \";\", <a href='https://www.dwd.de/DE/leistungen/opendata/help/warnungen/cap_warncellids_csv.html'>cap_warncellids_csv</a>)</div>"; html += "<div class='wetterwarnings'>CellId's für DWD-Wetterwarnungen: <input value='" + jsonsettings.CellIds.join(";") + "' id='wetterids'> (Trennen durch \";\", <a href='https://www.dwd.de/DE/leistungen/opendata/help/warnungen/cap_warncellids_csv.html'>cap_warncellids_csv</a>)</div><hr>";
html += "<div class='gridradius'>Radius für das Grid um den Startpunkt: <input value='" + jsonsettings.GridRadius + "' id='gridrad'>m</div>"; html += "<div class='gridradius'>Radius für das Grid um den Startpunkt: <input value='" + jsonsettings.GridRadius + "' id='gridrad'>m</div><hr>";
html += "<div class='fightdedection'>Fight Dedection Kameras: <br>" + this._renderFightDedection(jsonsettings.FightDedection) + "</div>"; html += "<div class='fightdedection'>Fight Dedection Kameras: <br>" + this._renderFightDedection(jsonsettings.FightDedection) + "</div><hr>";
html += "<div class='crowddensity'>Crowd Density Kameras: <br>" + this._renderCrowdDensity(jsonsettings.CrwodDensity) + "</div>"; html += "<div class='crowddensity'>Crowd Density Kameras: <br>" + this._renderCrowdDensity(jsonsettings.CrwodDensity) + "</div><hr>";
html += "<div class='sensorsettings'>Sensors: <br>" + this._renderSensorSettings(jsonsettings.Sensors) + "</div>"; html += "<div class='sensorsettings'>Sensors: <br>" + this._renderSensorSettings(jsonsettings.Sensors) + "</div><hr>";
html += "<div class='historysettings'>History: "+this._renderHistorySettings(jsonsettings.History)+"</div><hr>";
html += "<div class='savesettings'><img src='../icons/general/save.png' onclick='Settings.Save()' class='pointer'></div>"; html += "<div class='savesettings'><img src='../icons/general/save.png' onclick='Settings.Save()' class='pointer'></div>";
document.getElementById("content").innerHTML = html + "</div>"; document.getElementById("content").innerHTML = html + "</div>";
}, },
@ -159,6 +163,29 @@
} }
ret.Sensors = sensorjson; ret.Sensors = sensorjson;
ret.History = {};
if (document.getElementById("hist_yes").checked && !document.getElementById("hist_no").checked) {
ret.History.enabled = true;
var time = parseInt(document.getElementById("history_time").value);
if (isNaN(time)) {
time = 0;
}
var amount = parseInt(document.getElementById("history_amount").value);
if (isNaN(amount)) {
amount = 0;
}
if (time !== 0 && amount !== 0) {
alert("History: Entweder Zeit oder Menge muss 0 sein.");
return;
}
ret.History.time = time;
ret.History.amount = amount;
} else {
ret.History.enabled = false;
ret.History.time = 0;
ret.History.amount = 0;
}
var savesettings = new XMLHttpRequest(); var savesettings = new XMLHttpRequest();
savesettings.onreadystatechange = function () { savesettings.onreadystatechange = function () {
if (savesettings.readyState === 4) { if (savesettings.readyState === 4) {
@ -306,6 +333,20 @@
ret += "</table>"; ret += "</table>";
return ret; return ret;
}, },
_renderHistorySettings: function (json) {
if (!Object.prototype.hasOwnProperty.call(json, "enabled")) {
json.enabled = false;
}
if (!Object.prototype.hasOwnProperty.call(json, "time")) {
json.time = 0;
}
if (!Object.prototype.hasOwnProperty.call(json, "amount")) {
json.amount = 0;
}
var html = "Aktiv: <fieldset style='border:none;'> <label for='hist_no'>Nein </label> <input onclick=\"document.getElementById('history_settings_details').style.display='none'\" type='radio' id='hist_no' name='hist_en' value='no' " + (json.enabled ? "" : "checked='checked'") + "> <label for='hist_yes'>Ja </label> <input onclick=\"document.getElementById('history_settings_details').style.display='block'\" type='radio' id='hist_yes' name='hist_en' value='yes' " + (json.enabled ? "checked='checked'" : "") + "> </fieldset>";
html += "<span id='history_settings_details' style='display: " + (json.enabled ? "block" : "none") + "'>Zeit: <input type='number' id='history_time' value='" + json.time + "'>s, Menge: <input type='number' id='history_amount' value='" + json.amount +"'></span>"
return html;
},
_renderSensorSettings: function (json) { _renderSensorSettings: function (json) {
var ret = ""; var ret = "";
ret += "<table id='sensortable' class='settingstable'>"; ret += "<table id='sensortable' class='settingstable'>";
@ -326,5 +367,5 @@
ret += "<tfoot><tr><td></td><td></td><td></td><td></td><td><img src='../icons/general/add.png' onclick='Settings.AddSensor()' class='pointer'></td></tr></tfoot>"; ret += "<tfoot><tr><td></td><td></td><td></td><td></td><td><img src='../icons/general/add.png' onclick='Settings.AddSensor()' class='pointer'></td></tr></tfoot>";
ret += "</table>"; ret += "</table>";
return ret; return ret;
}, }
}; };

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -25,6 +25,10 @@
user-select: none; user-select: none;
-webkit-user-drag: none; -webkit-user-drag: none;
} }
/* Prevents IE11 from highlighting tiles in blue */
.leaflet-tile::selection {
background: transparent;
}
/* Safari renders non-retina tile on retina better with this, but Chrome is worse */ /* Safari renders non-retina tile on retina better with this, but Chrome is worse */
.leaflet-safari .leaflet-tile { .leaflet-safari .leaflet-tile {
image-rendering: -webkit-optimize-contrast; image-rendering: -webkit-optimize-contrast;
@ -237,7 +241,8 @@
.leaflet-marker-icon.leaflet-interactive, .leaflet-marker-icon.leaflet-interactive,
.leaflet-image-layer.leaflet-interactive, .leaflet-image-layer.leaflet-interactive,
.leaflet-pane > svg path.leaflet-interactive { .leaflet-pane > svg path.leaflet-interactive,
svg.leaflet-image-layer.leaflet-interactive path {
pointer-events: visiblePainted; /* IE 9-10 doesn't have auto */ pointer-events: visiblePainted; /* IE 9-10 doesn't have auto */
pointer-events: auto; pointer-events: auto;
} }
@ -527,7 +532,7 @@
} }
.leaflet-oldie .leaflet-popup-content-wrapper { .leaflet-oldie .leaflet-popup-content-wrapper {
zoom: 1; -ms-zoom: 1;
} }
.leaflet-oldie .leaflet-popup-tip { .leaflet-oldie .leaflet-popup-tip {
width: 24px; width: 24px;

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -7,6 +7,7 @@
_Markers: {}, _Markers: {},
_Sensors: {}, _Sensors: {},
_SensorSettings: {}, _SensorSettings: {},
_History: {},
/// public functions /// public functions
ChangeFilter: function (select) { ChangeFilter: function (select) {
this.VisibleMarkers = {}; this.VisibleMarkers = {};
@ -53,6 +54,21 @@
return this; return this;
}, },
/// private functions /// private functions
_ClearHistory: function (key) {
if (Object.prototype.hasOwnProperty.call(this._History, key)) {
if (typeof this._History[key].Polyline === 'object') {
this._History[key].Polyline.remove();
delete this._History[key];
}
}
},
_CreateLatLonFromHist: function (key) {
var latlngs = [];
for (var i = 0; i < this._History[key].Items.length; i++) {
latlngs.push([this._History[key].Items[i][0], this._History[key].Items[i][1]]);
}
return latlngs;
},
_ParseAJAXLoc: function (serverLocation) { _ParseAJAXLoc: function (serverLocation) {
this.LocationData = serverLocation; this.LocationData = serverLocation;
for (var key in this.LocationData) { for (var key in this.LocationData) {
@ -113,11 +129,16 @@
} }
} }
} }
if (positionItem.History.length > 0) {
this._UpdateHistory(positionItem.History, key);
} else {
this._ClearHistory(key);
}
} }
} }
MenuObject.UpdateStatus(); MenuObject.UpdateStatus();
MenuObject._Update_pannels_info(); MenuObject.UpdatePannelsInfo();
}, },
_ParseAJAXPanic: function (serverPanic) { _ParseAJAXPanic: function (serverPanic) {
this.PanicData = serverPanic; this.PanicData = serverPanic;
for (var id in this.PanicData) { for (var id in this.PanicData) {
@ -167,5 +188,38 @@
} }
} }
} }
},
_UpdateHistory: function (History, key) {
if (!Object.prototype.hasOwnProperty.call(this._History, key)) {
this._History[key] = { Items: History };
this._History[key].Polyline = L.polyline(this._CreateLatLonFromHist(key), { color: 'blue', weight: 2, bubblingMouseEvents: false, interactive: false }).addTo(MapObject.Map);
}
if (History[0][2] !== this._History[key].Items[0][2] || History[History.length - 1][2] !== this._History[key].Items[this._History[key].Items.length - 1][2]) {
if (History[History.length - 1][2] !== this._History[key].Items[this._History[key].Items.length - 1][2]) {
// Last element are different, so add element to the line
for (var i = History.length - 1; i >= 0; i--) {
if (History[i][2] === this._History[key].Items[this._History[key].Items.length - 1][2]) {
break;
}
}
for (var j = i + 1; j < History.length; j++) {
this._History[key].Items.push(History[j]);
}
}
if (History[0][2] !== this._History[key].Items[0][2]) {
//First elemt are different, so delete element from the line
var deletefirst = 0;
for (var k = 0; k < this._History[key].Items.length; k++) {
if (History[0][2] === this._History[key].Items[k][2]) {
break;
}
deletefirst++;
}
for (var l = 0; l < deletefirst; l++) {
this._History[key].Items.splice(0, 1);
}
}
this._History[key].Polyline.setLatLngs(this._CreateLatLonFromHist(key));
}
} }
}.Start(); }.Start();

View File

@ -69,6 +69,37 @@
adminlogin.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); adminlogin.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
adminlogin.send("user=" + encodeURI(document.getElementById("pannels_admin_name").value) + "&pass=" + encodeURI(document.getElementById("pannels_admin_pass").value)); adminlogin.send("user=" + encodeURI(document.getElementById("pannels_admin_name").value) + "&pass=" + encodeURI(document.getElementById("pannels_admin_pass").value));
}, },
UpdatePannelsInfo: function () {
document.getElementById("pannels_info").innerHTML = "";
if (Object.prototype.hasOwnProperty.call(MarkerObject.LocationData, this.statusToDevice)) {
var positionItem = MarkerObject.LocationData[this.statusToDevice];
var html = "<div class=\"name\">Name: <span class=\"bold\">" + positionItem["Name"] + "</span></div>";
html += "<div class=\"batt\"><span class=\"bold\">Batterie:</span> " + positionItem["Battery"] + "V <img src=\"icons/akku/" + positionItem["Batterysimple"] + "-4.png\"></div>";
if (positionItem["Fix"]) {
html += "<div class=\"gps\" style=\"color: green;\">GPS-Empfang</div>";
} else {
html += "<div class=\"gps\" style=\"color: red;\">kein GPS-Empfang</div>";
}
html += "<div class=\"coord\">" + positionItem["UTM"]["Base"] + " <span style=\"color: #b1a831;\">" + positionItem["UTM"]["FieldWidth"] + "</span><span style=\"color: #218c00;\">" + positionItem["UTM"]["Width"] + "</span> <span style=\"color: #b1a831;\">" + positionItem["UTM"]["FieldHeight"] + "</span><span style=\"color: #218c00;\">" + positionItem["UTM"]["Height"] + "</span></div>";
html += "<div class=\"height\"><span class=\"bold\">Höhe:</span> " + positionItem["Height"].toFixed(1) + " m</div>";
html += "<div class=\"hdop\"><span class=\"bold\">HDOP:</span> " + positionItem["Hdop"].toFixed(1) + "</div>";
html += "<div class=\"lanlot\"><span class=\"bold\">Dezimal:</span> " + positionItem["Latitude"].toFixed(5) + ", " + positionItem["Longitude"].toFixed(5) + "</div>";
html += "<div class=\"lastgps\"><span class=\"bold\">Letzter Wert:</span> Vor: " + FunctionsObject.TimeCalculation(positionItem["Lastgpspostime"], "difftext") + "</div>";
html += "<div class=\"update\"><span class=\"bold\">Update:</span> " + FunctionsObject.TimeCalculation(positionItem["Recievedtime"], "str") + "<br><span class=\"bold\">Vor:</span> " + FunctionsObject.TimeCalculation(positionItem["Recievedtime"], "difftext") + "</div>";
html += "<div><span class=\"bold\">RSSI:</span> " + positionItem["Rssi"] + ", <span class=\"bold\">SNR:</span> " + positionItem["Snr"] + "</div>";
if (Object.prototype.hasOwnProperty.call(MarkerObject.PanicData, this.statusToDevice)) {
var panicData = MarkerObject.PanicData[this.statusToDevice];
if (panicData["ButtonPressed"].length > 0) {
html += "<div class='alerts'><span class=\"bold\">Alerts:</span>";
for (var i = 0; i < panicData["ButtonPressed"].length; i++) {
html += "<span class='panicitem'>" + FunctionsObject.TimeCalculation(panicData["ButtonPressed"][i], "str") + " (vor " + FunctionsObject.TimeCalculation(panicData["ButtonPressed"][i], "difftext") + ")</span>";
}
html += "</div>";
}
}
document.getElementById("pannels_info").innerHTML = html;
}
},
UpdateStatus: function () { UpdateStatus: function () {
for (var id in MarkerObject.LocationData) { for (var id in MarkerObject.LocationData) {
if (Object.prototype.hasOwnProperty.call(MarkerObject.LocationData, id)) { if (Object.prototype.hasOwnProperty.call(MarkerObject.LocationData, id)) {
@ -88,7 +119,7 @@
} }
this._UpdateOverviewElement(positionItem, id); this._UpdateOverviewElement(positionItem, id);
} }
} }
}, },
/// private functions /// private functions
_UpdateOverviewElement: function (positionItem, id) { _UpdateOverviewElement: function (positionItem, id) {
@ -159,37 +190,6 @@
document.getElementById("pannels_admin").innerHTML = "<a href='/admin/' target='_blank'>Adminpannel</a>"; document.getElementById("pannels_admin").innerHTML = "<a href='/admin/' target='_blank'>Adminpannel</a>";
} }
}, },
_Update_pannels_info: function () {
document.getElementById("pannels_info").innerHTML = "";
if (Object.prototype.hasOwnProperty.call(MarkerObject.LocationData, this.statusToDevice)) {
var positionItem = MarkerObject.LocationData[this.statusToDevice];
var html = "<div class=\"name\">Name: <span class=\"bold\">" + positionItem["Name"] + "</span></div>";
html += "<div class=\"batt\"><span class=\"bold\">Batterie:</span> " + positionItem["Battery"] + "V <img src=\"icons/akku/" + positionItem["Batterysimple"] + "-4.png\"></div>";
if (positionItem["Fix"]) {
html += "<div class=\"gps\" style=\"color: green;\">GPS-Empfang</div>";
} else {
html += "<div class=\"gps\" style=\"color: red;\">kein GPS-Empfang</div>";
}
html += "<div class=\"coord\">" + positionItem["UTM"]["Base"] + " <span style=\"color: #b1a831;\">" + positionItem["UTM"]["FieldWidth"] + "</span><span style=\"color: #218c00;\">" + positionItem["UTM"]["Width"] + "</span> <span style=\"color: #b1a831;\">" + positionItem["UTM"]["FieldHeight"] + "</span><span style=\"color: #218c00;\">" + positionItem["UTM"]["Height"] + "</span></div>";
html += "<div class=\"height\"><span class=\"bold\">Höhe:</span> " + positionItem["Height"].toFixed(1) + " m</div>";
html += "<div class=\"hdop\"><span class=\"bold\">HDOP:</span> " + positionItem["Hdop"].toFixed(1) + "</div>";
html += "<div class=\"lanlot\"><span class=\"bold\">Dezimal:</span> " + positionItem["Latitude"].toFixed(5) + ", " + positionItem["Longitude"].toFixed(5) + "</div>";
html += "<div class=\"lastgps\"><span class=\"bold\">Letzter Wert:</span> Vor: " + FunctionsObject.TimeCalculation(positionItem["Lastgpspostime"], "difftext") + "</div>";
html += "<div class=\"update\"><span class=\"bold\">Update:</span> " + FunctionsObject.TimeCalculation(positionItem["Recievedtime"], "str") + "<br><span class=\"bold\">Vor:</span> " + FunctionsObject.TimeCalculation(positionItem["Recievedtime"], "difftext") + "</div>";
html += "<div><span class=\"bold\">RSSI:</span> " + positionItem["Rssi"] + ", <span class=\"bold\">SNR:</span> " + positionItem["Snr"] + "</div>";
if (Object.prototype.hasOwnProperty.call(MarkerObject.PanicData, this.statusToDevice)) {
var panicData = MarkerObject.PanicData[this.statusToDevice];
if (panicData["ButtonPressed"].length > 0) {
html += "<div class='alerts'><span class=\"bold\">Alerts:</span>";
for (var i = 0; i < panicData["ButtonPressed"].length; i++) {
html += "<span class='panicitem'>" + FunctionsObject.TimeCalculation(panicData["ButtonPressed"][i], "str") + " (vor " + FunctionsObject.TimeCalculation(panicData["ButtonPressed"][i], "difftext") + ")</span>";
}
html += "</div>";
}
}
document.getElementById("pannels_info").innerHTML = html;
}
},
_Update_pannels_admin: function () { _Update_pannels_admin: function () {
var testadmin = new XMLHttpRequest(); var testadmin = new XMLHttpRequest();
testadmin.onreadystatechange = function () { testadmin.onreadystatechange = function () {
@ -207,7 +207,7 @@
var html = ""; var html = "";
for (var i = 0; i < json.length; i++) { for (var i = 0; i < json.length; i++) {
var walert = json[i]; var walert = json[i];
html += "<div class='alertitem " + walert.Level +" "+ walert.Type + "'>" + html += "<div class='alertitem " + walert.Level + " " + walert.Type + "'>" +
"<span class='head'>" + walert.Headline + "</span>" + "<span class='head'>" + walert.Headline + "</span>" +
"<span class='ort'>" + walert.Location + "</span>" + "<span class='ort'>" + walert.Location + "</span>" +
"<span class='text'>" + walert.Body + (walert.Instructions !== "" ? "<br><br>" + walert.Instructions : "") + "</span>" + "<span class='text'>" + walert.Body + (walert.Instructions !== "" ? "<br><br>" + walert.Instructions : "") + "</span>" +