From 4ad9814a8461699b7fde670726ccf8146c4cf6d9 Mon Sep 17 00:00:00 2001 From: BlubbFish Date: Sun, 31 Mar 2019 12:57:59 +0200 Subject: [PATCH] [1.1.5] Add support for alert button Rename Panicclient to AlarmItem and Botclient to PositionItem, also use all dates in UTC functions.js is now responsible for timecalculations, so that the utc times are changed to the local browser time nav.js is now map.js so its more clear what it did Server.cs has now a function that gives the utc server time for timecorrection --- Lora-Map/Lora-Map.csproj | 9 ++- .../Model/{Panicclient.cs => AlarmItem.cs} | 12 ++-- .../Model/{Botclient.cs => PositionItem.cs} | 15 ++-- Lora-Map/Properties/AssemblyInfo.cs | 7 +- Lora-Map/Server.cs | 31 ++++---- Lora-Map/config-example/requests.conf.example | 2 +- Lora-Map/resources/index.html | 3 +- Lora-Map/resources/js/functions.js | 43 ++++++++++++ Lora-Map/resources/js/{nav.js => map.js} | 0 Lora-Map/resources/js/marker.js | 20 +++--- Lora-Map/resources/js/menu.js | 70 +++++++------------ 11 files changed, 126 insertions(+), 86 deletions(-) rename Lora-Map/Model/{Panicclient.cs => AlarmItem.cs} (85%) rename Lora-Map/Model/{Botclient.cs => PositionItem.cs} (82%) create mode 100644 Lora-Map/resources/js/functions.js rename Lora-Map/resources/js/{nav.js => map.js} (100%) diff --git a/Lora-Map/Lora-Map.csproj b/Lora-Map/Lora-Map.csproj index a34852e..1858338 100644 --- a/Lora-Map/Lora-Map.csproj +++ b/Lora-Map/Lora-Map.csproj @@ -46,9 +46,9 @@ - + - + @@ -115,6 +115,9 @@ PreserveNewest + + PreserveNewest + @@ -134,7 +137,7 @@ PreserveNewest - + PreserveNewest diff --git a/Lora-Map/Model/Panicclient.cs b/Lora-Map/Model/AlarmItem.cs similarity index 85% rename from Lora-Map/Model/Panicclient.cs rename to Lora-Map/Model/AlarmItem.cs index 344e64c..7f81e30 100644 --- a/Lora-Map/Model/Panicclient.cs +++ b/Lora-Map/Model/AlarmItem.cs @@ -3,26 +3,26 @@ using System.Globalization; using LitJson; namespace Fraunhofer.Fit.IoT.LoraMap.Model { - class Panicclient { + class AlarmItem { public Double Rssi { get; private set; } public Double Snr { get; private set; } - public DateTime Upatedtime { get; private set; } + public DateTime Lorarecievedtime { get; private set; } + public DateTime Recievedtime { get; private set; } public Double Latitude { get; private set; } public Double Longitude { get; private set; } public Double Hdop { get; private set; } public Boolean Fix { get; private set; } public Double Height { get; private set; } - public DateTime Triggerdtime { get; private set; } - public Panicclient(JsonData json) => this.Update(json); + public AlarmItem(JsonData json) => this.Update(json); public void Update(JsonData json) { - this.Triggerdtime = DateTime.Now; this.Rssi = (Double)json["Rssi"]; this.Snr = (Double)json["Snr"]; if(DateTime.TryParse((String)json["Receivedtime"], DateTimeFormatInfo.InvariantInfo, DateTimeStyles.AssumeUniversal, out DateTime updatetime)) { - this.Upatedtime = updatetime; + this.Lorarecievedtime = updatetime.ToUniversalTime(); } + this.Recievedtime = DateTime.UtcNow; this.Latitude = (Double)json["Gps"]["Latitude"]; this.Longitude = (Double)json["Gps"]["Longitude"]; this.Fix = (Boolean)json["Gps"]["Fix"]; diff --git a/Lora-Map/Model/Botclient.cs b/Lora-Map/Model/PositionItem.cs similarity index 82% rename from Lora-Map/Model/Botclient.cs rename to Lora-Map/Model/PositionItem.cs index 5ea3609..6044e56 100644 --- a/Lora-Map/Model/Botclient.cs +++ b/Lora-Map/Model/PositionItem.cs @@ -3,13 +3,15 @@ using System.Globalization; using LitJson; namespace Fraunhofer.Fit.IoT.LoraMap.Model { - class Botclient { + class PositionItem { public Double Rssi { get; private set; } public Double Snr { get; private set; } - public DateTime Upatedtime { get; private set; } + public DateTime Lorarecievedtime { get; private set; } + public DateTime Recievedtime { get; private set; } public Double Latitude { get; private set; } public Double Longitude { get; private set; } public Double Hdop { get; private set; } + public DateTime Lastgpspostime { get; private set; } public Double Battery { get; private set; } public Int32 Batterysimple { get; private set; } public Boolean Fix { get; private set; } @@ -17,7 +19,7 @@ namespace Fraunhofer.Fit.IoT.LoraMap.Model { public String Name { get; private set; } public String Icon { get; private set; } - public Botclient(JsonData json, JsonData marker) { + public PositionItem(JsonData json, JsonData marker) { this.Update(json); String id = GetId(json); if(marker.ContainsKey(id)) { @@ -48,6 +50,7 @@ namespace Fraunhofer.Fit.IoT.LoraMap.Model { && json["Gps"].ContainsKey("Longitude") && json["Gps"]["Longitude"].IsDouble && json["Gps"].ContainsKey("LastLatitude") && json["Gps"]["LastLatitude"].IsDouble && json["Gps"].ContainsKey("LastLongitude") && json["Gps"]["LastLongitude"].IsDouble + && json["Gps"].ContainsKey("LastLongitude") && json["Gps"]["LastGPSPos"].IsString && json["Gps"].ContainsKey("Hdop") && json["Gps"]["Hdop"].IsDouble && json["Gps"].ContainsKey("Fix") && json["Gps"]["Fix"].IsBoolean && json["Gps"].ContainsKey("Height") && json["Gps"]["Height"].IsDouble @@ -58,8 +61,9 @@ namespace Fraunhofer.Fit.IoT.LoraMap.Model { this.Rssi = (Double)json["Rssi"]; this.Snr = (Double)json["Snr"]; if(DateTime.TryParse((String)json["Receivedtime"], DateTimeFormatInfo.InvariantInfo, DateTimeStyles.AssumeUniversal, out DateTime updatetime)) { - this.Upatedtime = updatetime; + this.Lorarecievedtime = updatetime.ToUniversalTime(); } + this.Recievedtime = DateTime.UtcNow; this.Battery = Math.Round((Double)json["BatteryLevel"], 2); if(this.Battery < 3) { this.Batterysimple = 0; @@ -79,6 +83,9 @@ namespace Fraunhofer.Fit.IoT.LoraMap.Model { this.Latitude = (Double)json["Gps"]["LastLatitude"]; this.Longitude = (Double)json["Gps"]["LastLongitude"]; } + if(DateTime.TryParse((String)json["Gps"]["LastGPSPos"], DateTimeFormatInfo.InvariantInfo, DateTimeStyles.AssumeUniversal, out DateTime lastgpstime)) { + this.Lastgpspostime = lastgpstime.ToUniversalTime(); + } this.Hdop = (Double)json["Gps"]["Hdop"]; this.Height = (Double)json["Gps"]["Height"]; } diff --git a/Lora-Map/Properties/AssemblyInfo.cs b/Lora-Map/Properties/AssemblyInfo.cs index 2dc5b64..b05a0f2 100644 --- a/Lora-Map/Properties/AssemblyInfo.cs +++ b/Lora-Map/Properties/AssemblyInfo.cs @@ -10,7 +10,7 @@ using System.Runtime.InteropServices; [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("Fraunhofer FIT")] [assembly: AssemblyProduct("Lora-Map")] -[assembly: AssemblyCopyright("Copyright © 2018 - 10.03.2019")] +[assembly: AssemblyCopyright("Copyright © 2018 - 30.03.2019")] [assembly: AssemblyTrademark("Fraunhofer FIT, BlubbFish")] [assembly: AssemblyCulture("")] [assembly: NeutralResourcesLanguage("de-DE")] @@ -33,12 +33,13 @@ using System.Runtime.InteropServices; // 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.1.4")] -[assembly: AssemblyFileVersion("1.1.4")] +[assembly: AssemblyVersion("1.1.5")] +[assembly: AssemblyFileVersion("1.1.5")] /* * 1.1.1 Add Debian package config * 1.1.2 #2 Show versions number in Site * 1.1.3 #1 Click on icon and show details * 1.1.4 #3 Create icons for devices +* 1.1.5 Add support for alert button */ diff --git a/Lora-Map/Server.cs b/Lora-Map/Server.cs index bfda7b3..b958344 100644 --- a/Lora-Map/Server.cs +++ b/Lora-Map/Server.cs @@ -13,8 +13,8 @@ using LitJson; namespace Fraunhofer.Fit.IoT.LoraMap { class Server : Webserver { - private readonly SortedDictionary locations = new SortedDictionary(); - private readonly SortedDictionary panics = new SortedDictionary(); + private readonly SortedDictionary positions = new SortedDictionary(); + private readonly SortedDictionary alarms = new SortedDictionary(); private readonly JsonData marker; private readonly Dictionary markertable = new Dictionary(); @@ -23,20 +23,20 @@ namespace Fraunhofer.Fit.IoT.LoraMap { protected override void Backend_MessageIncomming(Object sender, BackendEvent e) { try { JsonData d = JsonMapper.ToObject(e.Message); - if (Botclient.CheckJson(d) && ((String)e.From).Contains("lora/data")) { - String name = Botclient.GetId(d); - if (this.locations.ContainsKey(name)) { - this.locations[name].Update(d); + if (PositionItem.CheckJson(d) && ((String)e.From).Contains("lora/data")) { + String name = PositionItem.GetId(d); + if (this.positions.ContainsKey(name)) { + this.positions[name].Update(d); } else { - this.locations.Add(name, new Botclient(d, this.marker)); + this.positions.Add(name, new PositionItem(d, this.marker)); } Console.WriteLine("Koordinate erhalten!"); - } else if(Panicclient.CheckJson(d) && ((String)e.From).Contains("lora/panic")) { - String name = Panicclient.GetId(d); - if(this.panics.ContainsKey(name)) { - this.panics[name].Update(d); + } else if(AlarmItem.CheckJson(d) && ((String)e.From).Contains("lora/panic")) { + String name = AlarmItem.GetId(d); + if(this.alarms.ContainsKey(name)) { + this.alarms[name].Update(d); } else { - this.panics.Add(name, new Panicclient(d)); + this.alarms.Add(name, new AlarmItem(d)); } Console.WriteLine("PANIC erhalten!"); } @@ -48,10 +48,10 @@ namespace Fraunhofer.Fit.IoT.LoraMap { protected override void SendResponse(HttpListenerContext cont) { try { if (cont.Request.Url.PathAndQuery.StartsWith("/loc")) { - this.SendJsonResponse(this.locations, cont); + this.SendJsonResponse(this.positions, cont); return; } else if(cont.Request.Url.PathAndQuery.StartsWith("/panic")) { - this.SendJsonResponse(this.panics, cont); + this.SendJsonResponse(this.alarms, cont); return; } else if (cont.Request.Url.PathAndQuery.StartsWith("/icons/marker/Marker.svg") && cont.Request.Url.PathAndQuery.Contains("?")) { String hash = cont.Request.Url.PathAndQuery.Substring(cont.Request.Url.PathAndQuery.IndexOf('?') + 1); @@ -64,6 +64,9 @@ namespace Fraunhofer.Fit.IoT.LoraMap { cont.Response.OutputStream.Write(buf, 0, buf.Length); Console.WriteLine("200 - " + cont.Request.Url.PathAndQuery); return; + } else if(cont.Request.Url.PathAndQuery.StartsWith("/currenttime")) { + this.SendJsonResponse(new Dictionary() { { "utc", DateTime.UtcNow } }, cont); + return; } } catch (Exception e) { Helper.WriteError("500 - " + e.Message); diff --git a/Lora-Map/config-example/requests.conf.example b/Lora-Map/config-example/requests.conf.example index 1d31b5d..5d9d8f8 100644 --- a/Lora-Map/config-example/requests.conf.example +++ b/Lora-Map/config-example/requests.conf.example @@ -1,2 +1,2 @@ -[js/nav.js] +[js/map.js] start_location=50.7, 7.2 \ No newline at end of file diff --git a/Lora-Map/resources/index.html b/Lora-Map/resources/index.html index 034f227..ed89f22 100644 --- a/Lora-Map/resources/index.html +++ b/Lora-Map/resources/index.html @@ -35,7 +35,8 @@ - + + diff --git a/Lora-Map/resources/js/functions.js b/Lora-Map/resources/js/functions.js new file mode 100644 index 0000000..31961fa --- /dev/null +++ b/Lora-Map/resources/js/functions.js @@ -0,0 +1,43 @@ +setInterval(timecorrectionrunner, 60000); +timecorrectionrunner(); + +function timecorrectionrunner() { + var timecorrection = new XMLHttpRequest(); + timecorrection.onreadystatechange = parseAjaxTimecorrection; + timecorrection.open("GET", "http://{%REQUEST_URL_HOST%}:8080/currenttime", true); + timecorrection.send(); +} + +var timeOffset = 0; + +function parseAjaxTimecorrection() { + if (this.readyState === 4 && this.status === 200) { + utcobject = JSON.parse(this.responseText); + if (utcobject.hasOwnProperty("utc")) { + timeOffset = Date.now() - Date.parse(utcobject["utc"]); + } + } +} + +function timeCalculation(timestr, type) { + if (type === "diffraw" || type === "difftext") { + var diff = Math.round((Date.now() - Date.parse(timestr) - timeOffset) / 1000); + if (type === "diffraw") { + return diff; + } + if (diff < 60) { + return diff + " s"; + } + if (diff < 60 * 60) { + return Math.floor(diff / 60) + " m"; + } + if (diff < 60 * 60 * 24) { + return Math.floor(diff / (60 * 60)) + " h"; + } + return Math.floor(diff / (60 * 60 * 24)) + " d"; + } else if (type === "str") { + var date = new Date(Date.parse(timestr) + timeOffset); + var str = date.toLocaleString(); + return str; + } +} \ No newline at end of file diff --git a/Lora-Map/resources/js/nav.js b/Lora-Map/resources/js/map.js similarity index 100% rename from Lora-Map/resources/js/nav.js rename to Lora-Map/resources/js/map.js diff --git a/Lora-Map/resources/js/marker.js b/Lora-Map/resources/js/marker.js index 6d54fb7..28a9fd8 100644 --- a/Lora-Map/resources/js/marker.js +++ b/Lora-Map/resources/js/marker.js @@ -19,24 +19,24 @@ function parseAjaxLoc() { serverLocation = JSON.parse(this.responseText); for (var key in serverLocation) { if (serverLocation.hasOwnProperty(key)) { - var markeritem = serverLocation[key]; - if (markeritem['Latitude'] !== 0 || markeritem['Longitude'] !== 0) { + var positionItem = serverLocation[key]; + if (positionItem['Latitude'] !== 0 || positionItem['Longitude'] !== 0) { if (!markers.hasOwnProperty(key)) { var marker = null; - if (markeritem['Icon'] === null) { - marker = L.marker([markeritem['Latitude'], markeritem['Longitude']], { 'title': markeritem['Name'] }); + if (positionItem['Icon'] === null) { + marker = L.marker([positionItem['Latitude'], positionItem['Longitude']], { 'title': positionItem['Name'] }); } else { var myIcon = L.divIcon({ className: 'pos-marker', iconSize: [56, 80], iconAnchor: [0, 80], - html: '' + html: '' }); - marker = L.marker([markeritem['Latitude'], markeritem['Longitude']], { 'title': markeritem['Name'], 'icon': myIcon }); + marker = L.marker([positionItem['Latitude'], positionItem['Longitude']], { 'title': positionItem['Name'], 'icon': myIcon }); } markers[key] = marker.addTo(mymap).on("click", showMarkerInfo, key); } else { - markers[key].setLatLng([markeritem['Latitude'], markeritem['Longitude']]); + markers[key].setLatLng([positionItem['Latitude'], positionItem['Longitude']]); } } } @@ -51,13 +51,13 @@ function parseAjaxPanic() { var panics = JSON.parse(this.responseText); for (var id in panics) { if (panics.hasOwnProperty(id)) { - var panicitem = panics[id]; + var alertItem = panics[id]; if (markers.hasOwnProperty(id)) { var marker = markers[id]; - if (timeDiffRaw(panicitem["Triggerdtime"]) <= 10 && marker._icon.className.indexOf(" marker-alert") === -1) { + if (timeCalculation(alertItem["Recievedtime"], "diffraw") <= 10 && marker._icon.className.indexOf(" marker-alert") === -1) { marker._icon.className += " marker-alert"; showMarkerInfoPerId(id); - } else if (timeDiffRaw(panicitem["Triggerdtime"]) > 10 && marker._icon.className.indexOf(" marker-alert") !== -1) { + } else if (timeCalculation(alertItem["Recievedtime"], "diffraw") > 10 && marker._icon.className.indexOf(" marker-alert") !== -1) { marker._icon.className = marker._icon.className.replace(" marker-alert", ""); } } diff --git a/Lora-Map/resources/js/menu.js b/Lora-Map/resources/js/menu.js index 442d619..e94b341 100644 --- a/Lora-Map/resources/js/menu.js +++ b/Lora-Map/resources/js/menu.js @@ -39,19 +39,20 @@ function showMarkerInfoMenu() { function updateDeviceStatus() { document.getElementById("pannels_info").innerHTML = ""; if (serverLocation.hasOwnProperty(statusToDevice)) { - var markeritem = serverLocation[statusToDevice]; - var html = "
Name: " + markeritem["Name"] + "
"; - html += "
Batterie: " + markeritem["Battery"] + "V
"; - if (markeritem["Fix"]) { + var positionItem = serverLocation[statusToDevice]; + var html = "
Name: " + positionItem["Name"] + "
"; + html += "
Batterie: " + positionItem["Battery"] + "V
"; + if (positionItem["Fix"]) { html += "
GPS-Empfang
"; } else { html += "
kein GPS-Empfang
"; } - html += "
" + markeritem["Latitude"].toFixed(7) + ", " + markeritem["Longitude"].toFixed(7) + "
"; - html += "
Höhe: " + markeritem["Height"].toFixed(1) + " m
"; - html += "
HDOP: " + markeritem["Hdop"].toFixed(1) + "
"; - html += "
Update: " + markeritem["Upatedtime"] + "
Vor: " + timeDiffToText(markeritem["Upatedtime"]) + "
"; - html += "
RSSI: " + markeritem["Rssi"] + ", SNR: " + markeritem["Snr"] + "
"; + html += "
" + positionItem["Latitude"].toFixed(7) + ", " + positionItem["Longitude"].toFixed(7) + "
"; + html += "
Letzter Wert: Vor: " + timeCalculation(positionItem["Lastgpspostime"], "difftext") + "
"; + html += "
Höhe: " + positionItem["Height"].toFixed(1) + " m
"; + html += "
HDOP: " + positionItem["Hdop"].toFixed(1) + "
"; + html += "
Update: " + timeCalculation(positionItem["Recievedtime"], "str") + "
Vor: " + timeCalculation(positionItem["Recievedtime"], "difftext") + "
"; + html += "
RSSI: " + positionItem["Rssi"] + ", SNR: " + positionItem["Snr"] + "
"; document.getElementById("pannels_info").innerHTML = html; } } @@ -61,71 +62,52 @@ var overviewStatus = new Array(); function updateStatus() { for (var id in serverLocation) { if (serverLocation.hasOwnProperty(id)) { - var markeritem = serverLocation[id]; + var positionItem = serverLocation[id]; if (typeof overviewStatus[id] === "undefined") { - overviewStatus[id] = createOverviewElement(markeritem, id); + overviewStatus[id] = createOverviewElement(positionItem, id); document.getElementById("pannels_pos").appendChild(overviewStatus[id]); } - updateOverviewElement(markeritem, id); + updateOverviewElement(positionItem, id); } } } -function updateOverviewElement(markeritem, id) { - if (markeritem["Batterysimple"] === 0) { +function updateOverviewElement(positionItem, id) { + if (positionItem["Batterysimple"] === 0) { document.getElementById("overview-color-id-" + id).style.backgroundColor = "red"; - } else if (markeritem["Batterysimple"] === 1 || markeritem["Batterysimple"] === 2) { + } else if (positionItem["Batterysimple"] === 1 || positionItem["Batterysimple"] === 2) { document.getElementById("overview-color-id-" + id).style.backgroundColor = "yellow"; - } else if (markeritem["Batterysimple"] === 3 || markeritem["Batterysimple"] === 4) { + } else if (positionItem["Batterysimple"] === 3 || positionItem["Batterysimple"] === 4) { document.getElementById("overview-color-id-" + id).style.backgroundColor = "green"; } - document.getElementById("overview-name-id-" + id).innerText = markeritem["Name"]; - document.getElementById("overview-akkuimg-id-" + id).src = "icons/akku/" + markeritem["Batterysimple"] + "-4.png"; - if (markeritem["Fix"]) { + document.getElementById("overview-name-id-" + id).innerText = positionItem["Name"]; + document.getElementById("overview-akkuimg-id-" + id).src = "icons/akku/" + positionItem["Batterysimple"] + "-4.png"; + if (positionItem["Fix"]) { document.getElementById("overview-gps-id-" + id).innerText = "GPS-Empfang"; document.getElementById("overview-gps-id-" + id).style.color = "green"; } else { document.getElementById("overview-gps-id-" + id).innerText = "kein GPS-Empfang"; document.getElementById("overview-gps-id-" + id).style.color = "red"; } - document.getElementById("overview-update-id-" + id).innerText = "Letzter Datenempfang: vor " + timeDiffToText(markeritem["Upatedtime"]); + document.getElementById("overview-update-id-" + id).innerText = "Letzter Datenempfang: vor " + timeCalculation(positionItem["Recievedtime"], "difftext"); } -function createOverviewElement(markeritem, id) { +function createOverviewElement(positionItem, id) { var divItem = document.createElement("div"); divItem.className = "item"; divItem.onclick = showMarkerInfoMenu; divItem.setAttribute("rel", id); divItem.innerHTML = ""; - if (markeritem['Icon'] !== null) { - divItem.innerHTML += ""; + if (positionItem['Icon'] !== null) { + divItem.innerHTML += ""; } else { divItem.innerHTML += ""; } divItem.innerHTML += "
" + "" + - "" + + "" + "
"; divItem.innerHTML += "
kein GPS-Empfang
"; - divItem.innerHTML += "
Letzter Datenempfang: vor " + timeDiffToText(markeritem["Upatedtime"]) + "
"; + divItem.innerHTML += "
Letzter Datenempfang: vor " + timeCalculation(positionItem["Recievedtime"], "difftext") + "
"; return divItem; -} - -function timeDiffToText(time) { - var diff = Date.now() - Date.parse(time); - diff = Math.round(diff / 1000); - if (diff < 60) { - return diff + " s"; - } - if (diff < 60 * 60) { - return Math.floor(diff / 60) + " m"; - } - if (diff < 60 * 60 * 24) { - return Math.floor(diff / (60 * 60)) + " h"; - } - return Math.floor(diff / (60 * 60 * 24)) + " d"; -} - -function timeDiffRaw(time) { - return (Date.now() - Date.parse(time)) / 1000; } \ No newline at end of file