def generate_timetable_from_hrdf(eckdatenId, generateFrom, generateTo, dbname, host): """Generiert einen Tagesfahrplan aus den HRDF-Daten für die Betriebstage im angegebenen Zeitbereich eckdatenId -- ID aus der Tabelle HRDF_ECKDATEN_TAB generateFrom -- Beginn des Zeitbereichs, für den der Tagesfahrlan generiert wird (String-Format '%d.%m.%Y') generateTo -- Ende des Zeitbereichs, für den der Tagesfahrplan generiert wird (String-Format '%d.%m.%Y') dbname -- Datenbankname host -- Host auf dem die Datenbank läuft """ hrdf_db = HrdfDB(dbname, host, "hrdf", "bmHRDF") if hrdf_db.connect(): # Initialisierung des HRDF-TTGenerators ttGenerator = HrdfTTG(hrdf_db) dtGenerateFrom = datetime.strptime(generateFrom, '%d.%m.%Y').date() dtGenerateTo = datetime.strptime(generateTo, '%d.%m.%Y').date() logger.info("Generierung des Tagesfahrplan für den Zeitraum von {:%d.%m.%Y} bis {:%d.%m.%Y}:".format(dtGenerateFrom, dtGenerateTo)) if ( ttGenerator.setup(eckdatenId, dtGenerateFrom, dtGenerateTo) ): iErrorCnt = ttGenerator.generateTT() if ( iErrorCnt == 0): logger.info("Der Tagesfahrplan für den Zeitraum von {:%d.%m.%Y} bis {:%d.%m.%Y} wurde erfolgreich generiert".format(dtGenerateFrom, dtGenerateTo)) else: logger.warning("Der Tagesfahrplan für den Zeitraum von {:%d.%m.%Y} bis {:%d.%m.%Y} konnte nicht vollständig generiert werden. {} fehlerhafte Fahrten".format(dtGenerateFrom, dtGenerateTo, iErrorCnt)) else: logger.error("Der Tagesfahrplan-Generator konnte nicht initialisiert werden") else: logger.error("Es konnte keine Verbindung zur Datenbank aufgebaut werden")
def load_hrdfzipfile(filename, dbname, host): """Lädt die HRDF-Zipdatei und schreibt den Inhalt der Dateien in die Datenbank filename -- Pfad/Name der Zipdatei die zu laden ist dbnanme -- Name der Datenbank, in die die Daten geschrieben werden host -- Host auf dem die Datenbank läuft Aufzunehmende HRDF-Dateien: ECKDATEN BITFELD ZUGART RICHTUNG ATTRIBUT_XX (sprachabhängig) INFOTEXT_XX (sprachabhängig) DURCHBI BFKOORD_GEO UMSTEIGB BFPRIOS METABHF FPLAN """ hrdf_db = HrdfDB(dbname, host, "hrdf", "bmHRDF") if hrdf_db.connect(): # ZipFile öffnen und zu lesende Dateien bestimmen hrdfzip = zipfile.ZipFile(filename, 'r') hrdffiles = ['ECKDATEN','BITFELD','RICHTUNG','BAHNHOF','GLEIS','ZUGART','ATTRIBUT','INFOTEXT','DURCHBI','BFKOORD_GEO','UMSTEIGB','BFPRIOS','METABHF','FPLAN'] # Initialisierung des HRDF-Readers und lesen der gewünschten HRDF-Dateien reader = HrdfReader(hrdfzip, hrdf_db, hrdffiles) reader.readfiles() else: logger.error("Es konnte keine Verbindung zur Datenbank aufgebaut werden")
def readfiles(self): """Liest die gewünschten HRDF-Dateien und schreibt sie in die Datenbank""" for filename in self.__hrdffiles: if filename == "ECKDATEN": self.read_eckdaten(filename) elif filename == "BITFELD": self.read_bitfeld(filename) elif filename == "RICHTUNG": self.read_richtung(filename) elif filename == "ZUGART": self.read_zugart(filename) elif filename == "ATTRIBUT": self.read_attribut(filename, "DE") self.read_attribut(filename, "EN") self.read_attribut(filename, "FR") self.read_attribut(filename, "IT") elif filename == "INFOTEXT": self.read_infotext(filename, "DE") self.read_infotext(filename, "EN") self.read_infotext(filename, "FR") self.read_infotext(filename, "IT") elif filename == "FPLAN": self.read_fplan(filename) elif filename == "BAHNHOF": self.read_bahnhof(filename) elif filename == "GLEIS": self.read_gleis(filename) elif filename == "DURCHBI": self.read_durchbi(filename) elif filename == "BFKOORD_GEO": self.read_bfkoordgeo(filename) elif filename == "UMSTEIGB": self.read_umsteigb(filename) elif filename == "BFPRIOS": self.read_bfprios(filename) elif filename == "METABHF": self.read_metabhf(filename) else: logger.error("Das Lesen der Datei ["+filename+"] wird nicht unterstützt") # Aufbereitung und Verdichtung der importierten Daten self.determine_linesperstop() self.determine_tripcount() logger.info("Der HRDF-Import <{}> wurde eingearbeitet".format(self.__hrdfzip.filename))
def run(self): """ Worker-Methode des Threads. Diese wird durch start() aufgerufen """ if (self.__hrdfdb.connect()): hasToExit = False while not hasToExit: try: dataItem = self.__workQueue.get(True, 0.100) self.processTrips(dataItem["eckdatenid"], dataItem["day"], dataItem["trips"]) self.__workQueue.task_done() except Empty: pass #logger.info("Thread {}-{} no work".format(self.__threadID, self.__name)) try: hasToExit = self.__commQueue.get(True, 0.010) self.__commQueue.put(hasToExit) except Empty: pass else: logger.error( "{} konnte keine Verbindung zur Datenbank aufbauen".format( self.__name))
def setup(self, eckdatenId, generateFrom, generateTo): """ Die Funktion richtet den Tagesfahrplan-Generator für die anstehende Generierung ein eckdatenId - Id aus der Tabelle HRDF_ECKDATEN_TAB generateFrom -- Beginn des Zeitbereichs, für den der Tagesfahrlan generiert wird generateTo -- Ende des Zeitbereichs, für den der Tagesfahrplan generiert wird """ bReturn = False self.__importFileName = "unknown" self.__eckdatenid = -1 self.__generateFrom = datetime.now().date() self.__generateTo = datetime.now().date() # Ermitteln/Verifizieren des gewünschten Fahrplans cur = self.__hrdfdb.connection.cursor() sql_string = "SELECT id, importFileName, validFrom, validTo, description FROM HRDF_ECKDATEN_TAB WHERE id = %s" cur.execute(sql_string, (eckdatenId, )) row = cur.fetchone() if (row is None): logger.error( "Der gewünschte Fahrplan <{}> wurde nicht gefunden".format( eckdatenId)) elif (generateFrom >= row[2] and generateTo <= row[3]): bReturn = True self.__importFileName = row[1] self.__generateFrom = generateFrom self.__generateTo = generateTo self.__eckdatenid = eckdatenId else: logger.error( "Der zu generierende Zeitbereich liegt außerhalb der Fahrplangrenzen" ) cur.close() return bReturn
def saveNewDailyTimetable(self, eckdatenid, generationDay, ttChunk, paketCnt, receivedPackets): """ Die Funktion speichert den übergebenen TimeTable-Chunk in der Datenbank. Um konsistent zu bleiben wird der bestehende Tagesfahrplan zuerst gelöscht Die Funktion wird als Thread aufgerufen eckdatenid - id der Fahrplandaten generationDay - Generierungsdatum ttChunk - Chunk (csv-Sting) eines Tagesfahrplans paketCnt - Anzahl der Pakete für diesen Tag """ self.__lock.acquire() self.__numOfCurrentDBThreads += 1 self.__DBThreadStarted = True self.__lock.release() # Lokale DB-Verbindung erstellen hrdfDBSingle = HrdfDB(self.__hrdfdb.dbname, self.__hrdfdb.host, self.__hrdfdb.user, self.__hrdfdb.password) if (hrdfDBSingle.connect()): # Das Löschen des Tagesfahrplans erfolgt kontrolliert vor dem Starten der Threads, die den neuen Fahrplan sichern # Speichern des Chunks in der Datenbank curSaveTrip = hrdfDBSingle.connection.cursor() strCopy = "COPY HRDF_DailyTimeTable_TAB (fk_eckdatenid,tripident,tripno,operationalno,tripversion,"\ "operatingday,stopsequenceno,stopident,stopname,stoppointident,stoppointname,arrstoppointtext,depstoppointtext,arrdatetime,depdatetime,noentry,noexit,"\ "categorycode,classno,categoryno,lineno,directionshort,directiontext,"\ "attributecode,attributetext_de,attributetext_fr,attributetext_en,attributetext_it,"\ "infotextcode,infotext_de,infotext_fr,infotext_en,infotext_it,"\ "longitude_geo,latitude_geo,altitude_geo,transfertime1,transfertime2,transferprio,tripno_continued,operationalno_continued,stopno_continued)"\ " FROM STDIN USING DELIMITERS ';' NULL AS ''" #logger.info("Sichern Chunk {} von {} für Tag {:%d.%m.%Y}".format(receivedPackets, paketCnt, generationDay)) dailytimetable_strIO = StringIO() dailytimetable_strIO.write(ttChunk) dailytimetable_strIO.seek(0) curSaveTrip.copy_expert(strCopy, dailytimetable_strIO) dailytimetable_strIO.close() curSaveTrip.close() hrdfDBSingle.connection.commit() # Beim letzten Paket if (receivedPackets == paketCnt): logger.info( "{:%d.%m.%Y} => Neuer Tagesfahrplan wurde komplett gesichert" .format(generationDay)) # Aktualisieren der Eckdatentabelle mit dem neuen Tag curUpdTTGenerated = hrdfDBSingle.connection.cursor() sql_updTTGenerated = "UPDATE HRDF.HRDF_Eckdaten_TAB SET ttgenerated = array_append(ttgenerated, %s) WHERE id = %s" curUpdTTGenerated.execute(sql_updTTGenerated, (str(generationDay), eckdatenid)) curUpdTTGenerated.close() hrdfDBSingle.connection.commit() else: logger.error( "{:%d.%m.%Y} => DB-Thread konnte keine Verbindung zur Datenbank aufbauen" .format(generationDay)) # DB-Thread-Zähler wieder zurücksetzen self.__lock.acquire() self.__numOfCurrentDBThreads -= 1 self.__lock.release()
def processTrips(self, eckdatenid, generationDay, trips): """ Die Funktion generiert den Tagesfahrplan für die übergebenen Trips am gewünschten Tag""" if (len(trips) > 1): #logger.error("{}: bearbeitet {} Fahrten".format(self.__name, len(trips))) tripStops = dict() dailytimetable_strIO = StringIO() numberOfGeneratedTrips = 0 iErrorCnt = 0 for trip in trips: tripStops.clear() origtripident = "{}-{}-{}".format(trip[1], trip[2], trip[3]) try: self.generateTrip(trip, tripStops, generationDay) # Ein Trip kann Taktdefinitionen enthalten, dann muss diese Fahrt mit ihren Stops x mal mit versetzten Zeiten eingetragen werden # Um die Einträge eindeutig der gleichen Fahrt zuordnen zu können wird bei Taktdefinitionen der TripIdentifier erweitert cycletimemin = 0 cyclecount = 0 cycledefs = False if (trip[5] is not None): cycledefs = True cyclecount = trip[5] cycletimemin = trip[6] i = 0 while i <= cyclecount: additionalCycletimeMin = cycletimemin * i # Erweiterung des TripIdentifiers um eine 4-stellige Zahl mit führenden Nullen # 1440 Minuten = 24 Std bei minütlicher Taktung if (cycledefs == True): tripident = "{}-{:04d}".format(origtripident, i) else: tripident = origtripident # Schreibe Fahrtinformation in Tabellenformat for tripStop in tripStops.values(): arrival = tripStop["stop"][3] departure = tripStop["stop"][4] noentry = False noexit = False arrdatetime = "" if (arrival is not None): if (arrival < 0): noexit = True arrival = abs(arrival) arrMins = (int(arrival / 100) * 60) + ( arrival % 100) + additionalCycletimeMin arrdatetime = str( datetime.combine(generationDay, time(0, 0)) + timedelta(minutes=arrMins)) depdatetime = "" if (departure is not None): if (departure < 0): noenty = True departure = abs(departure) depMins = (int(departure / 100) * 60) + ( departure % 100) + additionalCycletimeMin depdatetime = str( datetime.combine(generationDay, time(0, 0)) + timedelta(minutes=depMins)) # Attribute strAttributecode = "" strAttributetextDE = "" strAttributetextFR = "" strAttributetextEN = "" strAttributetextIT = "" if (len(tripStop["attributecode"]) > 0): strAttributecode = "{'" + "','".join( map(str, tripStop["attributecode"])) + "'}" if (len(tripStop["attributetext_de"]) > 0): strAttributetextDE = "{'" + "','".join( map(str, tripStop["attributetext_de"])) + "'}" if (len(tripStop["attributetext_fr"]) > 0): strAttributetextFR = "{'" + "','".join( map(str, tripStop["attributetext_fr"])) + "'}" if (len(tripStop["attributetext_en"]) > 0): strAttributetextEN = "{'" + "','".join( map(str, tripStop["attributetext_en"])) + "'}" if (len(tripStop["attributetext_it"]) > 0): strAttributetextIT = "{'" + "','".join( map(str, tripStop["attributetext_it"])) + "'}" # Infotexte strInfotextcode = "" strInfotextDE = "" strInfotextFR = "" strInfotextEN = "" strInfotextIT = "" if (len(tripStop["infotextcode"]) > 0): strInfotextcode = '{"' + '","'.join( map(self.infohelp, tripStop["infotextcode"])) + '"}' if (len(tripStop["infotext_de"]) > 0): strInfotextDE = '{"' + '","'.join( map(self.infohelp, tripStop["infotext_de"])) + '"}' if (len(tripStop["infotext_fr"]) > 0): strInfotextFR = '{"' + '","'.join( map(self.infohelp, tripStop["infotext_fr"])) + '"}' if (len(tripStop["infotext_en"]) > 0): strInfotextEN = '{"' + '","'.join( map(self.infohelp, tripStop["infotext_en"])) + '"}' if (len(tripStop["infotext_it"]) > 0): strInfotextIT = '{"' + '","'.join( map(self.infohelp, tripStop["infotext_it"])) + '"}' # Angaben zur Haltestelle strLongitudeGeo = "" strLatitudeGeo = "" strAltitudeGeo = "" strTransferTime1 = "" strTransferTime2 = "" strTransferPrio = "" strTripNoContinued = "" strOperationalNoContinued = "" strStopNoContinued = "" if (tripStop["longitude_geo"] is not None): strLongitudeGeo = str( tripStop["longitude_geo"]) if (tripStop["latitude_geo"] is not None): strLatitudeGeo = str(tripStop["latitude_geo"]) if (tripStop["altitude_geo"] is not None): strAltitudeGeo = str(tripStop["altitude_geo"]) if (tripStop["transfertime1"] is not None): strTransferTime1 = str( tripStop["transfertime1"]) if (tripStop["transfertime2"] is not None): strTransferTime2 = str( tripStop["transfertime2"]) if (tripStop["transferprio"] is not None): strTransferPrio = str(tripStop["transferprio"]) if (tripStop["tripno_continued"] is not None): strTripNoContinued = str( tripStop["tripno_continued"]) if (tripStop["operationalno_continued"] is not None): strOperationalNoContinued = str( tripStop["operationalno_continued"]) if (tripStop["stopno_continued"] is not None): strStopNoContinued = str( tripStop["stopno_continued"]) # Schreiben des Datensatzes dailytimetable_strIO.write(eckdatenid) dailytimetable_strIO.write(';') dailytimetable_strIO.write(tripident) dailytimetable_strIO.write(';') dailytimetable_strIO.write(str(trip[1])) dailytimetable_strIO.write(';') dailytimetable_strIO.write(trip[2]) dailytimetable_strIO.write(';') dailytimetable_strIO.write(str(trip[3])) dailytimetable_strIO.write(';') dailytimetable_strIO.write(str(generationDay)) dailytimetable_strIO.write(';') dailytimetable_strIO.write(str( tripStop["stop"][2])) dailytimetable_strIO.write(';') dailytimetable_strIO.write(str( tripStop["stop"][0])) dailytimetable_strIO.write(';') dailytimetable_strIO.write(tripStop["stop"][1]) dailytimetable_strIO.write(';') dailytimetable_strIO.write(str( tripStop["stop"][0])) dailytimetable_strIO.write(';') dailytimetable_strIO.write(tripStop["stop"][1]) dailytimetable_strIO.write(';') dailytimetable_strIO.write( tripStop["arrstoppointtext"]) dailytimetable_strIO.write(';') dailytimetable_strIO.write( tripStop["depstoppointtext"]) dailytimetable_strIO.write(';') dailytimetable_strIO.write(arrdatetime) dailytimetable_strIO.write(';') dailytimetable_strIO.write(depdatetime) dailytimetable_strIO.write(';') dailytimetable_strIO.write(str(noentry)) dailytimetable_strIO.write(';') dailytimetable_strIO.write(str(noexit)) dailytimetable_strIO.write(';') dailytimetable_strIO.write( tripStop["categorycode"]) dailytimetable_strIO.write(';') dailytimetable_strIO.write(str( tripStop["classno"])) dailytimetable_strIO.write(';') dailytimetable_strIO.write( str(tripStop["categoryno"])) dailytimetable_strIO.write(';') dailytimetable_strIO.write(tripStop["lineno"]) dailytimetable_strIO.write(';') dailytimetable_strIO.write( tripStop["directionshort"]) dailytimetable_strIO.write(';') dailytimetable_strIO.write( tripStop["directiontext"]) dailytimetable_strIO.write(';') dailytimetable_strIO.write(strAttributecode) dailytimetable_strIO.write(';') dailytimetable_strIO.write(strAttributetextDE) dailytimetable_strIO.write(';') dailytimetable_strIO.write(strAttributetextFR) dailytimetable_strIO.write(';') dailytimetable_strIO.write(strAttributetextEN) dailytimetable_strIO.write(';') dailytimetable_strIO.write(strAttributetextIT) dailytimetable_strIO.write(';') dailytimetable_strIO.write(strInfotextcode) dailytimetable_strIO.write(';') dailytimetable_strIO.write(strInfotextDE) dailytimetable_strIO.write(';') dailytimetable_strIO.write(strInfotextFR) dailytimetable_strIO.write(';') dailytimetable_strIO.write(strInfotextEN) dailytimetable_strIO.write(';') dailytimetable_strIO.write(strInfotextIT) dailytimetable_strIO.write(';') dailytimetable_strIO.write(strLongitudeGeo) dailytimetable_strIO.write(';') dailytimetable_strIO.write(strLatitudeGeo) dailytimetable_strIO.write(';') dailytimetable_strIO.write(strAltitudeGeo) dailytimetable_strIO.write(';') dailytimetable_strIO.write(strTransferTime1) dailytimetable_strIO.write(';') dailytimetable_strIO.write(strTransferTime2) dailytimetable_strIO.write(';') dailytimetable_strIO.write(strTransferPrio) dailytimetable_strIO.write(';') dailytimetable_strIO.write(strTripNoContinued) dailytimetable_strIO.write(';') dailytimetable_strIO.write( strOperationalNoContinued) dailytimetable_strIO.write(';') dailytimetable_strIO.write(strStopNoContinued) dailytimetable_strIO.write('\n') numberOfGeneratedTrips += 1 i += 1 except Exception as err: iErrorCnt += 1 logger.error( "Die Fahrt {} konnte nicht generiert werden. Error:\n{}" .format(tripident, err)) # Alle Fahrten des Sets im IO abgelegt => Zurückgabe an den Main-Thread logger.info( "\t{}: {:%d.%m.%Y} => {} Tagesfahrplaneinträge erstellt ...". format(self.__name, generationDay, numberOfGeneratedTrips)) # Ergebnis liefern dailytimetable_strIO.seek(0) self.__responseQueue.put( dict(day=generationDay, data=dailytimetable_strIO.getvalue())) dailytimetable_strIO.close() tripStops.clear()