Exemplo n.º 1
0
 def test_broadcast_alarm_event(self) -> None:
     alarmEvent = AlarmEvent(1302)
     self.webSocket.broadcastAlarmEvent(alarmEvent)
     (event, args) = self.__getReceived()
     assert(event == "alarm_event")
     assert(args is not None)
     assert(args['eventID'] == 1302)
 def test_handle_event_alarm(self) -> None:
     alarmEvent = AlarmEvent(1302)
     self.action.handleEvent(alarmEvent)
     (event, args) = self.__getReceived()
     assert (event == "alarm_event")
     assert (args is not None)
     assert (args['eventID'] == 1302)
Exemplo n.º 3
0
    def parseMessage(
            self, sourceEvent: SourceEvent,
            lastEvent: Optional[SourceEvent]) -> Optional[SourceEvent]:
        self.source = sourceEvent

        street = self.__search_payload(r'^[\t ]+Straße[\t ]+:[\t ]+([\w ]+)$')
        keyword = self.__search_payload(
            r'^[\t ]+Stichwort[\t ]+:[\t ]+([/\w\t ]*)$')
        heading = self.__search_payload(
            r'^[\t ]+Schlagwort[\t ]+:[\t ]+([\w -]+)$')
        city = self.__search_payload(r'^[\t ]+Ort[\t ]+:[\t ]+([\w -]+)$')
        district = self.__search_payload(
            r'^[\t ]+Ortsteil[\t ]+:[\t ]*([\w\t ]*)$')
        building = self.__search_payload(
            r'^[\t ]+Objekt[\t ]+:[\t ]*([\w\t ]*)$')
        lat = self.__search_payload(
            r'^https://www\.google\.de/maps/place/(\d+\.\d+),\d+\.\d+$')
        long = self.__search_payload(
            r'^https://www\.google\.de/maps/place/\d+\.\d+,(\d+\.\d+)$')
        comment_payload = self.__search_payload(
            r'^[\t ]+-+[\t ]+BEMERKUNG[\t ]+-+\n+[\t \n]([\w\s:#,.]+)-+[\t ]+Alarmmail'
        )
        comment_filtered = filter(lambda x: not re.match(r'^\n*$', x),
                                  comment_payload)
        comment = ''.join(comment_filtered)

        alarm_event = AlarmEvent.fromSourceEvent(sourceEvent)
        alarm_event.event = heading
        alarm_event.eventDetails = keyword
        event_location = ''
        if district:
            event_location += district
        if district and city:
            event_location += " ,"
        if city:
            event_location += city
        alarm_event.location = event_location
        event_location_details = ''
        if street:
            event_location_details += street
        if street and building:
            event_location_details += "\n"
        if building:
            event_location += "Objekt: {}".format(building)
        alarm_event.locationDetails = event_location_details
        alarm_event.locationLatitude = lat
        alarm_event.locationLongitude = long
        alarm_event.comment = comment

        alarm_event.flags = AlarmEvent.FLAGS_VALID
        return alarm_event
Exemplo n.º 4
0
    def __generateBinaryEvent(self) -> AlarmEvent:
        binaryEvent = AlarmEvent()

        moment = datetime.datetime.now()
        ts = moment.strftime(AlarmEvent.TIMESTAMP_FORMAT)
        binaryEvent.timestamp = ts
        binaryEvent.alarmTimestamp = ts
        binaryEvent.source = AlarmEvent.SOURCE_DUMMY
        binaryEvent.flags = AlarmEvent.FLAGS_BINARY
        binaryEvent.raw = "Einsatzalarmierung"

        return binaryEvent
Exemplo n.º 5
0
    def addEvent(self, alarmEvent: AlarmEvent, verbose: bool = True) -> int:
        if self.__conn is None: self.__assertInitializedFailed()  # return -1

        query = "INSERT INTO alarmevents (timestamp, event, eventdetails, location, locationdetails, comment, " \
                "alarmtimestamp, locationlatitude, locationlongitude, source, sender, raw, flags) " \
                "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
        try:
            cursor = self.__conn.execute(
                query, Database.__tupleWithoutIDFromAlarmEvent(alarmEvent))

            if cursor.rowcount != 1:
                self.error("Could not add alarm event")
                return -1

            alarmEvent.eventID = cursor.lastrowid

            if verbose:
                self.print(f"Added alarm event #{alarmEvent.eventID}")
            return alarmEvent.eventID
        except sqlite3.Error as e:
            self.error("Could not add alarm event", e)
            return -1
