initial support for lodur

This commit is contained in:
Tobias Brunner 2017-12-24 15:35:16 +01:00
parent 1ae30cdece
commit 5ce9b2b3b2
3 changed files with 226 additions and 17 deletions

View File

@ -12,9 +12,77 @@
* Connect to Lodur and create a new Einsatzrapport with
as much information as possible
## Todo
## TODO
* Parse PDF
* Lodur Connect (Create Einsatzrapport)
* IMAP idle
### Version 1
* Lodur Connect
* Fill in Einsatzprotokoll data
* Store tuple F_ID <-> LODUR_ID persistently
* Error Handling
* Parse PDF
* Store parsed data in Lodur text fields for copy/paste
* Cleanup code into proper functions and classes
* Lodur "API" class
### Future versions
* Generalize
* Documentation
* IMAP idle
* Display PDF on Dashboard
* Webapp to see what's going on
* Get as many data out of the PDFs as possible
* Simple webform to fill-in missing data (skipping Lodur completely)
* Webapp for chosing who was there during the Einsatz
## Lodur Information Gathering
### eins_stat_kantone
_02. Einsatzart FKS_
```
<option value="1">Brandbekämpfung</option>
<option value="2">Elementarereignisse</option>
<option value="3">Strassenrettung</option>
<option value="4">Technische Hilfeleistungen</option>
<option value="5">Ölwehr</option>
<option value="6">Chemierwehr inkl. B-Einsätze</option>
<option value="7">Strahlenwehr</option>
<option value="8">Einsätze auf Bahnanlagen</option>
<option value="9">BMA Unechte Alarme</option>
<option value="10">Verschiedene Einsätze</option>
<option value="11">Keine alarmmässigen Einsätze</option>
```
### emergency_concept_id / ver_sart
_03. Verrechnungsart_
* `emergency_concept_id` = value
* `ver_sart`= rc-id
```
<option value="2" rc-id="ab">ABC-Einsatz inkl. Oel (Ortsfeuerwehr)</option>
<option value="3" rc-id="ab">ABC-Einsätze inkl. Oel (Stützpunkte)</option>
<option value="4" rc-id="ab">ABC-Messwagen (Stützpunkte)</option>
<option value="5" rc-id="ab">Gaseinsätze (Ortsfeuerwehr)</option>
<option value="6" rc-id="ab">Verkehrsunfälle (ohne Strassenrettung)</option>
<option value="7" rc-id="ab">Strassenrettung (Ortsfeuerwehr)</option>
<option value="8" rc-id="ab">Strassenrettung (Stützpunkt)</option>
<option value="9" rc-id="ab">Fahrzeugbrände (ohne Brandstiftung)</option>
<option value="10" rc-id="th">BMA-Alarm</option>
<option value="18" rc-id="th">Hilfeleistungs-Einsätze, verrechenbar durch OFW</option>
<option value="19" rc-id="th">Unterstützung Rettungsdienst (ADL/Hilfskräfte)</option>
<option value="11" rc-id="uh">Dienstleistungen, Verrechenbar durch OFW</option>
<option value="12" rc-id="uh">Stützpunkteinsatz (Grossereignisse)</option>
<option value="14" rc-id="uh">Nachbarschaftshilfe Ortsfeuerwehr</option>
<option value="20" rc-id="uh">Kernaufgaben (Brand, Explosion, Elementar, Erdbeben)</option>
<option value="21" rc-id="uh">ADL-/HRF-Einsatz BRAND (ADL = Stüpt-Fahrzeug)</option>
<option value="13" rc-id="ak">ADL-/HRF-Einsatz BRAND (ADL = OFW-Fahrzeug)</option>
<option value="15" rc-id="tt">Grosstierrettung Stützpunkt (PIF mit Kran)</option>
```

108
lodur_connect.py Normal file
View File

