Auswertung von Mails mittels RaspberryPi und Upload zu Connect (angepasstes Python-Script)

  • Hallo zusammen,

    da ich jetzt einige Zeit in dieses Projekt gesteckt habe sowie große Code-Teile aus dieser Community übernommen habe und mir auch mal auf die Sprunge geholfen wurde, möchte ich das Ergebnis hier teilen. Evtl. hat ja jemand etwas davon.

    Ausgangslage:

    Kürzlich hat unsere Leitstelle auf ein neues Einsatzleitsystem umgestellt. Damit hatte sich auch das Layout der Alarmierungsmails, die ich für mehrere Rettungswachen mittels Patternauswertung im Einsatzmonitor ausgewertet habe, geändert. Größter Knackpunkt war die jetzt verpflichtende PGP-Verschlüsselung der Mails. Hier habe ich mittels virtueller Umgebung einen Ciphermail-Server*1 aufgesetzt, dieser prüft die E-Mail-Postfächer im Internet und holt diese direkt nach dem Eingang ab. Nach der Entschlüsselung gibt er die Mails weiter an einen weiteren, internen Mailserver*2. Nun hatte ich die entschlüsselten Mails auf einem Mailserver im internen Netz, worauf ich nur mit den Einsatzmonitoren an diesem Standort zugreifen konnte. Das wäre noch via VPN zu lösen gewesen. Allerdings hätte ich beim neuen Format der Mail ziemlich viele Patternvorlagen gebraucht und dann noch immer nicht die Auswertung hinbekommen, die ich haben wollte. Also habe ich mich an einer Python-Auswertung versucht und dieses Projekt ist entstanden. Basis meiner Arbeiten war das Script aus diesem Thread*3 mit dem Unterschied, dass ich das ganze auf einem RaspberryPi mit RaspberryPi OS lite*4 laufen habe. Wichtig: Der Code benötigt Python3!

    Was macht das Script?

    Erstmal ganz simpel das, was das Ursprungsscript auch macht: Es werden mehrere Mailpostfächer abgefragt und sobald eine neue (ungelesene) Mail vorliegt, diese via Regex*5 ausgelesen und die entsprechende Daten über die Öffentliche Connect Schnittstelle*6 an das Connect-Portal übertragen. Die Einsatzmonitore sind im Slavemodus*7 und werten selber nichts mehr aus, sie zeigen "nur" einen neuen Einsatz an, sobald dieser im Connect-Portal aufläuft.

    Was sind die Anpassungen?

    1.

    In der alarmparser.py erfolgt eine Decodierung der als base64-codierten Mail.

    2.

    Wird eine "Kreuzstraße" in der Alarmmail angeben, so werden die beiden Felder zusammengefasst und als Kreuzung angezeigt (z.B. Hauptstraße#Dorfstraße)

    3.

    Wenn Ortsteil und Ort gleich sind, dann wird das Feld Ortsteil geleert (mein innerer Monk, das sieht sonst doof aus - z.B. Hauptstraße 10, Musterhausen - Musterhausen)

    4.

    Wenn kein Ort angegeben wird (das passiert z.B. bei Einsätzen auf der Autobahn) dann wird der Inhalt des Feldes "Straße" ins Ortsfeld geschrieben (der Ort ist ein Pflichtfeld in Connect/der API. Da die Kartenanzeige die übergebenen Koordinaten nutzt, ist es am Ende egal was da wirklich drin steht).

    5.

    Wird nichtmal ein Ort übermittelt, dann wird das entsprechend ausgegeben (passiert bei eCall-Einsätzen immer öfter, die API lehnt Daten ohne Ort ab)

    6.

    Fallback: Fehlen sogar die Koordinaten, dann wird ein Punkt in der Nordsee übergeben. So wird ein Abbruch der Auswertung verhindert und eine blaue Karte angezeigt. Dieser Punkt war erforderlich, weil in manchen Konstellationen nur ein Objekt als Freitext übermittelt wird (z.B. bei direkten Rücktouren eines vorherigen KT).

    7. (jetzt wirds spannend)

    Das Feld "Einsatzstichwort" kennt verschiedene Syntax für das Stichwort. Ich brauche für die spätere Stichwortübersetzung in Connect verschiedene Ergebnisse, die ich im Feld "keyword" an die API schicke.

    Variante 1 - Rettungsdiensteinsatz aus AMPDS-Abfrage*8:

    Geliefert wird: "ALS gelb RD-31D04 Bewusstseinstrübung" - daraus wird:

    keyword: RD-31D04

    Zusatzfeld "AMPDS-Info": Bewusstseinstrübung

    Zusatzfeld "Kategorie": ALS gelb

    Zusatzfeld "übermittelter Code": RD-31D04

    In Connect habe ich die AMPDS-Codes gepflegt. Statt RD-31D04 wird als Einsatzstichwort auf dem Bildschirm daher in diesem Fall "Bewusstlosigkeit/Ohnmacht (Beinahe-)" angezeigt.

    Variante 2 - Feuerwehreinsatz aus FPDS-Abfrage*9:

    Geliefert wird: "F2 FW-69D06d Wohngebäude (Einfamilienhaus), Wohnung" - daraus wird:

    keyword: F2

    Zusatzfeld "AMPDS-Info": Wohngebäude (Einfamilienhaus), Wohnung

    Zusatzfeld "übermittelter Code": FW-69D06d

    Warum wechsele ich hier die Art der Auswertung? Ich habe bisher keine deutsche Übersetzung der FPDS-Code-Gruppen finden können. Daher findet in Connect die Stichwortübersetzung anhand des übermittelten Stichworts statt (hier "F2" wird "Feuer mittel").

    Variante 3 - nur Stichwort:

    Geliefert wird: "Anforderung NA" - daraus wird:

    keyword: Anforderung NA

    Variante 4 - MANV:

    Ein MANV soll nicht den Code anzeigen und auswerten, es soll sofort ersichtlich sein, dass es ein MANV ist und nicht "Verkehrsunfall-mehrere Beteiligte"

    Geliefert wird: "MANV25 Unfall RD-29B01Y Verletzungen, Mehrere Patienten und zusätzliche Rettungskräfte erforderlich" - daraus wird:

    keyword: MANV25 Unfall

    Zusatzfeld "AMPDS-Info": Verletzungen, Mehrere Patienten und zusätzliche Rettungskräfte erforderlich

    Zusatzfeld "Kategorie": MANV25 Unfall

    Zusatzfeld "übermittelter Code": RD-29B01Y

    Es kann übrigens auch sein, dass nur das Stichwort gewählt wird (wenn keine AMPDS-Abfrage stattgefunden hat). Dann greift wieder Variante 3.

    8. alarmierte Kräfte

    Die kommagetrennte Liste aus der Mail wird zunächst in eine Python-Liste umgebaut, evtl. Leerzeichen entfernt und dann als "assignedvehicles" an die API übergeben. Sind die Fahrzeuge hier vorhanden und der übermittelte Funkrufname exakt so im Feld ISSI hinterlegt, so erfolgt die Zuordnung zum Fahrzeug und die Anzeige am Bildschirm ist "schön". Aus "RD XX 1-83-1" wird dann "RTW 1 Musterhausen". Ansonsten wird der Text wie übergeben angezeigt.

    9. Zu guter Letzt noch etwas Kosmetik:

    Die Zusatzfelder werden nur angelegt, wenn sie wirklich Inhalt haben. Ansonsten zeigen die Monitore leere Felder an, das sieht nicht schön aus.

    ToDo:

    Folgende Punkte habe ich noch auf der Liste und werden mich, sobald ich Zeit dafür finde, versuchen umzusetzen:

    - direkte Entschlüsselung der Mail über den RaspberryPi (z.B. mittels python-gnupg*10

    - Sortierung der Zusatzfelder - bei Übergabe an die API sind diese immer nach Alphabet sortiert, daher die Bezeichnung "übermittelter Code" statt "Code"

    - In der Mail gibt es in seltenen Fällen im Sachverhalt einen Zeilenumbruch. Die zweite Zeile wird dann nicht in das API-Feld übernommen. Bisher habe ich das via Regex nicht hinbekommen, da offensichtlich eine zeilenweise Auswertung der Rohmail erfolgt.

    - fehlt der Ort und die Straße wird ins Ortsfeld übernommen (siehe Punkt 4) dann ist das doppelt. Sieht unschön aus.

    Das Ergebnis:

    An diesen, langen Text sind die drei veränderten Dateien angefügt. Für die grundsätzliche Installation und Einrichtung bitte im Ursprungsthread*3 schauen, da ist das schon super beschrieben.

    Der Code ist bestimmt auch nicht nach allen Regeln der Programmierkunst geschrieben, sorry dafür. Ich bin Notfallsanitäter, der schonmal was am Computer gemacht hat, kein klassischer ITler. Und ich gebe zu: Ein paar Codezeilen hat ChatGPT*11 für mich erstellt.

    Das Wichtigste: Es läuft und das in einer atemberaubenden Geschwindigkeit. Wie gesagt: Vielleicht kann ja jemand diese Zeilen gebrauchen. Und vielleicht hat ja noch jemand Tipps zur Verbesserung oder für die ToDos. Dann gerne. Ansonsten: Viel Spaß damit. :)

    Quellen / Links:

    *1 = https://www.ciphermail.info/download/

    *2 = https://www.hmailserver.com/

    *3: Mehrere E-Mail Postfächer auf einem PC auswerten und an Connect senden

    *4: https://www.raspberrypi.com/software/operating-systems/

    *5: https://de.wikipedia.org/wiki/Regul%C3%A4rer_Ausdruck

    *6: https://feuersoftware.com/doku/oeffentli…-schnittstelle/

    *7: https://feuersoftware.com/doku/einstellu…ect-verbindung/ (Einstellung und Erklärung zum Slavemodus)

    *8: https://de.wikipedia.org/wiki/Advanced_…Dispatch_System

    *9: https://prioritydispatch.net/fpds/

    *10: https://gnupg.readthedocs.io/en/latest/

    *11: https://chat.openai.com/