Skip to content

Einsatztypen

seiferta edited this page Sep 28, 2014 · 4 revisions

Es können verschiedene Erkennungs-Routinen für unterschiedliche Leitstellen eingebunden werden. Dafür muss nur das Layout der Faxe bekannt sein. Aus dem per OCR erkannten Text können dann die Einsatzdaten zusammengebaut werden. Um Fehler bei der OCR-Erkennung zu reduzieren, wird beispielsweise die Einsatzadresse über eine Ähnlichkeitsanalyse der gefundenen Adresse im Abgleich mit vorhandenen Straße genutzt. Damit kann über einen definierten Schwellenwert sichergestellt werden, dass Fehler weitestgehend korrigiert werden können.

Aktuell gibt es für folgende Leitstellen Routinen:

  • Feuerwehreinsatzzentrale München Land (FEZ), Landkreis München
  • ILS Erding, Landkreis Erding

Funktionsweise

im Verzeichnis /emonitor/modules/alarms/inc/ liegen die Konverter der verschiedenen Einsatztypen. Diese Faxchecker werden alle von der Klasse AlarmFaxChecker abgeleitet und können direkt über den Admin-Bereich hochgeladen werden.

z.B. faxchecker_xyz.py

from collections import OrderedDict
import difflib
from emonitor.modules.alarms.alarmutils import AlarmFaxChecker

__all__ = ['XYZAlarmFaxChecker']


class XYZAlarmFaxChecker(AlarmFaxChecker):
    __name__ = "ILS XYZ"
    __version__ = '0.1'

    fields = {}
    sections = OrderedDict()
    sections[u'EINSATZORT'] = (u'address', u'evalAddress')
    sections[u'ZIELORT'] = (u'address2', u'evalAddress2')
    ...
    keywords = [u'ILS XYZ']
    translations = [u'_sample_'] + AlarmFaxChecker.translations

    def getEvalMethods(self):
        return [m for m in self.__class__.__dict__.keys() if m.startswith('eval')]


    def buildAlarmFromText(self, alarmtype, rawtext):
        values = {}

        if alarmtype:
            sections = alarmtype.getSections()
            sectionnames = dict(zip([s.name.encode('utf-8') for s in sections], [s.key for s in sections]))
            sectionmethods = dict(zip([s.key for s in sections], [s.method for s in sections]))
            XYZAlarmFaxChecker().fields['alarmtype'] = (alarmtype, 0)
        else:  # kein passender Einsatztyp gefunden
            return values
        
        # beispielsweise:
        for l in rawtext.split("\n"):
            # finde Schlüsselworte, die Felder kennzeichnen
            # und fülle den Text der Felder in Variablen
            field = l..... # Feldname aus Zeile ermitteln (abhängig vom Layout)
            value = l..... # Feldinhalt aus Zeile ermitteln (abhängig vom Layout)

            # Werte den Feldnamen zuordnen
            XYZAlarmFaxChecker().fields[sectionnames[field[0]]] = (value, 0)

        for section in sections:  # sections durchgehen
            k = section.key
            if sectionmethods[k] != "":
                method = sectionmethods[k].split(';')[0]
                try:  # method parameters (optional)
                    method_params = sectionmethods[k].split(';')[1]
                except:
                    method_params = ''

                # execute methods
                try:
                    getattr(self, method)(k, alarmtype=alarmtype, options=method_params.split(';'))  # fieldname, parameters
                except:
                    if u'error' not in values:
                        values['error'] = ''
                    values['error'] += 'error in method: %s\n' % method

            for k in XYZAlarmFaxChecker().fields:
                try:
                    values[k] = (XYZAlarmFaxChecker().fields[k][0].decode('utf-8'), XYZAlarmFaxChecker().fields[k][1])
            except:
                values[k] = (XYZAlarmFaxChecker().fields[k][0], XYZAlarmFaxChecker().fields[k][1])

        return values

Sections

In der Definition der sections kann einem Klartextnamen ein Attributname und optional eine Methode definiert werden, die die Auswertung des Strings und damit die Umsetzung zu einem passenden Objektwert übernimmt.

sections[u'EINSATZORT'] = (u'address', u'evalAddress')

Im Beispiel muss es in faxchecker_xyz.py eine Methode evalAddress geben:

