From 5dc71dbf90a374ab38a8efe36207e195662f2b71 Mon Sep 17 00:00:00 2001 From: "Mohamad.Elsena" Date: Mon, 10 Feb 2025 09:48:27 +0100 Subject: [PATCH] =?UTF-8?q?weeee=F0=9F=92=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Dockerfile | 15 +++++++ config.py | 29 +++++++++++++ database.py | 106 +++++++++++++++++++++++++++++++++++++++++++++++ env.env | 7 ++++ main.py | 90 ++++++++++++++++++++++++++++++++++++++++ requirements.txt | 4 ++ 6 files changed, 251 insertions(+) create mode 100644 Dockerfile create mode 100644 config.py create mode 100644 database.py create mode 100644 env.env create mode 100644 main.py create mode 100644 requirements.txt diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..54d30c0 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,15 @@ +# Use Python 3.9 as the base image +FROM python:3.9-slim + +# Set the working directory +WORKDIR /app + +# Copy requirements and install dependencies +COPY requirements.txt . +RUN pip install --no-cache-dir -r requirements.txt + +# Copy the application code +COPY . . + +# Run the application +CMD ["python", "main.py"] \ No newline at end of file diff --git a/config.py b/config.py new file mode 100644 index 0000000..9df8c6e --- /dev/null +++ b/config.py @@ -0,0 +1,29 @@ +import os +from dotenv import load_dotenv + +# Load environment variables +load_dotenv() + +# DB API Configuration +DB_API_KEY = os.getenv("DB_API_KEY") +DB_API_URL = "https://api.deutschebahn.com/fahrplan-plus/v1" + +# Weather API Configuration +WEATHER_API_KEY = os.getenv("WEATHER_API_KEY") +WEATHER_API_URL = "https://api.openweathermap.org/data/2.5/weather" + +# Database Configuration +DB_HOST = os.getenv("DB_HOST", "localhost") +DB_PORT = os.getenv("DB_PORT", "5432") +DB_NAME = os.getenv("DB_NAME", "train_weather_db") +DB_USER = os.getenv("DB_USER", "postgres") +DB_PASSWORD = os.getenv("DB_PASSWORD", "password") + +# Station IDs (example values; validate via DB API) +STATION_IDS = { + "Frankfurt": "008000105", + "Berlin": "8010169", + "München": "008000000", + "Köln": "008000333", + "Stuttgart": "008000456" +} \ No newline at end of file diff --git a/database.py b/database.py new file mode 100644 index 0000000..af5abb3 --- /dev/null +++ b/database.py @@ -0,0 +1,106 @@ +import psycopg2 +from psycopg2 import sql +from config import DB_HOST, DB_PORT, DB_NAME, DB_USER, DB_PASSWORD + +def get_db_connection(): + """Connect to the PostgreSQL database.""" + return psycopg2.connect( + host=DB_HOST, + port=DB_PORT, + dbname=DB_NAME, + user=DB_USER, + password=DB_PASSWORD + ) + +def create_tables(): + """Create database tables if they don't exist.""" + commands = [ + """ + CREATE TABLE IF NOT EXISTS trains ( + train_id VARCHAR PRIMARY KEY, + train_type VARCHAR, + model VARCHAR, + capacity INT, + age_years FLOAT, + maintenance_history JSONB, + technical_specs JSONB + ) + """, + """ + CREATE TABLE IF NOT EXISTS schedules ( + schedule_id UUID PRIMARY KEY, + train_id VARCHAR, + route_id VARCHAR, + departure_station VARCHAR, + arrival_station VARCHAR, + scheduled_departure TIMESTAMP, + scheduled_arrival TIMESTAMP, + platform_departure VARCHAR, + platform_arrival VARCHAR, + distance_km FLOAT, + scheduled_stops INT, + service_type VARCHAR, + FOREIGN KEY (train_id) REFERENCES trains(train_id) + ) + """, + """ + CREATE TABLE IF NOT EXISTS actual_journeys ( + journey_id UUID PRIMARY KEY, + schedule_id UUID, + actual_departure TIMESTAMP, + actual_arrival TIMESTAMP, + actual_platform_departure VARCHAR, + actual_platform_arrival VARCHAR, + delay_departure_minutes INT, + delay_arrival_minutes INT, + cancellation_flag BOOLEAN, + cancellation_reason VARCHAR, + passenger_count INT, + load_factor FLOAT, + FOREIGN KEY (schedule_id) REFERENCES schedules(schedule_id) + ) + """, + """ + CREATE TABLE IF NOT EXISTS stations ( + station_id VARCHAR PRIMARY KEY, + station_name VARCHAR, + latitude FLOAT, + longitude FLOAT, + elevation FLOAT, + number_of_platforms INT, + daily_passenger_volume INT, + station_category INT, + facilities JSONB, + connection_types JSONB + ) + """, + """ + CREATE TABLE IF NOT EXISTS weather_history ( + weather_id UUID PRIMARY KEY, + station_id VARCHAR, + timestamp TIMESTAMP, + temperature FLOAT, + precipitation FLOAT, + wind_speed FLOAT, + wind_direction INT, + humidity FLOAT, + pressure FLOAT, + visibility FLOAT, + weather_condition VARCHAR, + FOREIGN KEY (station_id) REFERENCES stations(station_id) + ) + """ + ] + conn = None + try: + conn = get_db_connection() + cur = conn.cursor() + for command in commands: + cur.execute(command) + cur.close() + conn.commit() + except Exception as e: + print(f"Error creating tables: {e}") + finally: + if conn is not None: + conn.close() \ No newline at end of file diff --git a/env.env b/env.env new file mode 100644 index 0000000..7c71dc9 --- /dev/null +++ b/env.env @@ -0,0 +1,7 @@ +DB_API_KEY=your_db_api_key +WEATHER_API_KEY=your_weather_api_key +DB_HOST=localhost +DB_PORT=5432 +DB_NAME=train_weather_db +DB_USER=postgres +DB_PASSWORD=password \ No newline at end of file diff --git a/main.py b/main.py new file mode 100644 index 0000000..57143be --- /dev/null +++ b/main.py @@ -0,0 +1,90 @@ +import requests +import uuid +import time +from datetime import datetime +from apscheduler.schedulers.blocking import BlockingScheduler +from database import get_db_connection, create_tables +from config import DB_API_KEY, DB_API_URL, WEATHER_API_KEY, WEATHER_API_URL, STATION_IDS + +# Initialize scheduler +scheduler = BlockingScheduler() + +def fetch_train_schedules(): + """Fetch train schedules from DB API.""" + for station_name, station_id in STATION_IDS.items(): + url = f"{DB_API_URL}/departureBoard?station={station_id}" + headers = {"Authorization": f"Bearer {DB_API_KEY}"} + response = requests.get(url, headers=headers) + if response.status_code == 200: + schedules = response.json() + store_schedules(schedules, station_id) + else: + print(f"Failed to fetch schedules for {station_name}: {response.status_code}") + +def store_schedules(schedules, station_id): + """Store schedules in the database.""" + conn = get_db_connection() + cur = conn.cursor() + for schedule in schedules: + cur.execute( + """ + INSERT INTO schedules ( + schedule_id, train_id, route_id, departure_station, arrival_station, + scheduled_departure, scheduled_arrival, platform_departure, platform_arrival, + distance_km, scheduled_stops, service_type + ) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s) + """, + ( + str(uuid.uuid4()), schedule.get("train_id"), schedule.get("route_id"), + station_id, schedule.get("arrival_station"), + schedule.get("scheduled_departure"), schedule.get("scheduled_arrival"), + schedule.get("platform_departure"), schedule.get("platform_arrival"), + schedule.get("distance_km"), schedule.get("scheduled_stops"), + schedule.get("service_type") + ) + ) + conn.commit() + cur.close() + conn.close() + +def fetch_weather_data(): + """Fetch weather data for each station.""" + for station_name, station_id in STATION_IDS.items(): + url = f"{WEATHER_API_URL}?lat={STATION_LATITUDE}&lon={STATION_LONGITUDE}&appid={WEATHER_API_KEY}" + response = requests.get(url) + if response.status_code == 200: + weather = response.json() + store_weather_data(weather, station_id) + else: + print(f"Failed to fetch weather for {station_name}: {response.status_code}") + +def store_weather_data(weather, station_id): + """Store weather data in the database.""" + conn = get_db_connection() + cur = conn.cursor() + cur.execute( + """ + INSERT INTO weather_history ( + weather_id, station_id, timestamp, temperature, precipitation, + wind_speed, wind_direction, humidity, pressure, visibility, weather_condition + ) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s) + """, + ( + str(uuid.uuid4()), station_id, datetime.now(), weather.get("main", {}).get("temp"), + weather.get("rain", {}).get("1h", 0), weather.get("wind", {}).get("speed"), + weather.get("wind", {}).get("deg"), weather.get("main", {}).get("humidity"), + weather.get("main", {}).get("pressure"), weather.get("visibility"), + weather.get("weather", [{}])[0].get("main") + ) + ) + conn.commit() + cur.close() + conn.close() + +# Schedule tasks +scheduler.add_job(fetch_train_schedules, 'interval', minutes=10) +scheduler.add_job(fetch_weather_data, 'interval', hours=1) + +if __name__ == "__main__": + create_tables() + scheduler.start() \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..cf92bc1 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,4 @@ +requests==2.31.0 +psycopg2-binary==2.9.9 +apscheduler==3.10.1 +python-dotenv==1.0.0 \ No newline at end of file