Exemplo n.º 6
0
    def retrieveEvent(self) -> Optional[SourceEvent]:
        alarmEvent = None

        if self.__alarmTime is not None:
            # ensure signal is still active (prevent noise from triggering an alarm)
            if GPIO.input(self.__pin) != self.__active_high:
                self.__alarmTime = None
            else:
                self.clrPrint("Detected binary alarm")

                ts = self.__alarmTime.strftime(AlarmEvent.TIMESTAMP_FORMAT)

                alarmEvent = AlarmEvent()
                alarmEvent.timestamp = ts
                alarmEvent.alarmTimestamp = ts
                alarmEvent.source = AlarmEvent.SOURCE_BINARY
                alarmEvent.flags = AlarmEvent.FLAGS_BINARY
                alarmEvent.raw = self.__alarmMessage

                self.__alarmTime = None

        return alarmEvent
Exemplo n.º 7
0
    def __createTextEvent(self) -> AlarmEvent:
        moment = datetime.datetime.now()
        timestamp = moment.strftime(AlarmEvent.TIMESTAMP_FORMAT)

        newEvent = AlarmEvent()
        newEvent.source = SourceEvent.SOURCE_SMS
        newEvent.flags = AlarmEvent.FLAGS_VALID
        newEvent.sender = "112"
        newEvent.raw = "raw"
        newEvent.timestamp = timestamp
        newEvent.event = "event"
        newEvent.eventDetails = "eventDetails"
        newEvent.location = "location"
        newEvent.locationDetails = "locationDetails"
        newEvent.comment = "comment"
        newEvent.alarmTimestamp = timestamp
        newEvent.locationLatitude = 1.12
        newEvent.locationLongitude = 13.2
        return newEvent
Exemplo n.º 8
0
    def __createBinaryEvent(self) -> AlarmEvent:
        moment = datetime.datetime.now()
        timestamp = moment.strftime(AlarmEvent.TIMESTAMP_FORMAT)

        newEvent = AlarmEvent()
        newEvent.source = SourceEvent.SOURCE_BINARY
        newEvent.flags = AlarmEvent.FLAGS_BINARY
        newEvent.sender = ""
        newEvent.raw = ""
        newEvent.timestamp = timestamp
        newEvent.event = ""
        newEvent.eventDetails = ""
        newEvent.location = ""
        newEvent.locationDetails = ""
        newEvent.comment = ""
        newEvent.alarmTimestamp = timestamp
        newEvent.locationLatitude = 0.0
        newEvent.locationLongitude = 0.0
        return newEvent
Exemplo n.º 9
0
 def broadcastAlarmEvent(self, alarmEvent: AlarmEvent) -> None:
     self.__broadcast('alarm_event', alarmEvent.toJSON())
Exemplo n.º 10
0
 def __updateEvent(self, event: AlarmEvent) -> AlarmEvent:
     event.comment = Test_ActionUpdateDatabase.UPDATED_COMMENT
     return event
 def __createAlarmEvent(self, flags: str) -> AlarmEvent:
     alarmEvent = AlarmEvent()
     alarmEvent.event = Test_ActionSendMessagePowerAlarm.EVENT
     alarmEvent.eventDetails = Test_ActionSendMessagePowerAlarm.EVENT_DETAILS
     alarmEvent.location = Test_ActionSendMessagePowerAlarm.LOCATION
     alarmEvent.locationDetails = Test_ActionSendMessagePowerAlarm.LOCATION_DETAILS
     alarmEvent.comment = Test_ActionSendMessagePowerAlarm.COMMENT
     alarmEvent.raw = Test_ActionSendMessagePowerAlarm.RAW_CONTENT
     alarmEvent.locationLatitude = Test_ActionSendMessagePowerAlarm.LOCATION_LATITUDE
     alarmEvent.locationLongitude = Test_ActionSendMessagePowerAlarm.LOCATION_LONGITUDE
     alarmEvent.flags = flags
     return alarmEvent
Exemplo n.º 12
0
    def parseAlarmMessage(self, sourceEvent: SourceEvent) -> AlarmEvent:
        alarmEvent = None
        if isinstance(sourceEvent, AlarmEvent):
            # source event was parsed before and is actually/already a merged alarm event
            # (its former version is thus already stored in the database with a unique ID)
            # -> use the alarm event directly to preserve data like the unique ID
            alarmEvent = sourceEvent
        else:
            # create an alarm event from the new/unparsed source event
            alarmEvent = AlarmEvent.fromSourceEvent(sourceEvent)

        alarmEvent.flags = AlarmEvent.FLAGS_INVALID

        rawLines = self.getRawLines(alarmEvent)

        class ParserState(Enum):
            INITIAL = -1
            TIMESTAMP = 0
            LOCATION_AND_LOCATION_DETAILS = 1
            EVENT_DETAILS = 2
            EVENT = 3
            COMMENT = 4

        activeKeyID = ParserState.INITIAL

        aTimestamp = ""
        aLocationComplete = ""
        aEvent = ""
        aEventDetails = ""
        aComment = ""

        for line in rawLines:
            # detect new sections through keywords and/or relative line locations ...
            if line.startswith(self.__alarmHeader):
                activeKeyID = ParserState.INITIAL
                continue  # skip header (first line)
            if line.startswith('Alarmzeit:'):
                aTimestamp = line.replace('Alarmzeit:', '', 1)
                activeKeyID = ParserState.TIMESTAMP
            elif line.startswith('EO:'):
                aLocationComplete = line.replace('EO:', '', 1)
                # activeKeyID = ParserState.LOCATION_AND_LOCATION_DETAILS # only one line ?
                activeKeyID = ParserState.EVENT_DETAILS  # next line is event details (has no prefix)
            # elif line.startswith('SW:'):
            #     aEventDetails = line.replace('SW:', '', 1)
            #     activeKeyID = ParserState.EVENT_DETAILS
            elif line.startswith('STW:'):
                aEvent = line.replace('STW:', '', 1)
                activeKeyID = ParserState.EVENT
            elif line.startswith('Bem:'):
                aComment = line.replace('Bem:', '', 1)
                activeKeyID = ParserState.COMMENT

            # append remaining lines of the active sections to the corresponding variables ...
            elif activeKeyID == ParserState.TIMESTAMP:
                continue  # ignore additional timestamp lines
            elif activeKeyID == ParserState.LOCATION_AND_LOCATION_DETAILS:
                aLocationComplete = '\n'.join([aLocationComplete, line])
            elif activeKeyID == ParserState.EVENT_DETAILS:
                aEventDetails = '\n'.join([aEventDetails, line])
            elif activeKeyID == ParserState.EVENT:
                aEvent = '\n'.join([aEvent, line])
            elif activeKeyID == ParserState.COMMENT:
                aComment = '\n'.join([aComment, line])
            else:
                self.error("Parsing error: unknown line, ignoring...")

        alarmEvent.event = aEvent.strip()
        alarmEvent.eventDetails = aEventDetails.strip()
        alarmEvent.comment = aComment.strip()

        aLocationStripped = aLocationComplete.strip(string.whitespace + ",")
        aLocationParts = aLocationStripped.split(",", 2)
        alarmEvent.location = aLocationParts[0].strip() if (
            len(aLocationParts) > 0) else ""
        alarmEvent.locationDetails = aLocationParts[1].strip() if (
            len(aLocationParts) > 1) else ""

        try:
            aTimestampStripped = aTimestamp.strip()
            if len(aTimestampStripped
                   ) == MessageParserSMS.TIMESTAMP_LENGTH_LONG:
                ats = datetime.datetime.strptime(
                    aTimestampStripped, MessageParserSMS.TIMESTAMP_FORMAT_LONG)
                alarmEvent.alarmTimestamp = ats.strftime(
                    AlarmEvent.TIMESTAMP_FORMAT)
            elif len(aTimestampStripped
                     ) == MessageParserSMS.TIMESTAMP_LENGTH_SHORT:
                ats = datetime.datetime.strptime(
                    aTimestampStripped,
                    MessageParserSMS.TIMESTAMP_FORMAT_SHORT)
                alarmEvent.alarmTimestamp = ats.strftime(
                    AlarmEvent.TIMESTAMP_FORMAT)
        except Exception:
            self.error("Parsing error: invalid timestamp format")
            alarmEvent.alarmTimestamp = alarmEvent.timestamp

        # We require three things for a valid alarm event:
        #  - we at least parsed until the beginning of the last field (comment) - and thus end of the event field
        #  - we retrieved at least a (complete) event – we do not care about the event details though
        #  - we retrieved at least a (complete) location - we do not care about the location details though
        if activeKeyID == ParserState.COMMENT and alarmEvent.event != "" and alarmEvent.location != "":
            self.print("Received alarm message (valid)")
            alarmEvent.flags = AlarmEvent.FLAGS_VALID
        else:
            self.error(
                "Received alarm message (invalid - missing information)")
            alarmEvent.flags = AlarmEvent.FLAGS_INVALID

        return alarmEvent