@ -0,0 +1,108 @@
#!/usr/bin/env python3
import re
from datetime import datetime
import requests
import logging
import http.client
def create_einsatzrapport(username, password, base_url, f_id):
session = requests.session()
login_data = {
'login_member_name': username,
'login_member_pwd': password,
}
# Authenticate
session.post(base_url, data=login_data)
params = (
('modul', '36'),
('what', '144'),
('sp', '1'),
('event', ''),
('edit', ''),
('is_herznotfall', ''),
)
data = {
'e_r_num': (None, '1'), # 01. Einsatzrapportnummer
'eins_stat_kantone': (None, '1'), # 02. Einsatzart FKS
'emergency_concept_id': (None, '2'), # 03. Verrechnungsart
'ver_sart': (None, 'ab'), # 03. Verrechnungsart internal: ab, th, uh, ak, tt
'dtv_d': (None, str(datetime.now().day)), # 04. Datum von
'dtv_m': (None, str(datetime.now().month)), # 04. Datum von
'dtv_y': (None, str(datetime.now().year)), # 04. Datum von
'dtb_d': (None, str(datetime.now().day)), # 04. Datum bis
'dtb_m': (None, str(datetime.now().month)), # 04. Datum bis
'dtb_y': (None, str(datetime.now().year)), # 04. Datum bis
'ztv_h': (None, '11'), # 05. Zeit von
'ztv_m': (None, '11'), # 05. Zeit von
'ztb_h': (None, '12'), # 05. Zeit bis
'ztb_m': (None, '12'), # 05. Zeit bis
'e_ort_1': (None, '306'), # 06. Einsatzort: Urdorf 306, Birmensdorf 298
'eins_ereig': (None, f_id), # 07. Ereignis
'adr': (None, 'TBD'), # 08. Adresse
#'zh_alarmierung_h': (None, 'UNKNOWN'), # 12. Alarmierung
#'zh_alarmierung_m': (None, 'UNKNOWN'), # 12. Alarmierung
#'zh_fw_ausg_h': (None, 'UNKNOWN'), # 13. FW ausgerückt
#'zh_fw_ausg_m': (None, 'UNKNOWN'), # 13. FW ausgerückt
#'zh_am_schad_h': (None, 'UNKNOWN'), # 14. Am Schadenplatz
#'zh_am_schad_m': (None, 'UNKNOWN'), # 14. Am Schadenplatz
#'zh_fw_einge_h': (None, 'UNKNOWN'), # 15. FW eingerückt
#'zh_fw_einge_m': (None, 'UNKNOWN'), # 15. FW eingerückt
#'eins_erst_h': (None, 'UNKNOWN'), # 16. Einsatzbereitschaft erstellt
#'eins_erst_m': (None, 'UNKNOWN'), # 16. Einsatzbereitschaft erstellt
'ang_sit': (None, 'TBD1'), # 17. Angetroffene Situation
'mn': (None, 'TBD2'), # 19. Massnahmen
'bk': (None, 'TBD3'), # 20. Bemerkungen
'en_kr_feuwehr': (None, '1'), # 21. Einsatzkräfte
'ali_io': (None, '1'), # 24. Alarmierung
'kopie_gvz': (None, '1'), # 31. Kopie innert 10 Tagen an
'mannschaftd_einsa': (None, '70'), # 32. Einsatzleiter|in
}
# post data to create new einsatzrapport
answer = session.post(
'https://lodur-zh.ch/urdorf/index.php',
params=params,
files=data,
)
# very ugly way to find the assigned event id by lodur
# lodur really adds a script element at the bottom of the returned html
# with the location to reload the page - containing the assigned event id
lodur_id = re.search('modul=36&event=([0-9].*)&edit=1&what=144', answer.text).group(1)
return lodur_id
def upload_alarmdepesche(username, password, base_url, lodur_id, file_name, file_path):
http.client.HTTPConnection.debuglevel = 1
logging.basicConfig()
logging.getLogger().setLevel(logging.DEBUG)
requests_log = logging.getLogger("requests.packages.urllib3")
requests_log.setLevel(logging.DEBUG)
requests_log.propagate = True
session = requests.session()
login_data = {
'login_member_name': username,
'login_member_pwd': password,
}
# Authenticate
session.post(base_url, data=login_data)
params = (
('modul', '36'),
('what', '828'),
('event', lodur_id),
)
data = {'alarmdepesche': open(file_path, 'rb')}
session.post(
'https://lodur-zh.ch/urdorf/index.php',
params=params,
files=data,
)