@staticmethod
def evalAddress(fieldname, **params):
    _str = XYZAlarmFaxChecker().fields[fieldname][0]
    # _str ist der von OCR erkannte String, der weiterverarbeitet werden kann

    XYZAlarmFaxChecker().fields[fieldname] = (%s' % _str, 1)

Die Methoden schreiben ein Tupel in das entsprechende Attribut des Checkers. Der erste Wert ist der Klartext, der zweite Wert beinhaltet die ID des erkannten Objektes (z.B. die ID der im System gespeicherten Straße). 0 bedeutet, dass der Wert nicht in der internen Datenbank gefunden wurde.

Keywords

In der Definition der keywords können Klartextworte hinterlegt werden, die eine Unterscheidung der verschiedenen Alarmfaxe ermöglichen. Es sollten Worte sein, die auf alle Fälle immer für diesen Alarmtyp auf dem Fax zu finden sein müssen.

keywords = [u'ILS XYZ']

Translations

In der Definition der translations werden Übersetzungen bestimmter Variablen hinterlegt, die bei der Alarmerkennung und dem Erstellen des Einsatz-Objektes erforderlich sind (z.B. bma). Im Admin-Bereich können dann die Klartexte für diese Variablen gesetzt werden z.B. bma = Brandmeldeanlage. Diese Klartexte können für die unterschiedlichen Faxe unterschiedlich heißen und auch verwendet werden.

translations = [u'_sample_'] + AlarmFaxChecker.translations

im Beispiel werden zu den Standard-Werten weitere, eigene hinzugefügt (hier: sample)

Felder der Erkennung

Dazu muss anhand des Inhaltes des Faxes der Text zu Attributen eines Einsatzes umgesetzt werden. Jeder Einsatz besitzt eine Reihe an Attributen:

  • address [string] *
    Straßenname im Klartext

  • id.address [integer]
    id der Straße aus der Straßendefinition

  • address2 [string]
    Adresszusatz als Freitext, z.B. Kreuzung

  • alarmplan [integer]
    Nummer des Einsatzplanes (falls vorhanden)

  • city [string] *
    Ortsname

  • id.city [integer]
    id des Ortes

  • filename [string]
    Dateiname zum Fax-PDF

  • id.key [integer]
    id zum Key (siehe unten)

  • object [string]
    Name des hinterlegten Einsatzobjektes

  • id.object [integer]
    id des Einsatzobjektes

  • k.cars1 [list]
    Liste der ids der Primärfahrzeuge, mit Komma getrennt

  • k.cars2 [list]
    Liste der ids der Folgefahrzeuge, mit Komma getrennt

  • k.material [list]
    Liste der ids des Zusatzmaterials

  • marker [integer]
    0|1 steht für Marker nicht gesetzt oder gesetzt

  • person [string]
    Mitteiler oder Kontaktperson als Freitext

  • priority [integer]
    Priorität des Einsatzes:
    0= niedrig,
    1= normal,
    2= hoch,
    Standard beim Fax = normal

  • remark [string]
    Bemerkungsfeld als Freitext

  • streetno [string]
    Nummer ggf. Zusatz zur Hausnummer

  • lat [long]
    Koordinatenangabe der Einsatzposition

  • lng [long]
    Koordinatenangabe der Einsatzposition

  • zoom [integer]
    Zoomstufe für die Kartendarstellung

auf diese Attribute kann mit gettern und settern zugegriffen werden.

alarm.get('object')alarm.set('object', 'xyz')

Zusätzlich besitzt der Einsatz noch folgende Attribute, die direkt im Einsatz gespeichert werden und Pflichtfelder sind:

  • timestamp [timestamp]
    Datum des Einsatzes als timestamp

  • key [string]
    Alarmstrichwort und Schlagwort im Klartext

  • type [integer]
    Einsatzyp
    1: aus Fax erzeugt
    2: manuell erzeugt

  • state [integer]
    Aktueller Status des Einsatzes
    0: angelegt, noch nicht aktiv
    1: aktiv, Einsatz wird an die Monitore geliefert
    2: abgeschlossen, Einsatz ist bereits beendet 3: archiviert, Einsatz liegt im Archiv und kann nur noch im Hintergrund bearbeitet/gesehen werden