diff --git a/gtfs-realtime/proto/gtfs-realtime.proto b/gtfs-realtime/proto/gtfs-realtime.proto index eab8577f8..c65d03eab 100644 --- a/gtfs-realtime/proto/gtfs-realtime.proto +++ b/gtfs-realtime/proto/gtfs-realtime.proto @@ -228,6 +228,21 @@ message TripUpdate { // The stop is skipped, i.e., the vehicle will not stop at this stop. // Arrival and departure are optional. + // NOTE: This field is experimentally deprecated and users should consider using the + // experimental `MODIFIED` enum instead, which is intended to replace `SKIPPED` in favor of + // enabling more real-life scenarios to be represented, such as a vehicle that's running + // late being "drop-off only" to try and catch up back to schedule. In the future, it may be + // decided to completely remove `SKIPPED`, such as by using `reserved` instead, should + // `MODIFIED` be officially adopted as the replacement. If `MODIFIED` is later deprecated, + // `SKIPPED` should be un-deprecated in order to re-signal that it's the primary mechanism + // for communicating that a vehicle will not serve a particular stop. + // In this interim period, users may continue to use this value for compatability. + // However, as per migration-modified.md, feed producers may choose to fully migrate + // to use the more detailed `pickup_type` and `drop_off_type`, with proper + // notification to feed consumers. To represent the same scenario, users + // should use `MODIFIED` along with pickup_type=NO_PICKUP and + // drop_off_type=NO_DROP_OFF instead for when a vehicle will not serve + // a regularly scheduled stop. SKIPPED = 1; // No StopTimeEvents are given for this stop. @@ -245,6 +260,14 @@ message TripUpdate { // NOTE: This field is still experimental, and subject to change. It may be // formally adopted in the future. UNSCHEDULED = 3; + + // A schedule-based vehicle's StopTimeProperties differs from the static schedule in a way that impacts + // the rider experience, such as a vehicle not picking up passengers because a vehicle is "drop-off only" + // to catch up back to schedule when it's running late. StopTimeProperties must included to specify how + // the relationship has been modified. + // NOTE: This field is still experimental, and subject to change. It may be + // formally adopted in the future. + MODIFIED = 4; } optional ScheduleRelationship schedule_relationship = 5 [default = SCHEDULED]; @@ -267,6 +290,62 @@ message TripUpdate { // NOTE: This field is still experimental, and subject to change. It may be formally adopted in the future. optional string assigned_stop_id = 1; + // Supports real-time changes to pickup_type when it differs from what's specified in (CSV) GTFS + // in stop_times.txt. See definition of stop_times.pickup_type in (CSV) GTFS. + // If pickup_type is specified, StopTimeUpdate.schedule_relationship must be MODIFIED for schedule-based service + // unless pickup_type=NO_PICKUP and drop_off_type=NO_DROP_OFF. Then, as per migration-modified.md, + // StopTimeUpdate.schedule_relationship may be SKIPPED in an interim period for compatability reasons. + // For the same reason, when a stop is not fully skipped, StopTimeUpdate.schedule_relationship may be + // SCHEDULED in an interim period. + // NOTE: This field is still experimental, and subject to change. It may be formally adopted in the future. + optional PickupType pickup_type = 2; + + // Supports real-time changes to drop_off_type when it differs from what's specified in (CSV) GTFS + // in stop_times.txt. See definition of stop_times.drop_off_type in (CSV) GTFS. + // If drop_off_type is specified, StopTimeUpdate.schedule_relationship must be MODIFIED for scheduled-based service + // unless drop_off_type=NO_DROP_OFF and pickup_type=NO_PICKUP. Then, as per migration-modified.md, + // StopTimeUpdate.schedule_relationship may be SKIPPED in an interim period for compatability reasons. + // For the same reason, when a stop is not fully skipped, StopTimeUpdate.schedule_relationship may be + // SCHEDULED in an interim period. + // NOTE: This field is still experimental, and subject to change. It may be formally adopted in the future. + optional DropOffType drop_off_type = 3; + + // Indicates the pickup method for an updated stop time when it differs from what's specified in (CSV) GTFS + // in stop_times.txt. By default, if pickup_type is neither specified in real-time or in (CSV) GTFS, it is + // considered REGULAR_PICKUP. + // NOTE: This field is still experimental, and subject to change. It may be formally adopted in the future. + enum PickupType { + // See definition of stop_times.pickup_type=0 in (CSV) GTFS. + REGULAR_PICKUP = 0; + + // See definition of stop_times.pickup_type=1 in (CSV) GTFS. + NO_PICKUP = 1; + + // See definition of stop_times.pickup_type=2 in (CSV) GTFS. + MUST_PHONE_AGENCY_PICKUP = 2; + + // See definition of stop_times.pickup_type=3 in (CSV) GTFS. + MUST_ASK_DRIVER_PICKUP = 3; + } + + // Indicates the drop off method for an updated stop time when it differs from what's specified in (CSV) GTFS + // in stop_times.txt. By default, if drop_off_type is neither specified in real-time or in (CSV) GTFS, it is + // considered REGULAR_DROP_OFF. + // NOTE: This field is still experimental, and subject to change. It may be formally adopted in the future. + enum DropOffType { + // See definition of stop_times.drop_off_type=0 in (CSV) GTFS. + REGULAR_DROP_OFF = 0; + + // See definition of stop_times.drop_off_type=1 in (CSV) GTFS. + NO_DROP_OFF = 1; + + // See definition of stop_times.drop_off_type=2 in (CSV) GTFS. + MUST_PHONE_AGENCY_DROP_OFF = 2; + + // See definition of stop_times.drop_off_type=3 in (CSV) GTFS. + MUST_ASK_DRIVER_DROP_OFF = 3; + } + // The extensions namespace allows 3rd-party developers to extend the // GTFS Realtime Specification in order to add and evaluate new features // and modifications to the spec. diff --git a/gtfs-realtime/spec/en/examples/migration-modified.md b/gtfs-realtime/spec/en/examples/migration-modified.md new file mode 100644 index 000000000..1f7909c6b --- /dev/null +++ b/gtfs-realtime/spec/en/examples/migration-modified.md @@ -0,0 +1,44 @@ +## Migration Guide - Transition from SKIPPED to MODIFIED + +The GTFS-realtime `StopTimeUpdate.schedule_relationship` of `SKIPPED`, which is now experimentally deprecated, was used to indicate that a vehicle will not be serving a particular stop that was originally scheduled as a part of `stop_times.txt` in GTFS-static. + +The GTFS-static `pickup_type` and `drop_off_type` fields within `stop_times.txt` allow an agency to specify details on what a rider needs to do in order to board/alight at a given stop (e.g. a rider must explicitly request a drop-off at a stop, otherwise the driver will skip the stop). + +This migration guide defines how existing producers who use the `SKIPPED` enumeration for indicating that vehicle will not stop at a given stop or as a best approximation of partial service at a stop can provide a more nuanced picture of the level of service through `pickup_type` and `drop_off_type` via `StopTimeProperties` instead. The goal is to minimize disruption to producers and consumers during the transition. + +See the [Add pickup and drop-off types to GTFS-RT proposal on GitHub](https://github.com/google/transit/pull/265). + +### Initially providing SKIPPED and pickup_type / drop_off_type in same feed + +#### Producers + +If you are a producer who uses the `SKIPPED` enumeration for indicating that a vehicle will not stop at a given stop or as a best approximation of partial service at a stop, it is recommended that you continue to produce `SKIPPED` entities for those stop time updates but also add `pickup_type` and `drop_off_type` entities for the same `StopTimeUpdate`, such as a `NO_PICKUP` and `NO_DROP_OFF` for a stop that's will not be made. + +Here's an example of indicating to consumers that a vehicle will be "drop-off only": + +~~~ +entity { + id: "ei0" + trip_update { + ... + stop_time_update { + ... + schedule_relationship: SKIPPED + + stop_time_properties { + pickup_type: NO_PICKUP + drop_off_type: MUST_ASK_DRIVER_DROP_OFF + } + } + } +} +~~~ + +When a stop is not fully skipped and you'd like to provide additional information through `pickup_type` and `drop_off_type`, you may also use `SCHEDULED` in the interim. + +It is suggested that you notify existing consumers (e.g., via a developer mailing list) that the use of `SKIPPED` is being deprecated in favor of more nuanced information using `MODIFIED` by a set deadline and that consumers should start consuming the `MODIFIED` enumeration as well as `pickup_type` and `drop_off_type`. You should also provide a link to this migration guide. After the deadline passes, you can stop using `SKIPPED` entities for scenarios where `pickup_type` or `drop_off_type` are included and start using `MODIFIED` instead. + +#### Consumers +In this interim period, when `pickup_type` and `drop_off_type` are set in `StopTimeProperties`, it takes precedence over `schedule_relationship=SKIPPED` or `schedule_relationship=SCHEDULED`, meaning that the definitions of `SKIPPED` and `SCHEDULED` do not apply. Real-time arrival information should still be used to inform passengers rather being potentially ignored when `SKIPPED`. For example, a passenger-facing application could use this additional information to provide additional instructions or notification on how to board/alight, similar to what may happen with those fields being specified statically in `stop_times.txt`. + +In the future, instead of `SKIPPED`, as per above, you should expect `MODIFIED` instead, with `pickup_type=NO_PICKUP` and `drop_off_type=NO_DROP_OFF` in scenarios where a vehicle will entirely skip a scheduled stop. diff --git a/gtfs-realtime/spec/en/reference.md b/gtfs-realtime/spec/en/reference.md index 383d68012..5eda62528 100644 --- a/gtfs-realtime/spec/en/reference.md +++ b/gtfs-realtime/spec/en/reference.md @@ -184,8 +184,8 @@ The update is linked to a specific stop either through stop_sequence or stop_id, |------------------|------------|----------------|-------------------|-------------------| | **stop_sequence** | [uint32](https://developers.google.com/protocol-buffers/docs/proto#scalar) | Conditionally required | One | Must be the same as in stop_times.txt in the corresponding GTFS feed. Either stop_sequence or stop_id must be provided within a StopTimeUpdate - both fields cannot be empty. stop_sequence is required for trips that visit the same stop_id more than once (e.g., a loop) to disambiguate which stop the prediction is for. If `StopTimeProperties.assigned_stop_id` is populated, then `stop_sequence` must be populated. | | **stop_id** | [string](https://developers.google.com/protocol-buffers/docs/proto#scalar) | Conditionally required | One | Must be the same as in stops.txt in the corresponding GTFS feed. Either stop_sequence or stop_id must be provided within a StopTimeUpdate - both fields cannot be empty. If `StopTimeProperties.assigned_stop_id` is populated, it is preferred to omit `stop_id` and use only `stop_sequence`. If `StopTimeProperties.assigned_stop_id` and `stop_id` are populated, `stop_id` must match `assigned_stop_id`. | -| **arrival** | [StopTimeEvent](#message-stoptimeevent) | Conditionally required | One | If schedule_relationship is empty or SCHEDULED, either arrival or departure must be provided within a StopTimeUpdate - both fields cannot be empty. arrival and departure may both be empty when schedule_relationship is SKIPPED. If schedule_relationship is NO_DATA, arrival and departure must be empty. | -| **departure** | [StopTimeEvent](#message-stoptimeevent) | Conditionally required | One | If schedule_relationship is empty or SCHEDULED, either arrival or departure must be provided within a StopTimeUpdate - both fields cannot be empty. arrival and departure may both be empty when schedule_relationship is SKIPPED. If schedule_relationship is NO_DATA, arrival and departure must be empty. | +| **arrival** | [StopTimeEvent](#message-stoptimeevent) | Conditionally required | One | If schedule_relationship is empty or SCHEDULED, either arrival or departure must be provided within a StopTimeUpdate - both fields cannot be empty. arrival and departure may both be empty when the vehicle will not be stopping at all (previously SKIPPED (deprecated), now NO_PICKUP and NO_DROP_OFF) or if only `StopTimeProperties` is being updated when schedule_relationship is MODIFIED but no real-time timing is available. If schedule_relationship is NO_DATA, arrival and departure must be empty. | +| **departure** | [StopTimeEvent](#message-stoptimeevent) | Conditionally required | One | If schedule_relationship is empty or SCHEDULED, either arrival or departure must be provided within a StopTimeUpdate - both fields cannot be empty. arrival and departure may both be empty when the vehicle will not be stopping at all (previously SKIPPED (deprecated), now NO_PICKUP and NO_DROP_OFF) or if only `StopTimeProperties` is being updated when schedule_relationship is MODIFIED but no real-time timing is available. If schedule_relationship is NO_DATA, arrival and departure must be empty. | | **departure_occupancy_status** | [OccupancyStatus](#enum-occupancystatus) | Optional | One | The predicted state of passenger occupancy for the vehicle immediately after departure from the given stop. If provided, stop_sequence must be provided. To provide departure_occupancy_status without providing any real-time arrival or departure predictions, populate this field and set StopTimeUpdate.schedule_relationship = NO_DATA.

**Caution:** this field is still **experimental**, and subject to change. It may be formally adopted in the future. | | **schedule_relationship** | [ScheduleRelationship](#enum-schedulerelationship) | Optional | One | The default relationship is SCHEDULED. | | **stop_time_properties** | [StopTimeProperties](#message-stoptimeproperties) | Optional | One | Realtime updates for certain properties defined within GTFS stop_times.txt

**Caution:** this field is still **experimental**, and subject to change. It may be formally adopted in the future. | @@ -199,9 +199,10 @@ The relation between this StopTime and the static schedule. | _**Value**_ | _**Comment**_ | |-------------|---------------| | **SCHEDULED** | The vehicle is proceeding in accordance with its static schedule of stops, although not necessarily according to the times of the schedule. This is the **default** behavior. At least one of arrival and departure must be provided. Frequency-based trips (GTFS frequencies.txt with exact_times = 0) should not have a SCHEDULED value and should use UNSCHEDULED instead. | -| **SKIPPED** | The stop is skipped, i.e., the vehicle will not stop at this stop. Arrival and departure are optional. When set `SKIPPED` is not propagated to subsequent stops in the same trip (i.e., the vehicle will stop at subsequent stops in the trip unless those stops also have a `stop_time_update` with `schedule_relationship: SKIPPED`). Delay from a previous stop in the trip *does* propagate over the `SKIPPED` stop. In other words, if a `stop_time_update` with an `arrival` or `departure` prediction is not set for a stop after the `SKIPPED` stop, the prediction upstream of the `SKIPPED` stop will be propagated to the stop after the `SKIPPED` stop and subsequent stops in the trip until a `stop_time_update` for a subsequent stop is provided. | +| **SKIPPED** | (Experimentally deprecated) The stop is skipped, i.e., the vehicle will not stop at this stop. Arrival and departure are optional. When set `SKIPPED` is not propagated to subsequent stops in the same trip (i.e., the vehicle will stop at subsequent stops in the trip unless those stops also have a `stop_time_update` with `schedule_relationship: SKIPPED`). Delay from a previous stop in the trip *does* propagate over the `SKIPPED` stop. In other words, if a `stop_time_update` with an `arrival` or `departure` prediction is not set for a stop after the `SKIPPED` stop, the prediction upstream of the `SKIPPED` stop will be propagated to the stop after the `SKIPPED` stop and subsequent stops in the trip until a `stop_time_update` for a subsequent stop is provided.

**Caution:** this field is being **experimentally deprecated** and users should consider using the experimental `MODIFIED` enum instead, which is intended to replace `SKIPPED` in favor of enabling more real-life scenarios to be represented, such as a vehicle that's running late being "drop-off only" to try and catch up back to schedule. In this interim period, users may continue to use this value for compatability. To represent the same scenario, users should use `MODIFIED` along with `pickup_type=NO_PICKUP` and `drop_off_type=NO_DROP_OFF` instead for when a vehicle will not serve a regularly scheduled stop. | | **NO_DATA** | No data is given for this stop. It indicates that there is no realtime timing information available. When set NO_DATA is propagated through subsequent stops so this is the recommended way of specifying from which stop you do not have realtime timing information. When NO_DATA is set neither arrival nor departure should be supplied. | | **UNSCHEDULED** | The vehicle is operating a frequency-based trip (GTFS frequencies.txt with exact_times = 0). This value should not be used for trips that are not defined in GTFS frequencies.txt, or trips in GTFS frequencies.txt with exact_times = 1. Trips containing `stop_time_updates` with `schedule_relationship: UNSCHEDULED` must also set the TripDescriptor `schedule_relationship: UNSCHEDULED`

**Caution:** this field is still **experimental**, and subject to change. It may be formally adopted in the future. +| **MODIFIED** | The vehicle's relationship with the static schedule differs in a way that impacts the rider experience, such as a vehicle not picking up passengers because a vehicle is "drop-off only" to catch up back to schedule when it's running late. StopTimeProperties must included to specify how the relationship has been modified.

**Caution:** this field is still **experimental**, and subject to change. It may be formally adopted in the future. ## _message_ StopTimeProperties @@ -214,6 +215,38 @@ Realtime update for certain properties defined within GTFS stop_times.txt. | _**Field Name**_ | _**Type**_ | _**Required**_ | _**Cardinality**_ | _**Description**_ | |------------------|------------|----------------|-------------------|-------------------| | **assigned_stop_id** | [string](https://developers.google.com/protocol-buffers/docs/proto#scalar) | Optional | One | Supports real-time stop assignments. Refers to a `stop_id` defined in the GTFS `stops.txt`.
The new `assigned_stop_id` should not result in a significantly different trip experience for the end user than the `stop_id` defined in GTFS `stop_times.txt`. In other words, the end user should not view this new `stop_id` as an "unusual change" if the new stop was presented within an app without any additional context. For example, this field is intended to be used for platform assignments by using a `stop_id` that belongs to the same station as the stop originally defined in GTFS `stop_times.txt`.
To assign a stop without providing any real-time arrival or departure predictions, populate this field and set `StopTimeUpdate.schedule_relationship = NO_DATA`.
If this field is populated, `StopTimeUpdate.stop_sequence` must be populated and `StopTimeUpdate.stop_id` should not be populated. Stop assignments should be reflected in other GTFS-realtime fields as well (e.g., `VehiclePosition.stop_id`).

**Caution:** this field is still **experimental**, and subject to change. It may be formally adopted in the future. | +| **pickup_type** | [PickupType](#enum-pickuptype) | Optional | One | Supports real-time changes to pickup_type when it differs from what's specified in (CSV) GTFS in `stop_times.txt`. See definition of `stop_times.pickup_type` in (CSV) GTFS. If `pickup_type` is specified, `StopTimeUpdate.schedule_relationship` must be `MODIFIED` for schedule-based service unless pickup_type=NO_PICKUP and drop_off_type=NO_DROP_OFF. Then, as per migration-modified.md, StopTimeUpdate.schedule_relationship may be SKIPPED in an interim period for compatability reasons. For the same reason, when a stop is not fully skipped, StopTimeUpdate.schedule_relationship may be SCHEDULED in an interim period.

**Caution:** this field is still **experimental**, and subject to change. It may be formally adopted in the future. | +| **drop_off_type** | [DropOffType](#enum-dropofftype) | Optional | One | Supports real-time changes to drop_off_type when it differs from what's specified in (CSV) GTFS in `stop_times.txt`. See definition of `stop_times.drop_off_type` in (CSV) GTFS. If drop_off_type is specified, `StopTimeUpdate.schedule_relationship` must be `MODIFIED` for schedule-based service unless drop_off_type=NO_DROP_OFF and pickup_type=NO_PICKUP. Then, as per migration-modified.md, StopTimeUpdate.schedule_relationship may be SKIPPED in an interim period for compatability reasons. For the same reason, when a stop is not fully skipped, StopTimeUpdate.schedule_relationship may be SCHEDULED in an interim period.

**Caution:** this field is still **experimental**, and subject to change. It may be formally adopted in the future. | + +## _enum_ PickupType + +Indicates the pickup method for an updated stop time when it differs from what's specified in (CSV) GTFS in stop_times.txt By default, if pickup_type is neither specified in real-time or in (CSV) GTFS, it is considered REGULAR_PICKUP. + +**Caution:** this field is still **experimental**, and subject to change. It may be formally adopted in the future. + +#### Values + +| _**Value**_ | _**Comment**_ | +|-------------|---------------| +| **REGULAR_PICKUP** | See definition of stop_times.pickup_type=0 in (CSV) GTFS. | +| **NO_PICKUP** | See definition of stop_times.pickup_type=1 in (CSV) GTFS. | +| **MUST_PHONE_AGENCY_PICKUP** | See definition of stop_times.pickup_type=2 in (CSV) GTFS. | +| **MUST_ASK_DRIVER_PICKUP** | See definition of stop_times.pickup_type=3 in (CSV) GTFS. | + +## _enum_ DropOffType + +Indicates the drop off method for an updated stop time when it differs from what's specified in (CSV) GTFS in stop_times.txt. By default, if drop_off_type is neither specified in real-time or in (CSV) GTFS, it is considered REGULAR_DROP_OFF. + +**Caution:** this field is still **experimental**, and subject to change. It may be formally adopted in the future. + +#### Values + +| _**Value**_ | _**Comment**_ | +|-------------|---------------| +| **REGULAR_DROP_OFF** | See definition of stop_times.drop_off_type=0 in (CSV) GTFS. | +| **NO_DROP_OFF** | See definition of stop_times.drop_off_type=1 in (CSV) GTFS. | +| **MUST_PHONE_AGENCY_DROP_OFF** | See definition of stop_times.drop_off_type=2 in (CSV) GTFS. | +| **MUST_ASK_DRIVER_DROP_OFF** | See definition of stop_times.drop_off_type=3 in (CSV) GTFS. | ## _message_ TripProperties diff --git a/gtfs-realtime/spec/en/trip-updates.md b/gtfs-realtime/spec/en/trip-updates.md index ec45bee66..8556e131f 100644 --- a/gtfs-realtime/spec/en/trip-updates.md +++ b/gtfs-realtime/spec/en/trip-updates.md @@ -23,11 +23,11 @@ Each [StopTimeUpdate](reference.md#StopTimeUpdate) is linked to a stop. Ordinari The update can provide a exact timing for **arrival** and/or **departure** at a stop in [StopTimeUpdates](reference.md#StopTimeUpdate) using [StopTimeEvent](reference.md#StopTimeEvent). This should contain either an absolute **time** or a **delay** (i.e. an offset from the scheduled time in seconds). Delay can only be used in case the trip update refers to a scheduled GTFS trip, as opposed to a frequency-based trip. In this case, time should be equal to scheduled time + delay. You may also specify **uncertainty** of the prediction along with [StopTimeEvent](reference.md#StopTimeEvent), which is discussed in more detail in section [Uncertainty](#uncertainty) further down the page. -For each [StopTimeUpdate](reference.md#StopTimeUpdate), the default schedule relationship is **scheduled**. (Note that this is different from the schedule relationship for the trip). You may change this to **skipped** if the stop will not be stopped at, or **no data** if you only have realtime data for some of the trip. +For each [StopTimeUpdate](reference.md#StopTimeUpdate), the default schedule relationship is **scheduled**. (Note that this is different from the schedule relationship for the trip). You may change this to **skipped** if the stop will not be stopped at, **modified** if stop time properties are different than what's specified in `stop_times.txt`, or **no data** if you only have realtime data for some of the trip. **Updates should be sorted by stop_sequence** (or stop_ids in the order they occur in the trip). -If one or more stops are missing along the trip the `delay` from the update (or, if only `time` is provided in the update, a delay computed by comparing the `time` against the GTFS schedule time) is propagated to all subsequent stops. This means that updating a stop time for a certain stop will change all subsequent stops in the absence of any other information. Note that updates with a schedule relationship of `SKIPPED` will not stop delay propagation, but updates with schedule relationships of `SCHEDULED` (also the default value if schedule relationship is not provided) or `NO_DATA` will. +If one or more stops are missing along the trip the `delay` from the update (or, if only `time` is provided in the update, a delay computed by comparing the `time` against the GTFS schedule time) is propagated to all subsequent stops. This means that updating a stop time for a certain stop will change all subsequent stops in the absence of any other information. Note that updates with a schedule relationship of `SKIPPED` or `MODIFIED` will not stop delay propagation, but updates with schedule relationships of `SCHEDULED` (also the default value if schedule relationship is not provided) or `NO_DATA` will. **Example 1**