Exemplo n.º 13
0
 def fallbackAlarmMessage(self, sourceEvent: SourceEvent) -> AlarmEvent:
     self.error("Received alarm message (invalid - no alarm header)")
     alarmEvent = AlarmEvent.fromSourceEvent(sourceEvent)
     alarmEvent.alarmTimestamp = alarmEvent.timestamp
     alarmEvent.flags = AlarmEvent.FLAGS_INVALID
     return alarmEvent
Exemplo n.º 14
0
    def __generateAlarmEvent(self) -> AlarmEvent:
        alarmEvent = AlarmEvent()

        moment = datetime.datetime.now()
        ts = moment.strftime(AlarmEvent.TIMESTAMP_FORMAT)

        alarmEvent.timestamp = ts
        alarmEvent.alarmTimestamp = ts
        alarmEvent.source = AlarmEvent.SOURCE_DUMMY
        alarmEvent.flags = AlarmEvent.FLAGS_VALID
        alarmEvent.raw = "Dummy Alarm Message"
        alarmEvent.sender = "112"

        if self.__nextAlarm == 0:
            alarmEvent.event = "T 1"
            alarmEvent.eventDetails = "Test 1"
            alarmEvent.location = "Musterdorf"
            alarmEvent.locationDetails = "Hauptstraße 112"
            alarmEvent.comment = "Nix los hier"
        elif self.__nextAlarm == 1:
            alarmEvent.event = "T 2"
            alarmEvent.eventDetails = "Test 2"
            alarmEvent.location = "Musterheim"
            alarmEvent.locationDetails = "Hauptstraße 112"
            alarmEvent.comment = "Nix los hier"
        elif self.__nextAlarm == 2:
            alarmEvent.event = "T 3"
            alarmEvent.eventDetails = "Test 3"
            alarmEvent.location = "Musterstadt"
            alarmEvent.locationDetails = "Hauptstraße 112"
            alarmEvent.comment = "Nix los hier"

        # dummy location for maps
        #alarmEvent.location          = "<SPECIFY CITY>"
        #alarmEvent.locationDetails   = "<SPECIFY STREET>"

        # dummy comment to test CSV import/export
        #alarmEvent.comment           = "Test \"Test\" \\n Test;Test\nTest Test"

        # dummy alarm for screenshots
        #alarmEvent.event             = "B 1"
        #alarmEvent.eventDetails      = "Brand - Freifläche klein"
        #alarmEvent.location          = "Musterdorf"
        #alarmEvent.locationDetails   = "Hauptstraße 112"
        #alarmEvent.comment           = "Acker/Freifläche nahe Schloss\nBrennende Fläche < 100 qm"
        #alarmEvent.locationLatitude  = 0.0 # specify random location here for screenshots of the map
        #alarmEvent.locationLongitude = 0.0 # specify random location here for screenshots of the map

        self.__nextAlarm = (self.__nextAlarm +
                            1) % SourceDriverDummy.MAX_ALARMS

        return alarmEvent
Exemplo n.º 15
0
    def importEvents(self, filename: str, ignoreFirstLine: bool = True) -> int:
        alarmList = []
        try:
            with open(filename, 'r') as f:
                reader = csv.reader(f, delimiter=";", quotechar="\"", doublequote=True)
                alarmList = list(reader)
        except Exception:
            self.fatalContinue(f"Could not read CSV file ({filename})")
            return 1

        line = 0
        importedCount = 0
        invalidCount = 0
        for alarm in alarmList:
            line += 1

            if ignoreFirstLine and line == 1:
                continue

            #TODO: support multiple header lengths (to support file updates and older CSV files):
            #      retrieve column index by column name and provide a default value in case
            #      the CSV file does not contain all fields (e.g. because of an old file format)
            #      Important: adjust documentation accordingly

            if len(alarm) != CSVCommon.TOTAL_COLS:
                invalidCount += 1
                continue

            alarmEvent = AlarmEvent()

            try:
                alarmEvent.timestamp         = self.csv2dbTimestamp(alarm[CSVCommon.COL_TIMESTAMP])
                alarmEvent.event             = self.csv2dbText(alarm[CSVCommon.COL_EVENT])
                alarmEvent.eventDetails      = self.csv2dbText(alarm[CSVCommon.COL_EVENTDETAILS])
                alarmEvent.location          = self.csv2dbText(alarm[CSVCommon.COL_LOCATION])
                alarmEvent.locationDetails   = self.csv2dbText(alarm[CSVCommon.COL_LOCATIONDETAILS])
                alarmEvent.comment           = self.csv2dbText(alarm[CSVCommon.COL_COMMENT])
                alarmEvent.alarmTimestamp    = self.csv2dbTimestamp(alarm[CSVCommon.COL_ALARMTIMESTAMP])
                alarmEvent.locationLatitude  = float(alarm[CSVCommon.COL_LOCATIONLATITUDE])
                alarmEvent.locationLongitude = float(alarm[CSVCommon.COL_LOCATIONLONGITUDE])
                alarmEvent.source            = self.csv2dbText(alarm[CSVCommon.COL_SOURCE])
                alarmEvent.sender            = self.csv2dbText(alarm[CSVCommon.COL_SENDER])
                alarmEvent.raw               = self.csv2dbText(alarm[CSVCommon.COL_RAW])
                alarmEvent.flags             = self.csv2dbText(alarm[CSVCommon.COL_FLAGS])
            except Exception: # invalid timestamp, float, ...
                invalidCount += 1
                continue

            if self._database.addEvent(alarmEvent, verbose=False) < 0:
                invalidCount +=1
                continue

            importedCount += 1

        self.print(f"Imported {importedCount} event(s) into the DB")

        if invalidCount > 0:
            self.error(f"Ignored {invalidCount} invalid line(s)")
            return 1

        return 0
Exemplo n.º 16
0
 def __updateTextEvent(self, event: AlarmEvent) -> AlarmEvent:
     event.comment = "updated comment"
     return event
Exemplo n.º 17
0
    def test_csv(self) -> None:
        appInfo = AppInfo()
        dbFilename = os.path.join(appInfo.path, ".temp/situationboard.sqlite")
        inFilename = os.path.join(appInfo.path, "docs/dummy.csv")
        outFilename = os.path.join(appInfo.path, ".temp/dummy.csv")
        csvFilename = os.path.join(appInfo.path, ".temp/corner.csv")

        ###### TEST 1 (round trip) ######

        # create a new (empty) database
        d = Database(dbFilename, reset = True)
        assert(d.getEventCount(textOnly = False) == 0)

        # import data from CSV
        i = CSVImporter(d)
        result = i.importEvents(inFilename)
        assert(result == 0)
        assert(d.getEventCount(textOnly = False) > 0)

        # export data to CSV
        e = CSVExporter(d)
        result = e.exportEvents(outFilename)
        assert(result == 0)

        # compare CSV files
        assert(filecmp.cmp(inFilename, outFilename, shallow=False))

        # close database
        d.close()

        ###### TEST 2 (corner cases) ######

        # create a new (empty) database
        d = Database(dbFilename, reset = True)
        assert(d.getEventCount(textOnly = False) == 0)

        # add new event with pathologic content
        ts = datetime.datetime.now().strftime(AlarmEvent.TIMESTAMP_FORMAT)
        content = "Test\n;\\Test\nTest\"äöüß\"\"äöüß'äöüß''äöüß\näöüß"

        aeAdded = AlarmEvent()
        aeAdded.timestamp = ts
        aeAdded.event = content
        aeAdded.eventDetails = content
        aeAdded.location = content
        aeAdded.locationDetails = content
        aeAdded.comment = content
        aeAdded.alarmTimestamp = ts
        aeAdded.locationLatitude = 1.12
        aeAdded.locationLongitude = -13.2
        eventID = d.addEvent(aeAdded)

        # export data to CSV
        e = CSVExporter(d)
        result = e.exportEvents(csvFilename)
        assert(result == 0)

        # close database
        d.close()

        # create a new (empty) database
        d = Database(dbFilename, reset = True)

        # import data from CSV
        i = CSVImporter(d)
        result = i.importEvents(csvFilename)
        assert(result == 0)
        assert(d.getEventCount(textOnly = False) > 0)

        # load event
        aeLoaded = d.getEvent(eventID)
        assert(aeLoaded is not None)

        # compare event data
        assert(aeAdded.comment == aeLoaded.comment)

        # close database
        d.close()
Exemplo n.º 18
0
    def __alarmEventFromList(cls, eventData: List[Any]) -> AlarmEvent:
        alarmEvent = AlarmEvent(eventData[0])

        alarmEvent.timestamp = eventData[1]

        alarmEvent.event = eventData[2]
        alarmEvent.eventDetails = eventData[3]
        alarmEvent.location = eventData[4]
        alarmEvent.locationDetails = eventData[5]
        alarmEvent.comment = eventData[6]
        alarmEvent.alarmTimestamp = eventData[7]
        alarmEvent.locationLatitude = eventData[8]
        alarmEvent.locationLongitude = eventData[9]

        alarmEvent.source = eventData[10]
        alarmEvent.sender = eventData[11]
        alarmEvent.raw = eventData[12]
        alarmEvent.flags = eventData[13]

        return alarmEvent