python-openpublictransport 0.1.12__tar.gz → 0.1.14__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {python_openpublictransport-0.1.12 → python_openpublictransport-0.1.14}/PKG-INFO +1 -1
- {python_openpublictransport-0.1.12 → python_openpublictransport-0.1.14}/pyproject.toml +1 -1
- {python_openpublictransport-0.1.12 → python_openpublictransport-0.1.14}/src/openpublictransport/const.py +7 -0
- {python_openpublictransport-0.1.12 → python_openpublictransport-0.1.14}/src/openpublictransport/providers/__init__.py +21 -0
- python_openpublictransport-0.1.14/src/openpublictransport/providers/bart.py +26 -0
- python_openpublictransport-0.1.14/src/openpublictransport/providers/dart.py +29 -0
- python_openpublictransport-0.1.14/src/openpublictransport/providers/entur.py +207 -0
- python_openpublictransport-0.1.14/src/openpublictransport/providers/hafas_base.py +362 -0
- python_openpublictransport-0.1.14/src/openpublictransport/providers/hafas_mgate_base.py +303 -0
- python_openpublictransport-0.1.14/src/openpublictransport/providers/irishrail.py +32 -0
- python_openpublictransport-0.1.14/src/openpublictransport/providers/mobiliteit_lu.py +24 -0
- python_openpublictransport-0.1.14/src/openpublictransport/providers/ns.py +25 -0
- python_openpublictransport-0.1.14/src/openpublictransport/providers/oebb.py +43 -0
- python_openpublictransport-0.1.14/src/openpublictransport/providers/tpg.py +26 -0
- {python_openpublictransport-0.1.12 → python_openpublictransport-0.1.14}/src/python_openpublictransport.egg-info/PKG-INFO +1 -1
- {python_openpublictransport-0.1.12 → python_openpublictransport-0.1.14}/src/python_openpublictransport.egg-info/SOURCES.txt +12 -0
- python_openpublictransport-0.1.14/tests/test_entur.py +86 -0
- python_openpublictransport-0.1.14/tests/test_hafas_base.py +226 -0
- python_openpublictransport-0.1.14/tests/test_hafas_mgate.py +97 -0
- python_openpublictransport-0.1.12/src/openpublictransport/providers/oebb.py +0 -182
- {python_openpublictransport-0.1.12 → python_openpublictransport-0.1.14}/setup.cfg +0 -0
- {python_openpublictransport-0.1.12 → python_openpublictransport-0.1.14}/src/openpublictransport/__init__.py +0 -0
- {python_openpublictransport-0.1.12 → python_openpublictransport-0.1.14}/src/openpublictransport/data/uk_stations.json +0 -0
- {python_openpublictransport-0.1.12 → python_openpublictransport-0.1.14}/src/openpublictransport/exceptions.py +0 -0
- {python_openpublictransport-0.1.12 → python_openpublictransport-0.1.14}/src/openpublictransport/models.py +0 -0
- {python_openpublictransport-0.1.12 → python_openpublictransport-0.1.14}/src/openpublictransport/parsers.py +0 -0
- {python_openpublictransport-0.1.12 → python_openpublictransport-0.1.14}/src/openpublictransport/providers/avv.py +0 -0
- {python_openpublictransport-0.1.12 → python_openpublictransport-0.1.14}/src/openpublictransport/providers/base.py +0 -0
- {python_openpublictransport-0.1.12 → python_openpublictransport-0.1.14}/src/openpublictransport/providers/beg.py +0 -0
- {python_openpublictransport-0.1.12 → python_openpublictransport-0.1.14}/src/openpublictransport/providers/bsvg.py +0 -0
- {python_openpublictransport-0.1.12 → python_openpublictransport-0.1.14}/src/openpublictransport/providers/bvg.py +0 -0
- {python_openpublictransport-0.1.12 → python_openpublictransport-0.1.14}/src/openpublictransport/providers/db.py +0 -0
- {python_openpublictransport-0.1.12 → python_openpublictransport-0.1.14}/src/openpublictransport/providers/ding.py +0 -0
- {python_openpublictransport-0.1.12 → python_openpublictransport-0.1.14}/src/openpublictransport/providers/efa_base.py +0 -0
- {python_openpublictransport-0.1.12 → python_openpublictransport-0.1.14}/src/openpublictransport/providers/fptf_base.py +0 -0
- {python_openpublictransport-0.1.12 → python_openpublictransport-0.1.14}/src/openpublictransport/providers/gtfsde.py +0 -0
- {python_openpublictransport-0.1.12 → python_openpublictransport-0.1.14}/src/openpublictransport/providers/hvv.py +0 -0
- {python_openpublictransport-0.1.12 → python_openpublictransport-0.1.14}/src/openpublictransport/providers/kvv.py +0 -0
- {python_openpublictransport-0.1.12 → python_openpublictransport-0.1.14}/src/openpublictransport/providers/mvv.py +0 -0
- {python_openpublictransport-0.1.12 → python_openpublictransport-0.1.14}/src/openpublictransport/providers/national_rail.py +0 -0
- {python_openpublictransport-0.1.12 → python_openpublictransport-0.1.14}/src/openpublictransport/providers/nta.py +0 -0
- {python_openpublictransport-0.1.12 → python_openpublictransport-0.1.14}/src/openpublictransport/providers/nvbw.py +0 -0
- {python_openpublictransport-0.1.12 → python_openpublictransport-0.1.14}/src/openpublictransport/providers/nwl.py +0 -0
- {python_openpublictransport-0.1.12 → python_openpublictransport-0.1.14}/src/openpublictransport/providers/otp.py +0 -0
- {python_openpublictransport-0.1.12 → python_openpublictransport-0.1.14}/src/openpublictransport/providers/otp_base.py +0 -0
- {python_openpublictransport-0.1.12 → python_openpublictransport-0.1.14}/src/openpublictransport/providers/otp_custom.py +0 -0
- {python_openpublictransport-0.1.12 → python_openpublictransport-0.1.14}/src/openpublictransport/providers/rejseplanen.py +0 -0
- {python_openpublictransport-0.1.12 → python_openpublictransport-0.1.14}/src/openpublictransport/providers/rmv.py +0 -0
- {python_openpublictransport-0.1.12 → python_openpublictransport-0.1.14}/src/openpublictransport/providers/rvv.py +0 -0
- {python_openpublictransport-0.1.12 → python_openpublictransport-0.1.14}/src/openpublictransport/providers/sbb.py +0 -0
- {python_openpublictransport-0.1.12 → python_openpublictransport-0.1.14}/src/openpublictransport/providers/trafiklab.py +0 -0
- {python_openpublictransport-0.1.12 → python_openpublictransport-0.1.14}/src/openpublictransport/providers/transitous.py +0 -0
- {python_openpublictransport-0.1.12 → python_openpublictransport-0.1.14}/src/openpublictransport/providers/trias_base.py +0 -0
- {python_openpublictransport-0.1.12 → python_openpublictransport-0.1.14}/src/openpublictransport/providers/vagfr.py +0 -0
- {python_openpublictransport-0.1.12 → python_openpublictransport-0.1.14}/src/openpublictransport/providers/vbn.py +0 -0
- {python_openpublictransport-0.1.12 → python_openpublictransport-0.1.14}/src/openpublictransport/providers/vgn.py +0 -0
- {python_openpublictransport-0.1.12 → python_openpublictransport-0.1.14}/src/openpublictransport/providers/vrn.py +0 -0
- {python_openpublictransport-0.1.12 → python_openpublictransport-0.1.14}/src/openpublictransport/providers/vrr.py +0 -0
- {python_openpublictransport-0.1.12 → python_openpublictransport-0.1.14}/src/openpublictransport/providers/vvo.py +0 -0
- {python_openpublictransport-0.1.12 → python_openpublictransport-0.1.14}/src/openpublictransport/providers/vvs.py +0 -0
- {python_openpublictransport-0.1.12 → python_openpublictransport-0.1.14}/src/openpublictransport/py.typed +0 -0
- {python_openpublictransport-0.1.12 → python_openpublictransport-0.1.14}/src/python_openpublictransport.egg-info/dependency_links.txt +0 -0
- {python_openpublictransport-0.1.12 → python_openpublictransport-0.1.14}/src/python_openpublictransport.egg-info/requires.txt +0 -0
- {python_openpublictransport-0.1.12 → python_openpublictransport-0.1.14}/src/python_openpublictransport.egg-info/top_level.txt +0 -0
- {python_openpublictransport-0.1.12 → python_openpublictransport-0.1.14}/tests/test_national_rail.py +0 -0
- {python_openpublictransport-0.1.12 → python_openpublictransport-0.1.14}/tests/test_national_rail_parse.py +0 -0
- {python_openpublictransport-0.1.12 → python_openpublictransport-0.1.14}/tests/test_national_rail_static.py +0 -0
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "python-openpublictransport"
|
|
7
|
-
version = "0.1.
|
|
7
|
+
version = "0.1.14"
|
|
8
8
|
description = "Python library for public transport APIs (EFA, OTP2, TRIAS, FPTF, HAFAS, GTFS-RT)"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = { text = "MIT" }
|
|
@@ -31,6 +31,13 @@ PROVIDER_OPT = "openpublictransport"
|
|
|
31
31
|
PROVIDER_OTP_CUSTOM = "otp_custom"
|
|
32
32
|
PROVIDER_NATIONAL_RAIL = "national_rail"
|
|
33
33
|
PROVIDER_REJSEPLANEN = "rejseplanen"
|
|
34
|
+
PROVIDER_NS_NL = "ns_nl"
|
|
35
|
+
PROVIDER_MOBILITEIT_LU = "mobiliteit_lu"
|
|
36
|
+
PROVIDER_ENTUR_NO = "entur_no"
|
|
37
|
+
PROVIDER_BART_US = "bart_us"
|
|
38
|
+
PROVIDER_DART_US = "dart_us"
|
|
39
|
+
PROVIDER_IRISHRAIL_IE = "irishrail_ie"
|
|
40
|
+
PROVIDER_TPG_CH = "tpg_ch"
|
|
34
41
|
|
|
35
42
|
# API base URLs
|
|
36
43
|
API_BASE_URL_VRR = "https://openservice-test.vrr.de/static03/XML_DM_REQUEST"
|
|
@@ -34,6 +34,13 @@ from ..const import (
|
|
|
34
34
|
PROVIDER_VVS,
|
|
35
35
|
PROVIDER_NATIONAL_RAIL,
|
|
36
36
|
PROVIDER_REJSEPLANEN,
|
|
37
|
+
PROVIDER_NS_NL,
|
|
38
|
+
PROVIDER_MOBILITEIT_LU,
|
|
39
|
+
PROVIDER_ENTUR_NO,
|
|
40
|
+
PROVIDER_BART_US,
|
|
41
|
+
PROVIDER_DART_US,
|
|
42
|
+
PROVIDER_IRISHRAIL_IE,
|
|
43
|
+
PROVIDER_TPG_CH,
|
|
37
44
|
)
|
|
38
45
|
from .avv import AVVProvider
|
|
39
46
|
from .base import BaseProvider
|
|
@@ -65,6 +72,13 @@ from .vvo import VVOProvider
|
|
|
65
72
|
from .vvs import VVSProvider
|
|
66
73
|
from .national_rail import NationalRailProvider
|
|
67
74
|
from .rejseplanen import RejseplanenProvider
|
|
75
|
+
from .ns import NSProvider
|
|
76
|
+
from .mobiliteit_lu import MobiliteitLuProvider
|
|
77
|
+
from .entur import EnturProvider
|
|
78
|
+
from .bart import BARTProvider
|
|
79
|
+
from .dart import DARTProvider
|
|
80
|
+
from .irishrail import IrishRailProvider
|
|
81
|
+
from .tpg import TPGProvider
|
|
68
82
|
|
|
69
83
|
_PROVIDER_REGISTRY: Dict[str, Type[BaseProvider]] = {}
|
|
70
84
|
|
|
@@ -140,3 +154,10 @@ register_provider(PROVIDER_OPT, OPTProvider)
|
|
|
140
154
|
register_provider(PROVIDER_OTP_CUSTOM, OTPCustomProvider)
|
|
141
155
|
register_provider(PROVIDER_NATIONAL_RAIL, NationalRailProvider)
|
|
142
156
|
register_provider(PROVIDER_REJSEPLANEN, RejseplanenProvider)
|
|
157
|
+
register_provider(PROVIDER_NS_NL, NSProvider)
|
|
158
|
+
register_provider(PROVIDER_MOBILITEIT_LU, MobiliteitLuProvider)
|
|
159
|
+
register_provider(PROVIDER_ENTUR_NO, EnturProvider)
|
|
160
|
+
register_provider(PROVIDER_BART_US, BARTProvider)
|
|
161
|
+
register_provider(PROVIDER_DART_US, DARTProvider)
|
|
162
|
+
register_provider(PROVIDER_IRISHRAIL_IE, IrishRailProvider)
|
|
163
|
+
register_provider(PROVIDER_TPG_CH, TPGProvider)
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"""BART — Bay Area Rapid Transit (USA) provider.
|
|
2
|
+
|
|
3
|
+
Modern HAFAS ``mgate.exe`` gateway; unsigned. Config from
|
|
4
|
+
public-transport/transport-apis (``us/bart-hafas-mgate``).
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from ..const import PROVIDER_BART_US
|
|
8
|
+
from .hafas_mgate_base import HafasMgateBaseProvider
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class BARTProvider(HafasMgateBaseProvider):
|
|
12
|
+
"""BART (San Francisco Bay Area) via HAFAS mgate."""
|
|
13
|
+
|
|
14
|
+
mgate_endpoint = "https://planner.bart.gov/bin/mgate.exe"
|
|
15
|
+
mgate_auth = {"type": "AID", "aid": "kEwHkFUCIL500dym"}
|
|
16
|
+
mgate_client = {"id": "BART", "type": "WEB", "name": "webapp", "l": "vs_webapp"}
|
|
17
|
+
mgate_ver = "1.40"
|
|
18
|
+
timezone = "America/Los_Angeles"
|
|
19
|
+
|
|
20
|
+
@property
|
|
21
|
+
def provider_id(self) -> str:
|
|
22
|
+
return PROVIDER_BART_US
|
|
23
|
+
|
|
24
|
+
@property
|
|
25
|
+
def provider_name(self) -> str:
|
|
26
|
+
return "BART (San Francisco Bay Area)"
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"""DART — Des Moines Area Rapid Transit (Iowa, USA) provider.
|
|
2
|
+
|
|
3
|
+
Modern HAFAS ``mgate.exe`` gateway; unsigned. Config from
|
|
4
|
+
public-transport/transport-apis (``us/dart-hafas-mgate``). Note: that catalogue
|
|
5
|
+
entry is titled "Dallas Area Rapid Transit", but the endpoint actually serves
|
|
6
|
+
**Des Moines, Iowa** (DART Central Station, DSM/WDM/Ankeny/Johnston stops) —
|
|
7
|
+
verified live. Iowa is Central time, so the timezone is unchanged.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from ..const import PROVIDER_DART_US
|
|
11
|
+
from .hafas_mgate_base import HafasMgateBaseProvider
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class DARTProvider(HafasMgateBaseProvider):
|
|
15
|
+
"""DART (Des Moines, Iowa) via HAFAS mgate."""
|
|
16
|
+
|
|
17
|
+
mgate_endpoint = "https://dart.hafas.de/bin/mgate.exe"
|
|
18
|
+
mgate_auth = {"type": "AID", "aid": "XNFGL2aSkxfDeK8N4waOZnsdJ"}
|
|
19
|
+
mgate_client = {"id": "DART", "type": "WEB", "name": "webapp", "l": "vs_webapp"}
|
|
20
|
+
mgate_ver = "1.35"
|
|
21
|
+
timezone = "America/Chicago"
|
|
22
|
+
|
|
23
|
+
@property
|
|
24
|
+
def provider_id(self) -> str:
|
|
25
|
+
return PROVIDER_DART_US
|
|
26
|
+
|
|
27
|
+
@property
|
|
28
|
+
def provider_name(self) -> str:
|
|
29
|
+
return "DART (Des Moines)"
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
"""Entur (Norway) provider implementation.
|
|
2
|
+
|
|
3
|
+
Norway's national journey planner. Departures come from Entur's OTP
|
|
4
|
+
**transmodel** GraphQL API and stop search from Entur's geocoder. Both are
|
|
5
|
+
keyless; Entur only requires an identifying ``ET-Client-Name`` header.
|
|
6
|
+
|
|
7
|
+
* geocoder https://api.entur.io/geocoder/v1/autocomplete
|
|
8
|
+
* journeys https://api.entur.io/journey-planner/v3/graphql
|
|
9
|
+
|
|
10
|
+
Catalogued by public-transport/transport-apis as ``no/entur-otp``.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
import logging
|
|
14
|
+
from datetime import datetime
|
|
15
|
+
from typing import Any, Dict, List, Optional, Union
|
|
16
|
+
from urllib.parse import quote
|
|
17
|
+
from zoneinfo import ZoneInfo
|
|
18
|
+
|
|
19
|
+
import aiohttp
|
|
20
|
+
|
|
21
|
+
from ..const import PROVIDER_ENTUR_NO
|
|
22
|
+
from ..models import UnifiedDeparture
|
|
23
|
+
from .base import BaseProvider
|
|
24
|
+
|
|
25
|
+
_LOGGER = logging.getLogger(__name__)
|
|
26
|
+
|
|
27
|
+
GEOCODER_URL = "https://api.entur.io/geocoder/v1/autocomplete"
|
|
28
|
+
JOURNEY_PLANNER_URL = "https://api.entur.io/journey-planner/v3/graphql"
|
|
29
|
+
CLIENT_NAME = "nerdysoftpaw-openpublictransport"
|
|
30
|
+
|
|
31
|
+
# Transmodel transportMode (lower-case) -> unified transport type.
|
|
32
|
+
MODE_MAPPING = {
|
|
33
|
+
"rail": "train",
|
|
34
|
+
"coach": "bus",
|
|
35
|
+
"bus": "bus",
|
|
36
|
+
"trolleybus": "bus",
|
|
37
|
+
"tram": "tram",
|
|
38
|
+
"metro": "subway",
|
|
39
|
+
"water": "ferry",
|
|
40
|
+
"ferry": "ferry",
|
|
41
|
+
"funicular": "train",
|
|
42
|
+
"cableway": "tram",
|
|
43
|
+
"monorail": "subway",
|
|
44
|
+
"taxi": "taxi",
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
_DEPARTURES_QUERY = (
|
|
48
|
+
"query($id:String!,$n:Int!){"
|
|
49
|
+
"stopPlace(id:$id){"
|
|
50
|
+
"estimatedCalls(numberOfDepartures:$n,timeRange:7200){"
|
|
51
|
+
"aimedDepartureTime expectedDepartureTime realtime cancellation "
|
|
52
|
+
"destinationDisplay{frontText} quay{publicCode} "
|
|
53
|
+
"serviceJourney{line{publicCode transportMode}}"
|
|
54
|
+
"}}}"
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def _parse_dt(s: Optional[str]) -> Optional[datetime]:
|
|
59
|
+
try:
|
|
60
|
+
return datetime.fromisoformat(s) if s else None
|
|
61
|
+
except (ValueError, TypeError):
|
|
62
|
+
return None
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class EnturProvider(BaseProvider):
|
|
66
|
+
"""Entur (Norway) via transmodel GraphQL + Entur geocoder."""
|
|
67
|
+
|
|
68
|
+
@property
|
|
69
|
+
def provider_id(self) -> str:
|
|
70
|
+
return PROVIDER_ENTUR_NO
|
|
71
|
+
|
|
72
|
+
@property
|
|
73
|
+
def provider_name(self) -> str:
|
|
74
|
+
return "Entur (Norge)"
|
|
75
|
+
|
|
76
|
+
def get_timezone(self) -> str:
|
|
77
|
+
return "Europe/Oslo"
|
|
78
|
+
|
|
79
|
+
def _headers(self) -> Dict[str, str]:
|
|
80
|
+
return {"ET-Client-Name": CLIENT_NAME, "Accept": "application/json"}
|
|
81
|
+
|
|
82
|
+
async def search_stops(self, search_term: str) -> List[Dict[str, Any]]:
|
|
83
|
+
url = (
|
|
84
|
+
f"{GEOCODER_URL}?text={quote(search_term, safe='')}"
|
|
85
|
+
"&size=12&lang=en&layers=venue"
|
|
86
|
+
)
|
|
87
|
+
try:
|
|
88
|
+
async with self.session.get(
|
|
89
|
+
url, headers=self._headers(), timeout=aiohttp.ClientTimeout(total=10)
|
|
90
|
+
) as response:
|
|
91
|
+
if response.status != 200:
|
|
92
|
+
_LOGGER.error("Entur geocoder returned status %s", response.status)
|
|
93
|
+
return []
|
|
94
|
+
data = await response.json()
|
|
95
|
+
except Exception as e: # noqa: BLE001
|
|
96
|
+
_LOGGER.error("Error searching Entur stops: %s", e)
|
|
97
|
+
return []
|
|
98
|
+
|
|
99
|
+
return self._stops_from_geocoder(data)
|
|
100
|
+
|
|
101
|
+
@staticmethod
|
|
102
|
+
def _stops_from_geocoder(data: Dict[str, Any]) -> List[Dict[str, Any]]:
|
|
103
|
+
results: List[Dict[str, Any]] = []
|
|
104
|
+
for feature in data.get("features", []):
|
|
105
|
+
props = feature.get("properties", {}) if isinstance(feature, dict) else {}
|
|
106
|
+
stop_id = str(props.get("id") or "")
|
|
107
|
+
# Only stop places have a departure board.
|
|
108
|
+
if not stop_id.startswith("NSR:StopPlace:"):
|
|
109
|
+
continue
|
|
110
|
+
name = props.get("label") or props.get("name") or ""
|
|
111
|
+
if not name:
|
|
112
|
+
continue
|
|
113
|
+
results.append(
|
|
114
|
+
{
|
|
115
|
+
"id": stop_id,
|
|
116
|
+
"name": name,
|
|
117
|
+
"place": props.get("locality") or "",
|
|
118
|
+
"area_type": "stop",
|
|
119
|
+
}
|
|
120
|
+
)
|
|
121
|
+
return results
|
|
122
|
+
|
|
123
|
+
async def fetch_departures(
|
|
124
|
+
self,
|
|
125
|
+
station_id: Optional[str],
|
|
126
|
+
place_dm: str,
|
|
127
|
+
name_dm: str,
|
|
128
|
+
departures_limit: int,
|
|
129
|
+
) -> Optional[Dict[str, Any]]:
|
|
130
|
+
if not station_id:
|
|
131
|
+
_LOGGER.warning("Entur provider requires a station_id")
|
|
132
|
+
return None
|
|
133
|
+
|
|
134
|
+
payload = {
|
|
135
|
+
"query": _DEPARTURES_QUERY,
|
|
136
|
+
"variables": {"id": station_id, "n": departures_limit},
|
|
137
|
+
}
|
|
138
|
+
try:
|
|
139
|
+
async with self.session.post(
|
|
140
|
+
JOURNEY_PLANNER_URL,
|
|
141
|
+
json=payload,
|
|
142
|
+
headers=self._headers(),
|
|
143
|
+
timeout=aiohttp.ClientTimeout(total=15),
|
|
144
|
+
) as response:
|
|
145
|
+
if response.status != 200:
|
|
146
|
+
_LOGGER.warning("Entur journey planner returned status %s", response.status)
|
|
147
|
+
return None
|
|
148
|
+
data = await response.json()
|
|
149
|
+
except aiohttp.ClientError as e:
|
|
150
|
+
_LOGGER.warning("Entur journey planner request failed: %s", e)
|
|
151
|
+
return None
|
|
152
|
+
except Exception as e: # noqa: BLE001
|
|
153
|
+
_LOGGER.warning("Entur journey planner error: %s", e)
|
|
154
|
+
return None
|
|
155
|
+
|
|
156
|
+
stop_place = (data.get("data") or {}).get("stopPlace")
|
|
157
|
+
if not stop_place:
|
|
158
|
+
return {"stopEvents": []}
|
|
159
|
+
return {"stopEvents": stop_place.get("estimatedCalls") or []}
|
|
160
|
+
|
|
161
|
+
def parse_departure(
|
|
162
|
+
self, stop: Dict[str, Any], tz: Union[ZoneInfo, Any], now: datetime
|
|
163
|
+
) -> Optional[UnifiedDeparture]:
|
|
164
|
+
try:
|
|
165
|
+
aimed = _parse_dt(stop.get("aimedDepartureTime"))
|
|
166
|
+
if not aimed:
|
|
167
|
+
return None
|
|
168
|
+
expected = _parse_dt(stop.get("expectedDepartureTime")) or aimed
|
|
169
|
+
|
|
170
|
+
planned_local = aimed.astimezone(tz)
|
|
171
|
+
when_local = expected.astimezone(tz)
|
|
172
|
+
delay_minutes = int((when_local - planned_local).total_seconds() / 60)
|
|
173
|
+
|
|
174
|
+
line_info = (stop.get("serviceJourney") or {}).get("line") or {}
|
|
175
|
+
line = line_info.get("publicCode") or ""
|
|
176
|
+
mode = (line_info.get("transportMode") or "").lower()
|
|
177
|
+
transport_type = MODE_MAPPING.get(mode, "unknown")
|
|
178
|
+
|
|
179
|
+
destination = (stop.get("destinationDisplay") or {}).get("frontText") or "Unknown"
|
|
180
|
+
platform = (stop.get("quay") or {}).get("publicCode") or ""
|
|
181
|
+
|
|
182
|
+
minutes_until = max(0, int((when_local - now).total_seconds() / 60))
|
|
183
|
+
|
|
184
|
+
notices = None
|
|
185
|
+
if stop.get("cancellation"):
|
|
186
|
+
notices = ["Cancelled"]
|
|
187
|
+
|
|
188
|
+
return UnifiedDeparture(
|
|
189
|
+
line=line,
|
|
190
|
+
destination=destination,
|
|
191
|
+
departure_time=when_local.strftime("%H:%M"),
|
|
192
|
+
planned_time=planned_local.strftime("%H:%M"),
|
|
193
|
+
delay=delay_minutes,
|
|
194
|
+
platform=platform,
|
|
195
|
+
transportation_type=transport_type,
|
|
196
|
+
is_realtime=bool(stop.get("realtime")),
|
|
197
|
+
minutes_until_departure=minutes_until,
|
|
198
|
+
departure_time_obj=when_local,
|
|
199
|
+
description=None,
|
|
200
|
+
agency=None,
|
|
201
|
+
notices=notices,
|
|
202
|
+
planned_platform=None,
|
|
203
|
+
platform_changed=False,
|
|
204
|
+
)
|
|
205
|
+
except Exception as e: # noqa: BLE001
|
|
206
|
+
_LOGGER.debug("Error parsing Entur departure: %s", e)
|
|
207
|
+
return None
|