59
main.py
View File

@ -4,17 +4,17 @@
import os
import re
import datetime
from datetime import datetime
import asyncio
import logging
import time
import email
import email.parser
import imaplib
from datetime import datetime
import aioeasywebdav
from dotenv import load_dotenv, find_dotenv
import paho.mqtt.client as mqtt
from lodur_connect import create_einsatzrapport, upload_alarmdepesche
_EMAIL_SUBJECTS = '(OR SUBJECT "Einsatzausdruck_FW" SUBJECT "Einsatzprotokoll" UNSEEN)'
@ -32,6 +32,9 @@ tmp_dir = os.getenv("TMP_DIR", "/tmp")
mqtt_server = os.getenv("MQTT_SERVER")
mqtt_user = os.getenv("MQTT_USER")
mqtt_password = os.getenv("MQTT_PASSWORD")
lodur_user = os.getenv("LODUR_USER")
lodur_password = os.getenv("LODUR_PASSWORD")
lodur_base_url = os.getenv("LODUR_BASE_URL")
logging.basicConfig(
level=logging.INFO,
@ -53,7 +56,7 @@ def get_attachments(mqtt_client):
_EMAIL_SUBJECTS,
)
if typ != 'OK':
print('Error searching for matching messages')
logger.error('Error searching for matching messages')
raise
logger.info('Found ' + str(len(msg_ids[0].split())) + ' matching messages')
@ -61,27 +64,48 @@ def get_attachments(mqtt_client):
for msg_id in msg_ids[0].split():
subject = str()
f_id = str()
f_type = str()
# download message
typ, msg_data = imap.fetch(msg_id, '(RFC822)')
for response_part in msg_data:
if isinstance(response_part, tuple):
msg = email.message_from_string(str(response_part[1],'utf-8'))
msg = email.message_from_string(str(response_part[1], 'utf-8'))
subject = msg["subject"]
# extract F id from subject
f_id = re.search('.*: (F[0-9].*)',subject).group(1)
parse_subject = re.search('(.*): (F[0-9].*)', subject)
f_type = parse_subject.group(1)
f_id = parse_subject.group(2)
logger.info('Processing message: ' + subject)
logger.info('Detected F ID: ' + f_id)
mqtt_client.publish("pylokid/einsatz/" + f_id, subject)
# Mark as seen
# mark as seen
imap.store(msg_id, '+FLAGS', '(\\Seen)')
logger.info('Processing message: ' + subject)
logger.info('Detected type: ' + f_type)
logger.info('Detected F ID: ' + f_id)
# publish over MQTT
mqtt_client.publish("pylokid/einsatz/" + f_id, f_type)
# Talk to Lodur
if f_type == 'Einsatzausdruck_FW':
# create new Einsatzrapport in Lodur
logger.info('Sending data to Lodur')
lodur_id = create_einsatzrapport(
lodur_user,
lodur_password,
lodur_base_url,
f_id,
)
logger.info('Sent data to Lodur. Assigned Lodur ID: ' + lodur_id)
elif f_type == 'Einsatzprotokoll':
logger.info('Updating data in Lodur')
else:
logger.error('Unknown type: ' + f_type)
# extract attachment from body
mail = email.message_from_string(str(msg_data[0][1],'utf-8'))
mail = email.message_from_string(str(msg_data[0][1], 'utf-8'))
for part in mail.walk():
if part.get_content_maintype() == 'multipart':
@ -98,13 +122,22 @@ def get_attachments(mqtt_client):
logger.info('Saving attachment to ' + file_path)
if not os.path.isfile(file_path):
print(file_name)
file = open(file_path, 'wb')
file.write(part.get_payload(decode=True))
file.close()
upload_attachment(file_path, file_name, f_id)
logger.info('Uploading PDF to Lodur')
upload_alarmdepesche(
lodur_user,
lodur_password,
lodur_base_url,
lodur_id,
file_name,
file_path,
)
def upload_attachment(file, file_name, f_id):
# webdav connection