diff --git a/AIS/ReadMe.md b/AIS/ReadMe.md index b5bdde1d..b3a6fe7f 100644 --- a/AIS/ReadMe.md +++ b/AIS/ReadMe.md @@ -26,6 +26,10 @@ In der Übersicht nur Daten aus der Datenbank, vorerst keine Daten aus Wetris. 2) der Zeitpunkt des letzten Reports innerhalb der Zone 3) keine Referenz sondern Kopie der Position/Timestamp? - Alarm / Zuordnung sind unabhängig von der Gruppe. Die Gruppe / der Zulauf ergibt sich erst in der Webanwendung. (Ist das sinnvoll?) + - Für die Abfrage in der Gruppe der Zonen Außenweser/Binnenweser: Jeweils "neuester" Alarm: + - wenn kein weiterer Alarm: o : unspezifisch + - wenn vorh. Alarm in Zone mit niedrigere Seq : <- eingehend + - wenn vorh. Alarm in Zone mit höherer Seq : -> abgehend ## Stand Dez 22 diff --git a/AIS/bsmd.AIS2Service/AISZoneMonitor.cs b/AIS/bsmd.AIS2Service/AISZoneMonitor.cs index f94fece5..4b2846d7 100644 --- a/AIS/bsmd.AIS2Service/AISZoneMonitor.cs +++ b/AIS/bsmd.AIS2Service/AISZoneMonitor.cs @@ -45,18 +45,24 @@ namespace bsmd.AIS2Service { // load zones from storage List allZones = _storage.LoadMonitorZones(); - Dictionary> testZones = new Dictionary>(); + Dictionary> testDict = new Dictionary>(); + // letzte Alarme + // Dictionary currentAlarms = _storage.LoadAlarms(); + foreach(MonitorZone zone in allZones) { // load up Zone list for all assignment mmsi's (to check) foreach(MonitorAssignment ma in zone.Assignments) { - if(!testZones.ContainsKey(ma.MMSI)) testZones[ma.MMSI] = new List(); - testZones[ma.MMSI].Add(zone); + if(!testDict.ContainsKey(ma.MMSI)) testDict[ma.MMSI] = new List(); + ma.Alarms.AddRange(_storage.LoadAlarms(ma)); + AlarmAssignmentZone aazone = new AlarmAssignmentZone(); + aazone.Zone = zone; + aazone.Assignment = ma; + testDict[ma.MMSI].Add(aazone); } } - // loop while(!_stopFlag) { @@ -64,13 +70,40 @@ namespace bsmd.AIS2Service foreach(int mmsi in _sitRepDict.Keys) { - if(testZones.ContainsKey(mmsi)) + if(testDict.ContainsKey(mmsi)) { AIS_Target target = _sitRepDict[mmsi]; - foreach(MonitorZone zone in testZones[mmsi]) { - if(zone.IsPointInPolygon4(target.Position)) + foreach(AlarmAssignmentZone aazone in testDict[mmsi]) { + if(aazone.Zone.IsPointInPolygon4(target.Position)) { - _log.InfoFormat("{0} is in zone {1}", target.ToString(), zone.Name); + _log.InfoFormat("{0} is in zone {1}", target.ToString(), aazone.Zone.Name); + Alarm alarm; + if (aazone.Assignment.Alarms.Count > 0) + { + alarm = aazone.Assignment.Alarms[0]; + if(alarm.Timestamp_Last.HasValue && + ((DateTime.Now - alarm.Timestamp_Last.Value).TotalMinutes > Properties.Settings.Default.MinAlarmIntervalMins)) + { + // this "old" alarm will be triggered again (overwritten) + alarm.Acknowledged = null; + alarm.Timestamp_Last = null; + alarm.Timestamp_First = DateTime.Now; + } + else + { + // update the last time the target registered in the zone + alarm.Timestamp_Last = DateTime.Now; + } + } + else + { + // create new alarm + alarm = new Alarm(-1, aazone.Assignment); + alarm.Timestamp_First = DateTime.Now; + alarm.ZoneMonitorType = aazone.Assignment.MonitorType; + aazone.Assignment.Alarms.Add(alarm); + } + _storage.Save(alarm); } } } @@ -113,6 +146,15 @@ namespace bsmd.AIS2Service #endregion + #region class AssignmentZoneAlarm composition + + private class AlarmAssignmentZone + { + public MonitorZone Zone { get; set; } + public MonitorAssignment Assignment { get; set; } + } + + #endregion } } diff --git a/AIS/bsmd.AIS2Service/AIS_SQLiteStorage.cs b/AIS/bsmd.AIS2Service/AIS_SQLiteStorage.cs index 8ce456ec..2c9fad79 100644 --- a/AIS/bsmd.AIS2Service/AIS_SQLiteStorage.cs +++ b/AIS/bsmd.AIS2Service/AIS_SQLiteStorage.cs @@ -1,13 +1,12 @@ -using System; +using log4net; + +using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Data; -using System.Threading.Tasks; - -using System.Threading; - using System.Data.SQLite; -using log4net; -using System.Collections.Concurrent; +using System.Threading; +using System.Threading.Tasks; namespace bsmd.AIS2Service { @@ -180,7 +179,8 @@ namespace bsmd.AIS2Service int id = reader.GetInt32(0); Alarm alarm = new Alarm(id, assignment); alarm.Timestamp_First = reader.GetDateTime(1); - alarm.Timestamp_Last = reader.GetDateTime(2); + if(!reader.IsDBNull(2)) + alarm.Timestamp_Last = reader.GetDateTime(2); alarm.ZoneMonitorType = (MonitorAssignment.ZoneMonitorType)reader.GetInt32(3); if(!reader.IsDBNull(4)) alarm.Acknowledged = reader.GetDateTime(4); @@ -207,8 +207,10 @@ namespace bsmd.AIS2Service if (alarm.Id <= 0) { // insert - string saveAlarmString = $"INSERT INTO alarm (zone_assignment_id, timestamp_first, timestamp_last, type, acknowledged) VALUES ({alarm.Assignment.Id}, '{alarm.Timestamp_First}', '{alarm.Timestamp_Last}', {alarm.ZoneMonitorType}, {alarm.Acknowledged})"; + string saveAlarmString = $"INSERT INTO alarm (zone_assignment_id, timestamp_first, timestamp_last, type) VALUES ({alarm.Assignment.Id}, @TS_FIRST, @TS_LAST, {(int) alarm.ZoneMonitorType})"; SQLiteCommand cmd = new SQLiteCommand(saveAlarmString, _connection); + cmd.Parameters.AddWithValue("@TS_FIRST", alarm.Timestamp_First); + cmd.Parameters.AddWithValue("@TS_LAST", alarm.Timestamp_Last); int insertedRows = cmd.ExecuteNonQuery(); cmd.Dispose(); alarm.Id = GetLastInsertId(); @@ -217,8 +219,14 @@ namespace bsmd.AIS2Service else { // update - string updateAlarmString = $"UPDATE alarm SET acknowledged = {alarm.Acknowledged}, timestamp_last = '{alarm.Timestamp_Last}' WHERE id = {alarm.Id}"; + string updateAlarmString = $"UPDATE alarm SET acknowledged = @TS_ACK, timestamp_first = @TS_FIRST, timestamp_last = @TS_LAST WHERE id = {alarm.Id}"; SQLiteCommand cmd = new SQLiteCommand(updateAlarmString, _connection); + cmd.Parameters.AddWithValue("@TS_FIRST", alarm.Timestamp_First); + cmd.Parameters.AddWithValue("@TS_LAST", alarm.Timestamp_Last); + if(alarm.Acknowledged.HasValue) + cmd.Parameters.AddWithValue("@TS_ACK", alarm.Acknowledged); + else + cmd.Parameters.AddWithValue("@TS_ACK", DBNull.Value); int updatedRows = cmd.ExecuteNonQuery(); cmd.Dispose(); return (updatedRows == 1); diff --git a/AIS/bsmd.AIS2Service/App.config b/AIS/bsmd.AIS2Service/App.config index 353c1b8d..01211684 100644 --- a/AIS/bsmd.AIS2Service/App.config +++ b/AIS/bsmd.AIS2Service/App.config @@ -67,6 +67,9 @@ 120 + + 60 + diff --git a/AIS/bsmd.AIS2Service/MonitorZone.cs b/AIS/bsmd.AIS2Service/MonitorZone.cs index c244d332..778458fe 100644 --- a/AIS/bsmd.AIS2Service/MonitorZone.cs +++ b/AIS/bsmd.AIS2Service/MonitorZone.cs @@ -277,6 +277,8 @@ namespace bsmd.AIS2Service public long MonitorZoneId { get; set; } + public List Alarms { get; } = new List(); + public override string ToString() { return String.Format("{0} {1}", MMSI, MonitorType); @@ -298,7 +300,7 @@ namespace bsmd.AIS2Service public DateTime Timestamp_First { get; set; } - public DateTime Timestamp_Last { get; set; } + public DateTime? Timestamp_Last { get; set; } public DateTime? Acknowledged { get; set; } diff --git a/AIS/bsmd.AIS2Service/Properties/Settings.Designer.cs b/AIS/bsmd.AIS2Service/Properties/Settings.Designer.cs index 5a6caab3..8ea7f200 100644 --- a/AIS/bsmd.AIS2Service/Properties/Settings.Designer.cs +++ b/AIS/bsmd.AIS2Service/Properties/Settings.Designer.cs @@ -121,5 +121,14 @@ namespace bsmd.AIS2Service.Properties { return ((int)(this["MonitorTargetSaturationSecs"])); } } + + [global::System.Configuration.ApplicationScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("60")] + public int MinAlarmIntervalMins { + get { + return ((int)(this["MinAlarmIntervalMins"])); + } + } } } diff --git a/AIS/bsmd.AIS2Service/Properties/Settings.settings b/AIS/bsmd.AIS2Service/Properties/Settings.settings index c1f0c7de..33f3e9aa 100644 --- a/AIS/bsmd.AIS2Service/Properties/Settings.settings +++ b/AIS/bsmd.AIS2Service/Properties/Settings.settings @@ -35,5 +35,8 @@ 120 + + 60 + \ No newline at end of file