Merge branch 'main' of https://git.miaig.dev/mia/hafas-terminal-app
This commit is contained in:
commit
e66d33eefa
3 changed files with 144 additions and 58 deletions
110
README.md
110
README.md
|
|
@ -1,23 +1,95 @@
|
|||
# hafas-terminal-app
|
||||
|
||||
## Description
|
||||
The goal is to access the Hafas API to retrieve Data about the public transport network. Most important is to achieve Station to Station Routeplanning and Station Arrival/Departure Information.
|
||||
A Python-based terminal application for accessing public transport information via the HAFAS API. This tool provides station-to-station route planning and real-time arrival/departure information for public transport networks.
|
||||
|
||||
## Dependencies
|
||||
- Python
|
||||
- prompt_toolkit (tui)
|
||||
- kivy (mobile-ui) ((optional!!!))
|
||||
- requests
|
||||
- json
|
||||
- Hafas API Endpoint
|
||||
- Git
|
||||
## Features
|
||||
|
||||
## Timetable
|
||||
- ~~22.04.2026 - Short project presentation: 3min per Group, incl. UseCase, GitProject, Issues~~
|
||||
- ~~29.04.2026 - Scrum-Round mia/hafas-terminal-app#1~~
|
||||
- ~~06.05.2026 - Scrum-Round mia/hafas-terminal-app#2, optionally mia/hafas-terminal-app#3 and mia/hafas-terminal-app#4~~
|
||||
- 13.05.2026 - Scrum-Round #3, #4, #5
|
||||
- 20.05.2026 - Scrum-Round
|
||||
- 27.05.2026 - Scrum-Round
|
||||
- 03.06.2026 - Scrum-Round
|
||||
- 10.06.2026 - Presentations
|
||||
- **Route Planning**: Find optimal routes between stations
|
||||
- **Station Information**: View real-time arrivals and departures
|
||||
- **Terminal UI**: User-friendly command-line interface using prompt_toolkit
|
||||
- **Multiple Transport Methods**: Support for various public transport modes
|
||||
|
||||
## Requirements
|
||||
|
||||
### Core Dependencies
|
||||
- **Python 3.7+**: Programming language
|
||||
- **Hafas API Endpoint**: Access to a HAFAS public transport API
|
||||
|
||||
### Python Packages
|
||||
- `prompt_toolkit`: Terminal user interface (TUI)
|
||||
- `requests`: HTTP library for API communication
|
||||
- `kivy` (optional): Mobile UI support for future mobile versions
|
||||
|
||||
### Tools
|
||||
- `Git`: Version control
|
||||
|
||||
## Installation
|
||||
|
||||
### Option 1: Using Nix (Recommended)
|
||||
|
||||
1. Clone the repository:
|
||||
```bash
|
||||
git clone https://git.miaig.dev/mia/hafas-terminal-app.git
|
||||
cd hafas-terminal-app
|
||||
```
|
||||
|
||||
2. Enter the Nix development environment:
|
||||
```bash
|
||||
nix develop # Modern Nix with flakes
|
||||
# or
|
||||
nix-shell # Traditional Nix
|
||||
```
|
||||
|
||||
All dependencies will be automatically configured.
|
||||
|
||||
### Option 2: Using pip
|
||||
|
||||
1. Clone the repository:
|
||||
```bash
|
||||
git clone https://git.miaig.dev/mia/hafas-terminal-app.git
|
||||
cd hafas-terminal-app
|
||||
```
|
||||
|
||||
2. Create a virtual environment:
|
||||
```bash
|
||||
python -m venv venv
|
||||
source venv/bin/activate # On Windows: venv\Scripts\activate
|
||||
```
|
||||
|
||||
3. Install dependencies:
|
||||
```bash
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
Run the application:
|
||||
```bash
|
||||
python main.py
|
||||
```
|
||||
|
||||
### Features
|
||||
- Navigate between stations and search for routes
|
||||
- View departure and arrival times
|
||||
- Display detailed journey information
|
||||
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
hafas-terminal-app/
|
||||
├── main.py # Application entry point
|
||||
├── backend.py # Backend API communication logic
|
||||
├── route_planning.py # Route planning algorithms
|
||||
├── station_monitor.py # Station monitoring functionality
|
||||
├── flake.nix # Nix environment configuration
|
||||
├── README.md # This file
|
||||
└── docs/ # Documentation
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
This project is provided under the terms specified in the [LICENSE](./LICENSE) file.
|
||||
|
||||
## Contributing
|
||||
|
||||
Contributions are welcome! Please feel free to submit issues and pull requests to help improve the application.
|
||||
42
backend.py
42
backend.py
|
|
@ -9,7 +9,8 @@ The application will provide routing information and station departures/arrivals
|
|||
|
||||
import requests
|
||||
import json
|
||||
from datetime import datetime
|
||||
import re
|
||||
from datetime import date, datetime
|
||||
from prompt_toolkit import Application
|
||||
from prompt_toolkit.completion import WordCompleter
|
||||
|
||||
|
|
@ -43,6 +44,13 @@ class HafasClient:
|
|||
headers=self.headers)
|
||||
return json.loads(res.text)
|
||||
|
||||
def journeyRequest(self, origin, destination, via=None):
|
||||
time = datetime.now()
|
||||
res = self.session.post(self.baseUrl,
|
||||
data=json.dumps({"svcReqL": [{"req": {"arrLocL": [{"lid": f"A=1@L={destination}@"}], "viaLocL": via or [], "depLocL": [{"lid": f"A=1@L={origin}@"}], "outDate": time.strftime("%Y%m%d"), "outTime": time.strftime("%H%M%S"), "jnyFltrL": [{"type": "PROD", "mode": "INC", "value": "4087"}], "minChgTime": 0, "maxChg": -1, "numF": 1}, "meth": "TripSearch"}], "client": self.clientInfo, "ver": self.version, "lang": self.language, "auth": self.auth}),
|
||||
headers=self.headers)
|
||||
return json.loads(res.text)
|
||||
|
||||
|
||||
|
||||
def getStationNames(self, stationString):
|
||||
|
|
@ -75,20 +83,13 @@ class HafasClient:
|
|||
# - Departure/arrival time: departure["stbStop"]["dTimeS"] or ["aTimeS"]
|
||||
departures.append({
|
||||
"name": departure.get("dirTxt"),
|
||||
"line": (
|
||||
product.get("nameS")
|
||||
or product.get("number")
|
||||
or product.get("name")
|
||||
or product.get("prodCtx", {}).get("line")
|
||||
or product.get("prodCtx", {}).get("name")
|
||||
or product.get("prodCtx", {}).get("nameS")
|
||||
),
|
||||
"line": re.search(r'#ZB#([^#]+)', departure.get("jid")).group(1).strip(),
|
||||
"departure_time": self._format_time(stop.get(time_key)),
|
||||
"departure_time_raw": stop.get(time_key),
|
||||
"departure_time_real": self._format_time(stop.get(time_key_real)),
|
||||
"departure_time_real_raw": stop.get(time_key_real),
|
||||
"jid": departure.get("jid"),
|
||||
"raw": departure,
|
||||
# "raw": departure,
|
||||
})
|
||||
|
||||
return departures
|
||||
|
|
@ -114,13 +115,25 @@ class HafasClient:
|
|||
trip = self.getTrip(departures[0]["jid"])
|
||||
__import__('pprint').pprint(trip)
|
||||
|
||||
def moniterTest(self):
|
||||
def monitorTest(self):
|
||||
stationInput = input("Enter Station Name: ")
|
||||
station = self.getStationNames(stationInput)
|
||||
print(station)
|
||||
# departures = self.getArrDep(station[0][1], arrdep="DEP", count=1)
|
||||
departures = self.arrDepRequest(station[0][1], arrdep="DEP", count=1)
|
||||
print(departures)
|
||||
print("\n)------------------\n")
|
||||
departures = self.getArrDep(station[0][1], arrdep="DEP", count=2)
|
||||
__import__('pprint').pprint(departures)
|
||||
print("\n)------------------\n")
|
||||
arrivals = self.getArrDep(station[0][1], arrdep="ARR", count=2)
|
||||
__import__('pprint').pprint(arrivals)
|
||||
#arrivalsRaw = self.arrDepRequest(station[0][1], arrdep="ARR", count=1)
|
||||
#__import__('pprint').pprint(arrivalsRaw)
|
||||
|
||||
def journeyTest(self):
|
||||
origin = self.getStationNames(input("Origin: "))[0][1]
|
||||
destination = self.getStationNames(input("Destination: "))[0][1]
|
||||
journeys = self.journeyRequest(origin, destination)
|
||||
__import__('pprint').pprint(journeys)
|
||||
|
||||
|
||||
# streq = self.stationRequest(station)["svcResL"][0]["res"]["match"]["locL"]
|
||||
|
|
@ -140,4 +153,5 @@ class HafasClient:
|
|||
if __name__ == '__main__':
|
||||
client = HafasClient()
|
||||
# client.runTests()
|
||||
client.moniterTest()
|
||||
# client.monitorTest()
|
||||
client.journeyTest()
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ from prompt_toolkit.layout.containers import Window, VSplit, HSplit
|
|||
from prompt_toolkit.layout.controls import BufferControl
|
||||
from prompt_toolkit.key_binding import KeyBindings
|
||||
import threading
|
||||
import time
|
||||
|
||||
|
||||
def run_station_monitor(hafas: backend.HafasClient | None = None):
|
||||
|
|
@ -71,36 +70,37 @@ def run_station_monitor(hafas: backend.HafasClient | None = None):
|
|||
|
||||
user_input = userinputBuffer.text.strip()
|
||||
|
||||
if user_input:
|
||||
if not user_input:
|
||||
app_state = "MONITOR"
|
||||
return
|
||||
|
||||
app_state = "RESULTS"
|
||||
results = hafas.getStationNames(user_input)
|
||||
|
||||
if not results:
|
||||
arrivalBuffer.text = f"Keine Stationen gefunden für: {user_input}"
|
||||
departureBuffer.text= ""
|
||||
userinputBuffer.text=""
|
||||
departureBuffer.text = ""
|
||||
userinputBuffer.text = ""
|
||||
app_state = "MONITOR"
|
||||
return
|
||||
|
||||
else:
|
||||
station_name = results[0][1]
|
||||
station_id = results[0][0]
|
||||
station_name = results[0][0]
|
||||
station_id = results[0][1]
|
||||
|
||||
arrivals = hafas.getArrDep(station_id, arrdep="ARR", count=3)
|
||||
arrivalBuffer.text = f"Ankünfte für {station_name}:\n"
|
||||
for arrival in arrivals:
|
||||
arrivalBuffer.insert_text(f"\n {arrival}")
|
||||
|
||||
departures = hafas.getArrDep(station_id, arrdep="DEP", count=3)
|
||||
departureBuffer.text = f"Abfahrten für {station_name}:\n"
|
||||
for departure in departures:
|
||||
departureBuffer.insert_text(f"\n {departure}")
|
||||
arrivals = hafas.getArrDep(station_id, arrdep="ARR", count=5)
|
||||
arrivalBuffer.text = (
|
||||
f"Ankünfte für {station_name}:\n"
|
||||
+ "\n".join(f" {arrival["departure_time_real"]} {arrival["line"]} <-- {arrival["name"]}" for arrival in arrivals)
|
||||
)
|
||||
|
||||
departures = hafas.getArrDep(station_id, arrdep="DEP", count=5)
|
||||
departureBuffer.text = (
|
||||
f"Abfahrten für {station_name}:\n"
|
||||
+ "\n".join(f" {departure["departure_time_real"]} {departure["line"]} --> {departure["name"]}" for departure in departures)
|
||||
)
|
||||
|
||||
userinputBuffer.text = ""
|
||||
|
||||
else:
|
||||
app_state = "MONITOR"
|
||||
|
||||
|
||||
@keyB.add("c-q")
|
||||
def exit_(event):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue