bolster.data_sources.translink.departures ========================================= .. py:module:: bolster.data_sources.translink.departures .. autoapi-nested-parse:: Translink scheduled and real-time departure boards. Provides next-N departure information from any Translink stop using the undocumented Translink journey planner API (translink.co.uk). Two-step workflow: 1. Resolve a stop name to a Translink internal StopId via ``find_stop_id()``. 2. Fetch the next N departures from that stop via ``get_departures()``. Alternatively, use ``get_departures_by_name()`` as a single-call convenience wrapper that resolves the stop name and returns departures in one step. Departure times are returned as timezone-aware pandas Timestamps (UTC). ``SysActualDepartureDate`` in the API response is a .NET ``DateTime`` ticks value (100-nanosecond intervals since 0001-01-01 00:00:00 UTC); these are decoded via :func:`~bolster.data_sources.translink._base.net_ticks_to_timestamp`. .. rubric:: Example >>> deps = get_departures_by_name("Shankill, Cambria Street", n=3) >>> set(deps.columns) >= {"planned_departure", "actual_departure", "service", "destination"} True >>> len(deps) >= 1 True Attributes ---------- .. autoapisummary:: bolster.data_sources.translink.departures.logger Functions --------- .. autoapisummary:: bolster.data_sources.translink.departures.find_stop_id bolster.data_sources.translink.departures.get_departures bolster.data_sources.translink.departures.get_departures_by_name bolster.data_sources.translink.departures.validate_departures bolster.data_sources.translink.departures.get_departures_with_vehicles bolster.data_sources.translink.departures.get_direct_journeys Module Contents --------------- .. py:data:: logger .. py:function:: find_stop_id(query) Return the Translink internal StopId for the first result matching *query*. :param query: Partial or full stop name, e.g. ``"Cambria Street"`` or a NaPTAN ATCOCode such as ``"700000014482"``. :returns: Translink internal StopId string (e.g. ``"10012778"``). :raises TranslinkDataNotFoundError: If no stop matches the query. .. py:function:: get_departures(stop_id, n = 5, dt = None) Return the next *n* departures from a stop identified by Translink StopId. The API returns up to 8 departures per call. If more are needed, subsequent calls advance the ``DepartureOrArrivalDate`` to fetch additional pages. :param stop_id: Translink internal StopId (e.g. ``"10012778"``). Obtain via :func:`find_stop_id`. :param n: Number of departures to return (default 5). The API returns at most 8 per call; additional pages are fetched automatically if needed. :param dt: Reference datetime for the first departure (default: now, UTC). :returns: ``planned_departure`` (Timestamp[UTC]), ``actual_departure`` (Timestamp[UTC]), ``service`` (str), ``destination`` (str), ``transport_mode`` (str), ``is_real_time`` (bool), ``is_cancelled`` (bool), ``delay_minutes`` (float), ``unique_id`` (str). :rtype: DataFrame with columns :raises TranslinkDataNotFoundError: If the API request fails. :raises TranslinkValidationError: If the API returns an unexpected response. .. py:function:: get_departures_by_name(stop_name, n = 5, dt = None) Return the next *n* departures from a stop resolved by name. Convenience wrapper that calls :func:`find_stop_id` then :func:`get_departures`. :param stop_name: Stop name or NaPTAN ATCOCode to search for. :param n: Number of departures to return (default 5). :param dt: Reference datetime (default: now, UTC). :returns: DataFrame as returned by :func:`get_departures`, with an additional ``stop_name`` column showing the resolved stop name. :raises TranslinkDataNotFoundError: If the stop cannot be found or the API fails. .. py:function:: validate_departures(df) Validate that a departures DataFrame has the expected schema and values. :param df: DataFrame as returned by :func:`get_departures`. :returns: True if validation passes. :raises TranslinkValidationError: If required columns are missing or values are invalid. .. py:function:: get_departures_with_vehicles(stop_name, n = 5, dt = None, enrich_stops = False) Return next-N departures enriched with live vehicle positions where available. Fetches departures and live VMI vehicles in parallel (two API calls), then joins on line + direction + journey time proximity (±60 minute window). VMI vehicles are matched to departures by: 1. Line number (case-insensitive). 2. Inferred direction (inbound = destination contains "Belfast"/"CastleCourt"/ "Royal Avenue"/"City Centre"; outbound = everything else). 3. Journey ID (HHMM) within ±60 minutes of the actual departure time. Not all departures will have a matched vehicle — buses that have not yet started their journey are not yet in the VMI feed. :param stop_name: Stop name to search for (resolved via :func:`find_stop_id`). :param n: Number of departures to return (default 5). :param dt: Reference datetime (default: now, UTC). :param enrich_stops: If True, include ``current_stop_name`` and ``next_stop_name`` for matched vehicles. :returns: ``vehicle_id``, ``vehicle_lat``, ``vehicle_lon``, ``vehicle_delay_s``, ``current_stop``, ``next_stop``, and (if enrich_stops) ``current_stop_name``, ``next_stop_name``. Vehicle columns are ``None`` / ``NaN`` where no match. :rtype: DataFrame with all departure columns plus optional vehicle columns .. py:function:: get_direct_journeys(origin, destination, n = 5, dt = None) Return the next *n* direct bus/rail journeys between two stops. Uses the CIF timetable data (Metro/Glider and Ulsterbus/GoldLine) to find services that call at both stops in order, without requiring a change. No network calls are made beyond resolving stop names; all routing is done from the locally cached timetable. The workflow is: 1. Resolve both stop names to NaPTAN ATCOCodes via the CIF stop lookup. 2. Find all trips in the timetable that call at the origin before the destination (``find_direct_trips``). 3. Filter to trips whose scheduled origin departure is at or after *dt*, sorted by departure time. 4. Return the first *n* matching trips. :param origin: Origin stop name (resolved via :func:`~.stops.find_stop`). :param destination: Destination stop name. :param n: Maximum number of journeys to return (default 5). :param dt: Reference datetime (default: now, local Europe/London time). :returns: ``origin``, ``destination``, ``service``, ``scheduled_departure`` (HHMM str), ``scheduled_arrival`` (HHMM str), ``days``, ``direction``. :rtype: DataFrame with columns :raises TranslinkDataNotFoundError: If either stop cannot be resolved, or if no direct service runs between them at all.